r24667: Finally merge the registry improvements that Wilco Baan Hofman and I have
authorJelmer Vernooij <jelmer@samba.org>
Sun, 26 Aug 2007 15:16:40 +0000 (15:16 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 20:02:34 +0000 (15:02 -0500)
been working on for at least half a year now. Contains the following
improvements:

 * proper layering (finally!) for the registry library. Distinction is
   now made between 'real' backends (local, remote, wine, etc) and
   the low-level hive backends (regf, creg, ldb, ...) that are only used
   by the local registry backend
 * tests for all important hive and registry operations
 * re-enable RPC-WINREG tests (still needs more work though, as
   some return values aren't checked yet)
 * write support for REGF files
 * dir backend now supports setting/reading values, creating keys
 * support for storing security descriptors
 * remove CREG backend as it was incomplete, didn't match the data model
   and wasn't used at all anyway
 * support for parsing ADM files as used by the policy editor (see lib/policy)
 * support for parsing PREG files (format used by .POL files)
 * new streaming interface for registry diffs (improves speed and memory usage
for regdiff/regpatch significantly)

   ... and fixes a large number of bugs in the registry code

63 files changed:
.bzrignore
BRANCH.TODO [new file with mode: 0644]
source/lib/basic.mk
source/lib/policy/adm.h [new file with mode: 0644]
source/lib/policy/config.mk [new file with mode: 0644]
source/lib/policy/dumpadm.c [new file with mode: 0644]
source/lib/policy/lex.l [new file with mode: 0644]
source/lib/policy/parse_adm.y [new file with mode: 0644]
source/lib/registry/Doxyfile
source/lib/registry/README
source/lib/registry/TODO
source/lib/registry/common/reg_interface.c [deleted file]
source/lib/registry/config.mk
source/lib/registry/dir.c [new file with mode: 0644]
source/lib/registry/hive.c [new file with mode: 0644]
source/lib/registry/hive.h [new file with mode: 0644]
source/lib/registry/interface.c [new file with mode: 0644]
source/lib/registry/ldb.c [new file with mode: 0644]
source/lib/registry/local.c [new file with mode: 0644]
source/lib/registry/man/regdiff.1.xml
source/lib/registry/man/regpatch.1.xml
source/lib/registry/man/regshell.1.xml
source/lib/registry/man/regtree.1.xml
source/lib/registry/patchfile.c
source/lib/registry/patchfile.h [new file with mode: 0644]
source/lib/registry/patchfile_dotreg.c [new file with mode: 0644]
source/lib/registry/patchfile_preg.c [new file with mode: 0644]
source/lib/registry/reg_backend_dir.c [deleted file]
source/lib/registry/reg_backend_ldb.c [deleted file]
source/lib/registry/reg_backend_nt4.c [deleted file]
source/lib/registry/reg_backend_w95.c [deleted file]
source/lib/registry/regf.c [new file with mode: 0644]
source/lib/registry/regf.idl
source/lib/registry/registry.h
source/lib/registry/rpc.c [moved from source/lib/registry/reg_backend_rpc.c with 57% similarity]
source/lib/registry/samba.c [moved from source/lib/registry/reg_samba.c with 57% similarity]
source/lib/registry/tests/diff.c [new file with mode: 0644]
source/lib/registry/tests/generic.c
source/lib/registry/tests/hive.c [new file with mode: 0644]
source/lib/registry/tests/registry.c [new file with mode: 0644]
source/lib/registry/tools/common.c [new file with mode: 0644]
source/lib/registry/tools/regdiff.c
source/lib/registry/tools/regpatch.c
source/lib/registry/tools/regshell.c
source/lib/registry/tools/regtree.c
source/lib/registry/util.c [moved from source/lib/registry/common/reg_util.c with 74% similarity]
source/lib/registry/wine.c [moved from source/lib/registry/reg_backend_wine.c with 96% similarity]
source/lib/util/become_daemon.c
source/rpc_server/handles.c
source/rpc_server/winreg/rpc_winreg.c
source/samba4-skip
source/script/lex_compile.sh
source/scripting/ejs/smbcalls_ldb.c
source/setup/provision.reg [new file with mode: 0644]
source/smbd/server.c
source/torture/local/config.mk
source/torture/ndr/winreg.c
source/torture/rpc/handles.c
source/torture/rpc/rpc.c
source/torture/rpc/winreg.c
source/torture/ui.c
source/torture/ui.h
webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/translation/C.po

index a95a27c233c18acd815d4c5c5ff0a31087f52640..c0eb35d4e32832242f6c4f72b5cef7f239c59b52 100644 (file)
@@ -143,9 +143,19 @@ source/smbd/pidfile.h
 source/torture/rap/proto.h
 *_asn1.h
 *_asn1_files
-*_err.c
+*_proto.h
+source/heimdal/lib/hx509/asn1_*.c
 *_err.h
+*_err.c
+source/smbd/pidfile.h
+source/ntvfs/cifs_posix_cli/proto.h
+source/lib/util/util_tdb.h
+source/lib/cmdline/popt_credentials.h
+source/lib/policy/lex.c
+source/lib/policy/parse_adm.c
+source/lib/policy/parse_adm.h
 source/heimdal/lib/roken/err.h
+source/kdc/pac_glue.h
 source/scripting/ejs/ejsnet/proto.h
 source/heimdal/lib/hx509/asn1_*.c
 *.gcno
@@ -160,6 +170,7 @@ source/coverage
 source/st
 source/samba.info
 source/pidl/cover_db
+source/lib/registry/apidocs
 source/dsdb/repl/drepl_service_proto.h
 webapps/qooxdoo-0.6.5-sdk/frontend/framework/.cache
 webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/data
@@ -169,6 +180,7 @@ webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/class/qx/locale/translation
 webapps/qooxdoo-0.6.5-sdk/frontend/framework/source/translation/messages.pot
 source/torture/ndr/proto.h
 source/bin/modules/*
+source/lib/registry/API
 source/tests
 source/torture/unix/proto.h
 source/lib/tdb/bin/tdbtool
@@ -182,3 +194,5 @@ source/lib/ldb/examples/ldbreader
 source/lib/ldb/examples/ldifreader
 source/lib/tdb/bin/tdbbackup
 source/lib/tdb/bin/tdbdump
+source/lib/registry/tools/common.h
+source/librpc/ndr/ndr_table.h
diff --git a/BRANCH.TODO b/BRANCH.TODO
new file mode 100644 (file)
index 0000000..afa2ef7
--- /dev/null
@@ -0,0 +1,5 @@
+The following things still need to be fixed before this branch 
+can be merged:
+- RPC-WINREG
+- tests for diff functionality
+- test for classname and last_mod_time being kept
index 0f61ac6549ce9f102268da3e7533206465ea05cd..e993207b007c8caefe11217176da86272b076382 100644 (file)
@@ -5,6 +5,7 @@ include charset/config.mk
 include ldb/config.mk
 include tls/config.mk
 include registry/config.mk
+include policy/config.mk
 include messaging/config.mk
 include events/config.mk
 include cmdline/config.mk
diff --git a/source/lib/policy/adm.h b/source/lib/policy/adm.h
new file mode 100644 (file)
index 0000000..5751261
--- /dev/null
@@ -0,0 +1,48 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Copyright (C) 2006 Wilco Baan Hofman <wilco@baanhofman.nl>
+   Copyright (C) 2006 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.
+*/
+
+#ifndef __ADM_H__
+#define __ADM_H__
+
+struct adm_file {
+       struct adm_class *classes;
+};
+
+struct adm_class {
+       struct adm_category *categories;
+};
+
+struct adm_category {
+       struct adm_category *subcategories;
+       struct adm_policy *policies;
+};
+
+struct adm_policy {
+       struct adm_part *parts;
+
+};
+
+struct adm_part {
+       
+};
+
+struct adm_file *adm_read_file(const char *);
+
+#endif /* __ADM_H__ */
diff --git a/source/lib/policy/config.mk b/source/lib/policy/config.mk
new file mode 100644 (file)
index 0000000..f404d58
--- /dev/null
@@ -0,0 +1,12 @@
+[LIBRARY::LIBPOLICY]
+CFLAGS = -Iheimdal/lib/roken
+OBJ_FILES = lex.o parse_adm.o 
+PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBSAMBA-CONFIG LIBTALLOC CHARSET 
+
+lib/policy/lex.l: lib/policy/parse_adm.h
+
+lib/policy/parse_adm.h: lib/policy/parse_adm.c
+
+[BINARY::dumpadm]
+OBJ_FILES = dumpadm.o
+PRIVATE_DEPENDENCIES = LIBPOLICY LIBPOPT LIBSAMBA-CONFIG LIBTALLOC LIBSAMBA-UTIL CHARSET
diff --git a/source/lib/policy/dumpadm.c b/source/lib/policy/dumpadm.c
new file mode 100644 (file)
index 0000000..aba0915
--- /dev/null
@@ -0,0 +1,54 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Copyright (C) 2006 Wilco Baan Hofman <wilco@baanhofman.nl>
+   Copyright (C) 2006 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/popt/popt.h"
+#include "lib/policy/adm.h"
+
+int main(int argc, char **argv) 
+{
+       BOOL ret = True;
+       poptContext pc;
+       struct poptOption long_options[] = {
+               POPT_AUTOHELP
+               { 0, 0, 0, 0 }
+       };
+       
+       pc = poptGetContext(argv[0], argc, (const char **)argv, long_options, 0);
+       
+       poptSetOtherOptionHelp(pc, "<ADM-FILE> ...");
+
+       while ((poptGetNextOpt(pc) != -1)) 
+
+       if(!poptPeekArg(pc)) { 
+               poptPrintUsage(pc, stderr, 0);
+               exit(1);
+       }
+       
+       while (poptPeekArg(pc)) {
+               const char *name = poptGetArg(pc);
+
+               adm_read_file(name);
+       }
+
+       poptFreeContext(pc);
+
+       return ret;
+}
diff --git a/source/lib/policy/lex.l b/source/lib/policy/lex.l
new file mode 100644 (file)
index 0000000..1157bca
--- /dev/null
@@ -0,0 +1,142 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Copyright (C) 2006 Wilco Baan Hofman <wilco@baanhofman.nl>
+   Copyright (C) 2006 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/policy/parse_adm.h"
+void error_message (const char *format, ...);
+int yyparse (void);
+
+static int lineno = 1;
+static bool utf16 = false;
+
+#define YY_INPUT(buf,result,max_size) \
+{ \
+       if (utf16) { \
+               uint16_t v; \
+               if (fread(&v, 2, 1, yyin) < 1) \
+                       result = YY_NULL; \
+               else \
+                       result = push_codepoint(buf, v); \
+       } else { \
+               int c = getc(yyin); \
+               result = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
+       } \
+}
+
+%}
+
+%%
+
+ACTIONLIST { return ACTIONLIST; }
+CATEGORY { return CATEGORY; }
+CHECKBOX { return CHECKBOX; }
+CLASS { return CLASS; }
+DELETE { return DEL; }
+DEFAULT { return DEFAULT; }
+DROPDOWNLIST { return DROPDOWNLIST; }
+EDITTEXT { return EDITTEXT; }
+END { return END; }
+EXPLAIN { return EXPLAIN; }
+ITEMLIST { return ITEMLIST; }
+KEYNAME { return KEYNAME; }
+MACHINE { return MACHINE; }
+MIN { return MINIMUM; }
+MAX { return MAXIMUM; }
+NAME { return NAME; }
+NUMERIC { return NUMERIC; }
+PART { return PART; }
+POLICY { return POLICY; }
+REQUIRED { return REQUIRED; }
+SPIN { return SPIN; }
+SUPPORTED { return SUPPORTED; }
+TEXT { return TEXT; }
+USER { return USER; }
+VALUE { return VALUE; }
+VALUENAME { return VALUENAME; }
+VALUEON { return VALUEON; }
+VALUEOFF { return VALUEOFF; }
+=              { return EQUALS; }
+\[strings\]    { return STRINGSSECTION; }
+
+[0-9]+ {
+       char *e, *y = yytext;
+       yylval.integer = strtol((const char *)yytext, &e, 0);
+       if(e == y)
+               error_message("malformed constant (%s)", yytext);
+       else
+               return INTEGER;
+               }
+
+[A-Za-z\\{}][{}\-\\A-Za-z0-9_]* { 
+       yylval.text = strdup ((const char *)yytext);
+       return LITERAL;
+       }
+
+"!!"[A-Za-z][-A-Za-z0-9_]*  {
+       yylval.text = strdup ((const char *)yytext);
+       return LOOKUPLITERAL;
+       }
+[ \t]+
+\n                     { lineno++; }
+;[^\n]*\n              { lineno++; }
+\"([^\n]+)\n           { lineno++; yylval.text = strdup((const char *)yytext); return LITERAL; }
+%%
+
+#ifndef yywrap /* XXX */
+int
+yywrap () 
+{
+     return 1;
+}
+#endif
+
+
+void
+error_message (const char *format, ...)
+{
+       va_list args;
+
+       va_start (args, format);
+       fprintf (stderr, "%d:", lineno);
+       vfprintf (stderr, format, args);
+       va_end (args);
+}
+
+struct adm_file *adm_read_file(const char *file)
+{
+       uint8_t c[2];
+       yyin = fopen(file, "r");
+       if (yyin == NULL)
+               return NULL;
+
+       c[0] = getc(yyin);
+       c[1] = getc(yyin);
+       if (c[0] == 0xff && c[1] == 0xfe) {
+               utf16 = true;
+       } else {
+               rewind(yyin);
+       }
+
+       yyparse();
+
+       return NULL; /* FIXME */
+}
diff --git a/source/lib/policy/parse_adm.y b/source/lib/policy/parse_adm.y
new file mode 100644 (file)
index 0000000..450625f
--- /dev/null
@@ -0,0 +1,138 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Copyright (C) 2006 Wilco Baan Hofman <wilco@baanhofman.nl>
+   Copyright (C) 2006 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.
+
+   For more information on the .ADM file format:
+   http://msdn2.microsoft.com/en-us/library/aa372405.aspx 
+*/
+
+%{
+#include "config.h"
+void error_message (const char *format, ...);
+int yyparse (void);
+void yyerror (const char *s);
+extern int yylex (void);
+
+%}
+
+%union {
+       char *text;
+       int integer;
+}
+
+%token CATEGORY
+%token CLASS
+%token USER
+%token MACHINE
+%token POLICY
+%token KEYNAME
+%token EXPLAIN
+%token VALUENAME
+%token VALUEON VALUEOFF
+%token PART
+%token ITEMLIST
+%token NAME
+%token VALUE
+%token NUMERIC EDITTEXT TEXT DROPDOWNLIST CHECKBOX
+%token MINIMUM MAXIMUM DEFAULT
+%token END
+%token ACTIONLIST
+%token DEL
+%token SUPPORTED
+%token <text> LITERAL
+%token <integer> INTEGER
+%token <text> LOOKUPLITERAL
+%token CLIENTEXT
+%token REQUIRED
+%token NOSORT
+%token SPIN
+%token EQUALS
+%token STRINGSSECTION
+
+%start admfile
+
+%% 
+
+admfile: classes strings;
+
+classes: /* empty */ | class classes;
+
+class: CLASS classvalue categories;
+classvalue: USER|MACHINE;
+
+categories: /* empty */ | category categories;
+
+string: LITERAL | LOOKUPLITERAL;
+
+category: CATEGORY string categoryitems END CATEGORY;
+
+categoryitem: explain | category | policy | keyname;
+categoryitems: categoryitem categoryitems | /* empty */ ;
+
+policy: POLICY string policyitems END POLICY;
+policyitem: explain | keyname | valuename | valueon | valueoff | min | max | defaultvalue | supported | part;
+policyitems: policyitem policyitems | /* empty */;
+
+valuetype: NUMERIC | EDITTEXT | TEXT | DROPDOWNLIST | CHECKBOX;
+
+part: PART string valuetype partitems END PART;
+
+spin: SPIN INTEGER;
+
+partitem: keyname | valuename | valueon | valueoff | min | max | defaultvalue | itemlist | REQUIRED | spin;
+partitems: partitem partitems | /* empty */;
+
+min: MINIMUM INTEGER;
+max: MAXIMUM INTEGER;
+defaultvalue: DEFAULT INTEGER;
+
+explain: EXPLAIN string;
+value: DEL | NUMERIC INTEGER;
+
+valueon: VALUEON value;
+valueoff: VALUEOFF value;
+
+valuename: VALUENAME string;
+keyname: KEYNAME string;
+
+itemlist: ITEMLIST items END ITEMLIST;
+itemname: NAME string;
+itemvalue: VALUE value;
+
+item: itemname | itemvalue | DEFAULT | actionlist;
+items: /* empty */ | item items;
+
+supported: SUPPORTED string;
+
+actionlist: ACTIONLIST actions END ACTIONLIST;
+actions: valuename actions | itemvalue actions | /* empty */;
+
+variable: LITERAL EQUALS LITERAL;
+variables: variable variables | /* empty */;
+strings: STRINGSSECTION variables;
+
+%%
+
+void
+yyerror (const char *s)
+{
+     error_message ("%s\n", s);
+}
+
+
+
index ff591b6fe4fb5be04387e280d98f2520501a4417..efc01cd355a29218f147ae54ddbe44c22ade3c01 100644 (file)
@@ -15,7 +15,7 @@ WARN_IF_UNDOCUMENTED   = YES
 WARN_IF_DOC_ERROR      = YES
 WARN_NO_PARAMDOC       = NO
 WARN_FORMAT            = "$file:$line: $text"
-INPUT                  = . common
+INPUT                  = .
 FILE_PATTERNS          = *.c *.h *.dox
 GENERATE_HTML          = YES
 HTML_OUTPUT            = html
index db1fb7a67894a31f4e4669640e7a67c35998c519..07b2c016844f566ec30c9ea8934b73e6b51b8e38 100644 (file)
@@ -1,30 +1,31 @@
 This is the registry library. The registry is basically a bunch of
-hives that can be loaded from different places.
+hives, each of which is loaded from a file. When using a local registry, 
+it is possible to specify where hives should be loaded from, etc. 
 
-The various registry backends provide support for loading/saving
-specific types of hives:
+There are separate APIs for accessing the data in a hive and the 
+data in the registry itself. Each supports different backends. 
+
+The following "full registry" backends are currently provided:
+
+ * Remote (over DCE/RPC)
+ * Local (allows "mounting" hives)
+ * Wine (uses the wine plain-text file)
+
+The following hive backends are supported:
 
  - ldb 
- - w95 (USER.DAT-style files)
- - nt4 (NTUSER.DAT-style files)
- - gconf (GNOME configuration)
+ - regf (NTUSER.DAT-style files)
  - rpc (Remote individual hives)
+ - directory
 
-Instead of opening individual hives, one can also open a 'complete'
-registry by using one of these three functions:
- - reg_open_local() - load local registry, see below
- - reg_open_remote() - connect to remote registry over RPC
- - reg_open_wine() (not working yet)
-
-reg_open_local() loads a set of hives based on smb.conf settings.
+reg_open_samba() loads a set of hives based on smb.conf settings.
 Lines in smb.conf should have the following syntax:
 
 registry:<hivename> = <backend>:<location>
 
 So an example usage could be:
 
-registry:HKEY_CURRENT_USER = nt4:NTUSER.DAT
+registry:HKEY_CURRENT_USER = regf:NTUSER.DAT
 registry:HKEY_LOCAL_MACHINE = ldb:tdb://registry.tdb
 
 WERR_NOT_SUPPORTED will be returned for all hives that haven't been set.
index 562ed5657edf2e1577d5b4f62dc84f0d700ac4e1..5f1e7d034ba33ac0bb960a7a3a651c07c70b1018 100644 (file)
@@ -4,10 +4,10 @@
 reg_backend_dir:
  - value support
 
-reg_backend_w95.c:
+reg_backend_creg.c:
  - write support
  
-reg_backend_nt4:
+reg_backend_regf:
  - write support
 
 reg_backend_rpc:
diff --git a/source/lib/registry/common/reg_interface.c b/source/lib/registry/common/reg_interface.c
deleted file mode 100644 (file)
index 6ee8a72..0000000
+++ /dev/null
@@ -1,584 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-   Transparent registry backend handling
-   Copyright (C) Jelmer Vernooij                       2003-2004.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "lib/util/dlinklist.h"
-#include "lib/registry/registry.h"
-#include "build.h"
-
-/**
- * @file
- * @brief Main registry functions
- */
-
-/* List of available backends */
-static struct reg_init_function_entry *backends = NULL;
-
-static struct reg_init_function_entry *reg_find_backend_entry(const char *name);
-
-/** Register a new backend. */
-_PUBLIC_ NTSTATUS registry_register(const void *_hive_ops)
-{
-       const struct hive_operations *hive_ops = _hive_ops;
-       struct reg_init_function_entry *entry = backends;
-
-       DEBUG(5,("Attempting to register registry backend %s\n", hive_ops->name));
-
-       /* Check for duplicates */
-       if (reg_find_backend_entry(hive_ops->name)) {
-               DEBUG(0,("There already is a registry backend registered with the name %s!\n", hive_ops->name));
-               return NT_STATUS_OBJECT_NAME_COLLISION;
-       }
-
-       entry = talloc(talloc_autofree_context(), struct reg_init_function_entry);
-       entry->hive_functions = hive_ops;
-
-       DLIST_ADD(backends, entry);
-       DEBUG(5,("Successfully added registry backend '%s'\n", hive_ops->name));
-       return NT_STATUS_OK;
-}
-
-/** Find a backend in the list of available backends */
-static struct reg_init_function_entry *reg_find_backend_entry(const char *name)
-{
-       struct reg_init_function_entry *entry;
-
-       entry = backends;
-
-       while(entry) {
-               if (strcmp(entry->hive_functions->name, name) == 0) return entry;
-               entry = entry->next;
-       }
-
-       return NULL;
-}
-
-/** Initialize the registry subsystem */
-_PUBLIC_ NTSTATUS registry_init(void)
-{
-       init_module_fn static_init[] = STATIC_registry_MODULES;
-       init_module_fn *shared_init = load_samba_modules(NULL, "registry");
-
-       run_init_functions(static_init);
-       run_init_functions(shared_init);
-
-       talloc_free(shared_init);
-       
-       return NT_STATUS_OK;
-}
-
-/** Check whether a certain backend is present. */
-_PUBLIC_ BOOL reg_has_backend(const char *backend)
-{
-       return reg_find_backend_entry(backend) != NULL?True:False;
-}
-
-const struct reg_predefined_key reg_predefined_keys[] = {
-       {HKEY_CLASSES_ROOT,"HKEY_CLASSES_ROOT" },
-       {HKEY_CURRENT_USER,"HKEY_CURRENT_USER" },
-       {HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE" },
-       {HKEY_PERFORMANCE_DATA, "HKEY_PERFORMANCE_DATA" },
-       {HKEY_USERS, "HKEY_USERS" },
-       {HKEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG" },
-       {HKEY_DYN_DATA, "HKEY_DYN_DATA" },
-       {HKEY_PERFORMANCE_TEXT, "HKEY_PERFORMANCE_TEXT" },
-       {HKEY_PERFORMANCE_NLSTEXT, "HKEY_PERFORMANCE_NLSTEXT" },
-       { 0, NULL }
-};
-
-/** Obtain a list of predefined keys. */
-_PUBLIC_ int reg_list_predefs(TALLOC_CTX *mem_ctx, char ***predefs, uint32_t **hkeys)
-{
-       int i;
-       *predefs = talloc_array(mem_ctx, char *, ARRAY_SIZE(reg_predefined_keys));
-       *hkeys = talloc_array(mem_ctx, uint32_t, ARRAY_SIZE(reg_predefined_keys));
-
-       for (i = 0; reg_predefined_keys[i].name; i++) {
-               (*predefs)[i] = talloc_strdup(mem_ctx, reg_predefined_keys[i].name);
-               (*hkeys)[i] = reg_predefined_keys[i].handle;
-       }
-
-       return i;
-}
-
-/** Obtain name of specific hkey. */
-_PUBLIC_ const char *reg_get_predef_name(uint32_t hkey)
-{
-       int i;
-       for (i = 0; reg_predefined_keys[i].name; i++) {
-               if (reg_predefined_keys[i].handle == hkey) return reg_predefined_keys[i].name;
-       }
-
-       return NULL;
-}
-
-/** Get predefined key by name. */
-_PUBLIC_ WERROR reg_get_predefined_key_by_name(struct registry_context *ctx, const char *name, struct registry_key **key)
-{
-       int i;
-       
-       for (i = 0; reg_predefined_keys[i].name; i++) {
-               if (!strcasecmp(reg_predefined_keys[i].name, name)) return reg_get_predefined_key(ctx, reg_predefined_keys[i].handle, key);
-       }
-
-       DEBUG(1, ("No predefined key with name '%s'\n", name));
-       
-       return WERR_BADFILE;
-}
-
-/** Get predefined key by id. */
-_PUBLIC_ WERROR reg_get_predefined_key(struct registry_context *ctx, uint32_t hkey, struct registry_key **key)
-{
-       WERROR ret = ctx->get_predefined_key(ctx, hkey, key);
-
-       if (W_ERROR_IS_OK(ret)) {
-               (*key)->name = talloc_strdup(*key, reg_get_predef_name(hkey));
-               (*key)->path = ""; 
-       }
-
-       return ret;
-}
-
-/** Open a registry file/host/etc */
-_PUBLIC_ WERROR reg_open_hive(TALLOC_CTX *parent_ctx, const char *backend, const char *location, struct auth_session_info *session_info, struct cli_credentials *credentials, struct registry_key **root)
-{
-       struct registry_hive *rethive;
-       struct registry_key *retkey = NULL;
-       struct reg_init_function_entry *entry;
-       WERROR werr;
-
-       entry = reg_find_backend_entry(backend);
-       
-       if (!entry) {
-               DEBUG(0, ("No such registry backend '%s' loaded!\n", backend));
-               return WERR_GENERAL_FAILURE;
-       }
-
-       if(!entry->hive_functions || !entry->hive_functions->open_hive) {
-               return WERR_NOT_SUPPORTED;
-       }
-       
-       rethive = talloc(parent_ctx, struct registry_hive);
-       rethive->location = location?talloc_strdup(rethive, location):NULL;
-       rethive->session_info = talloc_reference(rethive, session_info);
-       rethive->credentials = talloc_reference(rethive, credentials);
-       rethive->functions = entry->hive_functions;
-       rethive->backend_data = NULL;
-
-       werr = entry->hive_functions->open_hive(rethive, &retkey);
-
-       if(!W_ERROR_IS_OK(werr)) {
-               return werr;
-       }
-
-       if(!retkey) {
-               DEBUG(0, ("Backend %s didn't provide root key!\n", backend));
-               return WERR_GENERAL_FAILURE;
-       }
-
-       rethive->root = retkey;
-
-       retkey->hive = rethive;
-       retkey->name = NULL;
-       retkey->path = talloc_strdup(retkey, "");
-       
-       *root = retkey;
-
-       return WERR_OK;
-}
-
-/**
- * Open a key 
- * First tries to use the open_key function from the backend
- * then falls back to get_subkey_by_name and later get_subkey_by_index 
- */
-_PUBLIC_ WERROR reg_open_key(TALLOC_CTX *mem_ctx, struct registry_key *parent, const char *name, struct registry_key **result)
-{
-       WERROR error;
-
-       if(!parent) {
-               DEBUG(0, ("Invalid parent key specified for open of '%s'\n", name));
-               return WERR_INVALID_PARAM;
-       }
-
-       if(!parent->hive->functions->open_key && 
-          (parent->hive->functions->get_subkey_by_name || 
-          parent->hive->functions->get_subkey_by_index)) {
-               char *orig = strdup(name), 
-                        *curbegin = orig, 
-                        *curend = strchr(orig, '\\');
-               struct registry_key *curkey = parent;
-
-               while(curbegin && *curbegin) {
-                       if(curend)*curend = '\0';
-                       error = reg_key_get_subkey_by_name(mem_ctx, curkey, curbegin, &curkey);
-                       if(!W_ERROR_IS_OK(error)) {
-                               SAFE_FREE(orig);
-                               return error;
-                       }
-                       if(!curend) break;
-                       curbegin = curend + 1;
-                       curend = strchr(curbegin, '\\');
-               }
-               SAFE_FREE(orig);
-
-               *result = curkey;
-               
-               return WERR_OK;
-       }
-
-       if(!parent->hive->functions->open_key) {
-               DEBUG(0, ("Registry backend doesn't have get_subkey_by_name nor open_key!\n"));
-               return WERR_NOT_SUPPORTED;
-       }
-
-       error = parent->hive->functions->open_key(mem_ctx, parent, name, result);
-
-       if(!W_ERROR_IS_OK(error)) return error;
-               
-       (*result)->hive = parent->hive;
-       (*result)->path = ((parent->hive->root == parent)?talloc_strdup(mem_ctx, name):talloc_asprintf(mem_ctx, "%s\\%s", parent->path, name));
-       (*result)->hive = parent->hive;
-
-       return WERR_OK;
-}
-
-/**
- * Get value by index
- */
-_PUBLIC_ WERROR reg_key_get_value_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *key, int idx, struct registry_value **val)
-{
-       if(!key) return WERR_INVALID_PARAM;
-
-       if(key->hive->functions->get_value_by_index) {
-               WERROR status = key->hive->functions->get_value_by_index(mem_ctx, key, idx, val);
-               if(!W_ERROR_IS_OK(status)) 
-                       return status;
-       } else {
-               return WERR_NOT_SUPPORTED;
-       }
-       
-       return WERR_OK;
-}
-
-/** 
- * Get the number of subkeys.
- */
-_PUBLIC_ WERROR reg_key_num_subkeys(const struct registry_key *key, uint32_t *count)
-{
-       if(!key) return WERR_INVALID_PARAM;
-       
-       if(key->hive->functions->num_subkeys) {
-               return key->hive->functions->num_subkeys(key, count);
-       }
-
-       if(key->hive->functions->get_subkey_by_index) {
-               int i;
-               WERROR error;
-               struct registry_key *dest = NULL;
-               TALLOC_CTX *mem_ctx = talloc_init("num_subkeys");
-               
-               for(i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(mem_ctx, key, i, &dest)); i++);
-               talloc_free(mem_ctx);
-
-               *count = i;
-               if(W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) error = WERR_OK;
-               return error;
-       }
-
-       return WERR_NOT_SUPPORTED;
-}
-
-/**
- * Get the number of values of a key.
- */
-_PUBLIC_ WERROR reg_key_num_values(const struct registry_key *key, uint32_t *count)
-{
-       
-       if(!key) return WERR_INVALID_PARAM;
-
-       if (key->hive->functions->num_values) {
-               return key->hive->functions->num_values(key, count);
-       }
-
-       if(key->hive->functions->get_value_by_index) {
-               int i;
-               WERROR error;
-               struct registry_value *dest;
-               TALLOC_CTX *mem_ctx = talloc_init("num_subkeys");
-               
-               for(i = 0; W_ERROR_IS_OK(error = key->hive->functions->get_value_by_index(mem_ctx, key, i, &dest)); i++);
-               talloc_free(mem_ctx);
-
-               *count = i;
-               if(W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) error = WERR_OK;
-               return error;
-       }
-
-       return WERR_NOT_SUPPORTED;
-}
-
-/**
- * Get subkey by index.
- */
-_PUBLIC_ WERROR reg_key_get_subkey_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *key, int idx, struct registry_key **subkey)
-{
-       if(!key) return WERR_INVALID_PARAM;
-
-       if(key->hive->functions->get_subkey_by_index) {
-               WERROR status = key->hive->functions->get_subkey_by_index(mem_ctx, key, idx, subkey);
-               if(!NT_STATUS_IS_OK(status)) return status;
-       } else {
-               return WERR_NOT_SUPPORTED;
-       }
-
-       if(key->hive->root == key) 
-               (*subkey)->path = talloc_strdup(mem_ctx, (*subkey)->name);
-       else 
-               (*subkey)->path = talloc_asprintf(mem_ctx, "%s\\%s", key->path, (*subkey)->name);
-
-       (*subkey)->hive = key->hive;
-       return WERR_OK;;
-}
-
-/**
- * Get subkey by name.
- */
-WERROR reg_key_get_subkey_by_name(TALLOC_CTX *mem_ctx, const struct registry_key *key, const char *name, struct registry_key **subkey)
-{
-       int i;
-       WERROR error = WERR_OK;
-
-       if(!key) return WERR_INVALID_PARAM;
-
-       if(key->hive->functions->get_subkey_by_name) {
-               error = key->hive->functions->get_subkey_by_name(mem_ctx, key,name,subkey);
-       } else if(key->hive->functions->open_key) {
-               error = key->hive->functions->open_key(mem_ctx, key, name, subkey);
-       } else if(key->hive->functions->get_subkey_by_index) {
-               for(i = 0; W_ERROR_IS_OK(error); i++) {
-                       error = reg_key_get_subkey_by_index(mem_ctx, key, i, subkey);
-                       if(W_ERROR_IS_OK(error) && !strcasecmp((*subkey)->name, name)) {
-                               break;
-                       }
-               }
-
-               if (W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) 
-                       error = WERR_DEST_NOT_FOUND;
-       } else {
-               return WERR_NOT_SUPPORTED;
-       }
-
-       if(!W_ERROR_IS_OK(error)) return error;
-
-       (*subkey)->path = talloc_asprintf(mem_ctx, "%s\\%s", key->path, (*subkey)->name);
-       (*subkey)->hive = key->hive;
-
-       return WERR_OK; 
-}
-
-/**
- * Get value by name.
- */
-_PUBLIC_ WERROR reg_key_get_value_by_name(TALLOC_CTX *mem_ctx, const struct registry_key *key, const char *name, struct registry_value **val)
-{
-       int i;
-       WERROR error = WERR_OK;
-
-       if(!key) return WERR_INVALID_PARAM;
-
-       if(key->hive->functions->get_value_by_name) {
-               error = key->hive->functions->get_value_by_name(mem_ctx, key,name, val);
-       } else {
-               for(i = 0; W_ERROR_IS_OK(error); i++) {
-                       error = reg_key_get_value_by_index(mem_ctx, key, i, val);
-                       if(W_ERROR_IS_OK(error) && !strcasecmp((*val)->name, name)) {
-                               break;
-                       }
-               }
-       }
-
-       if (W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS))
-               return WERR_DEST_NOT_FOUND;
-
-       return error;
-}
-
-/**
- * Delete a key.
- */
-_PUBLIC_ WERROR reg_key_del(struct registry_key *parent, const char *name)
-{
-       WERROR error;
-       if(!parent) return WERR_INVALID_PARAM;
-       
-       
-       if(!parent->hive->functions->del_key)
-               return WERR_NOT_SUPPORTED;
-       
-       error = parent->hive->functions->del_key(parent, name);
-       if(!W_ERROR_IS_OK(error)) return error;
-
-       return WERR_OK;
-}
-
-/**
- * Add a key.
- */
-_PUBLIC_ WERROR reg_key_add_name(TALLOC_CTX *mem_ctx, const struct registry_key *parent, const char *name, uint32_t access_mask, struct security_descriptor *desc, struct registry_key **newkey)
-{
-       WERROR error;
-       
-       if (!parent) return WERR_INVALID_PARAM;
-       
-       if (!parent->hive->functions->add_key) {
-               DEBUG(1, ("Backend '%s' doesn't support method add_key\n", parent->hive->functions->name));
-               return WERR_NOT_SUPPORTED;
-       }
-
-       error = parent->hive->functions->add_key(mem_ctx, parent, name, access_mask, desc, newkey);
-
-       if(!W_ERROR_IS_OK(error)) return error;
-
-       if (!*newkey) {
-               DEBUG(0, ("Backend returned WERR_OK, but didn't specify key!\n"));
-               return WERR_GENERAL_FAILURE;
-       }
-       
-       (*newkey)->hive = parent->hive;
-
-       return WERR_OK;
-}
-
-/**
- * Set a value.
- */
-_PUBLIC_ WERROR reg_val_set(struct registry_key *key, const char *value, uint32_t type, DATA_BLOB data)
-{
-       /* A 'real' set function has preference */
-       if (key->hive->functions->set_value) 
-               return key->hive->functions->set_value(key, value, type, data);
-
-       DEBUG(1, ("Backend '%s' doesn't support method set_value\n", key->hive->functions->name));
-       return WERR_NOT_SUPPORTED;
-}
-
-/**
- * Get the security descriptor on a key.
- */
-_PUBLIC_ WERROR reg_get_sec_desc(TALLOC_CTX *ctx, const struct registry_key *key, struct security_descriptor **secdesc)
-{
-       /* A 'real' set function has preference */
-       if (key->hive->functions->key_get_sec_desc) 
-               return key->hive->functions->key_get_sec_desc(ctx, key, secdesc);
-
-       DEBUG(1, ("Backend '%s' doesn't support method get_sec_desc\n", key->hive->functions->name));
-       return WERR_NOT_SUPPORTED;
-}
-
-/**
- * Delete a value.
- */
-_PUBLIC_ WERROR reg_del_value(const struct registry_key *key, const char *valname)
-{
-       WERROR ret = WERR_OK;
-       if(!key->hive->functions->del_value)
-               return WERR_NOT_SUPPORTED;
-
-       ret = key->hive->functions->del_value(key, valname);
-
-       if(!W_ERROR_IS_OK(ret)) return ret;
-
-       return ret;
-}
-
-/**
- * Flush a key to disk.
- */
-_PUBLIC_ WERROR reg_key_flush(const struct registry_key *key)
-{
-       if (!key) {
-               return WERR_INVALID_PARAM;
-       }
-       
-       if (key->hive->functions->flush_key) {
-               return key->hive->functions->flush_key(key);
-       }
-       
-       /* No need for flushing, apparently */
-       return WERR_OK;
-}
-
-/**
- * Get the maximum name and data lengths of the subkeys.
- */
-_PUBLIC_ WERROR reg_key_subkeysizes(const struct registry_key *key, uint32_t *max_subkeylen, uint32_t *max_subkeysize)
-{
-       int i = 0; 
-       struct registry_key *subkey;
-       WERROR error;
-       TALLOC_CTX *mem_ctx = talloc_init("subkeysize");
-
-       *max_subkeylen = *max_subkeysize = 0;
-
-       do {
-               error = reg_key_get_subkey_by_index(mem_ctx, key, i, &subkey);
-
-               if (W_ERROR_IS_OK(error)) {
-                       *max_subkeysize = MAX(*max_subkeysize, 0xFF);
-                       *max_subkeylen = MAX(*max_subkeylen, strlen(subkey->name));
-               }
-
-               i++;
-       } while (W_ERROR_IS_OK(error));
-
-       talloc_free(mem_ctx);
-
-       return WERR_OK;
-}
-
-/**
- * Get the maximum name and data lengths of the values.
- */
-_PUBLIC_ WERROR reg_key_valuesizes(const struct registry_key *key, uint32_t *max_valnamelen, uint32_t *max_valbufsize)
-{
-       int i = 0; 
-       struct registry_value *value;
-       WERROR error;
-       TALLOC_CTX *mem_ctx = talloc_init("subkeysize");
-
-       *max_valnamelen = *max_valbufsize = 0;
-
-       do {
-               error = reg_key_get_value_by_index(mem_ctx, key, i, &value);
-
-               if (W_ERROR_IS_OK(error)) {
-                       if (value->name) {
-                               *max_valnamelen = MAX(*max_valnamelen, strlen(value->name));
-                       }
-                       *max_valbufsize = MAX(*max_valbufsize, value->data.length);
-               }
-
-               i++;
-       } while (W_ERROR_IS_OK(error));
-
-       talloc_free(mem_ctx);
-
-       return WERR_OK;
-}
index cea37e7e2f1cf758e80fdaee4cb0478c7d47e738..de276d2b5eba210086e25b3616d68be2337f5fcb 100644 (file)
@@ -1,23 +1,10 @@
-# Registry backends
-
-################################################
-# Start MODULE registry_nt4
-[MODULE::registry_nt4]
-INIT_FUNCTION = registry_nt4_init
-SUBSYSTEM = registry
-OBJ_FILES = \
-               reg_backend_nt4.o
-PRIVATE_DEPENDENCIES = TDR_REGF
-# End MODULE registry_nt4
-################################################
-
 [SUBSYSTEM::TDR_REGF]
 PUBLIC_DEPENDENCIES = TDR 
 OBJ_FILES = tdr_regf.o
 
 # Special support for external builddirs
-lib/registry/reg_backend_nt4.c: lib/registry/tdr_regf.c
-$(srcdir)/lib/registry/reg_backend_nt4.c: lib/registry/tdr_regf.c
+lib/registry/regf.c: lib/registry/tdr_regf.c
+$(srcdir)/lib/registry/regf.c: lib/registry/tdr_regf.c
 lib/registry/tdr_regf.h: lib/registry/tdr_regf.c
 lib/registry/tdr_regf.c: $(srcdir)/lib/registry/regf.idl
        @CPP="$(CPP)" srcdir="$(srcdir)" $(PERL) $(srcdir)/pidl/pidl $(PIDL_ARGS) \
@@ -27,51 +14,6 @@ lib/registry/tdr_regf.c: $(srcdir)/lib/registry/regf.idl
 clean::
        @-rm -f lib/registry/regf.h lib/registry/tdr_regf*
 
-################################################
-# Start MODULE registry_w95
-[MODULE::registry_w95]
-INIT_FUNCTION = registry_w95_init
-SUBSYSTEM = registry
-OBJ_FILES = \
-               reg_backend_w95.o
-# End MODULE registry_w95
-################################################
-
-################################################
-# Start MODULE registry_dir
-[MODULE::registry_dir]
-INIT_FUNCTION = registry_dir_init
-SUBSYSTEM = registry
-OBJ_FILES = \
-               reg_backend_dir.o
-PRIVATE_DEPENDENCIES = LIBTALLOC
-# End MODULE registry_dir
-################################################
-
-################################################
-# Start MODULE registry_rpc
-[MODULE::registry_rpc]
-INIT_FUNCTION = registry_rpc_init
-OUTPUT_TYPE = INTEGRATED
-SUBSYSTEM = registry
-OBJ_FILES = \
-               reg_backend_rpc.o
-PRIVATE_DEPENDENCIES = RPC_NDR_WINREG
-# End MODULE registry_rpc
-################################################
-
-################################################
-# Start MODULE registry_ldb
-[MODULE::registry_ldb]
-INIT_FUNCTION = registry_ldb_init
-SUBSYSTEM = registry
-OBJ_FILES = \
-               reg_backend_ldb.o
-PRIVATE_DEPENDENCIES = \
-               LIBLDB  
-# End MODULE registry_ldb
-################################################
-
 ################################################
 # Start SUBSYSTEM registry
 [LIBRARY::registry]
@@ -79,16 +21,30 @@ VERSION = 0.0.1
 SO_VERSION = 0
 DESCRIPTION = Windows-style registry library
 OBJ_FILES = \
-               common/reg_interface.o \
-               common/reg_util.o \
-               reg_samba.o \
-               patchfile.o
-PRIVATE_DEPENDENCIES = \
-               LIBSAMBA-UTIL CHARSET
+               interface.o \
+               util.o \
+               samba.o \
+               patchfile_dotreg.o \
+               patchfile_preg.o \
+               patchfile.o \
+               regf.o \
+               hive.o \
+               local.o \
+               ldb.o \
+               dir.o \
+               rpc.o
+PUBLIC_DEPENDENCIES = \
+               LIBSAMBA-UTIL CHARSET TDR_REGF LIBLDB \
+               RPC_NDR_WINREG
 PUBLIC_HEADERS = registry.h
 # End MODULE registry_ldb
 ################################################
 
+[SUBSYSTEM::registry_common]
+PUBLIC_DEPENDENCIES = registry
+OBJ_FILES = tools/common.o
+PUBLIC_PROTO_HEADER = tools/common.h
+
 ################################################
 # Start BINARY regdiff
 [BINARY::regdiff]
@@ -106,7 +62,8 @@ MANPAGE = man/regdiff.1
 INSTALLDIR = BINDIR
 OBJ_FILES = tools/regpatch.o
 PRIVATE_DEPENDENCIES = \
-               LIBSAMBA-CONFIG registry LIBPOPT POPT_SAMBA POPT_CREDENTIALS
+               LIBSAMBA-CONFIG registry LIBPOPT POPT_SAMBA POPT_CREDENTIALS \
+               registry_common
 MANPAGE = man/regpatch.1
 # End BINARY regpatch
 ################################################
@@ -118,7 +75,7 @@ INSTALLDIR = BINDIR
 OBJ_FILES = tools/regshell.o
 PRIVATE_DEPENDENCIES = \
                LIBSAMBA-CONFIG LIBPOPT registry POPT_SAMBA POPT_CREDENTIALS \
-               SMBREADLINE
+               SMBREADLINE registry_common
 MANPAGE = man/regshell.1
 # End BINARY regshell
 ################################################
@@ -129,7 +86,8 @@ MANPAGE = man/regshell.1
 INSTALLDIR = BINDIR
 OBJ_FILES = tools/regtree.o
 PRIVATE_DEPENDENCIES = \
-               LIBSAMBA-CONFIG LIBPOPT registry POPT_SAMBA POPT_CREDENTIALS
+               LIBSAMBA-CONFIG LIBPOPT registry POPT_SAMBA POPT_CREDENTIALS \
+               registry_common
 MANPAGE = man/regtree.1
 # End BINARY regtree
 ################################################
diff --git a/source/lib/registry/dir.c b/source/lib/registry/dir.c
new file mode 100644 (file)
index 0000000..146c519
--- /dev/null
@@ -0,0 +1,333 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Registry interface
+   Copyright (C) Jelmer Vernooij                                         2004-2007.
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "hive.h"
+#include "system/dir.h"
+#include "system/filesys.h"
+
+struct dir_key {
+       struct hive_key key;
+       const char *path;
+};
+
+static struct hive_operations reg_backend_dir;
+
+static WERROR reg_dir_add_key(TALLOC_CTX *mem_ctx, 
+                                                         const struct hive_key *parent, 
+                                                         const char *name, const char *classname,
+                                                         struct security_descriptor *desc, 
+                                                         struct hive_key **result)
+{
+       struct dir_key *dk = talloc_get_type(parent, struct dir_key);
+       char *path;
+       int ret;
+
+       path = talloc_asprintf(mem_ctx, "%s/%s", dk->path, name);
+       ret = mkdir(path, 0700);
+       if (ret == 0) {
+               struct dir_key *key = talloc(mem_ctx, struct dir_key);
+               key->key.ops = &reg_backend_dir;
+               key->path = talloc_steal(key, path);
+               *result = (struct hive_key *)key;
+               return WERR_OK;
+       }
+
+       if (errno == EEXIST)
+               return WERR_ALREADY_EXISTS;
+       printf("FAILED %s BECAUSE: %s\n", path, strerror(errno));
+       return WERR_GENERAL_FAILURE;
+}
+
+static WERROR reg_dir_del_key(const struct hive_key *k, const char *name)
+{
+       struct dir_key *dk = talloc_get_type(k, struct dir_key);
+       char *child = talloc_asprintf(NULL, "%s/%s", dk->path, name);
+       WERROR ret;
+
+       if (rmdir(child) == 0) 
+               ret = WERR_OK; 
+       else if (errno == ENOENT)
+               ret = WERR_NOT_FOUND;
+       else
+               ret = WERR_GENERAL_FAILURE;
+
+       talloc_free(child);
+
+       return ret;
+}
+
+static WERROR reg_dir_open_key(TALLOC_CTX *mem_ctx, 
+                                                          const struct hive_key *parent, 
+                                                          const char *name, struct hive_key **subkey)
+{
+       DIR *d;
+       char *fullpath;
+       const struct dir_key *p = talloc_get_type(parent, struct dir_key);
+       struct dir_key *ret;
+       
+       if (name == NULL) {
+               DEBUG(0, ("NULL pointer passed as directory name!"));
+               return WERR_INVALID_PARAM;
+       }
+       
+       fullpath = talloc_asprintf(mem_ctx, "%s/%s", p->path, name);
+       
+       d = opendir(fullpath);
+       if (d == NULL) {
+               DEBUG(3,("Unable to open '%s': %s\n", fullpath, strerror(errno)));
+               return WERR_BADFILE;
+       }
+       closedir(d);
+       ret = talloc(mem_ctx, struct dir_key);
+       ret->key.ops = &reg_backend_dir;
+       ret->path = talloc_steal(ret, fullpath);
+       *subkey = (struct hive_key *)ret;
+       return WERR_OK;
+}
+
+static WERROR reg_dir_key_by_index(TALLOC_CTX *mem_ctx, 
+                                                                  const struct hive_key *k, uint32_t idx, 
+                                                                  const char **name,
+                                                                  const char **classname,
+                                                                  NTTIME *last_mod_time)
+{
+       struct dirent *e;
+       const struct dir_key *dk = talloc_get_type(k, struct dir_key);
+       int i = 0;
+       DIR *d;
+
+       d = opendir(dk->path);
+
+       if (d == NULL) 
+               return WERR_INVALID_PARAM;
+       
+       while((e = readdir(d))) {
+               if(!ISDOT(e->d_name) && !ISDOTDOT(e->d_name)) {
+                       struct stat stbuf;
+                       char *thispath;
+                       
+                       /* Check if file is a directory */
+                       asprintf(&thispath, "%s/%s", dk->path, e->d_name);
+                       stat(thispath, &stbuf);
+
+                       if (!S_ISDIR(stbuf.st_mode)) {
+                               SAFE_FREE(thispath);
+                               continue;
+                       }
+
+                       if (i == idx) {
+                               struct stat st;
+                               *name = talloc_strdup(mem_ctx, e->d_name);
+                               *classname = NULL;
+                               stat(thispath, &st);
+                               unix_to_nt_time(last_mod_time, st.st_mtime);
+                               SAFE_FREE(thispath);
+                               closedir(d);
+                               return WERR_OK;
+                       }
+                       i++;
+
+                       SAFE_FREE(thispath);
+               }
+       }
+
+       closedir(d);
+
+       return WERR_NO_MORE_ITEMS;
+}
+
+WERROR reg_open_directory(TALLOC_CTX *parent_ctx, 
+                                                 const char *location, struct hive_key **key)
+{
+       struct dir_key *dk;
+
+       if (location == NULL) 
+               return WERR_INVALID_PARAM;
+
+       dk = talloc(parent_ctx, struct dir_key);
+       dk->key.ops = &reg_backend_dir;
+       dk->path = talloc_strdup(dk, location);
+       *key = (struct hive_key *)dk;
+       return WERR_OK;
+}
+
+WERROR reg_create_directory(TALLOC_CTX *parent_ctx, 
+                                                       const char *location, struct hive_key **key)
+{
+       if (mkdir(location, 0700) != 0) {
+               *key = NULL;
+               return WERR_GENERAL_FAILURE;
+       }
+
+       return reg_open_directory(parent_ctx, location, key);
+}
+
+static WERROR reg_dir_get_info(TALLOC_CTX *ctx, const struct hive_key *key, 
+                                                          const char **classname,
+                                                          uint32_t *num_subkeys,
+                                                          uint32_t *num_values,
+                                                          NTTIME *lastmod)
+{
+       DIR *d;
+       const struct dir_key *dk = talloc_get_type(key, struct dir_key);
+       struct dirent *e;
+       struct stat st;
+
+       SMB_ASSERT(key != NULL);
+
+       if (classname != NULL)
+               *classname = NULL;
+
+       d = opendir(dk->path);
+       if (d == NULL) 
+               return WERR_INVALID_PARAM;
+
+       if (num_subkeys != NULL)
+               *num_subkeys = 0;
+
+       if (num_values != NULL)
+               *num_values = 0;
+
+       while((e = readdir(d))) {
+               if(!ISDOT(e->d_name) && !ISDOTDOT(e->d_name)) {
+                       char *path = talloc_asprintf(ctx, "%s/%s", dk->path, e->d_name);
+
+                       if (stat(path, &st) < 0) {
+                               DEBUG(0, ("Error statting %s: %s\n", path, strerror(errno)));
+                               continue;
+                       }
+
+                       if (S_ISDIR(st.st_mode) && num_subkeys != NULL)
+                               (*num_subkeys)++;
+
+                       if (!S_ISDIR(st.st_mode) && num_values != NULL)
+                               (*num_values)++;
+
+                       talloc_free(path);
+               }
+       }
+
+       closedir(d);
+
+       if (lastmod != NULL)
+               *lastmod = 0;
+       return WERR_OK;
+}
+
+static WERROR reg_dir_set_value (struct hive_key *key, const char *name, 
+                                                uint32_t type, const DATA_BLOB data)
+{
+       const struct dir_key *dk = talloc_get_type(key, struct dir_key);
+       char *path = talloc_asprintf(dk, "%s/%s", dk->path, name);
+
+       if (!file_save(path, data.data, data.length))
+               return WERR_GENERAL_FAILURE;
+
+       /* FIXME: Type */
+
+       return WERR_OK;
+}
+
+static WERROR reg_dir_get_value (TALLOC_CTX *mem_ctx, 
+                                                                struct hive_key *key, const char *name, 
+                                                                uint32_t *type, DATA_BLOB *data)
+{
+       const struct dir_key *dk = talloc_get_type(key, struct dir_key);
+       char *path = talloc_asprintf(mem_ctx, "%s/%s", dk->path, name);
+       size_t size;
+       char *contents;
+
+       contents = file_load(path, &size, mem_ctx);
+       talloc_free(path);
+       if (contents == NULL) 
+               return WERR_NOT_FOUND;
+
+       if (type != NULL)
+               *type = 4; /* FIXME */
+
+       data->data = (uint8_t *)contents;
+       data->length = size;
+
+       return WERR_OK;
+}
+       
+static WERROR reg_dir_enum_value (TALLOC_CTX *mem_ctx, 
+                                                                const struct hive_key *key, int idx, 
+                                                                const char **name, 
+                                                                uint32_t *type, DATA_BLOB *data)
+{
+       const struct dir_key *dk = talloc_get_type(key, struct dir_key);
+       DIR *d;
+       struct dirent *e;
+       int i;
+
+       d = opendir(dk->path);
+       if (d == NULL) {
+               DEBUG(3,("Unable to open '%s': %s\n", dk->path, strerror(errno)));
+               return WERR_BADFILE;
+       }
+
+       i = 0;
+       while((e = readdir(d))) {
+               if (ISDOT(e->d_name) || ISDOTDOT(e->d_name)) 
+                       continue;
+
+               if (i == idx) {
+                       if (name != NULL)
+                               *name = talloc_strdup(mem_ctx, e->d_name);
+                       W_ERROR_NOT_OK_RETURN(reg_dir_get_value(mem_ctx, key, *name, type, data));
+                       return WERR_OK;
+               }
+
+               i++;
+       }
+       closedir(d);
+
+       return WERR_NO_MORE_ITEMS;
+}
+
+
+static WERROR reg_dir_del_value (struct hive_key *key, const char *name)
+{
+       const struct dir_key *dk = talloc_get_type(key, struct dir_key);
+       char *path = talloc_asprintf(key, "%s/%s", dk->path, name);
+       if (unlink(path) < 0) {
+               talloc_free(path);
+               if (errno == ENOENT)
+                       return WERR_NOT_FOUND;
+               return WERR_GENERAL_FAILURE;
+       }
+       talloc_free(path);
+               
+       return WERR_OK;
+}
+
+static struct hive_operations reg_backend_dir = {
+       .name = "dir",
+       .get_key_by_name = reg_dir_open_key,
+       .get_key_info = reg_dir_get_info,
+       .add_key = reg_dir_add_key,
+       .del_key = reg_dir_del_key,
+       .enum_key = reg_dir_key_by_index,
+       .set_value = reg_dir_set_value,
+       .get_value_by_name = reg_dir_get_value,
+       .enum_value = reg_dir_enum_value,
+       .delete_value = reg_dir_del_value,
+};
diff --git a/source/lib/registry/hive.c b/source/lib/registry/hive.c
new file mode 100644 (file)
index 0000000..b2c826b
--- /dev/null
@@ -0,0 +1,145 @@
+
+/* 
+   Unix SMB/CIFS implementation.
+   Registry hive interface
+   Copyright (C) Jelmer Vernooij                                         2003-2007.
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "hive.h"
+#include "system/filesys.h"
+
+/** Open a registry file/host/etc */
+_PUBLIC_ WERROR reg_open_hive(TALLOC_CTX *parent_ctx, const char *location, 
+                                                         struct auth_session_info *session_info, 
+                                                         struct cli_credentials *credentials, 
+                                                         struct hive_key **root)
+{
+       int fd, num;
+       char peek[20];
+
+       /* Check for directory */
+       if (directory_exist(location)) {
+               return reg_open_directory(parent_ctx, location, root);
+       }
+
+       fd = open(location, O_RDWR);
+       if (fd == -1) {
+               return WERR_BADFILE;
+       }
+
+       num = read(fd, peek, 20);
+       if (num == -1) {
+               return WERR_BADFILE;
+       }
+
+       if (!strncmp(peek, "regf", 4)) {
+               close(fd);
+               return reg_open_regf_file(parent_ctx, location, root);
+       } else if (!strncmp(peek, "TDB file", 8)) {
+               close(fd);
+               return reg_open_ldb_file(parent_ctx, location, session_info, credentials, root);
+       }
+
+       return WERR_BADFILE;
+}
+
+_PUBLIC_ WERROR hive_key_get_info(TALLOC_CTX *mem_ctx, const struct hive_key *key,
+                                                const char **classname, uint32_t *num_subkeys, 
+                                                uint32_t *num_values,
+                                                NTTIME *last_change_time)
+{
+       return key->ops->get_key_info(mem_ctx, key, classname, num_subkeys, 
+                                                                       num_values, last_change_time);
+}
+
+_PUBLIC_ WERROR hive_key_add_name(TALLOC_CTX *ctx, const struct hive_key *parent_key,
+                                                const char *name, const char *classname, struct security_descriptor *desc,
+                                                struct hive_key **key)
+{
+       SMB_ASSERT(strchr(name, '\\') == NULL);
+
+       return parent_key->ops->add_key(ctx, parent_key, name, classname, desc, key);
+}
+
+_PUBLIC_ WERROR hive_key_del(const struct hive_key *key, const char *name)
+{
+       return key->ops->del_key(key, name);
+}
+
+_PUBLIC_ WERROR hive_get_key_by_name(TALLOC_CTX *mem_ctx,
+                                                          const struct hive_key *key, const char *name, 
+                                                          struct hive_key **subkey)
+{
+       return key->ops->get_key_by_name(mem_ctx, key, name, subkey);
+}
+
+WERROR hive_enum_key(TALLOC_CTX *mem_ctx,
+                                       const struct hive_key *key, uint32_t idx, 
+                                       const char **name,
+                                       const char **classname,
+                                       NTTIME *last_mod_time)
+{
+       return key->ops->enum_key(mem_ctx, key, idx, name, classname, 
+                                                         last_mod_time);
+}
+
+WERROR hive_set_value(struct hive_key *key, const char *name, uint32_t type,
+                                         const DATA_BLOB data)
+{
+       if (key->ops->set_value == NULL)
+               return WERR_NOT_SUPPORTED;
+
+       return key->ops->set_value(key, name, type, data);
+}
+
+WERROR hive_get_value (TALLOC_CTX *mem_ctx, 
+                                          struct hive_key *key, const char *name, 
+                                          uint32_t *type, DATA_BLOB *data)
+{
+       if (key->ops->get_value_by_name == NULL)
+               return WERR_NOT_SUPPORTED;
+
+       return key->ops->get_value_by_name(mem_ctx, key, name, type, data);
+}
+
+WERROR hive_get_value_by_index (TALLOC_CTX *mem_ctx, 
+                                          struct hive_key *key, uint32_t idx, const char **name, 
+                                          uint32_t *type, DATA_BLOB *data)
+{
+       if (key->ops->enum_value == NULL)
+               return WERR_NOT_SUPPORTED;
+
+       return key->ops->enum_value(mem_ctx, key, idx, name, type, data);
+}
+
+
+WERROR hive_del_value (struct hive_key *key, const char *name)
+{
+       if (key->ops->delete_value == NULL)
+               return WERR_NOT_SUPPORTED;
+
+       return key->ops->delete_value(key, name);
+}
+
+WERROR hive_key_flush(struct hive_key *key)
+{
+       if (key->ops->flush_key == NULL)
+               return WERR_OK;
+
+       return key->ops->flush_key(key);
+}
diff --git a/source/lib/registry/hive.h b/source/lib/registry/hive.h
new file mode 100644 (file)
index 0000000..33759fd
--- /dev/null
@@ -0,0 +1,197 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Registry hive interface
+   Copyright (C) Jelmer Vernooij                                         2003-2007.
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __REGISTRY_HIVE_H__
+#define __REGISTRY_HIVE_H__
+
+#include "core.h"
+#include "talloc.h"
+#include "librpc/gen_ndr/security.h"
+
+/**
+ * This file contains the hive API. This API is generally used for 
+ * reading a specific file that contains just one hive. 
+ *
+ * Good examples are .DAT (NTUSER.DAT) files.
+ *
+ * This API does not have any notification support (that 
+ * should be provided by the registry implementation), nor 
+ * does it understand what predefined keys are.
+ */
+
+struct hive_key {
+       const struct hive_operations *ops;
+};
+
+struct hive_operations {
+       const char *name;       
+
+       /**
+        * Open a specific subkey
+        */
+       WERROR (*enum_key) (TALLOC_CTX *mem_ctx,
+                                               const struct hive_key *key, uint32_t idx, 
+                                               const char **name,
+                                               const char **classname,
+                                               NTTIME *last_mod_time);
+
+       /**
+        * Open a subkey by name
+        */
+       WERROR (*get_key_by_name) (TALLOC_CTX *mem_ctx,
+                                                          const struct hive_key *key, const char *name, 
+                                                          struct hive_key **subkey);
+       
+       /**
+        * Add a new key.
+        */
+       WERROR (*add_key) (TALLOC_CTX *ctx,
+                                          const struct hive_key *parent_key, const char *name, 
+                                          const char *classname, struct security_descriptor *desc, 
+                                          struct hive_key **key);
+       /**
+        * Remove an existing key.
+        */
+       WERROR (*del_key) (const struct hive_key *key, const char *name);
+
+       /**
+        * Force write of a key to disk.
+        */
+       WERROR (*flush_key) (struct hive_key *key);
+
+       /**
+        * Retrieve a registry value with a specific index.
+        */
+       WERROR (*enum_value) (TALLOC_CTX *mem_ctx,
+                                                 const struct hive_key *key, int idx, 
+                                                 const char **name, uint32_t *type, 
+                                                 DATA_BLOB *data);
+
+       /**
+        * Retrieve a registry value with the specified name
+        */
+       WERROR (*get_value_by_name) (TALLOC_CTX *mem_ctx, 
+                                                                struct hive_key *key, const char *name, 
+                                                                uint32_t *type, DATA_BLOB *data);
+       
+       /**
+        * Set a value on the specified registry key.
+        */
+       WERROR (*set_value) (struct hive_key *key, const char *name, 
+                                                uint32_t type, const DATA_BLOB data);
+
+       /**
+        * Remove a value.
+        */
+       WERROR (*delete_value) (struct hive_key *key, const char *name);
+
+       /* Security Descriptors */
+
+       /**
+        * Change the security descriptor on a registry key.
+        *
+        * This should return WERR_NOT_SUPPORTED if the underlying 
+        * format does not have a mechanism for storing 
+        * security descriptors.
+        */
+       WERROR (*set_sec_desc) (struct hive_key *key, 
+                                                       const struct security_descriptor *desc);
+
+       /**
+        * Retrieve the security descriptor on a registry key.
+        *
+        * This should return WERR_NOT_SUPPORTED if the underlying 
+        * format does not have a mechanism for storing 
+        * security descriptors.
+        */
+       WERROR (*get_sec_desc) (TALLOC_CTX *ctx,
+                                                       const struct hive_key *key, 
+                                                       struct security_descriptor **desc);
+       
+       /**
+        * Retrieve general information about a key.
+        */
+       WERROR (*get_key_info) (TALLOC_CTX *mem_ctx,
+                                                       const struct hive_key *key,
+                                                       const char **classname,
+                                                       uint32_t *num_subkeys,
+                                                       uint32_t *num_values,
+                                                       NTTIME *last_change_time);
+};
+
+struct cli_credentials;
+struct auth_session_info;
+
+WERROR reg_open_hive(TALLOC_CTX *parent_ctx, const char *location, 
+                                                         struct auth_session_info *session_info, 
+                                                         struct cli_credentials *credentials, 
+                                                         struct hive_key **root);
+WERROR hive_key_get_info(TALLOC_CTX *mem_ctx, const struct hive_key *key,
+                                                const char **classname, uint32_t *num_subkeys, 
+                                                uint32_t *num_values,
+                                                NTTIME *last_change_time);
+WERROR hive_key_add_name(TALLOC_CTX *ctx, const struct hive_key *parent_key,
+                                                const char *name, const char *classname, struct security_descriptor *desc,
+                                                struct hive_key **key);
+_PUBLIC_ WERROR hive_key_del(const struct hive_key *key, const char *name);
+_PUBLIC_ WERROR hive_get_key_by_name(TALLOC_CTX *mem_ctx,
+                                                          const struct hive_key *key, const char *name, 
+                                                          struct hive_key **subkey);
+WERROR hive_enum_key(TALLOC_CTX *mem_ctx,
+                                       const struct hive_key *key, uint32_t idx, 
+                                       const char **name,
+                                       const char **classname,
+                                       NTTIME *last_mod_time);
+
+WERROR hive_set_value (struct hive_key *key, const char *name, 
+                                          uint32_t type, const DATA_BLOB data);
+
+WERROR hive_get_value (TALLOC_CTX *mem_ctx, 
+                                          struct hive_key *key, const char *name, 
+                                          uint32_t *type, DATA_BLOB *data);
+WERROR hive_get_value_by_index (TALLOC_CTX *mem_ctx, 
+                                          struct hive_key *key, uint32_t idx, const char **name, 
+                                          uint32_t *type, DATA_BLOB *data);
+
+WERROR hive_del_value (struct hive_key *key, const char *name);
+
+WERROR hive_key_flush(struct hive_key *key);
+
+
+/* Individual backends */
+WERROR reg_open_directory(TALLOC_CTX *parent_ctx, 
+                       const char *location, struct hive_key **key);
+WERROR reg_open_regf_file(TALLOC_CTX *parent_ctx, 
+                                                 const char *location, struct hive_key **key);
+WERROR reg_open_ldb_file(TALLOC_CTX *parent_ctx, const char *location, 
+                                                               struct auth_session_info *session_info,
+                                                               struct cli_credentials *credentials,
+                                                               struct hive_key **k);
+
+
+WERROR reg_create_directory(TALLOC_CTX *parent_ctx, 
+                       const char *location, struct hive_key **key);
+WERROR reg_create_regf_file(TALLOC_CTX *parent_ctx, 
+                                                        const char *location, 
+                                                        int major_version, 
+                                                        struct hive_key **key);
+
+
+#endif /* __REGISTRY_HIVE_H__ */
diff --git a/source/lib/registry/interface.c b/source/lib/registry/interface.c
new file mode 100644 (file)
index 0000000..4d75e99
--- /dev/null
@@ -0,0 +1,277 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Transparent registry backend handling
+   Copyright (C) Jelmer Vernooij                       2003-2007.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/util/dlinklist.h"
+#include "lib/registry/registry.h"
+#include "system/filesys.h"
+#include "build.h"
+
+
+/**
+ * @file
+ * @brief Main registry functions
+ */
+
+const struct reg_predefined_key reg_predefined_keys[] = {
+       {HKEY_CLASSES_ROOT,"HKEY_CLASSES_ROOT" },
+       {HKEY_CURRENT_USER,"HKEY_CURRENT_USER" },
+       {HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE" },
+       {HKEY_PERFORMANCE_DATA, "HKEY_PERFORMANCE_DATA" },
+       {HKEY_USERS, "HKEY_USERS" },
+       {HKEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG" },
+       {HKEY_DYN_DATA, "HKEY_DYN_DATA" },
+       {HKEY_PERFORMANCE_TEXT, "HKEY_PERFORMANCE_TEXT" },
+       {HKEY_PERFORMANCE_NLSTEXT, "HKEY_PERFORMANCE_NLSTEXT" },
+       { 0, NULL }
+};
+
+/** Obtain name of specific hkey. */
+_PUBLIC_ const char *reg_get_predef_name(uint32_t hkey)
+{
+       int i;
+       for (i = 0; reg_predefined_keys[i].name; i++) {
+               if (reg_predefined_keys[i].handle == hkey) 
+                       return reg_predefined_keys[i].name;
+       }
+
+       return NULL;
+}
+
+/** Get predefined key by name. */
+_PUBLIC_ WERROR reg_get_predefined_key_by_name(struct registry_context *ctx, 
+                                                                                          const char *name, 
+                                                                                          struct registry_key **key)
+{
+       int i;
+       
+       for (i = 0; reg_predefined_keys[i].name; i++) {
+               if (!strcasecmp(reg_predefined_keys[i].name, name)) 
+                       return reg_get_predefined_key(ctx, reg_predefined_keys[i].handle, 
+                                                                                 key);
+       }
+
+       DEBUG(1, ("No predefined key with name '%s'\n", name));
+       
+       return WERR_BADFILE;
+}
+
+/** Get predefined key by id. */
+_PUBLIC_ WERROR reg_get_predefined_key(const struct registry_context *ctx, 
+                                                                          uint32_t hkey, struct registry_key **key)
+{
+       return ctx->ops->get_predefined_key(ctx, hkey, key);
+}
+
+/**
+ * Open a key 
+ * First tries to use the open_key function from the backend
+ * then falls back to get_subkey_by_name and later get_subkey_by_index 
+ */
+_PUBLIC_ WERROR reg_open_key(TALLOC_CTX *mem_ctx, struct registry_key *parent, 
+                                                        const char *name, struct registry_key **result)
+{
+       if (parent == NULL) {
+               DEBUG(0, ("Invalid parent key specified for open of '%s'\n", name));
+               return WERR_INVALID_PARAM;
+       }
+
+       if (parent->context->ops->open_key == NULL) {
+               DEBUG(0, ("Registry backend doesn't have open_key!\n"));
+               return WERR_NOT_SUPPORTED;
+       }
+
+       return parent->context->ops->open_key(mem_ctx, parent, name, result);
+}
+
+/**
+ * Get value by index
+ */
+_PUBLIC_ WERROR reg_key_get_value_by_index(TALLOC_CTX *mem_ctx, 
+                                                                                  const struct registry_key *key, 
+                                                                                  uint32_t idx,
+                                                                                  const char **name,
+                                                                                  uint32_t *type,
+                                                                                  DATA_BLOB *data)
+{
+       if (key == NULL) 
+               return WERR_INVALID_PARAM;
+
+       if (key->context->ops->enum_value == NULL)
+               return WERR_NOT_SUPPORTED;
+
+       return key->context->ops->enum_value(mem_ctx, key, idx, name, type, 
+                                                                                                       data);
+}
+
+/** 
+ * Get the number of subkeys.
+ */
+_PUBLIC_ WERROR reg_key_get_info(TALLOC_CTX *mem_ctx, 
+                                                                const struct registry_key *key, 
+                                                                const char **classname,
+                                                                uint32_t *num_subkeys,
+                                                                uint32_t *num_values,
+                                                                NTTIME *last_change_time)
+{
+       if (key == NULL) 
+               return WERR_INVALID_PARAM;
+       
+       if (key->context->ops->get_key_info == NULL)
+               return WERR_NOT_SUPPORTED;
+
+       return key->context->ops->get_key_info(mem_ctx,
+                                                                                  key, classname, num_subkeys, 
+                                                                                  num_values, last_change_time);
+}
+
+/**
+ * Get subkey by index.
+ */
+_PUBLIC_ WERROR reg_key_get_subkey_by_index(TALLOC_CTX *mem_ctx, 
+               const struct registry_key *key, int idx, const char **name,
+               const char **keyclass, NTTIME *last_changed_time)
+{
+       if (key == NULL) 
+               return WERR_INVALID_PARAM;
+
+       if (key->context->ops->enum_key == NULL)
+               return WERR_NOT_SUPPORTED;
+
+       return key->context->ops->enum_key(mem_ctx, key, idx, name,
+                                                                                 keyclass, last_changed_time);
+}
+
+/**
+ * Get value by name.
+ */
+_PUBLIC_ WERROR reg_key_get_value_by_name(TALLOC_CTX *mem_ctx, 
+                                                                                 const struct registry_key *key, 
+                                                                                 const char *name, 
+                                                                                 uint32_t *type,
+                                                                                 DATA_BLOB *data)
+{
+       if (key == NULL) 
+               return WERR_INVALID_PARAM;
+
+       if (key->context->ops->get_value == NULL)
+               return WERR_NOT_SUPPORTED;
+
+       return key->context->ops->get_value(mem_ctx, key, name, type, data);
+}
+
+/**
+ * Delete a key.
+ */
+_PUBLIC_ WERROR reg_key_del(struct registry_key *parent, const char *name)
+{
+       if (parent == NULL) 
+               return WERR_INVALID_PARAM;
+       
+       if (parent->context->ops->delete_key == NULL)
+               return WERR_NOT_SUPPORTED;
+       
+       return parent->context->ops->delete_key(parent, name);
+}
+
+/**
+ * Add a key.
+ */
+_PUBLIC_ WERROR reg_key_add_name(TALLOC_CTX *mem_ctx, 
+                                                                struct registry_key *parent, 
+                                                                const char *name, const char *key_class, 
+                                                                struct security_descriptor *desc, 
+                                                                struct registry_key **newkey)
+{
+       if (parent == NULL) 
+               return WERR_INVALID_PARAM;
+       
+       if (parent->context->ops->create_key == NULL) {
+               DEBUG(1, ("Backend '%s' doesn't support method add_key\n", 
+                                 parent->context->ops->name));
+               return WERR_NOT_SUPPORTED;
+       }
+
+       return parent->context->ops->create_key(mem_ctx, parent, name, 
+                                                                                       key_class, desc, newkey);
+}
+
+/**
+ * Set a value.
+ */
+_PUBLIC_ WERROR reg_val_set(struct registry_key *key, const char *value, 
+                                                       uint32_t type, const DATA_BLOB data)
+{
+       if (key == NULL)
+               return WERR_INVALID_PARAM;
+
+       /* A 'real' set function has preference */
+       if (key->context->ops->set_value == NULL) {
+               DEBUG(1, ("Backend '%s' doesn't support method set_value\n", 
+                                 key->context->ops->name));
+               return WERR_NOT_SUPPORTED;
+       }
+
+       return key->context->ops->set_value(key, value, type, data);
+}
+
+/**
+ * Get the security descriptor on a key.
+ */
+_PUBLIC_ WERROR reg_get_sec_desc(TALLOC_CTX *ctx, 
+                                                                const struct registry_key *key, 
+                                                                struct security_descriptor **secdesc)
+{
+       if (key == NULL)
+               return WERR_INVALID_PARAM;
+
+       /* A 'real' set function has preference */
+       if (key->context->ops->get_security == NULL)  
+               return WERR_NOT_SUPPORTED;
+
+       return key->context->ops->get_security(ctx, key, secdesc);
+}
+
+/**
+ * Delete a value.
+ */
+_PUBLIC_ WERROR reg_del_value(struct registry_key *key, const char *valname)
+{
+       if (key == NULL)
+               return WERR_INVALID_PARAM;
+
+       if (key->context->ops->delete_value == NULL)
+               return WERR_NOT_SUPPORTED;
+
+       return key->context->ops->delete_value(key, valname);
+}
+
+/**
+ * Flush a key to disk.
+ */
+_PUBLIC_ WERROR reg_key_flush(struct registry_key *key)
+{
+       if (key == NULL)
+               return WERR_INVALID_PARAM;
+       
+       if (key->context->ops->flush_key == NULL)
+               return WERR_NOT_SUPPORTED;
+
+       return key->context->ops->flush_key(key);
+}
diff --git a/source/lib/registry/ldb.c b/source/lib/registry/ldb.c
new file mode 100644 (file)
index 0000000..8ee4d9f
--- /dev/null
@@ -0,0 +1,501 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Registry interface
+   Copyright (C) Jelmer Vernooij  2004-2007.
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "registry.h"
+#include "lib/ldb/include/ldb.h"
+#include "lib/ldb/include/ldb_errors.h"
+#include "db_wrap.h"
+#include "librpc/gen_ndr/winreg.h"
+
+static struct hive_operations reg_backend_ldb;
+
+struct ldb_key_data 
+{
+       struct hive_key key;
+       struct ldb_context *ldb;
+       struct ldb_dn *dn;
+       struct ldb_message **subkeys, **values;
+       int subkey_count, value_count;
+};
+
+static void reg_ldb_unpack_value(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char **name, 
+                                                                uint32_t *type, DATA_BLOB *data)
+{
+       const struct ldb_val *val;
+       if (name != NULL)
+               *name = talloc_strdup(mem_ctx, ldb_msg_find_attr_as_string(msg, "value", NULL));
+
+       if (type != NULL)
+               *type = ldb_msg_find_attr_as_uint(msg, "type", 0);
+       val = ldb_msg_find_ldb_val(msg, "data");
+
+       switch (*type)
+       {
+       case REG_SZ:
+       case REG_EXPAND_SZ:
+               data->length = convert_string_talloc(mem_ctx, CH_UTF8, CH_UTF16, 
+                                                                                        val->data, val->length, (void **)&data->data);
+               break;
+
+       case REG_DWORD: {
+               uint32_t tmp = strtoul((char *)val->data, NULL, 0);
+               *data = data_blob_talloc(mem_ctx, &tmp, 4);
+               }
+               break;
+
+       default:
+               *data = data_blob_talloc(mem_ctx, val->data, val->length);
+               break;
+       }
+}
+
+static struct ldb_message *reg_ldb_pack_value(struct ldb_context *ctx, 
+                                               TALLOC_CTX *mem_ctx, const char *name, 
+                                               uint32_t type, DATA_BLOB data)
+{
+       struct ldb_val val;
+       struct ldb_message *msg = talloc_zero(mem_ctx, struct ldb_message);
+       char *type_s;
+
+       ldb_msg_add_string(msg, "value", talloc_strdup(mem_ctx, name));
+
+       switch (type) {
+       case REG_SZ:
+       case REG_EXPAND_SZ:
+               val.length = convert_string_talloc(mem_ctx, CH_UTF16, CH_UTF8, 
+                                                                                  (void *)data.data, data.length, (void **)&val.data);
+               ldb_msg_add_value(msg, "data", &val, NULL);
+               break;
+
+       case REG_DWORD:
+               ldb_msg_add_string(msg, "data", talloc_asprintf(mem_ctx, "0x%x", IVAL(data.data, 0)));
+               break;
+       default:
+               ldb_msg_add_value(msg, "data", &data, NULL);
+       }
+
+
+       type_s = talloc_asprintf(mem_ctx, "%u", type);
+       ldb_msg_add_string(msg, "type", type_s); 
+
+       return msg;
+}
+
+
+static int reg_close_ldb_key(struct ldb_key_data *key)
+{
+       if (key->subkeys != NULL) {
+               talloc_free(key->subkeys); 
+               key->subkeys = NULL;
+       }
+
+       if (key->values != NULL) {
+               talloc_free(key->values); 
+               key->values = NULL;
+       }
+       return 0;
+}
+
+static struct ldb_dn *reg_path_to_ldb(TALLOC_CTX *mem_ctx, 
+                                                                         const struct hive_key *from, 
+                                                                         const char *path, const char *add)
+{
+       TALLOC_CTX *local_ctx;
+       struct ldb_dn *ret;
+       char *mypath = talloc_strdup(mem_ctx, path);
+       char *begin;
+       struct ldb_key_data *kd = talloc_get_type(from, struct ldb_key_data);
+       struct ldb_context *ldb = kd->ldb;
+
+       local_ctx = talloc_new(mem_ctx);
+
+       if (add) {
+               ret = ldb_dn_new(mem_ctx, ldb, add);
+       } else {
+               ret = ldb_dn_new(mem_ctx, ldb, NULL);
+       }
+       if (!ldb_dn_validate(ret)) {
+               talloc_free(ret);
+               talloc_free(local_ctx);
+               return NULL;
+       }
+
+       while (mypath) {
+               char *keyname;
+
+               begin = strrchr(mypath, '\\');
+
+               if (begin) keyname = begin + 1;
+               else keyname = mypath;
+
+               if(strlen(keyname)) {
+                       ldb_dn_add_base_fmt(ret, "key=%s", keyname);
+               }
+
+               if(begin) {
+                       *begin = '\0';
+               } else {
+                       break;
+               }
+       }
+
+       ldb_dn_add_base(ret, kd->dn);
+
+       talloc_free(local_ctx);
+
+       return ret;
+}
+
+static WERROR cache_subkeys(struct ldb_key_data *kd)
+{
+       struct ldb_context *c = kd->ldb;
+       struct ldb_result *res;
+       int ret;
+
+       ret = ldb_search(c, kd->dn, LDB_SCOPE_ONELEVEL, "(key=*)", NULL, &res);
+
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0, ("Error getting subkeys for '%s': %s\n", ldb_dn_get_linearized(kd->dn), ldb_errstring(c)));
+               return WERR_FOOBAR;
+       }
+
+       kd->subkey_count = res->count;
+       kd->subkeys = talloc_steal(kd, res->msgs);
+       talloc_free(res);
+
+       return WERR_OK;
+}
+
+static WERROR cache_values(struct ldb_key_data *kd)
+{
+       struct ldb_context *c = kd->ldb;
+       struct ldb_result *res;
+       int ret;
+
+       ret = ldb_search(c, kd->dn, LDB_SCOPE_ONELEVEL, "(value=*)", NULL, &res);
+
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0, ("Error getting values for '%s': %s\n", ldb_dn_get_linearized(kd->dn), ldb_errstring(c)));
+               return WERR_FOOBAR;
+       }
+       kd->value_count = res->count;
+       kd->values = talloc_steal(kd, res->msgs);
+       talloc_free(res);
+       return WERR_OK;
+}
+
+
+static WERROR ldb_get_subkey_by_id(TALLOC_CTX *mem_ctx, 
+                                                  const struct hive_key *k, uint32_t idx, 
+                                                  const char **name,
+                                                  const char **classname,
+                                                  NTTIME *last_mod_time)
+{
+       struct ldb_message_element *el;
+       struct ldb_key_data *kd = talloc_get_type(k, struct ldb_key_data);
+
+       /* Do a search if necessary */
+       if (kd->subkeys == NULL) {
+               W_ERROR_NOT_OK_RETURN(cache_subkeys(kd));
+       } 
+
+       if (idx >= kd->subkey_count) 
+               return WERR_NO_MORE_ITEMS;
+
+       el = ldb_msg_find_element(kd->subkeys[idx], "key");
+       SMB_ASSERT(el != NULL);
+       SMB_ASSERT(el->num_values != 0);
+       
+       if (name != NULL)
+               *name = talloc_strdup(mem_ctx, (char *)el->values[0].data);
+
+       if (classname != NULL)
+               *classname = NULL; /* TODO: Store properly */
+       
+       if (last_mod_time != NULL)
+               *last_mod_time = 0; /* TODO: we need to add this to the
+                                               ldb backend properly */
+
+       return WERR_OK;
+}
+
+static WERROR ldb_get_value_by_id(TALLOC_CTX *mem_ctx, const struct hive_key *k, int idx, 
+                                                                 const char **name, uint32_t *data_type, DATA_BLOB *data)
+{
+       struct ldb_key_data *kd = talloc_get_type(k, struct ldb_key_data);
+
+       /* Do the search if necessary */
+       if (kd->values == NULL) {
+               W_ERROR_NOT_OK_RETURN(cache_values(kd));
+       }
+
+       if(idx >= kd->value_count) return WERR_NO_MORE_ITEMS;
+
+       reg_ldb_unpack_value(mem_ctx, kd->values[idx], 
+                                                name, data_type, data);
+
+       return WERR_OK;
+}
+
+static WERROR ldb_get_value(TALLOC_CTX *mem_ctx, struct hive_key *k, 
+                                       const char *name, uint32_t *data_type, DATA_BLOB *data)
+{
+       struct ldb_key_data *kd = talloc_get_type(k, struct ldb_key_data);
+       struct ldb_context *c = kd->ldb;
+       struct ldb_result *res;
+       int ret;
+       char *query = talloc_asprintf(mem_ctx, "(value=%s)", name);
+
+       ret = ldb_search(c, kd->dn, LDB_SCOPE_ONELEVEL, query, NULL, &res);
+
+       talloc_free(query);
+
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0, ("Error getting values for '%s': %s\n", ldb_dn_get_linearized(kd->dn), ldb_errstring(c)));
+               return WERR_FOOBAR;
+       }
+
+       if (res->count == 0)
+               return WERR_NOT_FOUND;
+
+       reg_ldb_unpack_value(mem_ctx, res->msgs[0], NULL, data_type, data);
+
+       return WERR_OK;
+}
+
+static WERROR ldb_open_key(TALLOC_CTX *mem_ctx, const struct hive_key *h, 
+                                                  const char *name, struct hive_key **key)
+{
+       struct ldb_result *res;
+       struct ldb_dn *ldap_path;
+       int ret;
+       struct ldb_key_data *newkd;
+       struct ldb_key_data *kd = talloc_get_type(h, struct ldb_key_data);
+       struct ldb_context *c = kd->ldb;
+
+       ldap_path = reg_path_to_ldb(mem_ctx, h, name, NULL);
+
+       ret = ldb_search(c, ldap_path, LDB_SCOPE_BASE, "(key=*)", NULL, &res);
+
+       if (ret != LDB_SUCCESS) {
+               DEBUG(0, ("Error opening key '%s': %s\n", 
+                                 ldb_dn_get_linearized(ldap_path), ldb_errstring(c)));
+               return WERR_FOOBAR;
+       } else if (res->count == 0) {
+               DEBUG(0, ("Key '%s' not found\n", ldb_dn_get_linearized(ldap_path)));
+               talloc_free(res);
+               return WERR_NOT_FOUND;
+       }
+
+       newkd = talloc_zero(mem_ctx, struct ldb_key_data);
+       newkd->key.ops = &reg_backend_ldb;
+       newkd->ldb = talloc_reference(newkd, kd->ldb);
+       newkd->dn = ldb_dn_copy(mem_ctx, res->msgs[0]->dn); 
+
+       *key = (struct hive_key *)newkd;
+
+       talloc_free(res);
+
+       return WERR_OK;
+}
+
+WERROR reg_open_ldb_file(TALLOC_CTX *parent_ctx, const char *location, 
+                                                               struct auth_session_info *session_info,
+                                                               struct cli_credentials *credentials,
+                                                               struct hive_key **k)
+{
+       struct ldb_key_data *kd;
+       struct ldb_context *wrap;
+
+       if (location == NULL) 
+               return WERR_INVALID_PARAM;
+
+       wrap = ldb_wrap_connect(parent_ctx, location, session_info, 
+                                                       credentials, 0, NULL);
+
+       if (wrap == NULL) {
+               DEBUG(1, (__FILE__": unable to connect\n"));
+               return WERR_FOOBAR;
+       }
+
+       ldb_set_debug_stderr(wrap);
+
+       kd = talloc_zero(parent_ctx, struct ldb_key_data);
+       kd->key.ops = &reg_backend_ldb;
+       kd->ldb = talloc_reference(kd, wrap);
+       talloc_set_destructor (kd, reg_close_ldb_key);
+       kd->dn = ldb_dn_new(kd, wrap, "hive=NONE");
+
+       *k = (struct hive_key *)kd;
+
+       return WERR_OK;
+}
+
+static WERROR ldb_add_key (TALLOC_CTX *mem_ctx, const struct hive_key *parent, 
+                                                  const char *name, const char *classname,
+                                                  struct security_descriptor *sd, 
+                                                  struct hive_key **newkey)
+{
+       const struct ldb_key_data *parentkd = (const struct ldb_key_data *)parent;
+       struct ldb_message *msg;
+       struct ldb_key_data *newkd;
+       int ret;
+
+       msg = ldb_msg_new(mem_ctx);
+
+       msg->dn = reg_path_to_ldb(msg, parent, name, NULL);
+
+       ldb_msg_add_string(msg, "key", talloc_strdup(mem_ctx, name));
+       if (classname != NULL)
+               ldb_msg_add_string(msg, "classname", talloc_strdup(mem_ctx, classname));
+
+       ret = ldb_add(parentkd->ldb, msg);
+       if (ret < 0) {
+               DEBUG(1, ("ldb_msg_add: %s\n", ldb_errstring(parentkd->ldb)));
+               return WERR_FOOBAR;
+       } 
+
+       DEBUG(2, ("key added: %s\n", ldb_dn_get_linearized(msg->dn)));
+
+       newkd = talloc_zero(mem_ctx, struct ldb_key_data);
+       newkd->ldb = talloc_reference(newkd, parentkd->ldb);
+       newkd->key.ops = &reg_backend_ldb;
+       newkd->dn = talloc_steal(newkd, msg->dn);
+
+       *newkey = (struct hive_key *)newkd;
+
+       return WERR_OK;
+}
+
+static WERROR ldb_del_key (const struct hive_key *key, const char *child)
+{
+       int ret;
+       struct ldb_key_data *parentkd = talloc_get_type(key, struct ldb_key_data);
+       struct ldb_dn *childdn;
+
+       childdn = ldb_dn_copy(parentkd->ldb, parentkd->dn);
+       ldb_dn_add_child_fmt(childdn, "key=%s", child);
+
+       ret = ldb_delete(parentkd->ldb, childdn);
+
+       talloc_free(childdn);
+
+       if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+               return WERR_NOT_FOUND;
+       } else if (ret < 0) {
+               DEBUG(1, ("ldb_del_key: %s\n", ldb_errstring(parentkd->ldb)));
+               return WERR_FOOBAR;
+       }
+
+       return WERR_OK;
+}
+
+static WERROR ldb_del_value (struct hive_key *key, const char *child)
+{
+       int ret;
+       struct ldb_key_data *kd = talloc_get_type(key, struct ldb_key_data);
+       struct ldb_dn *childdn;
+
+       childdn = ldb_dn_copy(kd->ldb, kd->dn);
+       ldb_dn_add_child_fmt(childdn, "value=%s", child);
+
+       ret = ldb_delete(kd->ldb, childdn);
+
+       talloc_free(childdn);
+
+       if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+               return WERR_NOT_FOUND;
+       } else if (ret < 0) {
+               DEBUG(1, ("ldb_del_value: %s\n", ldb_errstring(kd->ldb)));
+               return WERR_FOOBAR;
+       }
+
+       return WERR_OK;
+}
+
+static WERROR ldb_set_value(struct hive_key *parent, 
+                                                       const char *name, uint32_t type, 
+                                                       const DATA_BLOB data)
+{
+       struct ldb_message *msg;
+       struct ldb_key_data *kd = talloc_get_type(parent, struct ldb_key_data);
+       int ret;
+       TALLOC_CTX *mem_ctx = talloc_init("ldb_set_value");
+
+       msg = reg_ldb_pack_value(kd->ldb, mem_ctx, name, type, data);
+
+       msg->dn = ldb_dn_copy(msg, kd->dn);
+       ldb_dn_add_child_fmt(msg->dn, "value=%s", name);
+
+       ret = ldb_add(kd->ldb, msg);
+       if (ret < 0) {
+               ret = ldb_modify(kd->ldb, msg);
+               if (ret < 0) {
+                       DEBUG(1, ("ldb_msg_add: %s\n", ldb_errstring(kd->ldb)));
+                       talloc_free(mem_ctx);
+                       return WERR_FOOBAR;
+               }
+       }
+       
+       talloc_free(mem_ctx);
+       return WERR_OK;
+}
+
+static WERROR ldb_get_key_info(TALLOC_CTX *mem_ctx, 
+                                                          const struct hive_key *key,
+                                                          const char **classname, 
+                                                          uint32_t *num_subkeys,
+                                                          uint32_t *num_values,
+                                                          NTTIME *last_change_time)
+{
+       struct ldb_key_data *kd = talloc_get_type(key, struct ldb_key_data);
+
+       /* FIXME */
+       if (classname != NULL)
+               *classname = NULL;
+
+       if (num_subkeys != NULL) {
+               W_ERROR_NOT_OK_RETURN(cache_subkeys(kd));
+               *num_subkeys = kd->subkey_count;
+       }
+
+       if (num_values != NULL) {
+               W_ERROR_NOT_OK_RETURN(cache_values(kd));
+               *num_values = kd->value_count;
+       }
+
+       if (last_change_time != NULL)
+               *last_change_time = 0;
+
+       return WERR_OK;
+}
+
+static struct hive_operations reg_backend_ldb = {
+       .name = "ldb",
+       .add_key = ldb_add_key,
+       .del_key = ldb_del_key,
+       .get_key_by_name = ldb_open_key,
+       .enum_value = ldb_get_value_by_id,
+       .enum_key = ldb_get_subkey_by_id,
+       .set_value = ldb_set_value,
+       .get_value_by_name = ldb_get_value,
+       .delete_value = ldb_del_value,
+       .get_key_info = ldb_get_key_info,
+};
diff --git a/source/lib/registry/local.c b/source/lib/registry/local.c
new file mode 100644 (file)
index 0000000..aefb11b
--- /dev/null
@@ -0,0 +1,333 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Transparent registry backend handling
+   Copyright (C) Jelmer Vernooij                       2003-2007.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "lib/util/dlinklist.h"
+#include "lib/registry/registry.h"
+#include "system/filesys.h"
+#include "build.h"
+
+struct reg_key_path {
+       uint32_t predefined_key;
+       const char **elements;
+};
+
+struct registry_local {
+       struct registry_context registry;
+
+       struct mountpoint {
+               struct reg_key_path path;
+               struct hive_key *key;
+               struct mountpoint *prev, *next;
+       } *mountpoints;
+
+       struct auth_session_info *session_info; 
+       struct cli_credentials *credentials;
+};
+
+struct local_key {
+       struct registry_key global;
+       struct reg_key_path path;
+       struct hive_key *hive_key;
+};
+
+
+struct registry_key *reg_import_hive_key(struct registry_context *ctx,
+                                                                            struct hive_key *hive, 
+                                                                                uint32_t predefined_key,
+                                                                                const char **elements)
+{
+       struct local_key *local_key;
+       struct reg_key_path parent_path;
+
+       parent_path.predefined_key = predefined_key;
+       parent_path.elements = elements;
+
+       local_key = talloc(ctx, struct local_key);
+       local_key->hive_key = talloc_steal(local_key, hive);
+       local_key->global.context = talloc_reference(local_key, ctx);
+       local_key->path = parent_path;
+
+       return (struct registry_key *)local_key;
+}
+
+
+static WERROR local_open_key(TALLOC_CTX *mem_ctx,
+                                                  struct registry_key *parent, 
+                                                  const char *path,
+                                                  struct registry_key **result)
+{
+       char *orig = talloc_strdup(mem_ctx, path),
+                *curbegin = orig, 
+                *curend = strchr(orig, '\\');
+       struct local_key *local_parent = talloc_get_type(parent, struct local_key);
+       struct hive_key *curkey = local_parent->hive_key;
+       WERROR error;
+       const char **elements = NULL;
+       int el;
+
+       if (local_parent->path.elements != NULL) {
+               elements = talloc_array(mem_ctx, const char *, 
+                                                       str_list_length(local_parent->path.elements) + 1);
+               for (el = 0; local_parent->path.elements[el] != NULL; el++) {
+                       elements[el] = talloc_reference(elements, 
+                                                                                       local_parent->path.elements[el]);
+               }
+               elements[el] = NULL;
+       } else {
+               elements = NULL;
+               el = 0;
+       }
+
+       while (curbegin != NULL && *curbegin) {
+               if (curend != NULL)
+                       *curend = '\0';
+               elements = talloc_realloc(mem_ctx, elements, const char *, el+2);
+               elements[el] = talloc_strdup(elements, curbegin);
+               el++;
+               elements[el] = NULL;
+               error = hive_get_key_by_name(mem_ctx, curkey, curbegin, &curkey);
+               if (!W_ERROR_IS_OK(error)) {
+                       DEBUG(2, ("Opening key %s failed: %s\n", curbegin, win_errstr(error)));
+                       talloc_free(orig);
+                       return error;
+               }
+               if (curend == NULL) 
+                       break;
+               curbegin = curend + 1;
+               curend = strchr(curbegin, '\\');
+       }
+       talloc_free(orig);
+
+       *result = reg_import_hive_key(local_parent->global.context, curkey, 
+                                                                 local_parent->path.predefined_key,
+                                                                 talloc_steal(curkey, elements));
+       
+       return WERR_OK;
+}
+
+WERROR local_get_predefined_key (const struct registry_context *ctx, 
+         uint32_t key_id, struct registry_key **key) 
+{      
+       struct registry_local *rctx = talloc_get_type(ctx, struct registry_local);
+       struct mountpoint *mp;
+
+       for (mp = rctx->mountpoints; mp != NULL; mp = mp->next) {
+               if (mp->path.predefined_key == key_id && 
+                       mp->path.elements == NULL)
+                       break;
+       }
+
+       if (mp == NULL)
+               return WERR_NOT_FOUND;
+       
+       *key = reg_import_hive_key(ctx, mp->key, 
+                                                          mp->path.predefined_key, 
+                                                          mp->path.elements
+                                                          );
+
+       return WERR_OK;
+}
+
+WERROR local_enum_key(TALLOC_CTX *mem_ctx,
+                                         const struct registry_key *key, uint32_t idx,
+                                         const char **name,
+                                         const char **keyclass,
+                                         NTTIME *last_changed_time)
+{
+       const struct local_key *local = (const struct local_key *)key;
+
+       return hive_enum_key(mem_ctx, local->hive_key, idx, name, keyclass, 
+                                                 last_changed_time);
+}
+
+static WERROR local_create_key (TALLOC_CTX *mem_ctx, 
+                                                               struct registry_key *parent_key, 
+                                                               const char *name,
+                                                               const char *key_class,
+                                                               struct security_descriptor *security,
+                                                               struct registry_key **key)
+{
+       const struct local_key *local_parent;
+       struct hive_key *hivekey;
+       const char **elements;
+       int i;
+       char *last_part;
+
+       last_part = strrchr(name, '\\');
+       if (last_part == NULL) {
+               last_part = name;
+               local_parent = (const struct local_key *)parent_key;
+       } else {
+               W_ERROR_NOT_OK_RETURN(reg_open_key(mem_ctx, parent_key, 
+                                                         talloc_strndup(mem_ctx, name, last_part-name),
+                                                         &local_parent));
+               last_part++;
+       }
+
+       W_ERROR_NOT_OK_RETURN(hive_key_add_name(mem_ctx, local_parent->hive_key, 
+                                                               last_part, key_class, security, &hivekey));
+
+       if (local_parent->path.elements != NULL) {
+               elements = talloc_array(hivekey, const char *, 
+                                                               str_list_length(local_parent->path.elements)+2);
+               for (i = 0; local_parent->path.elements[i] != NULL; i++) {
+                       elements[i] = talloc_reference(elements, 
+                                                                                  local_parent->path.elements[i]);
+               }
+       } else {
+               elements = talloc_array(hivekey, const char *, 2);
+               i = 0;
+       }
+
+       elements[i] = talloc_strdup(elements, name);
+       elements[i+1] = NULL;
+
+       *key = reg_import_hive_key(local_parent->global.context, hivekey, 
+                                                          local_parent->path.predefined_key,
+                                                          elements);
+
+       return WERR_OK;
+}
+
+static WERROR local_set_value (struct registry_key *key, const char *name,
+                                               uint32_t type, const DATA_BLOB data)
+{
+       struct local_key *local = (struct local_key *)key;
+
+       return hive_set_value(local->hive_key, name, type, data);
+}
+
+static WERROR local_get_value (TALLOC_CTX *mem_ctx,
+                                                const struct registry_key *key,
+                                                const char *name, uint32_t *type, DATA_BLOB *data)
+{
+       const struct local_key *local = (const struct local_key *)key;
+
+       return hive_get_value(mem_ctx, local->hive_key, name, type, data);
+}
+
+static WERROR local_enum_value (TALLOC_CTX *mem_ctx,
+                                                 const struct registry_key *key, uint32_t idx,
+                                                 const char **name,
+                                                 uint32_t *type,
+                                                 DATA_BLOB *data)
+{
+       const struct local_key *local = (const struct local_key *)key;
+
+       return hive_get_value_by_index(mem_ctx, local->hive_key, idx, 
+                                                                  name, type, data);
+}
+
+static WERROR local_delete_key (struct registry_key *key, const char *name)
+{
+       const struct local_key *local = (const struct local_key *)key;
+
+       return hive_key_del(local->hive_key, name);
+}
+
+static WERROR local_delete_value (struct registry_key *key, const char *name)
+{
+       const struct local_key *local = (const struct local_key *)key;
+
+       return hive_del_value(local->hive_key, name);
+}
+
+static WERROR local_flush_key (struct registry_key *key)
+{
+       const struct local_key *local = (const struct local_key *)key;
+
+       return hive_key_flush(local->hive_key);
+}
+
+static WERROR local_get_key_info (TALLOC_CTX *mem_ctx,
+                                               const struct registry_key *key,
+                                               const char **classname,
+                                               uint32_t *num_subkeys,
+                                               uint32_t *num_values,
+                                               NTTIME *last_change_time)
+{
+       const struct local_key *local = (const struct local_key *)key;
+
+       return hive_key_get_info(mem_ctx, local->hive_key, 
+                                                        classname, num_subkeys, num_values, 
+                                                        last_change_time);
+}
+
+const static struct registry_operations local_ops = {
+       .name = "local",
+       .open_key = local_open_key,
+       .get_predefined_key = local_get_predefined_key,
+       .enum_key = local_enum_key,
+       .create_key = local_create_key,
+       .set_value = local_set_value,
+       .get_value = local_get_value,
+       .enum_value = local_enum_value,
+       .delete_key = local_delete_key,
+       .delete_value = local_delete_value,
+       .flush_key = local_flush_key,
+       .get_key_info = local_get_key_info,
+};
+
+WERROR reg_open_local(TALLOC_CTX *mem_ctx, struct registry_context **ctx, 
+                               struct auth_session_info *session_info, 
+                               struct cli_credentials *credentials)
+{
+       struct registry_local *ret = talloc_zero(mem_ctx, struct registry_local);
+
+       W_ERROR_HAVE_NO_MEMORY(ret);
+
+       ret->registry.ops = &local_ops;
+       ret->session_info = session_info;
+       ret->credentials = credentials;
+
+       *ctx = (struct registry_context *)ret;
+       
+       return WERR_OK;
+}
+
+WERROR reg_mount_hive(struct registry_context *rctx, 
+                                         struct hive_key *hive_key,
+                                         uint32_t key_id,
+                                         const char **elements) 
+{
+       struct registry_local *reg_local = talloc_get_type(rctx, struct registry_local);
+       struct mountpoint *mp = talloc(rctx, struct mountpoint);
+       int i = 0;
+
+       mp->path.predefined_key = key_id;
+       mp->prev = mp->next = NULL;
+       mp->key = hive_key;
+       if (elements != NULL) {
+               mp->path.elements = talloc_array(mp, const char *, 
+                                                                                str_list_length(elements));
+               for (i = 0; elements[i] != NULL; i++) {
+                       mp->path.elements[i] = talloc_reference(mp->path.elements, 
+                                                                                                       elements[i]);
+               }
+               mp->path.elements[i] = NULL;
+       } else {
+               mp->path.elements = NULL;
+       }
+
+       DLIST_ADD(reg_local->mountpoints, mp);
+
+       return WERR_OK;
+}
index 0e237bfecee5ae051255ad0e870dc0ecfdc006a3..7bcaa1502ce01b21cc17cf5b50fbbcf5908a0386 100644 (file)
@@ -54,7 +54,7 @@
                <varlistentry>
                        <term>--backend BACKEND</term>
                        <listitem><para>Name of backend to load. Possible values are: 
-                                       w95, nt4, gconf, dir and rpc. The default is <emphasis>dir</emphasis>.
+                                       creg, regf, dir and rpc. The default is <emphasis>dir</emphasis>.
                                </para>
                                <para>
                                        This argument can be specified twice: once for the first 
index c04bad9e66d24be193ca9e955792e94601f34893..d9dcdcbf80194eb9efb1912984c5cb563ac93df7 100644 (file)
@@ -49,7 +49,7 @@
                <varlistentry>
                        <term>--backend BACKEND</term>
                        <listitem><para>Name of backend to load. Possible values are: 
-                                       w95, nt4, gconf, dir and rpc. The default is <emphasis>dir</emphasis>.
+                                       creg, regf, dir and rpc. The default is <emphasis>dir</emphasis>.
                </para></listitem>
                </varlistentry>
                
index edec729120d5ccb662392979857329b22b9e3ead..9f16d8cc2416bce76e0fb43913e2dc79c14ed3bd 100644 (file)
@@ -48,7 +48,7 @@
                <varlistentry>
                        <term>--backend BACKEND</term>
                        <listitem><para>Name of backend to load. Possible values are: 
-                                       w95, nt4, gconf, dir and rpc. The default is <emphasis>dir</emphasis>.
+                                       creg, regf, dir and rpc. The default is <emphasis>dir</emphasis>.
                </para></listitem>
                </varlistentry>
                
index aa31855a2bbb6f3eae0838e09042d2a6c165c24e..93f15e1fb2b5cece4be398f968c550036d752c96 100644 (file)
@@ -48,7 +48,7 @@
                <varlistentry>
                        <term>--backend BACKEND</term>
                        <listitem><para>Name of backend to load. Possible values are: 
-                                       w95, nt4, gconf, dir and rpc. The default is <emphasis>dir</emphasis>.
+                                       creg, regf, dir and rpc. The default is <emphasis>dir</emphasis>.
                </para></listitem>
                </varlistentry>
                
index 12847eedd83f3628cd3b8c21fe155e3ca093bc2e..50c8f54397ed6c669fde186fe976292d1cd7277a 100644 (file)
@@ -1,8 +1,9 @@
 /* 
    Unix SMB/CIFS implementation.
-   Reading .REG files
+   Reading registry patch files
    
-   Copyright (C) Jelmer Vernooij 2004
+   Copyright (C) Jelmer Vernooij 2004-2007
+   Copyright (C) Wilco Baan Hofman 2006
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 */
 
 #include "includes.h"
+#include "lib/registry/patchfile.h"
 #include "lib/registry/registry.h"
 #include "system/filesys.h"
 
-/**
- * @file
- * @brief Registry patch files
- */
-
-#define DEFAULT_IDENT_STRING "SAMBA4 REGISTRY"
-
-static struct reg_diff_key *diff_find_add_key(struct reg_diff *diff, const char *path)
-{
-       int i;
-       
-       for (i = 0; diff->numkeys; i++) {
-               if (!strcasecmp(diff->keys[i].name, path))
-                       return &diff->keys[i];
-       }
 
-       diff->keys = talloc_realloc(diff, diff->keys, struct reg_diff_key, diff->numkeys+2);
-       diff->keys[diff->numkeys].name = talloc_strdup(diff->keys, path);
-       diff->keys[diff->numkeys].changetype = REG_DIFF_CHANGE_KEY;
-       diff->keys[diff->numkeys].numvalues = 0;
-       diff->keys[diff->numkeys].values = NULL;
+_PUBLIC_ WERROR reg_preg_diff_load(int fd, const struct reg_diff_callbacks *callbacks, void *callback_data);
 
-       diff->numkeys++;
-       return NULL;
-}
+_PUBLIC_ WERROR reg_dotreg_diff_load(int fd, const struct reg_diff_callbacks *callbacks, void *callback_data);
 
 /*
  * Generate difference between two keys
  */
-static WERROR reg_generate_diff_key(struct reg_diff *diff, struct registry_key *oldkey, struct registry_key *newkey)
+WERROR reg_generate_diff_key(struct registry_key *oldkey, 
+                                                        struct registry_key *newkey,
+                                                        const char *path,
+                                                        const struct reg_diff_callbacks *callbacks,
+                                                        void *callback_data)
 {
        int i;
        struct registry_key *t1, *t2;
-       struct registry_value *v1, *v2;
-       WERROR error1, error2;
+       char *tmppath;
+       const char *keyname1;
+       WERROR error, error1, error2;
        TALLOC_CTX *mem_ctx = talloc_init("writediff");
+       uint32_t old_num_subkeys, old_num_values,
+                        new_num_subkeys, new_num_values;
 
-       /* Subkeys that were deleted */
-       for(i = 0; W_ERROR_IS_OK(error1 = reg_key_get_subkey_by_index(mem_ctx, oldkey, i, &t1)); i++) {
-               error2 = reg_key_get_subkey_by_name(mem_ctx, newkey, t1->name, &t2);
+       if (oldkey != NULL) {
+               error = reg_key_get_info(mem_ctx, oldkey, NULL, &old_num_subkeys, &old_num_values,
+                                                                NULL);
+               if (!W_ERROR_IS_OK(error)) {
+                       DEBUG(0, ("Error occured while getting key info: %s\n", 
+                                         win_errstr(error)));
+                       return error;
+               }
+       } else {
+               old_num_subkeys = 0;
+               old_num_values = 0;
+       }
 
-               if (W_ERROR_IS_OK(error2))
+       /* Subkeys that were deleted */
+       for (i = 0; i < old_num_subkeys; i++) {
+               error1 = reg_key_get_subkey_by_index(mem_ctx, oldkey, i, &keyname1,
+                                                                                        NULL, NULL);
+               if (!W_ERROR_IS_OK(error1)) {
+                       DEBUG(0, ("Error occured while getting subkey by index: %s\n", 
+                                         win_errstr(error2)));
                        continue;
+               }
+
+               if (newkey != NULL) {
+                       error2 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
+
+                       if (W_ERROR_IS_OK(error2))
+                               continue;
+               } else {
+                       error2 = WERR_DEST_NOT_FOUND;
+                       t2 = NULL;
+               }
 
                if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
-                       DEBUG(0, ("Error occured while getting subkey by name: %d\n", W_ERROR_V(error2)));
+                       DEBUG(0, ("Error occured while getting subkey by name: %s\n", 
+                                         win_errstr(error2)));
+                       talloc_free(mem_ctx);
                        return error2;
                }
 
                /* newkey didn't have such a subkey, add del diff */
-               diff->keys = talloc_realloc(diff, diff->keys, struct reg_diff_key, diff->numkeys+2);
-               diff->keys[diff->numkeys].name = talloc_strdup(diff->keys, t1->path);
-               diff->keys[diff->numkeys].changetype = REG_DIFF_DEL_KEY;
-               diff->numkeys++;
+               tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
+               callbacks->del_key(callback_data, tmppath);
+               talloc_free(tmppath);   
        }
 
-       if(!W_ERROR_EQUAL(error1, WERR_NO_MORE_ITEMS)) {
-               DEBUG(0, ("Error occured while getting subkey by index: %d\n", W_ERROR_V(error1)));
-               talloc_free(mem_ctx);
-               return error1;
+       if (newkey != NULL) {
+               error = reg_key_get_info(mem_ctx, newkey, NULL, &new_num_subkeys, &new_num_values,
+                                                                NULL);
+               if (!W_ERROR_IS_OK(error)) {
+                       DEBUG(0, ("Error occured while getting key info: %s\n", 
+                                         win_errstr(error)));
+                       return error;
+               }
+       } else {
+               new_num_subkeys = 0;
+               new_num_values = 0;
        }
 
        /* Subkeys that were added */
-       for(i = 0; W_ERROR_IS_OK(error1 = reg_key_get_subkey_by_index(mem_ctx, newkey, i, &t1)); i++) {
-               error2 = reg_key_get_subkey_by_name(mem_ctx, oldkey, t1->name, &t2);
+       for(i = 0; i < new_num_subkeys; i++) {
+               error1 = reg_key_get_subkey_by_index(mem_ctx, newkey, i, &keyname1, 
+                                                                                        NULL, NULL);
+               if (!W_ERROR_IS_OK(error1)) {
+                       DEBUG(0, ("Error occured while getting subkey by index: %s\n", 
+                                         win_errstr(error1)));
+                       talloc_free(mem_ctx);
+                       return error1;
+               }
+
+               if (oldkey != NULL) {
+                       error2 = reg_open_key(mem_ctx, oldkey, keyname1, &t1);
+                               
+                       if (W_ERROR_IS_OK(error2))
+                               continue;
+               } else {
+                       t1 = NULL;
+                       error2 = WERR_DEST_NOT_FOUND;
+               }
                        
-               if (W_ERROR_IS_OK(error2))
-                       continue;
-               
                if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
-                       DEBUG(0, ("Error occured while getting subkey by name: %d\n", W_ERROR_V(error2)));
+                       DEBUG(0, ("Error occured while getting subkey by name: %s\n", 
+                                         win_errstr(error2)));
+                       talloc_free(mem_ctx);
                        return error2;
                }
 
                /* oldkey didn't have such a subkey, add add diff */
-               diff->keys = talloc_realloc(diff, diff->keys, struct reg_diff_key, diff->numkeys+2);
-               diff->keys[diff->numkeys].name = talloc_strdup(diff->keys, t1->path);
-               diff->keys[diff->numkeys].changetype = REG_DIFF_CHANGE_KEY;
-               diff->keys[diff->numkeys].numvalues = 0;
-               diff->keys[diff->numkeys].values = NULL;
-               diff->numkeys++;
-
-               reg_generate_diff_key(diff, t1, t2);
-       }
+               tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
+               callbacks->add_key(callback_data, tmppath);
 
-       if(!W_ERROR_EQUAL(error1, WERR_NO_MORE_ITEMS)) {
-               DEBUG(0, ("Error occured while getting subkey by index: %d\n", W_ERROR_V(error1)));
-               talloc_free(mem_ctx);
-               return error1;
+               W_ERROR_NOT_OK_RETURN(
+                               reg_open_key(mem_ctx, newkey, keyname1, &t2));
+
+               reg_generate_diff_key(t1, t2, tmppath, callbacks, callback_data);
+               talloc_free(tmppath);
        }
 
        /* Values that were changed */
-       for(i = 0; W_ERROR_IS_OK(error1 = reg_key_get_value_by_index(mem_ctx, newkey, i, &v1)); i++) {
-               struct reg_diff_key *thiskey = NULL;
-               error2 = reg_key_get_value_by_name(mem_ctx, oldkey, v1->name, &v2);
+       for(i = 0; i < new_num_values; i++) {
+               const char *name;
+               uint32_t type1, type2;
+               DATA_BLOB contents1, contents2;
+
+               error1 = reg_key_get_value_by_index(mem_ctx, newkey, i, 
+                                                                                       &name, &type1, &contents1);
+               if (!W_ERROR_IS_OK(error1)) {
+                       DEBUG(0, ("Unable to get key by index: %s\n", 
+                                         win_errstr(error1)));
+                       talloc_free(mem_ctx);
+                       return error1;
+               }
+
+               if (oldkey != NULL) {
+                       error2 = reg_key_get_value_by_name(mem_ctx, oldkey, name, 
+                                                                                  &type2, &contents2);
+               } else 
+                       error2 = WERR_DEST_NOT_FOUND;
        
                if(!W_ERROR_IS_OK(error2) && 
                   !W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
-                       DEBUG(0, ("Error occured while getting value by name: %d\n", W_ERROR_V(error2)));
+                       DEBUG(0, ("Error occured while getting value by name: %s\n", 
+                                         win_errstr(error2)));
+                       talloc_free(mem_ctx);
                        return error2;
                }
 
-               if (W_ERROR_IS_OK(error2) && data_blob_cmp(&v1->data, &v2->data) == 0)
+               if (W_ERROR_IS_OK(error2) && data_blob_cmp(&contents1, &contents2) == 0)
                        continue;
 
-               thiskey = diff_find_add_key(diff, oldkey->path);
-               thiskey->values = talloc_realloc(diff, thiskey->values, struct reg_diff_value, thiskey->numvalues+2);
-               thiskey->values[thiskey->numvalues].name = talloc_strdup(thiskey->values, v1->name);
-               thiskey->values[thiskey->numvalues].type = v2->data_type;
-               thiskey->values[thiskey->numvalues].changetype = REG_DIFF_SET_VAL;
-               thiskey->values[thiskey->numvalues].data = data_blob_dup_talloc(thiskey->values, &v2->data);
-               thiskey->numvalues++;
-       }
-
-       if(!W_ERROR_EQUAL(error1, WERR_NO_MORE_ITEMS)) {
-               DEBUG(0, ("Error occured while getting value by index: %d\n", W_ERROR_V(error1)));
-               talloc_free(mem_ctx);
-               return error1;
+               callbacks->set_value(callback_data, path, name, type1, contents1);
        }
 
        /* Values that were deleted */
-       for(i = 0; W_ERROR_IS_OK(error1 = reg_key_get_value_by_index(mem_ctx, oldkey, i, &v1)); i++) {
-               struct reg_diff_key *thiskey = NULL;
-               error2 = reg_key_get_value_by_name(mem_ctx, newkey, v1->name, &v2);
+       for (i = 0; i < old_num_values; i++) {
+               const char *name;
+               error1 = reg_key_get_value_by_index(mem_ctx, oldkey, i, &name, 
+                                                                                       NULL, NULL);
+               if (!W_ERROR_IS_OK(error1)) {
+                       DEBUG(0, ("Error ocurred getting value by index: %s\n", 
+                                         win_errstr(error1)));
+                       talloc_free(mem_ctx);
+                       return error1;
+               }
+
+               error2 = reg_key_get_value_by_name(mem_ctx, newkey, name, NULL, 
+                                                                                  NULL);
 
                if (W_ERROR_IS_OK(error2))
                        continue;
 
                if (!W_ERROR_EQUAL(error2, WERR_DEST_NOT_FOUND)) {
-                       DEBUG(0, ("Error occured while getting value by name: %d\n", W_ERROR_V(error2)));
+                       DEBUG(0, ("Error occured while getting value by name: %s\n", 
+                                         win_errstr(error2)));
                        return error2;
                }
 
-               thiskey = diff_find_add_key(diff, oldkey->path);
-               thiskey->values = talloc_realloc(diff, thiskey->values, struct reg_diff_value, thiskey->numvalues+2);
-               thiskey->values[thiskey->numvalues].name = talloc_strdup(thiskey->values, v1->name);
-               thiskey->values[thiskey->numvalues].changetype = REG_DIFF_DEL_VAL;
-               thiskey->numvalues++;
-       }
-
-       if(!W_ERROR_EQUAL(error1, WERR_NO_MORE_ITEMS)) {
-               DEBUG(0, ("Error occured while getting value by index: %d\n", W_ERROR_V(error1)));
-               talloc_free(mem_ctx);
-               return error1;
+               callbacks->del_value(callback_data, path, name);
        }
 
        talloc_free(mem_ctx);
@@ -175,244 +214,206 @@ static WERROR reg_generate_diff_key(struct reg_diff *diff, struct registry_key *
 /**
  * Generate diff between two registry contexts 
  */
-_PUBLIC_ struct reg_diff *reg_generate_diff(TALLOC_CTX *mem_ctx, struct registry_context *ctx1, struct registry_context *ctx2)
+_PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1, 
+                                 struct registry_context *ctx2, 
+                                 const struct reg_diff_callbacks *callbacks,
+                                 void *callback_data)
 {
-       struct reg_diff *diff = talloc_zero(mem_ctx, struct reg_diff);
        int i;
        WERROR error;
 
-       for(i = HKEY_CLASSES_ROOT; i <= HKEY_PERFORMANCE_NLSTEXT; i++) {
-               struct registry_key *r1, *r2;
+       for(i = HKEY_FIRST; i <= HKEY_LAST; i++) {
+               struct registry_key *r1 = NULL, *r2 = NULL;
                error = reg_get_predefined_key(ctx1, i, &r1);
-               if (!W_ERROR_IS_OK(error)) {
+               if (!W_ERROR_IS_OK(error) && !W_ERROR_EQUAL(error, WERR_NOT_FOUND)) {
                        DEBUG(0, ("Unable to open hive %s for backend 1\n", reg_get_predef_name(i)));
-                       continue;
                }
                
                error = reg_get_predefined_key(ctx2, i, &r2);
-               if (!W_ERROR_IS_OK(error)) {
+               if (!W_ERROR_IS_OK(error) && !W_ERROR_EQUAL(error, WERR_NOT_FOUND)) {
                        DEBUG(0, ("Unable to open hive %s for backend 2\n", reg_get_predef_name(i)));
-                       continue;
                }
 
-               reg_generate_diff_key(diff, r1, r2);
-       }
-
-       return diff;
-}
-
-/**
- * Save registry diff
- */
-_PUBLIC_ WERROR reg_diff_save(const struct reg_diff *diff, const char *filename)
-{
-       int xf, i, j;
-
-       if (filename) {
-               xf = open(filename, O_CREAT, 0755);
-               if (xf == -1) {
-                       DEBUG(0, ("Unable to open %s\n", filename));
-                       return WERR_BADFILE;
-               }
-       } else 
-               xf = STDIN_FILENO;
-
-       fdprintf(xf, "%s\n\n", diff->format?diff->format:DEFAULT_IDENT_STRING);
-
-       for (i = 0; i < diff->numkeys; i++) {
-               if (diff->keys[i].changetype == REG_DIFF_DEL_KEY) {
-                       fdprintf(xf, "-%s\n\n",  diff->keys[i].name);
+               if (r1 == NULL && r2 == NULL)
                        continue;
-               }
 
-               fdprintf(xf, "[%s]\n", diff->keys[i].name);
-
-               for (j = 0; j < diff->keys[i].numvalues; j++) {
-                       fdprintf(xf, "\"%s\"=", diff->keys[i].values[j].name);
-                       switch (diff->keys[i].values[j].changetype) {
-                               case REG_DIFF_DEL_VAL:
-                                       fdprintf(xf, "-\n");
-                                       break;
-                               case REG_DIFF_SET_VAL:
-                                       fdprintf(xf, "%s:%s\n", 
-                                                        str_regtype(diff->keys[i].values[j].type), 
-                                                        reg_val_data_string(NULL, 
-                                                               diff->keys[i].values[j].type, 
-                                                               &diff->keys[i].values[j].data));
-                                       break;
-                       }
+               error = reg_generate_diff_key(r1, r2, reg_get_predef_name(i), callbacks, callback_data);
+               if (!W_ERROR_IS_OK(error)) {
+                       DEBUG(0, ("Unable to determine diff: %s\n", win_errstr(error)));
+                       return error;
                }
-
-               fdprintf(xf, "\n");
        }
-
-       close(xf);
-
+       if (callbacks->done != NULL) {
+               callbacks->done(callback_data);
+       }
        return WERR_OK;
 }
 
 /**
  * Load diff file
  */
-_PUBLIC_ struct reg_diff *reg_diff_load(TALLOC_CTX *ctx, const char *fn)
+_PUBLIC_ WERROR reg_diff_load(const char *filename, const struct reg_diff_callbacks *callbacks, void *callback_data)
 {
-       struct reg_diff *diff;
        int fd;
-       char *line, *p, *q;
-       struct reg_diff_key *curkey = NULL;
-       struct reg_diff_value *curval;
-
-       fd = open(fn, O_RDONLY, 0);
+       char hdr[4];
+       
+       fd = open(filename, O_RDONLY, 0);
        if (fd == -1) {
-               DEBUG(0, ("Error opening registry patch file `%s'\n", fn));
-               return NULL;
+               DEBUG(0, ("Error opening registry patch file `%s'\n", filename));
+               return WERR_GENERAL_FAILURE;
        }
 
-       diff = talloc_zero(ctx, struct reg_diff);
-       if (diff == NULL) {
-               close(fd);
-               return NULL;
+       if (read(fd, &hdr, 4) != 4) {
+               DEBUG(0, ("Error reading registry patch file `%s'\n", filename));
+               return WERR_GENERAL_FAILURE;
        }
-       
-       diff->format = afdgets(fd, diff, 0);
-       if (!diff->format) {
-               talloc_free(diff);
-               close(fd);
-               return NULL;
+
+       /* Reset position in file */
+       lseek(fd, 0, SEEK_SET);
+#if 0
+       if (strncmp(hdr, "CREG", 4) == 0) {
+               /* Must be a W9x CREG Config.pol file */
+               return reg_creg_diff_load(diff, fd);
+       } else if (strncmp(hdr, "regf", 4) == 0) {
+               /* Must be a REGF NTConfig.pol file */
+               return reg_regf_diff_load(diff, fd);
+       } else 
+#endif 
+       if (strncmp(hdr, "PReg", 4) == 0) {
+               /* Must be a GPO Registry.pol file */
+               return reg_preg_diff_load(fd, callbacks, callback_data);
+       } else {
+               /* Must be a normal .REG file */
+               return reg_dotreg_diff_load(fd, callbacks, callback_data);
        }
+}
 
-       while ((line = afdgets(fd, diff, 0))) {
-               /* Ignore comments and empty lines */
-               if (strlen(line) == 0 || line[0] == ';') {
-                       curkey = NULL;
-                       talloc_free(line);
-                       continue;
-               }
+/**
+ * The reg_diff_apply functions
+ */
+static WERROR reg_diff_apply_add_key(void *_ctx, const char *key_name) 
+{
+       struct registry_context *ctx = _ctx;
+       struct registry_key *tmp;
+       WERROR error;
 
-               /* Start of key */
-               if (line[0] == '[') {
-                       p = strchr_m(line, ']');
-                       if (p[strlen(p)-2] != ']') {
-                               DEBUG(0, ("Malformed line\n"));
-                               return NULL;
-                       }
-                       diff->keys = talloc_realloc(diff, diff->keys, struct reg_diff_key, diff->numkeys+2);
-                       diff->keys[diff->numkeys].name = talloc_strndup(diff->keys, line+1, strlen(line)-2);
-                       diff->keys[diff->numkeys].changetype = REG_DIFF_CHANGE_KEY;
-                       diff->keys[diff->numkeys].numvalues = 0;
-                       diff->keys[diff->numkeys].values = NULL;
-                       curkey = &diff->keys[diff->numkeys];
-                       diff->numkeys++;
-                       talloc_free(line);
-                       continue;
-               }
+       error = reg_key_add_abs(ctx, ctx, key_name, 0, NULL, &tmp);
 
-               /* Deleting key */
-               if (line[0] == '-') {
-                       diff->keys = talloc_realloc(diff, diff->keys, struct reg_diff_key, diff->numkeys+2);
-                       diff->keys[diff->numkeys].name = talloc_strdup(diff->keys, line+1);
-                       diff->keys[diff->numkeys].changetype = REG_DIFF_DEL_KEY;
-                       diff->numkeys++;
-                       talloc_free(line);
-                       continue;
-               }
+       if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) && !W_ERROR_IS_OK(error)) {
+               DEBUG(0, ("Error adding new key '%s': %s\n", key_name, win_errstr(error)));
+               return error;
+       }
+       return WERR_OK;
+}
 
-               /* Deleting/Changing value */
-               p = strchr_m(line, '=');
-               if (p == NULL) {
-                       DEBUG(0, ("Malformed line\n"));
-                       talloc_free(line);
-                       continue;
-               }
+static WERROR reg_diff_apply_del_key(void *_ctx, const char *key_name) 
+{
+       struct registry_context *ctx = _ctx;
+       WERROR error;
 
-               *p = '\0'; p++;
+       error = reg_key_del_abs(ctx, key_name);
 
-               if (curkey == NULL) {
-                       DEBUG(0, ("Value change without key\n"));
-                       talloc_free(line);
-                       continue;
-               }
+       if(!W_ERROR_IS_OK(error)) {
+               DEBUG(0, ("Unable to delete key '%s'\n", key_name));
+               return error;
+       }
+       
+       return WERR_OK;
+}
 
-               curkey->values = talloc_realloc(diff->keys, curkey->values, struct reg_diff_value, curkey->numvalues+2);
-               curval = &curkey->values[curkey->numvalues];
-               curkey->numvalues++;
-               curval->name = talloc_strdup(curkey->values, line);
+static WERROR reg_diff_apply_set_value(void *_ctx, const char *path, const char *value_name, uint32_t value_type, DATA_BLOB value)
+{
+       struct registry_context *ctx = _ctx;
+       struct registry_key *tmp;
+       WERROR error;
+       
+       /* Open key */
+       error = reg_open_key_abs(ctx, ctx, path, &tmp);
 
-               /* Delete value */
-               if (strcmp(p, "-")) {
-                       curval->changetype = REG_DIFF_DEL_VAL;
-                       talloc_free(line);
-                       continue;
-               }
-               
-               q = strchr_m(p, ':');
-               if (q) {
-                       *q = '\0'; 
-                       q++;
-               }
+       if (W_ERROR_EQUAL(error, WERR_DEST_NOT_FOUND)) {
+               DEBUG(0, ("Error opening key '%s'\n", path));
+               return error;
+       }
 
-               curval->changetype = REG_DIFF_SET_VAL;
-               reg_string_to_val(curkey->values, q?p:"REG_SZ", q?q:p, &curval->type, &curval->data);
+       /* Set value */
+       error = reg_val_set(tmp, value_name, 
+                                value_type, value);
+       if (!W_ERROR_IS_OK(error)) {
+               DEBUG(0, ("Error setting value '%s'\n", value_name));
+               return error;
+       }       
+       
+       return WERR_OK;
+}
 
-               talloc_free(line);
+static WERROR reg_diff_apply_del_value (void *_ctx, const char *key_name, const char *value_name)
+{
+       struct registry_context *ctx = _ctx;
+       struct registry_key *tmp;
+       WERROR error;
+       
+       /* Open key */
+       error = reg_open_key_abs(ctx, ctx, key_name, &tmp);
+
+       if (!W_ERROR_IS_OK(error)) {
+               DEBUG(0, ("Error opening key '%s'\n", key_name));
+               return error;
        }
 
-       close(fd);
+       error = reg_del_value(tmp, value_name);
+       if (!W_ERROR_IS_OK(error)) {
+               DEBUG(0, ("Error deleting value '%s'\n", value_name));
+               return error;
+       }
+       
 
-       return diff;
+       return WERR_OK;
 }
 
-/**
- * Apply diff to a registry context 
- */
-_PUBLIC_ BOOL reg_diff_apply (const struct reg_diff *diff, struct registry_context *ctx)
+static WERROR reg_diff_apply_del_all_values(void *_ctx, const char *key_name)
 {
-       TALLOC_CTX *mem_ctx = talloc_init("apply_cmd_file");
-       struct registry_key *tmp = NULL;
+       struct registry_context *ctx = _ctx;
+       struct registry_key *key;
        WERROR error;
-       int i, j;
+       int i;
+       uint32_t num_values;
 
-       for (i = 0; i < diff->numkeys; i++) {
-               if (diff->keys[i].changetype == REG_DIFF_DEL_KEY) {
-                       error = reg_key_del_abs(ctx, diff->keys[i].name);
+       error = reg_open_key_abs(ctx, ctx, key_name, &key);
 
-                       if(!W_ERROR_IS_OK(error)) {
-                               DEBUG(0, ("Unable to delete key '%s'\n", diff->keys[i].name));
-                               return False;
-                       }
+       if (!W_ERROR_IS_OK(error)) {
+               DEBUG(0, ("Error opening key '%s'\n", key_name));
+               return error;
+       }
 
-                       continue;
-               }
+       W_ERROR_NOT_OK_RETURN(reg_key_get_info(ctx, key, 
+                                                                                  NULL, 
+                                                                                  NULL,
+                                                                                  &num_values, 
+                                                                                  NULL));
+
+       for (i = 0; i < num_values; i++) {
+               const char *name;
+               W_ERROR_NOT_OK_RETURN(reg_key_get_value_by_index(ctx, key, i, &name, 
+                                                                                                                NULL, NULL));
+               W_ERROR_NOT_OK_RETURN(reg_del_value(key, name));
+       }
 
-               /* Add / change key */
-               error = reg_open_key_abs(mem_ctx, ctx, diff->keys[i].name, &tmp);
+       return WERR_OK;
+}
 
-               /* If we found it, apply the other bits, else create such a key */
-               if (W_ERROR_EQUAL(error, WERR_DEST_NOT_FOUND)) {
-                       if(!W_ERROR_IS_OK(reg_key_add_abs(mem_ctx, ctx, diff->keys[i].name, 0, NULL, &tmp))) {
-                               DEBUG(0, ("Error adding new key '%s'\n", diff->keys[i].name));
-                               return False;
-                       }
-               }
+/** 
+ * Apply diff to a registry context 
+ */
+_PUBLIC_ WERROR reg_diff_apply (const char *filename, struct registry_context *ctx)
+{
+       struct reg_diff_callbacks callbacks;
 
-               for (j = 0; j < diff->keys[i].numvalues; j++) {
-                       if (diff->keys[i].values[j].changetype == REG_DIFF_DEL_VAL) {
-                               error = reg_del_value(tmp, diff->keys[i].values[j].name);
-                               if (!W_ERROR_IS_OK(error)) {
-                                       DEBUG(0, ("Error deleting value '%s'\n", diff->keys[i].values[j].name));
-                                       return False;
-                               }
-                       
-                               error = reg_val_set(tmp, diff->keys[i].values[j].name, 
-                                                        diff->keys[i].values[j].type,
-                                                        diff->keys[i].values[j].data);
-                               if (!W_ERROR_IS_OK(error)) {
-                                       DEBUG(0, ("Error setting value '%s'\n", diff->keys[i].values[j].name));
-                                       return False;
-                               }       
-                       }
-               }
-       }
+       callbacks.add_key = reg_diff_apply_add_key;
+       callbacks.del_key = reg_diff_apply_del_key;
+       callbacks.set_value = reg_diff_apply_set_value;
+       callbacks.del_value = reg_diff_apply_del_value;
+       callbacks.del_all_values = reg_diff_apply_del_all_values;
+       callbacks.done = NULL;
 
-       return True;
+       return reg_diff_load(filename, &callbacks, ctx);
 }
diff --git a/source/lib/registry/patchfile.h b/source/lib/registry/patchfile.h
new file mode 100644 (file)
index 0000000..194e2a1
--- /dev/null
@@ -0,0 +1,52 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Patchfile interface
+   Copyright (C) Jelmer Vernooij 2006
+   Copyright (C) Wilco Baan Hofman 2006
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _PATCHFILE_H
+#define _PATCHFILE_H 
+
+#include "lib/registry/registry.h"
+
+struct reg_diff_callbacks {
+       WERROR (*add_key) (void *callback_data, const char *key_name);
+       WERROR (*set_value) (void *callback_data, const char *key_name, 
+                                                const char *value_name, uint32_t value_type, DATA_BLOB value);
+       WERROR (*del_value) (void *callback_data, const char *key_name, const char *value_name);
+       WERROR (*del_key) (void *callback_data, const char *key_name);
+       WERROR (*del_all_values) (void *callback_data, const char *key_name);
+       WERROR (*done) (void *callback_data);
+};
+
+_PUBLIC_ WERROR reg_diff_apply (const char *filename, 
+                                                               struct registry_context *ctx);
+
+_PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1, 
+                                 struct registry_context *ctx2, 
+                                 const struct reg_diff_callbacks *callbacks,
+                                 void *callback_data);
+_PUBLIC_ WERROR reg_dotreg_diff_save(TALLOC_CTX *ctx, const char *filename, 
+                               struct reg_diff_callbacks **callbacks, void **callback_data);
+_PUBLIC_ WERROR reg_generate_diff_key(struct registry_key *oldkey, 
+                                   struct registry_key *newkey,
+                                   const char *path,
+                                   const struct reg_diff_callbacks *callbacks,
+                                   void *callback_data);
+
+#endif /* _PATCHFILE_H */
diff --git a/source/lib/registry/patchfile_dotreg.c b/source/lib/registry/patchfile_dotreg.c
new file mode 100644 (file)
index 0000000..f11ceb1
--- /dev/null
@@ -0,0 +1,247 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Reading .REG files
+   
+   Copyright (C) Jelmer Vernooij 2004-2007
+   Copyright (C) Wilco Baan Hofman 2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* FIXME Newer .REG files, created by Windows XP and above use unicode UTF-16 */
+
+#include "includes.h"
+#include "lib/registry/patchfile.h"
+#include "lib/registry/registry.h"
+#include "system/filesys.h"
+
+/**
+ * @file
+ * @brief Registry patch files
+ */
+
+#define HEADER_STRING "REGEDIT4"
+
+struct dotreg_data {
+       int fd;
+};
+
+static WERROR reg_dotreg_diff_add_key(void *_data, const char *key_name)
+{
+       struct dotreg_data *data = _data;
+
+       fdprintf(data->fd, "\n[%s]\n", key_name);
+       
+       return WERR_OK;
+}
+
+static WERROR reg_dotreg_diff_del_key(void *_data, const char *key_name)
+{
+       struct dotreg_data *data = _data;
+
+       fdprintf(data->fd, "\n[-%s]\n", key_name);
+       
+       return WERR_OK;
+}
+
+static WERROR reg_dotreg_diff_set_value(void *_data, const char *path, 
+                                                                               const char *value_name, uint32_t value_type, DATA_BLOB value)
+{
+       struct dotreg_data *data = _data;
+
+       fdprintf(data->fd, "\"%s\"=%s:%s\n",
+                       value_name, str_regtype(value_type), 
+                       reg_val_data_string(NULL, value_type, value));
+               
+       return WERR_OK;
+}
+
+static WERROR reg_dotreg_diff_del_value(void *_data, const char *path, const char *value_name)
+{
+       struct dotreg_data *data = _data;
+
+       fdprintf(data->fd, "\"%s\"=-\n", value_name);
+
+       return WERR_OK;
+}
+
+static WERROR reg_dotreg_diff_done(void *_data)
+{
+       struct dotreg_data *data = _data;
+
+       close(data->fd);
+       talloc_free(data);
+
+       return WERR_OK;
+}
+
+static WERROR reg_dotreg_diff_del_all_values (void *callback_data, const char *key_name)
+{
+       return WERR_NOT_SUPPORTED;
+}
+
+/**
+ * Save registry diff
+ */
+_PUBLIC_ WERROR reg_dotreg_diff_save(TALLOC_CTX *ctx, const char *filename, 
+                                                                        struct reg_diff_callbacks **callbacks, void **callback_data)
+{
+       struct dotreg_data *data;
+
+       data = talloc_zero(ctx, struct dotreg_data);
+       *callback_data = data;
+
+       if (filename) {
+               data->fd = open(filename, O_CREAT, 0755);
+               if (data->fd == -1) {
+                       DEBUG(0, ("Unable to open %s\n", filename));
+                       return WERR_BADFILE;
+               }
+       } else {
+               data->fd = STDOUT_FILENO;
+       }
+
+       fdprintf(data->fd, "%s\n", HEADER_STRING);
+
+       *callbacks = talloc(ctx, struct reg_diff_callbacks);
+
+       (*callbacks)->add_key = reg_dotreg_diff_add_key;
+       (*callbacks)->del_key = reg_dotreg_diff_del_key;
+       (*callbacks)->set_value = reg_dotreg_diff_set_value;
+       (*callbacks)->del_value = reg_dotreg_diff_del_value;
+       (*callbacks)->del_all_values = reg_dotreg_diff_del_all_values;
+       (*callbacks)->done = reg_dotreg_diff_done;
+
+       return WERR_OK;
+}      
+
+/**
+ * Load diff file
+ */
+_PUBLIC_ WERROR reg_dotreg_diff_load(int fd, const struct reg_diff_callbacks *callbacks, void *callback_data)
+{
+       char *line, *p, *q;
+       char *curkey = NULL;
+       TALLOC_CTX *mem_ctx = talloc_init("reg_dotreg_diff_load");
+       WERROR error;
+       uint32_t value_type;
+       DATA_BLOB value;
+
+       line = afdgets(fd, mem_ctx, 0);
+       if (!line) {
+               DEBUG(0, ("Can't read from file.\n"));
+               talloc_free(mem_ctx);
+               close(fd);
+               return WERR_GENERAL_FAILURE;
+       }
+
+       while ((line = afdgets(fd, mem_ctx, 0))) {
+               /* Ignore comments and empty lines */
+               if (strlen(line) == 0 || line[0] == ';') {
+                       talloc_free(line);
+                       
+                       if (curkey) {   
+                               talloc_free(curkey);
+                       }
+                       curkey = NULL;
+                       continue;
+               }
+
+               /* Start of key */
+               if (line[0] == '[') {
+                       p = strchr_m(line, ']');
+                       if (p[strlen(p)-1] != ']') {
+                               DEBUG(0, ("Missing ']'\n"));
+                               return WERR_GENERAL_FAILURE;
+                       }
+                       /* Deleting key */
+                       if (line[1] == '-') {
+                               curkey = talloc_strndup(line, line+2, strlen(line)-3);
+
+                               error = callbacks->del_key(callback_data, curkey);
+                               if (!W_ERROR_IS_OK(error)) {
+                                       DEBUG(0,("Error deleting key %s\n", curkey));
+                                       talloc_free(mem_ctx);
+                                       return error;
+                               }
+
+                               talloc_free(line);
+                               curkey = NULL;
+                               continue;
+                       }
+                       curkey = talloc_strndup(mem_ctx, line+1, strlen(line)-2);
+
+                       error = callbacks->add_key(callback_data, curkey);
+                       if (!W_ERROR_IS_OK(error)) {
+                               DEBUG(0,("Error adding key %s\n", curkey));
+                               talloc_free(mem_ctx);
+                               return error;
+                       }
+
+                       talloc_free(line);
+                       continue;
+               }
+
+               /* Deleting/Changing value */
+               p = strchr_m(line, '=');
+               if (p == NULL) {
+                       DEBUG(0, ("Malformed line\n"));
+                       talloc_free(line);
+                       continue;
+               }
+
+               *p = '\0'; p++;
+
+               if (curkey == NULL) {
+                       DEBUG(0, ("Value change without key\n"));
+                       talloc_free(line);
+                       continue;
+               }
+
+               /* Delete value */
+               if (strcmp(p, "-")) {
+                       error = callbacks->del_value(callback_data, curkey, line);
+                       if (!W_ERROR_IS_OK(error)) {
+                               DEBUG(0, ("Error deleting value %s in key %s\n", line, curkey));
+                               talloc_free(mem_ctx);
+                               return error;
+                       }
+
+                       talloc_free(line);
+                       continue;
+               }
+               
+               q = strchr_m(p, ':');
+               if (q) {
+                       *q = '\0'; 
+                       q++;
+               }
+
+               reg_string_to_val(line, q?p:"REG_SZ", q?q:p, &value_type, &value);
+               
+               error = callbacks->set_value(callback_data, curkey, line, value_type, value); 
+               if (!W_ERROR_IS_OK(error)) {
+                       DEBUG(0, ("Error setting value for %s in %s\n", line, curkey));
+                       talloc_free(mem_ctx);
+                       return error;
+               }
+
+               talloc_free(line);
+       }
+
+       close(fd);
+
+       return WERR_OK;
+}
diff --git a/source/lib/registry/patchfile_preg.c b/source/lib/registry/patchfile_preg.c
new file mode 100644 (file)
index 0000000..1c8d765
--- /dev/null
@@ -0,0 +1,270 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Reading Registry.pol PReg registry files
+   
+   Copyright (C) Wilco Baan Hofman 2006
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "lib/registry/registry.h"
+#include "system/filesys.h"
+#include "pstring.h"
+
+struct preg_data {
+       int fd;
+};
+
+static WERROR preg_read_utf16(int fd, char *c)
+{
+       uint16_t v;
+
+       if (read(fd, &v, 2) < 2) {
+               return WERR_GENERAL_FAILURE;
+       }
+       push_codepoint(c, v);
+       return WERR_OK;
+}
+
+/* FIXME These functions need to be implemented */
+static WERROR reg_preg_diff_add_key(void *_data, const char *key_name)
+{
+       struct preg_data *data = _data;
+       return WERR_OK;
+}
+
+static WERROR reg_preg_diff_del_key(void *_data, const char *key_name)
+{
+       struct preg_data *data = _data;
+       return WERR_OK;
+}
+
+static WERROR reg_preg_diff_set_value(void *_data, const char *key_name, const char *value_name, uint32_t value_type, DATA_BLOB value_data)
+{
+       struct preg_data *data = _data;
+       return WERR_OK;
+}
+
+static WERROR reg_preg_diff_del_value(void *_data, const char *key_name, const char *value_name)
+{
+       struct preg_data *data = _data;
+       return WERR_OK;
+}
+
+static WERROR reg_preg_diff_del_all_values(void *_data, const char *key_name)
+{
+       struct preg_data *data = _data;
+       return WERR_OK;
+}
+
+static WERROR reg_preg_diff_done(void *_data)
+{
+       struct preg_data *data = _data;
+
+       close(data->fd);
+       talloc_free(data);
+       return WERR_OK;
+}
+
+/**
+ * Save registry diff
+ */
+_PUBLIC_ WERROR reg_preg_diff_save(TALLOC_CTX *ctx, const char *filename, struct reg_diff_callbacks **callbacks, void **callback_data)
+{
+       struct preg_data *data;
+       struct {
+               char hdr[4];
+               uint32_t version;
+       } preg_header;
+               
+
+       data = talloc_zero(ctx, struct preg_data);
+       *callback_data = data;
+
+       if (filename) {
+               data->fd = open(filename, O_CREAT, 0755);
+               if (data->fd == -1) {
+                       DEBUG(0, ("Unable to open %s\n", filename));
+                       return WERR_BADFILE;
+               }
+       } else {
+               data->fd = STDOUT_FILENO;
+       }
+       snprintf(preg_header.hdr, 4, "PReg");
+       SIVAL(&preg_header, 4, 1);
+       write(data->fd, (uint8_t *)&preg_header,8); 
+
+       *callbacks = talloc(ctx, struct reg_diff_callbacks);
+       
+       (*callbacks)->add_key = reg_preg_diff_add_key;
+       (*callbacks)->del_key = reg_preg_diff_del_key;
+       (*callbacks)->set_value = reg_preg_diff_set_value;
+       (*callbacks)->del_value = reg_preg_diff_del_value;
+       (*callbacks)->del_all_values = reg_preg_diff_del_all_values;
+       (*callbacks)->done = reg_preg_diff_done;
+       
+       return WERR_OK;
+}
+/**
+ * Load diff file
+ */
+_PUBLIC_ WERROR reg_preg_diff_load(int fd, const struct reg_diff_callbacks *callbacks, void *callback_data)
+{
+       struct {
+               char hdr[4];
+               uint32_t version;
+       } preg_header;
+       pstring buf;
+       char *buf_ptr = buf;
+       TALLOC_CTX *mem_ctx = talloc_init("reg_preg_diff_load");
+
+       
+       /* Read first 8 bytes (the header) */
+       if (read(fd, &preg_header, 8) != 8) {
+               DEBUG(0, ("Could not read PReg file: %s\n",
+                               strerror(errno)));
+               close(fd);
+               return WERR_GENERAL_FAILURE;
+       }
+       if (strncmp(preg_header.hdr, "PReg", 4) != 0) {
+               DEBUG(0, ("This file is not a valid preg registry file\n"));
+               close(fd);
+               return WERR_GENERAL_FAILURE;
+       }
+       if (preg_header.version > 1) {
+               DEBUG(0, ("Warning: file format version is higher than expected.\n"));
+       }               
+
+       /* Read the entries */
+       while(1) {
+               char *key, *value_name;
+               uint32_t value_type, length;
+               DATA_BLOB data;
+               
+               if (!W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr))) {
+                       break;
+               }
+               if (*buf_ptr != '[') {
+                       DEBUG(0, ("Error in PReg file.\n"));
+                       close(fd);
+                       return WERR_GENERAL_FAILURE;
+               }
+       
+               /* Get the path */
+               buf_ptr = buf;
+               while (W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) && *buf_ptr != ';' && buf_ptr-buf < sizeof(buf)) { 
+                       buf_ptr++;
+               }
+               key = talloc_asprintf(mem_ctx, "\\%s", buf);
+       
+               /* Get the name */
+               buf_ptr = buf;
+               while (W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) && *buf_ptr != ';' && buf_ptr-buf < sizeof(buf)) { 
+                       buf_ptr++;
+               }
+               value_name = talloc_strdup(mem_ctx, buf);
+
+               /* Get the type */
+               if (read(fd, &value_type, 4) < 4) {
+                       DEBUG(0, ("Error while reading PReg\n"));
+                       close(fd);
+                       return WERR_GENERAL_FAILURE;
+               }
+               /* Read past delimiter */
+               buf_ptr = buf;
+               if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) && *buf_ptr == ';') && buf_ptr-buf < sizeof(buf)) {
+                       DEBUG(0, ("Error in PReg file.\n"));
+                       close(fd);
+                       return WERR_GENERAL_FAILURE;
+               }
+               /* Get data length */
+               if (read(fd, &length, 4) < 4) {
+                       DEBUG(0, ("Error while reading PReg\n"));
+                       close(fd);
+                       return WERR_GENERAL_FAILURE;
+               }
+               /* Read past delimiter */
+               buf_ptr = buf;
+               if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) && *buf_ptr == ';') && buf_ptr-buf < sizeof(buf)) {
+                       DEBUG(0, ("Error in PReg file.\n"));
+                       close(fd);
+                       return WERR_GENERAL_FAILURE;
+               }       
+               /* Get the data */
+               buf_ptr = buf;
+               if (length < sizeof(buf) && read(fd, buf_ptr, length) != length) {
+                       DEBUG(0, ("Error while reading PReg\n"));
+                       close(fd);
+                       return WERR_GENERAL_FAILURE;
+               }
+               data.length = length;
+               data.data = talloc_memdup(mem_ctx, buf, length);
+               
+               /* Check if delimiter is in place (whine if it isn't) */
+               buf_ptr = buf;
+               if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) && *buf_ptr == ']') && buf_ptr-buf < sizeof(buf)) {
+                       DEBUG(0, ("Warning: Missing ']' in PReg file, expected ']', got '%c' 0x%x.\n",*buf_ptr, *buf_ptr));
+               }
+
+               if (strcasecmp(value_name, "**DelVals") == 0) {
+                       callbacks->del_all_values(callback_data, key);
+               } else if (strncasecmp(value_name, "**Del.",6) == 0) {
+                       char *p = value_name+6;
+                       
+                       callbacks->del_value(callback_data, key, p);
+               } else  if (strcasecmp(value_name, "**DeleteValues") == 0) {
+                       char *p, *q;
+
+                       p = (char *) data.data;
+                       
+                       while ((q = strchr_m(p, ';'))) {
+                               *q = '\0'; 
+                               q++;
+
+                               callbacks->del_value(callback_data, key, p);
+
+                               p = q;
+                       }
+                       callbacks->del_value(callback_data, key, p);
+               } else if (strcasecmp(value_name, "**DeleteKeys") == 0) {
+                       char *p, *q, *full_key;
+
+                       p = (char *) data.data;
+                       
+                       while ((q = strchr_m(p, ';'))) {
+                               *q = '\0';
+                               q++;
+       
+                               full_key = talloc_asprintf(mem_ctx, "%s\\%s", key, p);
+                               callbacks->del_key(callback_data, full_key);
+                               talloc_free(full_key);
+
+                               p = q; 
+                       }
+                       full_key = talloc_asprintf(mem_ctx, "%s\\%s", key, p);
+                       callbacks->del_key(callback_data, full_key);
+                       talloc_free(full_key);
+               } else {
+                       callbacks->add_key(callback_data, key);
+                       callbacks->set_value(callback_data, key, value_name, value_type, data);
+               }
+               talloc_free(key);
+               talloc_free(value_name);
+               talloc_free(data.data);
+       }
+       close(fd);      
+       return WERR_OK;
+}
diff --git a/source/lib/registry/reg_backend_dir.c b/source/lib/registry/reg_backend_dir.c
deleted file mode 100644 (file)
index c2dd3da..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-   Registry interface
-   Copyright (C) Jelmer Vernooij                                         2004.
-   
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "registry.h"
-#include "system/dir.h"
-#include "system/filesys.h"
-
-static WERROR reg_dir_add_key(TALLOC_CTX *mem_ctx, const struct registry_key *parent, const char *name, uint32_t access_mask, struct security_descriptor *desc, struct registry_key **result)
-{
-       char *path;
-       int ret;
-       asprintf(&path, "%s%s\\%s", parent->hive->location, parent->path, name);
-       path = reg_path_win2unix(path);
-       ret = mkdir(path, 0700);
-       SAFE_FREE(path);
-       if(ret == 0)return WERR_OK; /* FIXME */
-       return WERR_INVALID_PARAM;
-}
-
-static WERROR reg_dir_del_key(const struct registry_key *k, const char *name)
-{
-       char *child = talloc_asprintf(NULL, "%s/%s", (char *)k->backend_data, name);
-       WERROR ret;
-
-       if (rmdir(child) == 0) ret = WERR_OK; else ret = WERR_GENERAL_FAILURE;
-
-       talloc_free(child);
-
-       return ret;
-}
-
-static WERROR reg_dir_open_key(TALLOC_CTX *mem_ctx, const struct registry_key *p, const char *name, struct registry_key **subkey)
-{
-       DIR *d;
-       char *fullpath, *unixpath;
-       struct registry_key *ret;
-       
-       if(!name) {
-               DEBUG(0, ("NULL pointer passed as directory name!"));
-               return WERR_INVALID_PARAM;
-       }
-
-       
-       fullpath = talloc_asprintf(mem_ctx, "%s/%s", (char *)p->backend_data, name);
-       unixpath = reg_path_win2unix(fullpath);
-       
-       d = opendir(unixpath);
-       if(!d) {
-               DEBUG(3,("Unable to open '%s': %s\n", unixpath, strerror(errno)));
-               return WERR_BADFILE;
-       }
-       closedir(d);
-       ret = talloc(mem_ctx, struct registry_key);
-       ret->hive = p->hive;
-       ret->path = fullpath;
-       ret->backend_data = unixpath;
-       *subkey = ret;
-       return WERR_OK;
-}
-
-static WERROR reg_dir_key_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *k, int idx, struct registry_key **key)
-{
-       struct dirent *e;
-       char *fullpath = k->backend_data;
-       int i = 0;
-       DIR *d;
-
-       d = opendir(fullpath);
-
-       if(!d) return WERR_INVALID_PARAM;
-       
-       while((e = readdir(d))) {
-               if(!ISDOT(e->d_name) && !ISDOTDOT(e->d_name)) {
-                       struct stat stbuf;
-                       char *thispath;
-                       
-                       /* Check if file is a directory */
-                       asprintf(&thispath, "%s/%s", fullpath, e->d_name);
-                       stat(thispath, &stbuf);
-
-                       if(S_ISDIR(stbuf.st_mode)) {
-                               if(i == idx) {
-                                       (*key) = talloc(mem_ctx, struct registry_key);
-                                       (*key)->name = talloc_strdup(*key, e->d_name);
-                                       (*key)->path = NULL;
-                                       (*key)->backend_data = talloc_strdup(*key, thispath);
-                                       SAFE_FREE(thispath);
-                                       closedir(d);
-                                       return WERR_OK;
-                               }
-                               i++;
-                       }
-
-                       SAFE_FREE(thispath);
-               }
-       }
-
-       closedir(d);
-
-       return WERR_NO_MORE_ITEMS;
-}
-
-static WERROR reg_dir_open(struct registry_hive *h, struct registry_key **key)
-{
-       if(!h->location) return WERR_INVALID_PARAM;
-
-       *key = talloc(h, struct registry_key);
-       (*key)->backend_data = talloc_strdup(*key, h->location);
-       return WERR_OK;
-}
-
-static struct hive_operations reg_backend_dir = {
-       .name = "dir",
-       .open_hive = reg_dir_open,
-       .open_key = reg_dir_open_key,
-       .add_key = reg_dir_add_key,
-       .del_key = reg_dir_del_key,
-       .get_subkey_by_index = reg_dir_key_by_index
-};
-
-NTSTATUS registry_dir_init(void)
-{
-       return registry_register(&reg_backend_dir);
-}
diff --git a/source/lib/registry/reg_backend_ldb.c b/source/lib/registry/reg_backend_ldb.c
deleted file mode 100644 (file)
index ca9327c..0000000
+++ /dev/null
@@ -1,405 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-   Registry interface
-   Copyright (C) Jelmer Vernooij  2004.
-   
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "registry.h"
-#include "lib/ldb/include/ldb.h"
-#include "lib/ldb/include/ldb_errors.h"
-#include "db_wrap.h"
-#include "librpc/gen_ndr/winreg.h"
-
-struct ldb_key_data 
-{
-       struct ldb_dn *dn;
-       struct ldb_message **subkeys, **values;
-       int subkey_count, value_count;
-};
-
-static int ldb_free_hive (struct registry_hive *hive)
-{
-       talloc_free(hive->backend_data);
-       hive->backend_data = NULL;
-       return 0;
-}
-
-static void reg_ldb_unpack_value(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char **name, uint32_t *type, DATA_BLOB *data)
-{
-       const struct ldb_val *val;
-       *name = talloc_strdup(mem_ctx, ldb_msg_find_attr_as_string(msg, "value", NULL));
-       *type = ldb_msg_find_attr_as_uint(msg, "type", 0);
-       val = ldb_msg_find_ldb_val(msg, "data");
-
-       switch (*type)
-       {
-       case REG_SZ:
-       case REG_EXPAND_SZ:
-               data->length = convert_string_talloc(mem_ctx, CH_UTF8, CH_UTF16, val->data, val->length, (void **)&data->data);
-               break;
-
-       case REG_DWORD: {
-               uint32_t tmp = strtoul((char *)val->data, NULL, 0);
-               *data = data_blob_talloc(mem_ctx, &tmp, 4);
-               }
-               break;
-
-       default:
-               *data = data_blob_talloc(mem_ctx, val->data, val->length);
-               break;
-       }
-}
-
-static struct ldb_message *reg_ldb_pack_value(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, const char *name, uint32_t type, DATA_BLOB data)
-{
-       struct ldb_val val;
-       struct ldb_message *msg = talloc_zero(mem_ctx, struct ldb_message);
-       char *type_s;
-
-       ldb_msg_add_string(msg, "value", talloc_strdup(mem_ctx, name));
-
-       switch (type) {
-       case REG_SZ:
-       case REG_EXPAND_SZ:
-               val.length = convert_string_talloc(mem_ctx, CH_UTF16, CH_UTF8, (void *)data.data, data.length, (void **)&val.data);
-               ldb_msg_add_value(msg, "data", &val, NULL);
-               break;
-
-       case REG_DWORD:
-               ldb_msg_add_string(msg, "data", talloc_asprintf(mem_ctx, "0x%x", IVAL(data.data, 0)));
-               break;
-       default:
-               ldb_msg_add_value(msg, "data", &data, NULL);
-       }
-
-
-       type_s = talloc_asprintf(mem_ctx, "%u", type);
-       ldb_msg_add_string(msg, "type", type_s); 
-
-       return msg;
-}
-
-
-static int reg_close_ldb_key(struct registry_key *key)
-{
-       struct ldb_key_data *kd = talloc_get_type(key->backend_data, struct ldb_key_data);
-/*     struct ldb_context *c = key->hive->backend_data; */
-
-       if (kd->subkeys) {
-               talloc_free(kd->subkeys); 
-               kd->subkeys = NULL;
-       }
-
-       if (kd->values) {
-               talloc_free(kd->values); 
-               kd->values = NULL;
-       }
-       return 0;
-}
-
-static struct ldb_dn *reg_path_to_ldb(TALLOC_CTX *mem_ctx, const struct registry_key *from, const char *path, const char *add)
-{
-       TALLOC_CTX *local_ctx;
-       struct ldb_dn *ret;
-       char *mypath = talloc_strdup(mem_ctx, path);
-       char *begin;
-       struct ldb_key_data *kd = talloc_get_type(from->backend_data, struct ldb_key_data);
-       struct ldb_context *ldb = talloc_get_type(from->hive->backend_data, struct ldb_context);
-
-       local_ctx = talloc_new(mem_ctx);
-
-       if (add) {
-               ret = ldb_dn_new(mem_ctx, ldb, add);
-       } else {
-               ret = ldb_dn_new(mem_ctx, ldb, NULL);
-       }
-       if ( ! ldb_dn_validate(ret)) {
-               talloc_free(ret);
-               talloc_free(local_ctx);
-               return NULL;
-       }
-
-       while(mypath) {
-               char *keyname;
-
-               begin = strrchr(mypath, '\\');
-
-               if (begin) keyname = begin + 1;
-               else keyname = mypath;
-
-               if(strlen(keyname)) {
-                       ldb_dn_add_base_fmt(ret, "key=%s", keyname);
-               }
-
-               if(begin) {
-                       *begin = '\0';
-               } else {
-                       break;
-               }
-       }
-
-       ldb_dn_add_base(ret, kd->dn);
-
-       talloc_free(local_ctx);
-
-       return ret;
-}
-
-
-static WERROR ldb_get_subkey_by_id(TALLOC_CTX *mem_ctx, const struct registry_key *k, int idx, struct registry_key **subkey)
-{
-       struct ldb_context *c = talloc_get_type(k->hive->backend_data, struct ldb_context);
-       struct ldb_message_element *el;
-       struct ldb_key_data *kd = talloc_get_type(k->backend_data, struct ldb_key_data);
-       struct ldb_key_data *newkd;
-
-       /* Do a search if necessary */
-       if (kd->subkeys == NULL) {
-               struct ldb_result *res;
-               int ret;
-
-               ret = ldb_search(c, kd->dn, LDB_SCOPE_ONELEVEL, "(key=*)", NULL, &res);
-
-               if (ret != LDB_SUCCESS) {
-                       DEBUG(0, ("Error getting subkeys for '%s': %s\n", ldb_dn_get_linearized(kd->dn), ldb_errstring(c)));
-                       return WERR_FOOBAR;
-               }
-
-               kd->subkey_count = res->count;
-               kd->subkeys = talloc_steal(kd, res->msgs);
-               talloc_free(res);
-       } 
-
-       if (idx >= kd->subkey_count) return WERR_NO_MORE_ITEMS;
-
-       el = ldb_msg_find_element(kd->subkeys[idx], "key");
-       
-       *subkey = talloc(mem_ctx, struct registry_key);
-       talloc_set_destructor(*subkey, reg_close_ldb_key);
-       (*subkey)->name = talloc_strdup(mem_ctx, (char *)el->values[0].data);
-       (*subkey)->backend_data = newkd = talloc_zero(*subkey, struct ldb_key_data);
-       (*subkey)->last_mod = 0; /* TODO: we need to add this to the
-                                   ldb backend properly */
-       newkd->dn = ldb_dn_copy(mem_ctx, kd->subkeys[idx]->dn);
-
-       return WERR_OK;
-}
-
-static WERROR ldb_get_value_by_id(TALLOC_CTX *mem_ctx, const struct registry_key *k, int idx, struct registry_value **value)
-{
-       struct ldb_context *c = talloc_get_type(k->hive->backend_data, struct ldb_context);
-       struct ldb_key_data *kd = talloc_get_type(k->backend_data, struct ldb_key_data);
-
-       /* Do the search if necessary */
-       if (kd->values == NULL) {
-               struct ldb_result *res;
-               int ret;
-
-               ret = ldb_search(c, kd->dn, LDB_SCOPE_ONELEVEL, "(value=*)", NULL, &res);
-
-               if (ret != LDB_SUCCESS) {
-                       DEBUG(0, ("Error getting values for '%s': %s\n", ldb_dn_get_linearized(kd->dn), ldb_errstring(c)));
-                       return WERR_FOOBAR;
-               }
-               kd->value_count = res->count;
-               kd->values = talloc_steal(kd, res->msgs);
-               talloc_free(res);
-       }
-
-       if(idx >= kd->value_count) return WERR_NO_MORE_ITEMS;
-
-       *value = talloc(mem_ctx, struct registry_value);
-
-       reg_ldb_unpack_value(mem_ctx, kd->values[idx], &(*value)->name, &(*value)->data_type, &(*value)->data);
-
-       return WERR_OK;
-}
-
-static WERROR ldb_open_key(TALLOC_CTX *mem_ctx, const struct registry_key *h, const char *name, struct registry_key **key)
-{
-       struct ldb_context *c = talloc_get_type(h->hive->backend_data, struct ldb_context);
-       struct ldb_result *res;
-       struct ldb_dn *ldap_path;
-       int ret;
-       struct ldb_key_data *newkd;
-
-       ldap_path = reg_path_to_ldb(mem_ctx, h, name, NULL);
-
-       ret = ldb_search(c, ldap_path, LDB_SCOPE_BASE, "(key=*)", NULL, &res);
-
-       if (ret != LDB_SUCCESS) {
-               DEBUG(0, ("Error opening key '%s': %s\n", ldb_dn_get_linearized(ldap_path), ldb_errstring(c)));
-               return WERR_FOOBAR;
-       } else if (res->count == 0) {
-               talloc_free(res);
-               return WERR_BADFILE;
-       }
-
-       *key = talloc(mem_ctx, struct registry_key);
-       talloc_set_destructor(*key, reg_close_ldb_key);
-       (*key)->name = talloc_strdup(mem_ctx, strrchr(name, '\\')?strchr(name, '\\'):name);
-       (*key)->backend_data = newkd = talloc_zero(*key, struct ldb_key_data);
-       newkd->dn = ldb_dn_copy(mem_ctx, res->msgs[0]->dn); 
-
-       talloc_free(res);
-
-       return WERR_OK;
-}
-
-static WERROR ldb_open_hive(struct registry_hive *hive, struct registry_key **k)
-{
-       struct ldb_key_data *kd;
-       struct ldb_context *wrap;
-
-       if (!hive->location) return WERR_INVALID_PARAM;
-
-       wrap = ldb_wrap_connect(hive, hive->location, hive->session_info, hive->credentials, 0, NULL);
-
-       if(!wrap) {
-               DEBUG(1, ("ldb_open_hive: unable to connect\n"));
-               return WERR_FOOBAR;
-       }
-
-       ldb_set_debug_stderr(wrap);
-       hive->backend_data = wrap;
-
-       *k = talloc_zero(hive, struct registry_key);
-       talloc_set_destructor (*k, reg_close_ldb_key);
-       talloc_set_destructor (hive, ldb_free_hive);
-       (*k)->name = talloc_strdup(*k, "");
-       (*k)->backend_data = kd = talloc_zero(*k, struct ldb_key_data);
-       kd->dn = ldb_dn_new(*k, wrap, "hive=NONE");
-       
-
-       return WERR_OK;
-}
-
-static WERROR ldb_add_key (TALLOC_CTX *mem_ctx, const struct registry_key *parent, const char *name, uint32_t access_mask, struct security_descriptor *sd, struct registry_key **newkey)
-{
-       struct ldb_context *ctx = talloc_get_type(parent->hive->backend_data, struct ldb_context);
-       struct ldb_message *msg;
-       struct ldb_key_data *newkd;
-       int ret;
-
-       msg = ldb_msg_new(mem_ctx);
-
-       msg->dn = reg_path_to_ldb(msg, parent, name, NULL);
-
-       ldb_msg_add_string(msg, "key", talloc_strdup(mem_ctx, name));
-
-       ret = ldb_add(ctx, msg);
-       if (ret < 0) {
-               DEBUG(1, ("ldb_msg_add: %s\n", ldb_errstring(ctx)));
-               return WERR_FOOBAR;
-       }
-
-       *newkey = talloc_zero(mem_ctx, struct registry_key);
-       (*newkey)->name = talloc_strdup(mem_ctx, name);
-
-       (*newkey)->backend_data = newkd = talloc_zero(*newkey, struct ldb_key_data);
-       newkd->dn = talloc_steal(newkd, msg->dn);
-
-       return WERR_OK;
-}
-
-static WERROR ldb_del_key (const struct registry_key *key, const char *child)
-{
-       struct ldb_context *ctx = talloc_get_type(key->hive->backend_data, struct ldb_context);
-       int ret;
-       struct ldb_key_data *kd = talloc_get_type(key->backend_data, struct ldb_key_data);
-       struct ldb_dn *childdn;
-
-       childdn = ldb_dn_copy(ctx, kd->dn);
-       ldb_dn_add_child_fmt(childdn, "key=%s", child);
-
-       ret = ldb_delete(ctx, childdn);
-
-       talloc_free(childdn);
-
-       if (ret < 0) {
-               DEBUG(1, ("ldb_del_key: %s\n", ldb_errstring(ctx)));
-               return WERR_FOOBAR;
-       }
-
-       return WERR_OK;
-}
-
-static WERROR ldb_del_value (const struct registry_key *key, const char *child)
-{
-       int ret;
-       struct ldb_context *ctx = talloc_get_type(key->hive->backend_data, struct ldb_context);
-       struct ldb_key_data *kd = talloc_get_type(key->backend_data, struct ldb_key_data);
-       struct ldb_dn *childdn;
-
-       childdn = ldb_dn_copy(ctx, kd->dn);
-       ldb_dn_add_child_fmt(childdn, "value=%s", child);
-
-       ret = ldb_delete(ctx, childdn);
-
-       talloc_free(childdn);
-
-       if (ret < 0) {
-               DEBUG(1, ("ldb_del_value: %s\n", ldb_errstring(ctx)));
-               return WERR_FOOBAR;
-       }
-
-       return WERR_OK;
-}
-
-static WERROR ldb_set_value (const struct registry_key *parent, const char *name, uint32_t type, DATA_BLOB data)
-{
-       struct ldb_context *ctx = talloc_get_type(parent->hive->backend_data, struct ldb_context);
-       struct ldb_message *msg;
-       struct ldb_key_data *kd = talloc_get_type(parent->backend_data, struct ldb_key_data);
-       int ret;
-       TALLOC_CTX *mem_ctx = talloc_init("ldb_set_value");
-
-       msg = reg_ldb_pack_value(ctx, mem_ctx, name, type, data);
-
-       msg->dn = ldb_dn_copy(msg, kd->dn);
-       ldb_dn_add_child_fmt(msg->dn, "value=%s", name);
-
-       ret = ldb_add(ctx, msg);
-       if (ret < 0) {
-               ret = ldb_modify(ctx, msg);
-               if (ret < 0) {
-                       DEBUG(1, ("ldb_msg_add: %s\n", ldb_errstring(ctx)));
-                       talloc_free(mem_ctx);
-                       return WERR_FOOBAR;
-               }
-       }
-       
-       talloc_free(mem_ctx);
-       return WERR_OK;
-}
-
-static struct hive_operations reg_backend_ldb = {
-       .name = "ldb",
-       .add_key = ldb_add_key,
-       .del_key = ldb_del_key,
-       .open_hive = ldb_open_hive,
-       .open_key = ldb_open_key,
-       .get_value_by_index = ldb_get_value_by_id,
-       .get_subkey_by_index = ldb_get_subkey_by_id,
-       .set_value = ldb_set_value,
-       .del_value = ldb_del_value,
-};
-
-NTSTATUS registry_ldb_init(void)
-{
-       return registry_register(&reg_backend_ldb);
-}
diff --git a/source/lib/registry/reg_backend_nt4.c b/source/lib/registry/reg_backend_nt4.c
deleted file mode 100644 (file)
index 74261c5..0000000
+++ /dev/null
@@ -1,1124 +0,0 @@
-/*
-   Samba CIFS implementation
-   Registry backend for REGF files
-   Copyright (C) 2005 Jelmer Vernooij, jelmer@samba.org
-   Copyright (C) 2006 Wilco Baan Hofman, wilco@baanhofman.nl
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-#include "includes.h"
-#include "lib/registry/registry.h"
-#include "system/filesys.h"
-#include "system/time.h"
-#include "lib/registry/tdr_regf.h"
-#include "librpc/gen_ndr/ndr_security.h"
-
-/* TODO:
- *  - Return error codes that make more sense
- *  - Locking
- */
-
-/*
- * Read HBIN blocks into memory
- */
-
-struct regf_data {
-       int fd;
-       struct hbin_block **hbins;
-       struct regf_hdr *header;
-};
-
-static struct hbin_block *hbin_by_offset (const struct regf_data *data, uint32_t offset, uint32_t *rel_offset)
-{
-       int i;
-
-       for (i = 0; data->hbins[i]; i++) {
-               if (offset >= data->hbins[i]->offset_from_first && 
-                       offset < data->hbins[i]->offset_from_first+
-                                        data->hbins[i]->offset_to_next) {
-                       if (rel_offset)
-                               *rel_offset = offset - data->hbins[i]->offset_from_first - 0x20;
-                       return data->hbins[i];
-               }
-       }
-
-       return NULL;
-}
-
-/*
- * Validate a regf header
- * For now, do nothing, but we should check the checksum
- */
-static uint32_t regf_hdr_checksum(const uint8_t *buffer)
-{
-       uint32_t checksum = 0, x;
-       int i;
-       
-       for (i = 0; i < 0x01FB; i+= 4) {
-               x = IVAL(buffer, i);
-               checksum ^= x;
-       }
-
-       return checksum;
-}
-
-static DATA_BLOB hbin_get(const struct regf_data *data, uint32_t offset)
-{
-       DATA_BLOB ret;
-       struct hbin_block *hbin;
-       uint32_t rel_offset;
-       ret.data = NULL;
-       ret.length = 0;
-
-       hbin = hbin_by_offset(data, offset, &rel_offset);
-
-       if (hbin == NULL) {
-               DEBUG(1, ("Can't find HBIN containing 0x%04x\n", offset));
-               return ret;
-       }
-
-       ret.length = IVAL(hbin->data, rel_offset);
-       if (!(ret.length & 0x80000000)) {
-               DEBUG(0, ("Trying to use dirty block at 0x%04x\n", offset));
-               return ret;
-       }
-
-       /* remove high bit */
-       ret.length = (ret.length ^ 0xffffffff) + 1;
-
-       ret.length -= 4; /* 4 bytes for the length... */
-       ret.data = hbin->data + 
-               (offset - hbin->offset_from_first - 0x20) + 4;
-       
-       return ret;
-}
-
-static BOOL hbin_get_tdr (struct regf_data *regf, uint32_t offset, TALLOC_CTX *ctx, tdr_pull_fn_t pull_fn, void *p)
-{
-       struct tdr_pull pull;
-
-       ZERO_STRUCT(pull);
-
-       pull.data = hbin_get(regf, offset);
-       if (!pull.data.data) {
-               DEBUG(1, ("Unable to get data at 0x%04x\n", offset));
-               return False;
-       }
-       
-       if (NT_STATUS_IS_ERR(pull_fn(&pull, ctx, p))) {
-               DEBUG(1, ("Error parsing record at 0x%04x using tdr\n", offset));
-               return False;
-       }
-
-       return True;
-}
-
-/* Allocate some new data */
-static DATA_BLOB hbin_alloc (struct regf_data *data, uint32_t size, uint32_t *offset)
-{
-       DATA_BLOB ret;
-       uint32_t rel_offset = -1; /* Relative offset ! */
-       struct hbin_block *hbin = NULL;
-       int i;
-
-       *offset = 0;
-
-       if (size == 0)
-               return data_blob(NULL, 0);
-
-       size += 4; /* Need to include uint32 for the length */
-
-       /* Allocate as a multiple of 8 */
-       size = (size + 7) & ~7;
-
-       ret.data = NULL;
-       ret.length = 0;
-
-       for (i = 0; (hbin = data->hbins[i]); i++) {
-               int j;
-               uint32_t my_size;
-               for (j = 0; j < hbin->offset_to_next-0x20; j+= my_size) {
-                       uint32_t header = IVAL(hbin->data, j + 4);
-                       my_size = IVAL(hbin->data, j);
-
-                       if (my_size == 0x0) {
-                               DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
-                               return ret;
-                       }
-
-                       if (my_size % 8 != 0) {
-                               DEBUG(0, ("Encountered non-aligned block!\n"));
-                       }
-
-                       if (my_size & 0x80000000) { /* Used... */
-                               my_size = (my_size ^ 0xffffffff) + 1;
-                       } else if (my_size == size) { /* exact match */
-                               rel_offset = j;
-                               DEBUG(4, ("Found free block of exact size %d in middle of HBIN\n", size));
-                               break;
-                       } else if (my_size > size) { /* data will remain */
-                               rel_offset = j;
-                               SIVAL(hbin->data, rel_offset+size, my_size-size); 
-                               DEBUG(4, ("Found free block of size %d (needing %d) in middle of HBIN\n", my_size, size));
-                               break;
-                       }
-
-                       if (header == 0xffffffff &&
-                               hbin->offset_to_next-rel_offset >= size)  {
-                               rel_offset = j;
-
-                               DEBUG(4, ("Found free block of size %d at end of HBIN\n", size));
-                               /* Mark new free block size */
-                               SIVAL(hbin->data, rel_offset+size,hbin->offset_to_next - rel_offset - size - 0x20);
-                               SIVAL(hbin->data, rel_offset+size+0x4, 0xffffffff);
-                               break;
-                       }
-
-                       if (header == 0xffffffff)  {
-                               break;
-                       }
-               }
-
-               if (rel_offset != -1)
-                       break;
-       }
-       
-       /* No space available in previous hbins, 
-        * allocate new one */
-       if (data->hbins[i] == NULL) { 
-               DEBUG(4, ("No space available in other HBINs for block of size %d, allocating new HBIN\n", size));
-               data->hbins = talloc_realloc(data, data->hbins, struct hbin_block *, i+2);
-               hbin = talloc(data->hbins, struct hbin_block);
-               data->hbins[i] = hbin;
-               data->hbins[i+1] = NULL;
-
-               hbin->HBIN_ID = talloc_strdup(hbin, "hbin");
-               hbin->offset_from_first = (i == 0?0:data->hbins[i-1]->offset_from_first+data->hbins[i-1]->offset_to_next);
-               hbin->offset_to_next = 0x1000;
-               hbin->unknown[0] = 0;
-               hbin->unknown[0] = 0;
-               unix_to_nt_time(&hbin->last_change, time(NULL));
-               hbin->block_size = hbin->offset_to_next;
-               hbin->data = talloc_zero_array(hbin, uint8_t, hbin->block_size - 0x20);
-
-               rel_offset = 0x0;
-               SIVAL(hbin->data, size, hbin->block_size - size - 0x20);
-               SIVAL(hbin->data, size + 0x4, 0xffffffff);
-       }
-
-       /* Set size and mark as used */
-       SIVAL(hbin->data, rel_offset, size | 0x80000000);
-
-       ret.data = hbin->data + rel_offset + 0x4; /* Skip past length */
-       ret.length = size - 0x4;
-       if (offset) {
-               uint32_t new_rel_offset;
-               *offset = hbin->offset_from_first + rel_offset + 0x20;
-               SMB_ASSERT(hbin_by_offset(data, *offset, &new_rel_offset) == hbin);
-               SMB_ASSERT(new_rel_offset == rel_offset);
-       }
-
-       return ret;
-}
-
-/* Store a data blob. Return the offset at which it was stored */
-static uint32_t hbin_store (struct regf_data *data, DATA_BLOB blob)
-{
-       uint32_t ret;
-       DATA_BLOB dest = hbin_alloc(data, blob.length, &ret);
-
-       memcpy(dest.data, blob.data, blob.length);
-
-       return ret;
-}
-
-static uint32_t hbin_store_tdr (struct regf_data *data, tdr_push_fn_t push_fn, void *p)
-{
-       struct tdr_push *push = talloc_zero(data, struct tdr_push);
-       uint32_t ret;
-       
-       if (NT_STATUS_IS_ERR(push_fn(push, p))) {
-               DEBUG(0, ("Error during push\n"));
-               return -1;
-       }
-
-       ret = hbin_store(data, push->data);
-
-       talloc_free(push);
-
-       return ret;
-}
-
-
-/* Free existing data */
-static void hbin_free (struct regf_data *data, uint32_t offset)
-{
-       uint32_t size;
-       uint32_t rel_offset;
-       struct hbin_block *hbin;
-
-       SMB_ASSERT (offset > 0);
-       
-       hbin = hbin_by_offset(data, offset, &rel_offset);
-
-       if (hbin == NULL)
-               return;
-       
-       /* Get original size */
-       size = IVAL(hbin->data, rel_offset);
-
-       if (!(size & 0x80000000)) {
-               DEBUG(1, ("Trying to free already freed block at 0x%04x\n", offset));
-               return;
-       }
-
-       /* Mark block as free */
-       SIVAL(hbin->data, rel_offset, size &~ 0x80000000);
-}
-
-/* Store a data blob data was already stored, but hsa changed in size
- * Will try to save it at the current location if possible, otherwise 
- * does a free + store */
-static uint32_t hbin_store_resize (struct regf_data *data, uint32_t orig_offset, DATA_BLOB blob)
-{
-       uint32_t rel_offset;
-       struct hbin_block *hbin = hbin_by_offset(data, orig_offset, &rel_offset);
-       uint32_t my_size;
-       uint32_t orig_size;
-       uint32_t needed_size;
-       uint32_t possible_size;
-       int i;
-
-       SMB_ASSERT(orig_offset > 0);
-
-       if (!hbin)
-               return hbin_store(data, blob);
-
-       /* Get original size */
-       orig_size = IVAL(hbin->data, rel_offset);
-
-       needed_size = blob.length + 4; /* Add uint32 containing length */
-       needed_size = (needed_size + 7) & ~7; /* Align */
-
-       /* Fits into current allocated block */
-       if (orig_size >= needed_size) {
-               memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
-               return orig_offset;
-       }
-
-       possible_size = orig_size;
-
-       /* Check if it can be combined with the next few free records */
-       for (i = rel_offset; 
-                i < hbin->offset_to_next - 0x20; 
-                i += my_size) {
-               uint32_t header;
-               if (IVAL(hbin->data, i) & 0x80000000) /* Used */
-                       break;
-
-               my_size = IVAL(hbin->data, i);
-               header = IVAL(hbin->data, i + 4);
-               if (header == 0xffffffff) {
-                       possible_size = hbin->offset_to_next - 0x20 - rel_offset;
-               } else if (my_size == 0x0) {
-                       DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
-                       break;
-               } else {
-                       possible_size += my_size;
-               }
-
-               if (possible_size >= blob.length) {
-                       SIVAL(hbin->data, rel_offset, possible_size);
-                       memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
-                       return orig_offset;
-               }
-
-               if (header == 0xffffffff) 
-                       break;
-       }
-
-       hbin_free(data, orig_offset);
-       return hbin_store(data, blob);
-}
-
-static uint32_t hbin_store_tdr_resize (struct regf_data *regf, tdr_push_fn_t push_fn, uint32_t orig_offset, void *p)
-{
-       struct tdr_push *push = talloc_zero(regf, struct tdr_push);
-       uint32_t ret;
-       
-       if (NT_STATUS_IS_ERR(push_fn(push, p))) {
-               DEBUG(0, ("Error during push\n"));
-               return -1;
-       }
-
-       ret = hbin_store_resize(regf, orig_offset, push->data);
-
-       talloc_free(push);
-
-       return ret;
-}
-
-static WERROR regf_num_subkeys (const struct registry_key *key, uint32_t *count)
-{
-       struct nk_block *nk = key->backend_data;
-
-       *count = nk->num_subkeys;
-       
-       return WERR_OK;
-}
-
-static WERROR regf_num_values (const struct registry_key *key, uint32_t *count)
-{
-       struct nk_block *nk = key->backend_data;
-
-       *count = nk->num_values;
-
-       return WERR_OK;
-}
-
-static struct registry_key *regf_get_key (TALLOC_CTX *ctx, struct regf_data *regf, uint32_t offset)
-{
-       struct registry_key *ret;
-       struct nk_block *nk;
-
-       ret = talloc_zero(ctx, struct registry_key);
-       nk = talloc(ret, struct nk_block);
-       if (!hbin_get_tdr(regf, offset, nk, (tdr_pull_fn_t)tdr_pull_nk_block, nk)) {
-               DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset));
-               return NULL;
-       }
-
-       if (strcmp(nk->header, "nk") != 0) {
-               DEBUG(0, ("Expected nk record, got %s\n", nk->header));
-               talloc_free(ret);
-               return NULL;
-       }
-
-       ret->name = talloc_steal(ret, nk->key_name);
-       ret->last_mod = nk->last_change;
-
-       if (nk->clsname_offset != -1) {
-               DATA_BLOB data = hbin_get(regf, nk->clsname_offset);
-               ret->class_name = talloc_strndup(ret, (char*)data.data, nk->clsname_length);
-       }
-       ret->backend_data = nk;
-
-       return ret;
-}
-
-static WERROR regf_get_value (TALLOC_CTX *ctx, const struct registry_key *key, int idx, struct registry_value **ret)
-{
-       struct nk_block *nk = key->backend_data;
-       struct vk_block *vk;
-       struct regf_data *regf = key->hive->backend_data;
-       uint32_t vk_offset;
-       DATA_BLOB data;
-
-       if (idx >= nk->num_values)
-               return WERR_NO_MORE_ITEMS;
-
-       data = hbin_get(regf, nk->values_offset);
-       if (!data.data) {
-               DEBUG(0, ("Unable to find value list\n"));
-               return WERR_GENERAL_FAILURE;
-       }
-
-       if (data.length < nk->num_values * 4) {
-               DEBUG(1, ("Value counts mismatch\n"));
-       }
-
-       vk_offset = IVAL(data.data, idx * 4);
-
-       *ret = talloc_zero(ctx, struct registry_value);
-       if (!(*ret)) 
-               return WERR_NOMEM;
-
-       vk = talloc(*ret, struct vk_block);
-       if (!vk)
-               return WERR_NOMEM;
-       
-       if (!hbin_get_tdr(regf, vk_offset, vk, (tdr_pull_fn_t)tdr_pull_vk_block, vk)) {
-               DEBUG(0, ("Unable to get VK block at %d\n", vk_offset));
-               return WERR_GENERAL_FAILURE;
-       }
-
-       (*ret)->name = talloc_steal(*ret, vk->data_name);
-       (*ret)->data_type = vk->data_type;
-       if (vk->data_length & 0x80000000) { 
-               vk->data_length &=~0x80000000;
-               (*ret)->data.data = (uint8_t *)&vk->data_offset;
-               (*ret)->data.length = vk->data_length;
-       } else {
-               (*ret)->data = hbin_get(regf, vk->data_offset);
-       }
-
-       if ((*ret)->data.length < vk->data_length) {
-               DEBUG(1, ("Read data less than indicated data length!\n"));
-       }
-       
-       return WERR_OK;
-}
-
-static WERROR regf_get_subkey_by_index (TALLOC_CTX *ctx, const struct registry_key *key, int idx, struct registry_key **ret)
-{
-       DATA_BLOB data;
-       struct nk_block *nk = key->backend_data;
-       uint32_t key_off=0;
-
-       if (idx >= nk->num_subkeys)
-               return WERR_NO_MORE_ITEMS;
-
-       data = hbin_get(key->hive->backend_data, nk->subkeys_offset);
-       if (!data.data) {
-               DEBUG(0, ("Unable to find subkey list\n"));
-               return WERR_GENERAL_FAILURE;
-       }
-
-       if (!strncmp((char *)data.data, "li", 2)) {
-               struct li_block li;
-               struct tdr_pull pull;
-
-               DEBUG(10, ("Subkeys in LI list\n"));
-               ZERO_STRUCT(pull);
-               pull.data = data;
-
-               if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
-                       DEBUG(0, ("Error parsing LI list\n"));
-                       return WERR_GENERAL_FAILURE;
-               }
-               SMB_ASSERT(!strncmp(li.header, "li",2));
-
-               if (li.key_count != nk->num_subkeys) {
-                       DEBUG(0, ("Subkey counts don't match\n"));
-                       return WERR_GENERAL_FAILURE;
-               }
-               key_off = li.nk_offset[idx];
-       
-       } else if (!strncmp((char *)data.data, "lf", 2)) {
-               struct lf_block lf;
-               struct tdr_pull pull;
-
-               DEBUG(10, ("Subkeys in LF list\n"));
-               ZERO_STRUCT(pull);
-               pull.data = data;
-
-               if (NT_STATUS_IS_ERR(tdr_pull_lf_block(&pull, nk, &lf))) {
-                       DEBUG(0, ("Error parsing LF list\n"));
-                       return WERR_GENERAL_FAILURE;
-               }
-               SMB_ASSERT(!strncmp(lf.header, "lf",2));
-
-               if (lf.key_count != nk->num_subkeys) {
-                       DEBUG(0, ("Subkey counts don't match\n"));
-                       return WERR_GENERAL_FAILURE;
-               }
-
-               key_off = lf.hr[idx].nk_offset;
-       } else if (!strncmp((char *)data.data, "lh", 2)) {
-               struct lh_block lh;
-               struct tdr_pull pull;
-               
-               DEBUG(10, ("Subkeys in LH list"));
-               ZERO_STRUCT(pull);
-               pull.data = data;
-               
-               if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
-                       DEBUG(0, ("Error parsing LH list\n"));
-                       return WERR_GENERAL_FAILURE;
-               }
-               SMB_ASSERT(!strncmp(lh.header, "lh",2));
-               
-               if (lh.key_count != nk->num_subkeys) {
-                       DEBUG(0, ("Subkey counts don't match\n"));
-                       return WERR_GENERAL_FAILURE;
-               }
-               key_off = lh.hr[idx].nk_offset;
-       } else if (!strncmp((char *)data.data, "ri", 2)) {
-               struct ri_block ri;
-               struct tdr_pull pull;
-               uint16_t i;
-               uint16_t sublist_count = 0;
-               
-               ZERO_STRUCT(pull);
-               pull.data = data;
-               
-               if (NT_STATUS_IS_ERR(tdr_pull_ri_block(&pull, nk, &ri))) {
-                       DEBUG(0, ("Error parsing RI list\n"));
-                       return WERR_GENERAL_FAILURE;
-               }
-               SMB_ASSERT(!strncmp(ri.header, "ri",2));
-               
-               for (i = 0; i < ri.key_count; i++) {
-                       DATA_BLOB list_data;
-                       
-                       /* Get sublist data blob */
-                       list_data = hbin_get(key->hive->backend_data, ri.offset[i]);
-                       if (!list_data.data) {
-                               DEBUG(0, ("Error getting RI list."));
-                               return WERR_GENERAL_FAILURE;
-                       }
-                       
-                       ZERO_STRUCT(pull);
-                       pull.data = list_data;
-                       
-                       if (!strncmp((char *)list_data.data, "li", 2)) {
-                               struct li_block li;
-
-                               if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
-                                       DEBUG(0, ("Error parsing LI list from RI\n"));
-                                       return WERR_GENERAL_FAILURE;
-                               }
-                               SMB_ASSERT(!strncmp(li.header, "li",2));
-                               
-                               /* Advance to next sublist if necessary */
-                               if (idx >= sublist_count + li.key_count) {
-                                       sublist_count += li.key_count;
-                                       continue;
-                               }
-                               key_off = li.nk_offset[idx - sublist_count];
-                               sublist_count += li.key_count;
-                               break;
-                       } else if (!strncmp((char *)list_data.data, "lh", 2)) {
-                               struct lh_block lh;
-                               
-                               if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
-                                       DEBUG(0, ("Error parsing LH list from RI\n"));
-                                       return WERR_GENERAL_FAILURE;
-                               }
-                               SMB_ASSERT(!strncmp(lh.header, "lh",2));
-
-                               
-                               /* Advance to next sublist if necessary */
-                               if (idx >= sublist_count + lh.key_count) {
-                                       sublist_count += lh.key_count;
-                                       continue;
-                               }
-                               key_off = lh.hr[idx - sublist_count].nk_offset;
-                               sublist_count += lh.key_count;
-                               break;
-                       } else {
-                               DEBUG(0,("Unknown sublist in ri block\n"));
-                               SMB_ASSERT(0);
-                       }
-                       
-               }
-       
-               if (idx > sublist_count) {
-                       return WERR_NO_MORE_ITEMS;
-               }
-
-       } else {
-               DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n", nk->subkeys_offset, data.data[0], data.data[1]));
-               return WERR_GENERAL_FAILURE;
-       }
-
-       *ret = regf_get_key (ctx, key->hive->backend_data, key_off);
-
-       return WERR_OK;
-}
-
-static WERROR regf_match_subkey_by_name (TALLOC_CTX *ctx, const struct registry_key *key, uint32_t offset, const char *name, uint32_t *ret) 
-{
-       DATA_BLOB subkey_data;
-       struct nk_block subkey;
-       struct tdr_pull pull;
-       
-       subkey_data = hbin_get(key->hive->backend_data, offset);
-       if (!subkey_data.data) {
-               DEBUG(0, ("Unable to retrieve subkey HBIN\n"));
-               return WERR_GENERAL_FAILURE;
-       }
-
-       ZERO_STRUCT(pull);
-       pull.data = subkey_data;
-       
-       if (NT_STATUS_IS_ERR(tdr_pull_nk_block(&pull, ctx, &subkey))) {
-               DEBUG(0, ("Error parsing NK structure.\n"));
-               return WERR_GENERAL_FAILURE;
-       }
-       if (strncmp(subkey.header, "nk", 2)) {
-               DEBUG(0, ("Not an NK structure.\n"));
-               return WERR_GENERAL_FAILURE;
-       }
-       if (!strcasecmp(subkey.key_name, name)) {
-               *ret = offset;
-       } else {
-               *ret = 0;
-       }
-       return WERR_OK;
-}
-       
-static WERROR regf_get_subkey_by_name (TALLOC_CTX *ctx, const struct registry_key *key, const char *name, struct registry_key **ret)
-{
-       DATA_BLOB data;
-       struct nk_block *nk = key->backend_data;
-       uint32_t key_off = 0;
-
-       data = hbin_get(key->hive->backend_data, nk->subkeys_offset);
-       if (!data.data) {
-               DEBUG(0, ("Unable to find subkey list\n"));
-               return WERR_GENERAL_FAILURE;
-       }
-
-       if (!strncmp((char *)data.data, "li",2)) {
-               struct li_block li;
-               struct tdr_pull pull;
-               uint16_t i;
-
-               DEBUG(10, ("Subkeys in LI list\n"));
-               ZERO_STRUCT(pull);
-               pull.data = data;
-               
-               if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
-                       DEBUG(0, ("Error parsing LI list\n"));
-                       return WERR_GENERAL_FAILURE;
-               }
-               SMB_ASSERT(!strncmp(li.header, "li",2));
-
-               if (li.key_count != nk->num_subkeys) {
-                       DEBUG(0, ("Subkey counts don't match\n"));
-                       return WERR_GENERAL_FAILURE;
-               }
-               
-               for (i = 0; i < li.key_count; i++) {
-                       W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, li.nk_offset[i], name, &key_off));
-                       if (key_off) {
-                               break;
-                       }
-               }
-               if (!key_off) {
-                       return WERR_DEST_NOT_FOUND;
-               }
-       } else if (!strncmp((char *)data.data, "lf",2)) {
-               struct lf_block lf;
-               struct tdr_pull pull;
-               uint16_t i;
-
-               DEBUG(10, ("Subkeys in LF list\n"));
-               ZERO_STRUCT(pull);
-               pull.data = data;
-               
-               if (NT_STATUS_IS_ERR(tdr_pull_lf_block(&pull, nk, &lf))) {
-                       DEBUG(0, ("Error parsing LF list\n"));
-                       return WERR_GENERAL_FAILURE;
-               }
-               SMB_ASSERT(!strncmp(lf.header, "lf",2));
-
-               if (lf.key_count != nk->num_subkeys) {
-                       DEBUG(0, ("Subkey counts don't match\n"));
-                       return WERR_GENERAL_FAILURE;
-               }
-               
-               for (i = 0; i < lf.key_count; i++) {
-                       if (strncmp(lf.hr[i].hash, name, 4)) {
-                               continue;
-                       }
-                       W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, lf.hr[i].nk_offset, name, &key_off));
-                       if (key_off) {
-                               break;
-                       }
-               }
-               if (!key_off) {
-                       return WERR_DEST_NOT_FOUND;
-               }
-       } else if (!strncmp((char *)data.data, "lh",2)) {
-               struct lh_block lh;
-               struct tdr_pull pull;
-               uint16_t i;
-               uint32_t hash = 0;
-               char *hash_name;
-
-               DEBUG(10, ("Subkeys in LH list\n"));
-               ZERO_STRUCT(pull);
-               pull.data = data;
-               
-               if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
-                       DEBUG(0, ("Error parsing LH list\n"));
-                       return WERR_GENERAL_FAILURE;
-               }
-               SMB_ASSERT(!strncmp(lh.header, "lh",2));
-
-               if (lh.key_count != nk->num_subkeys) {
-                       DEBUG(0, ("Subkey counts don't match\n"));
-                       return WERR_GENERAL_FAILURE;
-               }
-               
-               /* Compute hash for the name */
-               hash_name = strupper_talloc(nk, name);          
-               for (i = 0; *(hash_name + i) != 0; i++) {
-                       hash *= 37;
-                       hash += *(hash_name + i);
-               }
-               for (i = 0; i < lh.key_count; i++) {
-                       if (lh.hr[i].base37 != hash) {
-                               continue;
-                       }
-                       W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, lh.hr[i].nk_offset, name, &key_off));
-                       if (key_off) {
-                               break;
-                       }
-               }       
-               if (!key_off) {
-                       return WERR_DEST_NOT_FOUND;
-               }
-       } else if (!strncmp((char *)data.data, "ri", 2)) {
-               struct ri_block ri;
-               struct tdr_pull pull;
-               uint16_t i, j;
-
-               DEBUG(10, ("Subkeys in RI list\n"));
-               ZERO_STRUCT(pull);
-               pull.data = data;
-               
-               if (NT_STATUS_IS_ERR(tdr_pull_ri_block(&pull, nk, &ri))) {
-                       DEBUG(0, ("Error parsing RI list\n"));
-                       return WERR_GENERAL_FAILURE;
-               }
-               SMB_ASSERT(!strncmp(ri.header, "ri",2));
-
-                       
-               for (i = 0; i < ri.key_count; i++) {
-                       DATA_BLOB list_data;
-                       
-                       /* Get sublist data blob */
-                       list_data = hbin_get(key->hive->backend_data, ri.offset[i]);
-                       if (!list_data.data) {
-                               DEBUG(0, ("Error getting RI list."));
-                               return WERR_GENERAL_FAILURE;
-                       }
-                               
-                       ZERO_STRUCT(pull);
-                       pull.data = list_data;
-                       
-                       if (!strncmp((char *)list_data.data, "li", 2)) {
-                               struct li_block li;
-       
-                               if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
-                                       DEBUG(0, ("Error parsing LI list from RI\n"));
-                                       return WERR_GENERAL_FAILURE;
-                               }
-                               SMB_ASSERT(!strncmp(li.header, "li",2));
-                               
-                               for (j = 0; j < li.key_count; j++) {
-                                       W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, 
-                                                               li.nk_offset[j], name, &key_off));
-                                       if (key_off) {
-                                               break;
-                                       }
-                               }
-                       } else if (!strncmp((char *)list_data.data, "lh", 2)) {
-                               struct lh_block lh;
-                               uint32_t hash = 0;
-                               char *hash_name;
-                               
-                               if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
-                                       DEBUG(0, ("Error parsing LH list from RI\n"));
-                                       return WERR_GENERAL_FAILURE;
-                               }
-                               SMB_ASSERT(!strncmp(lh.header, "lh",2));
-
-                               /* Compute hash for the name */
-                               hash_name = strupper_talloc(nk, name);          
-                               for (j = 0; *(hash_name + j) != 0; j++) {
-                                       hash *= 37;
-                                       hash += *(hash_name + j);
-                               }
-                               for (j = 0; j < lh.key_count; j++) {
-                                       if (lh.hr[j].base37 != hash) {
-                                               continue;
-                                       }
-                                       W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, 
-                                                               lh.hr[j].nk_offset, name, &key_off));
-                                       if (key_off) {
-                                               break;
-                                       }
-                               }
-                       }
-                       if (key_off) {
-                               break;
-                       }
-                               
-               }
-               if (!key_off) {
-                       return WERR_DEST_NOT_FOUND;
-               }
-       } else {
-               DEBUG(0, ("Unknown subkey list type.\n"));
-               return WERR_GENERAL_FAILURE;
-       }
-
-       *ret = regf_get_key (ctx, key->hive->backend_data, key_off);
-       return WERR_OK;
-}
-
-static WERROR regf_set_sec_desc (const struct registry_key *key, const struct security_descriptor *sec_desc)
-{
-       /* FIXME */
-       return WERR_NOT_SUPPORTED;
-}
-
-static WERROR regf_get_sec_desc(TALLOC_CTX *ctx, const struct registry_key *key, struct security_descriptor **sd)
-{
-       struct nk_block *nk = key->backend_data;
-       struct sk_block sk;
-       struct regf_data *regf = key->hive->backend_data;
-       DATA_BLOB data;
-
-       if (!hbin_get_tdr(regf, nk->sk_offset, ctx, (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
-               DEBUG(0, ("Unable to find security descriptor\n"));
-               return WERR_GENERAL_FAILURE;
-       }
-               
-       if (strcmp(sk.header, "sk") != 0) {
-               DEBUG(0, ("Expected 'sk', got '%s'\n", sk.header));
-               return WERR_GENERAL_FAILURE;
-       }
-
-       *sd = talloc(ctx, struct security_descriptor);
-       if (!*sd)
-               return WERR_NOMEM;
-
-       data.data = sk.sec_desc;
-       data.length = sk.rec_size;
-       if (NT_STATUS_IS_ERR(ndr_pull_struct_blob(&data, ctx, *sd, (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
-               DEBUG(0, ("Error parsing security descriptor\n"));
-               return WERR_GENERAL_FAILURE;
-       }
-
-       return WERR_OK;
-}
-
-static uint32_t lf_add_entry (struct regf_data *regf, uint32_t list_offset, const char *name, uint32_t key_offset)
-{
-       uint32_t ret;
-       struct lf_block lf;
-
-       ZERO_STRUCT(lf);
-
-       /* Add to subkeys list */
-       if (list_offset == -1) { /* Need to create subkeys list */
-               lf.header = "lf";
-       } else {
-               if (!hbin_get_tdr(regf, list_offset, regf, (tdr_pull_fn_t)tdr_pull_lf_block, &lf)) {
-                       DEBUG(0, ("Can't get subkeys list\n"));
-                       return -1;
-               }
-       }
-
-       lf.hr = talloc_realloc(regf, lf.hr, struct hash_record, lf.key_count+1);
-       lf.hr[lf.key_count].nk_offset = key_offset;
-       lf.hr[lf.key_count].hash = talloc_strndup(regf, name, 4);
-       lf.key_count++;
-
-       ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t)tdr_push_lf_block, list_offset, &lf);
-
-       talloc_free(lf.hr);
-       
-       return ret;
-}
-
-static WERROR regf_del_value (const struct registry_key *parent, const char *name)
-{
-       /* FIXME */
-       return WERR_NOT_SUPPORTED;
-}
-
-
-static WERROR regf_del_key (const struct registry_key *parent, const char *name)
-{
-       struct nk_block *nk = parent->backend_data;
-
-       SMB_ASSERT(nk);
-       
-       if (nk->subkeys_offset == -1) 
-               return WERR_BADFILE;
-
-       /* FIXME */
-
-       return WERR_NOT_SUPPORTED;
-}
-
-static WERROR regf_add_key (TALLOC_CTX *ctx, const struct registry_key *parent, const char *name, uint32_t access_mask, struct security_descriptor *sec_desc, struct registry_key **ret)
-{
-       struct nk_block *parent_nk = parent->backend_data, nk;
-       struct regf_data *regf = parent->hive->backend_data;
-       uint32_t offset;
-
-       nk.header = "nk";
-       nk.type = REG_SUB_KEY;
-       unix_to_nt_time(&nk.last_change, time(NULL));
-       nk.uk1 = 0;
-       nk.parent_offset = 0; /* FIXME */
-       nk.num_subkeys = 0;
-       nk.uk2 = 0;
-       nk.subkeys_offset = -1;
-       nk.unknown_offset = -1;
-       nk.num_values = 0;
-       nk.sk_offset = 0;
-       memset(nk.unk3, 0, 5);
-       nk.clsname_offset = -1;
-       nk.clsname_length = 0;
-       nk.key_name = name;
-       
-       offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_nk_block, &nk);
-
-       parent_nk->subkeys_offset = lf_add_entry(regf, parent_nk->subkeys_offset, name, nk.parent_offset);
-
-       parent_nk->num_subkeys++;
-
-       hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block, nk.parent_offset, parent_nk);
-
-       *ret = regf_get_key(ctx, regf, offset);
-
-       /* FIXME: Set sec desc ! */
-       return WERR_OK;
-}
-
-static WERROR regf_set_value (const struct registry_key *key, const char *name, uint32_t type, const DATA_BLOB data)
-{
-       /* FIXME */
-
-       return WERR_NOT_SUPPORTED;
-}
-
-#if 0 /* Unused */
-
-static WERROR regf_save_hbin(struct registry_hive *hive, struct hbin_block *hbin)
-{
-       struct regf_data *regf = hive->backend_data;
-
-       /* go to right offset */
-       if (lseek(regf->fd, SEEK_SET, regf->header->data_offset + hbin->offset_from_first) == -1) {
-               DEBUG(0, ("Error lseeking in regf file\n"));
-               return WERR_GENERAL_FAILURE;
-       }
-
-       if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd, (tdr_push_fn_t)tdr_push_hbin_block, hbin))) {
-               DEBUG(0, ("Error writing HBIN block\n"));       
-               return WERR_GENERAL_FAILURE;
-       }
-
-       return WERR_OK;
-}
-
-#endif
-
-static WERROR nt_open_hive (struct registry_hive *h, struct registry_key **key)
-{
-       struct regf_data *regf;
-       struct regf_hdr *regf_hdr;
-       struct tdr_pull pull;
-       int i;
-
-       regf = (struct regf_data *)talloc_zero(h, struct regf_data);
-       h->backend_data = regf;
-
-       DEBUG(5, ("Attempting to load registry file\n"));
-
-       /* Get the header */
-       regf->fd = open(h->location, O_RDWR);
-
-       if (regf->fd == -1) {
-               DEBUG(0,("Could not load file: %s, %s\n", h->location,
-                                strerror(errno)));
-               return WERR_GENERAL_FAILURE;
-       }
-
-       ZERO_STRUCT(pull);
-       pull.data.data = (uint8_t*)fd_load(regf->fd, &pull.data.length, regf);
-
-       if (pull.data.data == NULL) {
-               DEBUG(0, ("Error reading data\n"));
-               return WERR_GENERAL_FAILURE;
-       }
-
-       regf_hdr = talloc(regf, struct regf_hdr);
-       if (NT_STATUS_IS_ERR(tdr_pull_regf_hdr(&pull, regf_hdr, regf_hdr))) {
-               return WERR_GENERAL_FAILURE;
-       }
-
-       regf->header = regf_hdr;
-
-       if (strcmp(regf_hdr->REGF_ID, "regf") != 0) {
-               DEBUG(0, ("Unrecognized NT registry header id: %s, %s\n",
-                                 regf_hdr->REGF_ID, h->location));
-       }
-
-       DEBUG(1, ("Registry '%s' read. Version %d.%d.%d.%d\n", 
-                         regf_hdr->description, regf_hdr->version.major,
-                         regf_hdr->version.minor, regf_hdr->version.release,
-                         regf_hdr->version.build));
-
-       /*
-        * Validate the header ...
-        */
-       if (regf_hdr_checksum(pull.data.data) != regf_hdr->chksum) {
-               DEBUG(0, ("Registry file checksum error: %s: %d,%d\n",
-                                 h->location, regf_hdr->chksum, regf_hdr_checksum(pull.data.data)));
-               return WERR_GENERAL_FAILURE;
-       }
-
-       pull.offset = 0x1000;
-
-       i = 0;
-       /* Read in all hbin blocks */
-       regf->hbins = talloc_array(regf, struct hbin_block *, 1);
-       regf->hbins[0] = NULL;
-
-       while (pull.offset < pull.data.length && pull.offset < regf->header->last_block) {
-               struct hbin_block *hbin = talloc(regf->hbins, struct hbin_block);
-
-               if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(&pull, hbin, hbin))) {
-                       DEBUG(0, ("[%d] Error parsing HBIN block\n", i));
-                       return WERR_FOOBAR;
-               }
-
-               if (strcmp(hbin->HBIN_ID, "hbin") != 0) {
-                       DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n", i, hbin->HBIN_ID));
-                       return WERR_FOOBAR;
-               }
-
-               regf->hbins[i] = hbin;
-               i++;
-               regf->hbins = talloc_realloc(regf, regf->hbins, struct hbin_block *, i+2);
-               regf->hbins[i] = NULL;
-       } 
-
-       DEBUG(1, ("%d HBIN blocks read\n", i));
-
-       *key = regf_get_key(h, regf, 0x20);
-
-       return WERR_OK;
-}
-
-static struct hive_operations reg_backend_nt4 = {
-       .name = "nt4",
-       .open_hive = nt_open_hive,
-       .num_subkeys = regf_num_subkeys,
-       .num_values = regf_num_values,
-       .get_subkey_by_index = regf_get_subkey_by_index,
-       .get_subkey_by_name = regf_get_subkey_by_name,
-       .get_value_by_index = regf_get_value,
-       .key_get_sec_desc = regf_get_sec_desc,
-       .key_set_sec_desc = regf_set_sec_desc,
-       .add_key = regf_add_key,
-       .set_value = regf_set_value,
-       .del_key = regf_del_key,
-       .del_value = regf_del_value,
-};
-
-NTSTATUS registry_nt4_init(void)
-{
-       return registry_register(&reg_backend_nt4);
-}
diff --git a/source/lib/registry/reg_backend_w95.c b/source/lib/registry/reg_backend_w95.c
deleted file mode 100644 (file)
index a0b6e01..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
-   Samba Unix/Linux SMB client utility libeditreg.c 
-   Copyright (C) 2004 Jelmer Vernooij, jelmer@samba.org
-
-   Backend for Windows '95 registry files. Explanation of file format 
-   comes from http://www.cs.mun.ca/~michael/regutils/.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-#include "includes.h"
-#include "registry.h"
-#include "system/filesys.h"
-#include "system/shmem.h"
-
-/**
- * The registry starts with a header that contains pointers to 
- * the rgdb.
- *
- * After the main header follows the RGKN header (key index table).
- * The RGKN keys are listed after each other. They are put into 
- * blocks, the first having a length of 0x2000 bytes, the others 
- * being 0x1000 bytes long.
- *
- * After the RGKN header follow one or more RGDB blocks. These blocks 
- * contain keys. A key is followed by its name and its values.
- *
- * Values are followed by their name and then their data.
- *
- * Basically the idea is that the RGKN contains the associations between 
- * the keys and the RGDB contains the actual data.
- */
-
-typedef uint32_t DWORD;
-typedef unsigned short WORD;
-
-typedef struct creg_block {
-       DWORD CREG_ID;          /* CREG */
-       DWORD uk1;
-       DWORD rgdb_offset;
-       DWORD chksum;
-       WORD  num_rgdb;
-       WORD  flags;
-       DWORD uk2;
-       DWORD uk3;
-       DWORD uk4;
-} CREG_HDR;
-
-typedef struct rgkn_block {
-       DWORD RGKN_ID;          /* RGKN */
-       DWORD size;
-       DWORD root_offset;
-       DWORD free_offset;
-       DWORD flags;
-       DWORD chksum;
-       DWORD uk1;
-       DWORD uk2;
-} RGKN_HDR;
-
-typedef struct reg_id {
-       WORD id;
-       WORD rgdb;
-} REG_ID;
-
-typedef struct rgkn_key {
-       DWORD type;                     /* 0x00000000 = normal key, 0x80000000 = free block */
-       DWORD hash;                     /* Contains either hash or size of free blocks that follows */
-       DWORD next_free;
-       DWORD parent_offset;
-       DWORD first_child_offset;
-       DWORD next_offset;
-       REG_ID id;
-} RGKN_KEY;
-
-
-typedef struct rgdb_block {
-       DWORD RGDB_ID;          /* RGDB */
-       DWORD size;
-       DWORD unused_size;
-       WORD flags;
-       WORD section;
-       DWORD free_offset;      /* -1 if there is no free space */
-       WORD max_id;
-       WORD first_free_id;
-       DWORD uk1;
-       DWORD chksum;
-} RGDB_HDR;
-
-typedef struct rgdb_key {
-       DWORD size;
-       REG_ID id;
-       DWORD used_size;
-       WORD  name_len;
-       WORD  num_values;
-       DWORD uk1;
-} RGDB_KEY;
-
-typedef struct rgdb_value {
-       DWORD type;
-       DWORD uk1;
-       WORD name_len;
-       WORD data_len;
-} RGDB_VALUE;
-
-typedef struct creg_struct_s {
-       int fd;
-       BOOL modified;
-       char *base;
-       struct stat sbuf;
-       CREG_HDR *creg_hdr;
-       RGKN_HDR *rgkn_hdr;
-       RGDB_KEY ***rgdb_keys;
-} CREG;
-
-#if 0 /* unused */
-#define RGKN_START_SIZE 0x2000
-#define RGKN_INC_SIZE   0x1000
-#endif
-
-#define LOCN_RGKN(creg, o) ((RGKN_KEY *)((creg)->base + sizeof(CREG_HDR) + o))
-#define LOCN_RGDB_BLOCK(creg, o) (((creg)->base + (creg)->creg_hdr->rgdb_offset + o))
-#define LOCN_RGDB_KEY(creg, rgdb, id) ((RGDB_KEY *)((creg)->rgdb_keys[(rgdb)][(id)]))
-
-static DWORD str_to_dword(const char *a) {
-    int i;
-    unsigned long ret = 0;
-    for(i = strlen(a)-1; i >= 0; i--) {
-        ret = ret * 0x100 + a[i];
-    }
-    return ret;
-}
-
-#if 0 /* unused */
-
-static DWORD calc_hash(const char *str) {
-       DWORD ret = 0;
-       int i;
-       for(i = 0; str[i] && str[i] != '\\'; i++) {
-               ret+=toupper(str[i]);
-       }
-       return ret;
-}
-
-static void parse_rgkn_block(CREG *creg, off_t start_off, off_t end_off) 
-{
-       off_t i;
-       for(i = start_off; end_off - i > sizeof(RGKN_KEY); i+= sizeof(RGKN_KEY)) {
-               RGKN_KEY *key = (RGKN_KEY *)LOCN_RGKN(creg, i);
-               if(key->type == 0) {
-                       DEBUG(4,("Regular, id: %d, %d, parent: %x, firstchild: %x, next: %x hash: %lX\n", key->id.id, key->id.rgdb, key->parent_offset, key->first_child_offset, key->next_offset, (long)key->hash));
-               } else if(key->type == 0x80000000) {
-                       DEBUG(3,("free\n"));
-                       i += key->hash;
-               } else {
-                       DEBUG(0,("Invalid key type in RGKN: %0X\n", key->type));
-               }
-       }
-}
-
-#endif
-
-static void parse_rgdb_block(CREG *creg, RGDB_HDR *rgdb_hdr)
-{
-       DWORD used_size = rgdb_hdr->size - rgdb_hdr->unused_size;
-       DWORD offset = 0;
-
-       while(offset < used_size) {
-               RGDB_KEY *key = (RGDB_KEY *)(((char *)rgdb_hdr) + sizeof(RGDB_HDR) + offset);
-               
-               if(!(key->id.id == 0xFFFF && key->id.rgdb == 0xFFFF))creg->rgdb_keys[key->id.rgdb][key->id.id] = key;
-               offset += key->size;
-       }
-}
-
-static WERROR w95_open_reg (struct registry_hive *h, struct registry_key **root)
-{
-       CREG *creg;
-       DWORD creg_id, rgkn_id;
-       DWORD i;
-       DWORD offset;
-
-       creg = talloc(h, CREG);
-       memset(creg, 0, sizeof(CREG));
-       h->backend_data = creg;
-
-       if((creg->fd = open(h->location, O_RDONLY, 0000)) < 0) {
-               return WERR_FOOBAR;
-       }
-
-    if (fstat(creg->fd, &creg->sbuf) < 0) {
-               return WERR_FOOBAR;
-    }
-
-    creg->base = mmap(0, creg->sbuf.st_size, PROT_READ, MAP_SHARED, creg->fd, 0);
-                                                                                                                                              
-    if (creg->base == (void *)-1) {
-               DEBUG(0,("Could not mmap file: %s, %s\n", h->location, strerror(errno)));
-        return WERR_FOOBAR;
-    }
-
-       creg->creg_hdr = (CREG_HDR *)creg->base;
-
-       if ((creg_id = IVAL(&creg->creg_hdr->CREG_ID,0)) != str_to_dword("CREG")) {
-               DEBUG(0, ("Unrecognized Windows 95 registry header id: 0x%0X, %s\n", 
-                                 creg_id, h->location));
-               return WERR_FOOBAR;
-       }
-
-       creg->rgkn_hdr = (RGKN_HDR *)LOCN_RGKN(creg, 0);
-
-       if ((rgkn_id = IVAL(&creg->rgkn_hdr->RGKN_ID,0)) != str_to_dword("RGKN")) {
-               DEBUG(0, ("Unrecognized Windows 95 registry key index id: 0x%0X, %s\n", 
-                                 rgkn_id, h->location));
-               return WERR_FOOBAR;
-       }
-
-#if 0  
-       /* If'ed out because we only need to parse this stuff when allocating new 
-        * entries (which we don't do at the moment */
-       /* First parse the 0x2000 long block */
-       parse_rgkn_block(creg, sizeof(RGKN_HDR), 0x2000);
-
-       /* Then parse the other 0x1000 length blocks */
-       for(offset = 0x2000; offset < creg->rgkn_hdr->size; offset+=0x1000) {
-               parse_rgkn_block(creg, offset, offset+0x1000);
-       }
-#endif
-
-       creg->rgdb_keys = talloc_array(h, RGDB_KEY **, creg->creg_hdr->num_rgdb);
-
-       offset = 0;
-       DEBUG(3, ("Reading %d rgdb entries\n", creg->creg_hdr->num_rgdb));
-       for(i = 0; i < creg->creg_hdr->num_rgdb; i++) {
-               RGDB_HDR *rgdb_hdr = (RGDB_HDR *)LOCN_RGDB_BLOCK(creg, offset);
-               
-               if(strncmp((char *)&(rgdb_hdr->RGDB_ID), "RGDB", 4)) {
-                       DEBUG(0, ("unrecognized rgdb entry: %4d, %s\n", 
-                                         rgdb_hdr->RGDB_ID, h->location));
-                       return WERR_FOOBAR;
-               } else {
-                       DEBUG(3, ("Valid rgdb entry, first free id: %d, max id: %d\n", rgdb_hdr->first_free_id, rgdb_hdr->max_id));
-               }
-
-
-               creg->rgdb_keys[i] = talloc_array(h, RGDB_KEY *, rgdb_hdr->max_id+1);
-               memset(creg->rgdb_keys[i], 0, sizeof(RGDB_KEY *) * (rgdb_hdr->max_id+1));
-
-               parse_rgdb_block(creg, rgdb_hdr);
-
-               offset+=rgdb_hdr->size;
-       }
-       
-       /* First element in rgkn should be root key */
-       *root = talloc(h, struct registry_key);
-       (*root)->name = NULL;
-       (*root)->backend_data = LOCN_RGKN(creg, sizeof(RGKN_HDR));
-       
-       return WERR_OK;
-}
-
-static WERROR w95_get_subkey_by_index (TALLOC_CTX *mem_ctx, const struct registry_key *parent, int n, struct registry_key **key)
-{
-       CREG *creg = parent->hive->backend_data;
-       RGKN_KEY *rgkn_key = parent->backend_data;
-       RGKN_KEY *child;
-       DWORD child_offset;
-       DWORD cur = 0;
-       
-       /* Get id of first child */
-       child_offset = rgkn_key->first_child_offset;
-
-       while(child_offset != 0xFFFFFFFF) {
-               child = LOCN_RGKN(creg, child_offset);
-
-               /* n == cur ? return! */
-               if(cur == n) {
-                       RGDB_KEY *rgdb_key;
-                       rgdb_key = LOCN_RGDB_KEY(creg, child->id.rgdb, child->id.id);
-                       if(!rgdb_key) {
-                               DEBUG(0, ("Can't find %d,%d in RGDB table!\n", child->id.rgdb, child->id.id));
-                               return WERR_FOOBAR;
-                       }
-                       *key = talloc(mem_ctx, struct registry_key);
-                       (*key)->backend_data = child;
-                       (*key)->name = talloc_strndup(mem_ctx, (char *)rgdb_key + sizeof(RGDB_KEY), rgdb_key->name_len);
-                       return WERR_OK;
-               }
-
-               cur++;
-               
-               child_offset = child->next_offset;
-       }
-
-       return WERR_NO_MORE_ITEMS;
-}
-
-static WERROR w95_num_values(const struct registry_key *k, uint32_t *count)
-{
-       RGKN_KEY *rgkn_key = k->backend_data;
-       RGDB_KEY *rgdb_key = LOCN_RGDB_KEY((CREG *)k->hive->backend_data, rgkn_key->id.rgdb, rgkn_key->id.id);
-
-       if(!rgdb_key) return WERR_FOOBAR;
-       
-       *count = rgdb_key->num_values;
-       
-       return WERR_OK;
-}
-
-static WERROR w95_get_value_by_id(TALLOC_CTX *mem_ctx, const struct registry_key *k, int idx, struct registry_value **value)
-{
-       RGKN_KEY *rgkn_key = k->backend_data;
-       DWORD i;
-       DWORD offset = 0;
-       RGDB_KEY *rgdb_key = LOCN_RGDB_KEY((CREG *)k->hive->backend_data, rgkn_key->id.rgdb, rgkn_key->id.id);
-       RGDB_VALUE *curval = NULL;
-
-       if(!rgdb_key) return WERR_FOOBAR;
-       
-       if(idx >= rgdb_key->num_values) return WERR_NO_MORE_ITEMS;
-       
-       for(i = 0; i < idx; i++) {
-               curval = (RGDB_VALUE *)(((char *)rgdb_key) + sizeof(RGDB_KEY) + rgdb_key->name_len + offset);
-               offset+=sizeof(RGDB_VALUE) + curval->name_len + curval->data_len;
-       }
-
-       *value = talloc(mem_ctx, struct registry_value);
-       (*value)->name = talloc_strndup(mem_ctx, (char *)curval+sizeof(RGDB_VALUE), curval->name_len);
-               
-       (*value)->data = data_blob_talloc(mem_ctx, curval+sizeof(RGDB_VALUE)+curval->name_len, curval->data_len);
-       (*value)->data_type = curval->type;
-       
-       return WERR_OK;
-}
-
-static struct hive_operations reg_backend_w95 = {
-       .name = "w95",
-       .open_hive = w95_open_reg,
-       .get_value_by_index = w95_get_value_by_id,
-       .num_values = w95_num_values,
-       .get_subkey_by_index = w95_get_subkey_by_index,
-};
-
-NTSTATUS registry_w95_init(void)
-{
-       return registry_register(&reg_backend_w95);
-}
diff --git a/source/lib/registry/regf.c b/source/lib/registry/regf.c
new file mode 100644 (file)
index 0000000..7fa7103
--- /dev/null
@@ -0,0 +1,1923 @@
+/*
+   Samba CIFS implementation
+   Registry backend for REGF files
+   Copyright (C) 2005-2007 Jelmer Vernooij, jelmer@samba.org
+   Copyright (C) 2006 Wilco Baan Hofman, wilco@baanhofman.nl
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+#include "includes.h"
+#include "lib/registry/hive.h"
+#include "system/filesys.h"
+#include "system/time.h"
+#include "lib/registry/tdr_regf.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/winreg.h"
+
+static struct hive_operations reg_backend_regf;
+
+/**
+ * There are several places on the web where the REGF format is explained; 
+ *
+ * TODO: Links
+ */
+
+/* TODO:
+ *  - Return error codes that make more sense
+ *  - Locking
+ *  - do more things in-memory
+ */
+
+/*
+ * Read HBIN blocks into memory
+ */
+
+struct regf_data {
+       int fd;
+       struct hbin_block **hbins;
+       struct regf_hdr *header;
+};
+
+static WERROR regf_save_hbin(struct regf_data *data);
+
+struct regf_key_data {
+       struct hive_key key;
+       struct regf_data *hive; 
+       uint32_t offset;
+       struct nk_block *nk;
+};
+
+static struct hbin_block *hbin_by_offset(const struct regf_data *data, 
+                                                                                uint32_t offset, uint32_t *rel_offset)
+{
+       int i;
+
+       for (i = 0; data->hbins[i]; i++) {
+               if (offset >= data->hbins[i]->offset_from_first && 
+                       offset < data->hbins[i]->offset_from_first+
+                                        data->hbins[i]->offset_to_next) {
+                       if (rel_offset != NULL)
+                               *rel_offset = offset - data->hbins[i]->offset_from_first - 0x20;
+                       return data->hbins[i];
+               }
+       }
+
+       return NULL;
+}
+
+/**
+ * Validate a regf header
+ * For now, do nothing, but we should check the checksum
+ */
+static uint32_t regf_hdr_checksum(const uint8_t *buffer)
+{
+       uint32_t checksum = 0, x;
+       int i;
+       
+       for (i = 0; i < 0x01FB; i+= 4) {
+               x = IVAL(buffer, i);
+               checksum ^= x;
+       }
+
+       return checksum;
+}
+
+/**
+ * Obtain the contents of a HBIN block
+ */
+static DATA_BLOB hbin_get(const struct regf_data *data, uint32_t offset)
+{
+       DATA_BLOB ret;
+       struct hbin_block *hbin;
+       uint32_t rel_offset;
+
+       ret.data = NULL;
+       ret.length = 0;
+
+       hbin = hbin_by_offset(data, offset, &rel_offset);
+
+       if (hbin == NULL) {
+               DEBUG(1, ("Can't find HBIN containing 0x%04x\n", offset));
+               return ret;
+       }
+
+       ret.length = IVAL(hbin->data, rel_offset);
+       if (!(ret.length & 0x80000000)) {
+               DEBUG(0, ("Trying to use dirty block at 0x%04x\n", offset));
+               return ret;
+       }
+
+       /* remove high bit */
+       ret.length = (ret.length ^ 0xffffffff) + 1;
+
+       ret.length -= 4; /* 4 bytes for the length... */
+       ret.data = hbin->data + 
+               (offset - hbin->offset_from_first - 0x20) + 4;
+       
+       return ret;
+}
+
+static bool hbin_get_tdr (struct regf_data *regf, uint32_t offset, 
+                                                 TALLOC_CTX *ctx, tdr_pull_fn_t pull_fn, void *p)
+{
+       struct tdr_pull pull;
+
+       ZERO_STRUCT(pull);
+
+       pull.data = hbin_get(regf, offset);
+       if (!pull.data.data) {
+               DEBUG(1, ("Unable to get data at 0x%04x\n", offset));
+               return false;
+       }
+       
+       if (NT_STATUS_IS_ERR(pull_fn(&pull, ctx, p))) {
+               DEBUG(1, ("Error parsing record at 0x%04x using tdr\n", offset));
+               return false;
+       }
+
+       return true;
+}
+
+/* Allocate some new data */
+static DATA_BLOB hbin_alloc(struct regf_data *data, uint32_t size, 
+                                                       uint32_t *offset)
+{
+       DATA_BLOB ret;
+       uint32_t rel_offset = -1; /* Relative offset ! */
+       struct hbin_block *hbin = NULL;
+       int i;
+
+       *offset = 0;
+
+       if (size == 0)
+               return data_blob(NULL, 0);
+
+       size += 4; /* Need to include int32 for the length */
+
+       /* Allocate as a multiple of 8 */
+       size = (size + 7) & ~7;
+
+       ret.data = NULL;
+       ret.length = 0;
+
+       for (i = 0; (hbin = data->hbins[i]); i++) {
+               int j;
+               int32_t my_size;
+               for (j = 0; j < hbin->offset_to_next-0x20; j+= my_size) {
+                       my_size = IVALS(hbin->data, j);
+
+                       if (my_size == 0x0) {
+                               DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
+                               return ret;
+                       }
+
+                       if (my_size % 8 != 0) {
+                               DEBUG(0, ("Encountered non-aligned block!\n"));
+                       }
+
+                       if (my_size < 0) { /* Used... */
+                               my_size = -my_size;
+                       } else if (my_size == size) { /* exact match */
+                               rel_offset = j;
+                               DEBUG(4, ("Found free block of exact size %d in middle of HBIN\n", size));
+                               break;
+                       } else if (my_size > size) { /* data will remain */
+                               rel_offset = j;
+                               /* Split this block and mark the next block as free */
+                               SIVAL(hbin->data, rel_offset+size, my_size-size); 
+                               DEBUG(4, ("Found free block of size %d (needing %d) in middle of HBIN\n", my_size, size));
+                               break;
+                       }
+               }
+
+               if (rel_offset != -1)
+                       break;
+       }
+       
+       /* No space available in previous hbins, 
+        * allocate new one */
+       if (data->hbins[i] == NULL) { 
+               DEBUG(4, ("No space available in other HBINs for block of size %d, allocating new HBIN\n", size));
+               data->hbins = talloc_realloc(data, data->hbins, struct hbin_block *, i+2);
+               hbin = talloc(data->hbins, struct hbin_block);
+               SMB_ASSERT(hbin != NULL);
+
+               data->hbins[i] = hbin;
+               data->hbins[i+1] = NULL;
+
+               hbin->HBIN_ID = talloc_strdup(hbin, "hbin");
+               hbin->offset_from_first = (i == 0?0:data->hbins[i-1]->offset_from_first+data->hbins[i-1]->offset_to_next);
+               hbin->offset_to_next = 0x1000;
+               hbin->unknown[0] = 0;
+               hbin->unknown[0] = 0;
+               unix_to_nt_time(&hbin->last_change, time(NULL));
+               hbin->block_size = hbin->offset_to_next;
+               hbin->data = talloc_zero_array(hbin, uint8_t, hbin->block_size - 0x20);
+
+               rel_offset = 0x0;
+               SIVAL(hbin->data, size, hbin->block_size - size - 0x20);
+       }
+
+       /* Set size and mark as used */
+       SIVAL(hbin->data, rel_offset, -size);
+
+       ret.data = hbin->data + rel_offset + 0x4; /* Skip past length */
+       ret.length = size - 0x4;
+       if (offset) {
+               uint32_t new_rel_offset;
+               *offset = hbin->offset_from_first + rel_offset + 0x20;
+               SMB_ASSERT(hbin_by_offset(data, *offset, &new_rel_offset) == hbin);
+               SMB_ASSERT(new_rel_offset == rel_offset);
+       }
+
+       return ret;
+}
+
+/* Store a data blob. Return the offset at which it was stored */
+static uint32_t hbin_store (struct regf_data *data, DATA_BLOB blob)
+{
+       uint32_t ret;
+       DATA_BLOB dest = hbin_alloc(data, blob.length, &ret);
+
+       memcpy(dest.data, blob.data, blob.length);
+
+       return ret;
+}
+
+static uint32_t hbin_store_tdr (struct regf_data *data, tdr_push_fn_t push_fn, void *p)
+{
+       struct tdr_push *push = talloc_zero(data, struct tdr_push);
+       uint32_t ret;
+       
+       if (NT_STATUS_IS_ERR(push_fn(push, p))) {
+               DEBUG(0, ("Error during push\n"));
+               return -1;
+       }
+
+       ret = hbin_store(data, push->data);
+
+       talloc_free(push);
+
+       return ret;
+}
+
+
+/* Free existing data */
+static void hbin_free (struct regf_data *data, uint32_t offset)
+{
+       int32_t size;
+       uint32_t rel_offset;
+       int32_t next_size; 
+       struct hbin_block *hbin;
+
+       SMB_ASSERT (offset > 0);
+       
+       hbin = hbin_by_offset(data, offset, &rel_offset);
+
+       if (hbin == NULL)
+               return;
+       
+       /* Get original size */
+       size = IVALS(hbin->data, rel_offset);
+
+       if (size > 0) {
+               DEBUG(1, ("Trying to free already freed block at 0x%04x\n", offset));
+               return;
+       }
+       /* Mark as unused */
+       size = -size;
+       
+       /* If the next block is free, merge into big free block */
+       if (rel_offset + size < hbin->offset_to_next) {
+               next_size = IVALS(hbin->data, rel_offset+size);
+               if (next_size > 0) {
+                       size += next_size;
+               }
+       }
+
+       /* Write block size */
+       SIVALS(hbin->data, rel_offset, size);
+}
+
+/**
+ * Store a data blob data was already stored, but has changed in size
+ * Will try to save it at the current location if possible, otherwise 
+ * does a free + store */
+static uint32_t hbin_store_resize(struct regf_data *data, 
+                                                                 uint32_t orig_offset, DATA_BLOB blob)
+{
+       uint32_t rel_offset;
+       struct hbin_block *hbin = hbin_by_offset(data, orig_offset, &rel_offset);
+       int32_t my_size;
+       int32_t orig_size;
+       int32_t needed_size;
+       int32_t possible_size;
+       int i;
+
+       SMB_ASSERT(orig_offset > 0);
+
+       if (!hbin)
+               return hbin_store(data, blob);
+
+       /* Get original size */
+       orig_size = -IVALS(hbin->data, rel_offset);
+
+       needed_size = blob.length + 4; /* Add int32 containing length */
+       needed_size = (needed_size + 7) & ~7; /* Align */
+
+       /* Fits into current allocated block */
+       if (orig_size >= needed_size) {
+               memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
+               /* If the difference in size is greater than 0x4, split the block
+                * and free/merge it */
+               if (orig_size - needed_size > 0x4) {
+                       SIVALS(hbin->data, rel_offset, -needed_size);
+                       SIVALS(hbin->data, rel_offset + needed_size, needed_size-orig_size);
+                       hbin_free(data, orig_offset + needed_size);
+               }
+               return orig_offset;
+       }
+
+       possible_size = orig_size;
+
+       /* Check if it can be combined with the next few free records */
+       for (i = rel_offset; i < hbin->offset_to_next - 0x20; i += my_size) {
+               if (IVALS(hbin->data, i) < 0) /* Used */
+                       break;
+
+               my_size = IVALS(hbin->data, i);
+               
+               if (my_size == 0x0) {
+                       DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
+                       break;
+               } else {
+                       possible_size += my_size;
+               }
+
+               if (possible_size >= blob.length) {
+                       SIVAL(hbin->data, rel_offset, -possible_size);
+                       memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
+                       return orig_offset;
+               }
+       }
+
+       hbin_free(data, orig_offset);
+       return hbin_store(data, blob);
+}
+
+static uint32_t hbin_store_tdr_resize (struct regf_data *regf, tdr_push_fn_t push_fn, 
+                                                                          uint32_t orig_offset, void *p)
+{
+       struct tdr_push *push = talloc_zero(regf, struct tdr_push);
+       uint32_t ret;
+       
+       if (NT_STATUS_IS_ERR(push_fn(push, p))) {
+               DEBUG(0, ("Error during push\n"));
+               return -1;
+       }
+
+       ret = hbin_store_resize(regf, orig_offset, push->data);
+
+       talloc_free(push);
+
+       return ret;
+}
+
+static uint32_t regf_create_lh_hash(const char *name) 
+{
+       char *hash_name;
+       uint32_t ret = 0;
+       uint16_t i;
+
+       hash_name = strupper_talloc(NULL, name);                
+       for (i = 0; *(hash_name + i) != 0; i++) {
+               ret *= 37;
+               ret += *(hash_name + i);
+       }
+       talloc_free(hash_name);
+       return ret;
+}
+
+static WERROR regf_get_info (TALLOC_CTX *mem_ctx,
+                                                        const struct hive_key *key, 
+                                                        const char **classname,
+                                                        uint32_t *num_subkeys,
+                                                        uint32_t *num_values,
+                                                        NTTIME *last_mod_time)
+{
+       const struct regf_key_data *private_data = 
+               (const struct regf_key_data *)key;
+
+       if (num_subkeys != NULL)
+               *num_subkeys = private_data->nk->num_subkeys;
+
+       if (num_values != NULL)
+               *num_values = private_data->nk->num_values;
+
+       if (classname != NULL) {
+               if (private_data->nk->clsname_offset != -1) {
+                       DATA_BLOB data = hbin_get(private_data->hive, 
+                                                                         private_data->nk->clsname_offset);
+                       *classname = talloc_strndup(mem_ctx, 
+                                                        (char*)data.data, private_data->nk->clsname_length);
+               } else 
+                       *classname = NULL;
+       }
+
+       /* TODO: Last mod time */
+       
+       return WERR_OK;
+}
+
+static struct regf_key_data *regf_get_key(TALLOC_CTX *ctx, 
+                                                                                 struct regf_data *regf, 
+                                                                                 uint32_t offset)
+{
+       struct nk_block *nk;
+       struct regf_key_data *ret;
+
+       ret = talloc_zero(ctx, struct regf_key_data);
+       ret->key.ops = &reg_backend_regf;
+       ret->hive = talloc_reference(ret, regf);
+       ret->offset = offset;
+       nk = talloc(ret, struct nk_block);
+       if (nk == NULL)
+               return NULL;
+
+       ret->nk = nk;
+
+       if (!hbin_get_tdr(regf, offset, nk, (tdr_pull_fn_t)tdr_pull_nk_block, nk)) {
+               DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset));
+               return NULL;
+       }
+
+       if (strcmp(nk->header, "nk") != 0) {
+               DEBUG(0, ("Expected nk record, got %s\n", nk->header));
+               talloc_free(ret);
+               return NULL;
+       }
+
+       return ret;
+}
+
+
+static WERROR regf_get_value(TALLOC_CTX *ctx, const struct hive_key *key, 
+                                                         int idx, const char **name, 
+                                                         uint32_t *data_type, DATA_BLOB *data)
+{
+       const struct regf_key_data *private_data = 
+                       (const struct regf_key_data *)key;
+       struct vk_block *vk;
+       struct regf_data *regf = private_data->hive;
+       uint32_t vk_offset;
+       DATA_BLOB tmp;
+
+       if (idx >= private_data->nk->num_values)
+               return WERR_NO_MORE_ITEMS;
+
+       tmp = hbin_get(regf, private_data->nk->values_offset);
+       if (!tmp.data) {
+               DEBUG(0, ("Unable to find value list\n"));
+               return WERR_GENERAL_FAILURE;
+       }
+
+       if (tmp.length < private_data->nk->num_values * 4) {
+               DEBUG(1, ("Value counts mismatch\n"));
+       }
+
+       vk_offset = IVAL(tmp.data, idx * 4);
+
+       vk = talloc(NULL, struct vk_block);
+       W_ERROR_HAVE_NO_MEMORY(vk);
+       
+       if (!hbin_get_tdr(regf, vk_offset, vk, (tdr_pull_fn_t)tdr_pull_vk_block, vk)) {
+               DEBUG(0, ("Unable to get VK block at %d\n", vk_offset));
+               talloc_free(vk);
+               return WERR_GENERAL_FAILURE;
+       }
+
+       /* FIXME: name character set ?*/
+       if (name != NULL)
+               *name = talloc_strndup(ctx, vk->data_name, vk->name_length);
+
+       if (data_type != NULL)
+               *data_type = vk->data_type;
+
+       if (vk->data_length & 0x80000000) { 
+               vk->data_length &=~0x80000000;
+               data->data = (uint8_t *)&vk->data_offset;
+               data->length = vk->data_length;
+       } else {
+               *data = hbin_get(regf, vk->data_offset);
+       }
+
+       if (data->length < vk->data_length) {
+               DEBUG(1, ("Read data less than indicated data length!\n"));
+       }
+
+       talloc_free(vk);
+       
+       return WERR_OK;
+}
+
+static WERROR regf_get_value_by_name (TALLOC_CTX *mem_ctx, 
+                                                                struct hive_key *key, const char *name, 
+                                                                uint32_t *type, DATA_BLOB *data)
+{
+       int i;
+       const char *vname;
+       WERROR error;
+
+       /* FIXME: Do binary search? Is this list sorted at all? */
+
+       for (i = 0; W_ERROR_IS_OK(error = regf_get_value(mem_ctx, key, i, 
+                                                                                        &vname, type, data)); i++) {
+               if (!strcmp(vname, name))
+                       return WERR_OK;
+    }
+
+       if (W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS))
+               return WERR_NOT_FOUND;
+
+       return error;
+}
+       
+
+static WERROR regf_get_subkey_by_index (TALLOC_CTX *ctx, 
+                                                                               const struct hive_key *key, 
+                                                                               uint32_t idx, const char **name,
+                                                                               const char **classname,
+                                                                               NTTIME *last_mod_time)
+{
+       DATA_BLOB data;
+       struct regf_key_data *ret;
+       const struct regf_key_data *private_data = (const struct regf_key_data *)key;
+       struct nk_block *nk = private_data->nk;
+       uint32_t key_off=0;
+
+       if (idx >= nk->num_subkeys)
+               return WERR_NO_MORE_ITEMS;
+
+       data = hbin_get(private_data->hive, nk->subkeys_offset);
+       if (!data.data) {
+               DEBUG(0, ("Unable to find subkey list\n"));
+               return WERR_GENERAL_FAILURE;
+       }
+
+       if (!strncmp((char *)data.data, "li", 2)) {
+               struct li_block li;
+               struct tdr_pull pull;
+
+               DEBUG(10, ("Subkeys in LI list\n"));
+               ZERO_STRUCT(pull);
+               pull.data = data;
+
+               if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
+                       DEBUG(0, ("Error parsing LI list\n"));
+                       return WERR_GENERAL_FAILURE;
+               }
+               SMB_ASSERT(!strncmp(li.header, "li", 2));
+
+               if (li.key_count != nk->num_subkeys) {
+                       DEBUG(0, ("Subkey counts don't match\n"));
+                       return WERR_GENERAL_FAILURE;
+               }
+               key_off = li.nk_offset[idx];
+       
+       } else if (!strncmp((char *)data.data, "lf", 2)) {
+               struct lf_block lf;
+               struct tdr_pull pull;
+
+               DEBUG(10, ("Subkeys in LF list\n"));
+               ZERO_STRUCT(pull);
+               pull.data = data;
+
+               if (NT_STATUS_IS_ERR(tdr_pull_lf_block(&pull, nk, &lf))) {
+                       DEBUG(0, ("Error parsing LF list\n"));
+                       return WERR_GENERAL_FAILURE;
+               }
+               SMB_ASSERT(!strncmp(lf.header, "lf", 2));
+
+               if (lf.key_count != nk->num_subkeys) {
+                       DEBUG(0, ("Subkey counts don't match\n"));
+                       return WERR_GENERAL_FAILURE;
+               }
+
+               key_off = lf.hr[idx].nk_offset;
+       } else if (!strncmp((char *)data.data, "lh", 2)) {
+               struct lh_block lh;
+               struct tdr_pull pull;
+               
+               DEBUG(10, ("Subkeys in LH list\n"));
+               ZERO_STRUCT(pull);
+               pull.data = data;
+               
+               if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
+                       DEBUG(0, ("Error parsing LH list\n"));
+                       return WERR_GENERAL_FAILURE;
+               }
+               SMB_ASSERT(!strncmp(lh.header, "lh", 2));
+               
+               if (lh.key_count != nk->num_subkeys) {
+                       DEBUG(0, ("Subkey counts don't match\n"));
+                       return WERR_GENERAL_FAILURE;
+               }
+               key_off = lh.hr[idx].nk_offset;
+       } else if (!strncmp((char *)data.data, "ri", 2)) {
+               struct ri_block ri;
+               struct tdr_pull pull;
+               uint16_t i;
+               uint16_t sublist_count = 0;
+               
+               DEBUG(10, ("Subkeys in RI list\n"));
+               ZERO_STRUCT(pull);
+               pull.data = data;
+               
+               if (NT_STATUS_IS_ERR(tdr_pull_ri_block(&pull, nk, &ri))) {
+                       DEBUG(0, ("Error parsing RI list\n"));
+                       return WERR_GENERAL_FAILURE;
+               }
+               SMB_ASSERT(!strncmp(ri.header, "ri", 2));
+               
+               for (i = 0; i < ri.key_count; i++) {
+                       DATA_BLOB list_data;
+                       
+                       /* Get sublist data blob */
+                       list_data = hbin_get(private_data->hive, ri.offset[i]);
+                       if (!list_data.data) {
+                               DEBUG(0, ("Error getting RI list."));
+                               return WERR_GENERAL_FAILURE;
+                       }
+                       
+                       ZERO_STRUCT(pull);
+                       pull.data = list_data;
+                       
+                       if (!strncmp((char *)list_data.data, "li", 2)) {
+                               struct li_block li;
+
+                               DEBUG(10, ("Subkeys in RI->LI list\n"));
+
+                               if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
+                                       DEBUG(0, ("Error parsing LI list from RI\n"));
+                                       return WERR_GENERAL_FAILURE;
+                               }
+                               SMB_ASSERT(!strncmp(li.header, "li", 2));
+                               
+                               /* Advance to next sublist if necessary */
+                               if (idx >= sublist_count + li.key_count) {
+                                       sublist_count += li.key_count;
+                                       continue;
+                               }
+                               key_off = li.nk_offset[idx - sublist_count];
+                               sublist_count += li.key_count;
+                               break;
+                       } else if (!strncmp((char *)list_data.data, "lh", 2)) {
+                               struct lh_block lh;
+                               
+                               DEBUG(10, ("Subkeys in RI->LH list\n"));
+
+                               if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
+                                       DEBUG(0, ("Error parsing LH list from RI\n"));
+                                       return WERR_GENERAL_FAILURE;
+                               }
+                               SMB_ASSERT(!strncmp(lh.header, "lh", 2));
+
+                               /* Advance to next sublist if necessary */
+                               if (idx >= sublist_count + lh.key_count) {
+                                       sublist_count += lh.key_count;
+                                       continue;
+                               }
+                               key_off = lh.hr[idx - sublist_count].nk_offset;
+                               sublist_count += lh.key_count;
+                               break;
+                       } else {
+                               DEBUG(0,("Unknown sublist in ri block\n"));
+
+                               return WERR_GENERAL_FAILURE;
+                       }
+                       
+               }
+       
+               if (idx > sublist_count) {
+                       return WERR_NO_MORE_ITEMS;
+               }
+
+       } else {
+               DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n", 
+                                 nk->subkeys_offset, data.data[0], data.data[1]));
+               return WERR_GENERAL_FAILURE;
+       }
+
+       ret = regf_get_key (ctx, private_data->hive, key_off);
+
+       if (classname != NULL) {
+               if (ret->nk->clsname_offset != -1) {
+                       DATA_BLOB db = hbin_get(ret->hive, 
+                                                                         ret->nk->clsname_offset);
+                       *classname = talloc_strndup(ctx, 
+                                                        (char*)db.data, ret->nk->clsname_length);
+               } else 
+                       *classname = NULL;
+       }
+
+       if (last_mod_time != NULL)
+               *last_mod_time = ret->nk->last_change;
+
+       if (name != NULL)
+               *name = talloc_steal(ctx, ret->nk->key_name);
+
+       talloc_free(ret);
+
+       return WERR_OK;
+}
+
+static WERROR regf_match_subkey_by_name(TALLOC_CTX *ctx, 
+                                               const struct hive_key *key, uint32_t offset, 
+                                               const char *name, uint32_t *ret) 
+{
+       DATA_BLOB subkey_data;
+       struct nk_block subkey;
+       struct tdr_pull pull;
+       const struct regf_key_data *private_data = 
+               (const struct regf_key_data *)key;
+       
+       subkey_data = hbin_get(private_data->hive, offset);
+       if (!subkey_data.data) {
+               DEBUG(0, ("Unable to retrieve subkey HBIN\n"));
+               return WERR_GENERAL_FAILURE;
+       }
+
+       ZERO_STRUCT(pull);
+       pull.data = subkey_data;
+       
+       if (NT_STATUS_IS_ERR(tdr_pull_nk_block(&pull, ctx, &subkey))) {
+               DEBUG(0, ("Error parsing NK structure.\n"));
+               return WERR_GENERAL_FAILURE;
+       }
+
+       if (strncmp(subkey.header, "nk", 2)) {
+               DEBUG(0, ("Not an NK structure.\n"));
+               return WERR_GENERAL_FAILURE;
+       }
+
+       if (!strcasecmp(subkey.key_name, name)) {
+               *ret = offset;
+       } else {
+               *ret = 0;
+       }
+       return WERR_OK;
+}
+       
+static WERROR regf_get_subkey_by_name(TALLOC_CTX *ctx, 
+                                                                         const struct hive_key *key, 
+                                                                         const char *name, 
+                                                                         struct hive_key **ret)
+{
+       DATA_BLOB data;
+       const struct regf_key_data *private_data = 
+               (const struct regf_key_data *)key;
+       struct nk_block *nk = private_data->nk;
+       uint32_t key_off = 0;
+
+       data = hbin_get(private_data->hive, nk->subkeys_offset);
+       if (!data.data) {
+               DEBUG(0, ("Unable to find subkey list\n"));
+               return WERR_GENERAL_FAILURE;
+       }
+
+       if (!strncmp((char *)data.data, "li", 2)) {
+               struct li_block li;
+               struct tdr_pull pull;
+               uint16_t i;
+
+               DEBUG(10, ("Subkeys in LI list\n"));
+               ZERO_STRUCT(pull);
+               pull.data = data;
+               
+               if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
+                       DEBUG(0, ("Error parsing LI list\n"));
+                       return WERR_GENERAL_FAILURE;
+               }
+               SMB_ASSERT(!strncmp(li.header, "li", 2));
+
+               if (li.key_count != nk->num_subkeys) {
+                       DEBUG(0, ("Subkey counts don't match\n"));
+                       return WERR_GENERAL_FAILURE;
+               }
+               
+               for (i = 0; i < li.key_count; i++) {
+                       W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, li.nk_offset[i], name, &key_off));
+                       if (key_off != 0)
+                               break;
+               }
+               if (key_off == 0)
+                       return WERR_NOT_FOUND;
+       } else if (!strncmp((char *)data.data, "lf", 2)) {
+               struct lf_block lf;
+               struct tdr_pull pull;
+               uint16_t i;
+
+               DEBUG(10, ("Subkeys in LF list\n"));
+               ZERO_STRUCT(pull);
+               pull.data = data;
+               
+               if (NT_STATUS_IS_ERR(tdr_pull_lf_block(&pull, nk, &lf))) {
+                       DEBUG(0, ("Error parsing LF list\n"));
+                       return WERR_GENERAL_FAILURE;
+               }
+               SMB_ASSERT(!strncmp(lf.header, "lf", 2));
+
+               if (lf.key_count != nk->num_subkeys) {
+                       DEBUG(0, ("Subkey counts don't match\n"));
+                       return WERR_GENERAL_FAILURE;
+               }
+               
+               for (i = 0; i < lf.key_count; i++) {
+                       if (strncmp(lf.hr[i].hash, name, 4)) {
+                               continue;
+                       }
+                       W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, lf.hr[i].nk_offset, name, &key_off));
+                       if (key_off != 0)
+                               break;
+               }
+               if (key_off == 0)
+                       return WERR_NOT_FOUND;
+       } else if (!strncmp((char *)data.data, "lh", 2)) {
+               struct lh_block lh;
+               struct tdr_pull pull;
+               uint16_t i;
+               uint32_t hash;
+
+               DEBUG(10, ("Subkeys in LH list\n"));
+               ZERO_STRUCT(pull);
+               pull.data = data;
+               
+               if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
+                       DEBUG(0, ("Error parsing LH list\n"));
+                       return WERR_GENERAL_FAILURE;
+               }
+               SMB_ASSERT(!strncmp(lh.header, "lh", 2));
+
+               if (lh.key_count != nk->num_subkeys) {
+                       DEBUG(0, ("Subkey counts don't match\n"));
+                       return WERR_GENERAL_FAILURE;
+               }
+               
+               hash = regf_create_lh_hash(name);
+               for (i = 0; i < lh.key_count; i++) {
+                       if (lh.hr[i].base37 != hash) {
+                               continue;
+                       }
+                       W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, lh.hr[i].nk_offset, name, &key_off));
+                       if (key_off != 0)
+                               break;
+               }       
+               if (key_off == 0)
+                       return WERR_NOT_FOUND;
+       } else if (!strncmp((char *)data.data, "ri", 2)) {
+               struct ri_block ri;
+               struct tdr_pull pull;
+               uint16_t i, j;
+
+               DEBUG(10, ("Subkeys in RI list\n"));
+               ZERO_STRUCT(pull);
+               pull.data = data;
+               
+               if (NT_STATUS_IS_ERR(tdr_pull_ri_block(&pull, nk, &ri))) {
+                       DEBUG(0, ("Error parsing RI list\n"));
+                       return WERR_GENERAL_FAILURE;
+               }
+               SMB_ASSERT(!strncmp(ri.header, "ri", 2));
+                       
+               for (i = 0; i < ri.key_count; i++) {
+                       DATA_BLOB list_data;
+                       
+                       /* Get sublist data blob */
+                       list_data = hbin_get(private_data->hive, ri.offset[i]);
+                       if (list_data.data == NULL) {
+                               DEBUG(0, ("Error getting RI list."));
+                               return WERR_GENERAL_FAILURE;
+                       }
+                               
+                       ZERO_STRUCT(pull);
+                       pull.data = list_data;
+                       
+                       if (!strncmp((char *)list_data.data, "li", 2)) {
+                               struct li_block li;
+       
+                               if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
+                                       DEBUG(0, ("Error parsing LI list from RI\n"));
+                                       return WERR_GENERAL_FAILURE;
+                               }
+                               SMB_ASSERT(!strncmp(li.header, "li", 2));
+                               
+                               for (j = 0; j < li.key_count; j++) {
+                                       W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, 
+                                                               li.nk_offset[j], name, &key_off));
+                                       if (key_off)
+                                               break;
+                               }
+                       } else if (!strncmp((char *)list_data.data, "lh", 2)) {
+                               struct lh_block lh;
+                               uint32_t hash;
+                               
+                               if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
+                                       DEBUG(0, ("Error parsing LH list from RI\n"));
+                                       return WERR_GENERAL_FAILURE;
+                               }
+                               SMB_ASSERT(!strncmp(lh.header, "lh", 2));
+
+                               hash = regf_create_lh_hash(name);
+                               for (j = 0; j < lh.key_count; j++) {
+                                       if (lh.hr[j].base37 != hash) {
+                                               continue;
+                                       }
+                                       W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, 
+                                                               lh.hr[j].nk_offset, name, &key_off));
+                                       if (key_off)
+                                               break;
+                               }
+                       }
+                       if (key_off)
+                               break;
+               }
+               if (!key_off)
+                       return WERR_NOT_FOUND;
+       } else {
+               DEBUG(0, ("Unknown subkey list type.\n"));
+               return WERR_GENERAL_FAILURE;
+       }
+
+       *ret = (struct hive_key *)regf_get_key (ctx, private_data->hive, key_off);
+       return WERR_OK;
+}
+
+static WERROR regf_set_sec_desc (struct hive_key *key, 
+                                                                const struct security_descriptor *sec_desc)
+{
+       const struct regf_key_data *private_data = 
+               (const struct regf_key_data *)key;
+       struct sk_block cur_sk, sk, new_sk;
+       struct regf_data *regf = private_data->hive;
+       struct nk_block root;
+       DATA_BLOB data;
+       uint32_t sk_offset, cur_sk_offset;
+       bool update_cur_sk = false;
+
+       /* Get the root nk */
+       hbin_get_tdr(regf, regf->header->data_offset, regf, 
+                                (tdr_pull_fn_t) tdr_pull_nk_block, &root);
+
+       /* Push the security descriptor to a blob */
+       if (NT_STATUS_IS_ERR(ndr_push_struct_blob(&data, regf, sec_desc, 
+                                       (ndr_push_flags_fn_t)ndr_push_security_descriptor))) {
+               DEBUG(0, ("Unable to push security descriptor\n"));
+               return WERR_GENERAL_FAILURE;
+       }
+
+       /* Get the current security descriptor for the key */   
+       if (!hbin_get_tdr(regf, private_data->nk->sk_offset, regf, 
+                                         (tdr_pull_fn_t) tdr_pull_sk_block, &cur_sk)) {
+               DEBUG(0, ("Unable to find security descriptor for current key\n"));
+               return WERR_BADFILE;
+       }
+       /* If there's no change, change nothing. */
+       if (memcmp(data.data, cur_sk.sec_desc, MIN(data.length, cur_sk.rec_size)) == 0) {
+               return WERR_OK;
+       }
+
+       /* Delete the current sk if only this key is using it */        
+       if (cur_sk.ref_cnt == 1) {
+               /* Get the previous security descriptor for the key */  
+               if (!hbin_get_tdr(regf, cur_sk.prev_offset, regf, 
+                                                 (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
+                       DEBUG(0, ("Unable to find prev security descriptor for current key\n"));
+                       return WERR_BADFILE;
+               }
+               /* Change and store the previous security descriptor */
+               sk.next_offset = cur_sk.next_offset;
+               hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, cur_sk.prev_offset, &sk);
+               
+               /* Get the next security descriptor for the key */      
+               if (!hbin_get_tdr(regf, cur_sk.next_offset, regf, (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
+                       DEBUG(0, ("Unable to find next security descriptor for current key\n"));
+                       return WERR_BADFILE;
+               }
+               /* Change and store the next security descriptor */
+               sk.prev_offset = cur_sk.prev_offset;
+               hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, cur_sk.next_offset, &sk);
+
+               hbin_free(regf, private_data->nk->sk_offset);
+       } else {
+               /* This key will no longer be referring to this sk */
+               cur_sk.ref_cnt--;
+               update_cur_sk = true;
+       }
+
+       sk_offset = root.sk_offset;
+
+       do {
+               cur_sk_offset = sk_offset;
+               if (!hbin_get_tdr(regf, sk_offset, regf, (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
+                       DEBUG(0, ("Unable to find security descriptor\n"));
+                       return WERR_BADFILE;
+               }
+               if (memcmp(data.data, sk.sec_desc, MIN(data.length, sk.rec_size)) == 0) {
+                       private_data->nk->sk_offset = sk_offset;
+                       sk.ref_cnt++;
+                       hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, sk_offset, &sk);
+                       hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block, private_data->offset, private_data->nk);
+                       return WERR_OK;
+               }
+               sk_offset = sk.next_offset;
+       } while (sk_offset != root.sk_offset);
+       
+       ZERO_STRUCT(new_sk);
+       new_sk.header = "sk";
+       new_sk.prev_offset = cur_sk_offset;
+       new_sk.next_offset = root.sk_offset;
+       new_sk.ref_cnt = 1;
+       new_sk.rec_size = data.length;
+       new_sk.sec_desc = data.data;
+       
+       sk_offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_sk_block, &new_sk);
+       if (sk_offset == -1) {
+               DEBUG(0, ("Error storing sk block\n"));
+               return WERR_GENERAL_FAILURE;
+       }
+       private_data->nk->sk_offset = sk_offset;
+
+       if (update_cur_sk) {
+               hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, private_data->nk->sk_offset, &cur_sk);
+       }
+
+       /* Get the previous security descriptor for the key */  
+       if (!hbin_get_tdr(regf, new_sk.prev_offset, regf, (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
+               DEBUG(0, ("Unable to find security descriptor for previous key\n"));
+               return WERR_BADFILE;
+       }
+       /* Change and store the previous security descriptor */
+       sk.next_offset = sk_offset;
+       hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, cur_sk.prev_offset, &sk);
+       
+       /* Get the next security descriptor for the key (always root, as we append) */  
+       if (!hbin_get_tdr(regf, new_sk.next_offset, regf, (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
+               DEBUG(0, ("Unable to find security descriptor for current key\n"));
+               return WERR_BADFILE;
+       }
+       /* Change and store the next security descriptor (always root, as we append) */
+       sk.prev_offset = sk_offset;
+       hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, root.sk_offset, &sk);
+
+
+       /* Store the nk. */
+       hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block, private_data->offset, private_data->nk);
+       return WERR_OK;
+}
+
+static WERROR regf_get_sec_desc(TALLOC_CTX *ctx, const struct hive_key *key, 
+                                                               struct security_descriptor **sd)
+{
+       const struct regf_key_data *private_data = 
+               (const struct regf_key_data *)key;
+       struct sk_block sk;
+       struct regf_data *regf = private_data->hive;
+       DATA_BLOB data;
+
+       if (!hbin_get_tdr(regf, private_data->nk->sk_offset, ctx, (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
+               DEBUG(0, ("Unable to find security descriptor\n"));
+               return WERR_GENERAL_FAILURE;
+       }
+               
+       if (strcmp(sk.header, "sk") != 0) {
+               DEBUG(0, ("Expected 'sk', got '%s'\n", sk.header));
+               return WERR_GENERAL_FAILURE;
+       }
+
+       *sd = talloc(ctx, struct security_descriptor);
+       W_ERROR_HAVE_NO_MEMORY(*sd);
+
+       data.data = sk.sec_desc;
+       data.length = sk.rec_size;
+       if (NT_STATUS_IS_ERR(ndr_pull_struct_blob(&data, ctx, *sd, (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
+               DEBUG(0, ("Error parsing security descriptor\n"));
+               return WERR_GENERAL_FAILURE;
+       }
+
+       return WERR_OK;
+}
+
+static WERROR regf_sl_add_entry(struct regf_data *regf, uint32_t list_offset, 
+                                       const char *name, uint32_t key_offset, uint32_t *ret)
+{
+       DATA_BLOB data;
+
+       /* Create a new key if necessary */
+       if (list_offset == -1) { 
+               if (regf->header->version.major != 1) {
+                       DEBUG(0, ("Can't store keys in unknown registry format\n"));
+                       return WERR_NOT_SUPPORTED;
+               }
+               if (regf->header->version.minor < 3) { 
+                       /* Store LI */
+                       struct li_block li;
+                       ZERO_STRUCT(li);
+                       li.header = "li";
+                       li.key_count = 1; 
+
+                       li.nk_offset = talloc_array(regf, uint32_t, 1);
+                       W_ERROR_HAVE_NO_MEMORY(li.nk_offset);
+                       li.nk_offset[0] = key_offset;
+
+                       *ret = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_li_block, &li);
+
+                       talloc_free(li.nk_offset);
+               } else if (regf->header->version.minor == 3 || regf->header->version.minor == 4) {
+                       /* Store LF */
+                       struct lf_block lf;
+                       ZERO_STRUCT(lf);
+                       lf.header = "lf";
+                       lf.key_count = 1;
+                       
+                       lf.hr = talloc_array(regf, struct hash_record, 1);
+                       W_ERROR_HAVE_NO_MEMORY(lf.hr);
+                       lf.hr[0].nk_offset = key_offset;
+                       lf.hr[0].hash = talloc_strndup(lf.hr, name, 4);
+                       W_ERROR_HAVE_NO_MEMORY(lf.hr[0].hash);
+
+                       *ret = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_lf_block, &lf);
+
+                       talloc_free(lf.hr);
+               } else if (regf->header->version.minor == 5) {
+                       /* Store LH */
+                       struct lh_block lh;
+                       ZERO_STRUCT(lh);
+                       lh.header = "lh";
+                       lh.key_count = 1;
+                       
+                       lh.hr = talloc_array(regf, struct lh_hash, 1);
+                       W_ERROR_HAVE_NO_MEMORY(lh.hr);
+                       lh.hr[0].nk_offset = key_offset;
+                       lh.hr[0].base37 = regf_create_lh_hash(name);
+
+                       *ret = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_lh_block, &lh);
+
+                       talloc_free(lh.hr);
+               }
+               return WERR_OK;
+       } 
+       
+       data = hbin_get(regf, list_offset);
+       if (!data.data) {
+               DEBUG(0, ("Unable to find subkey list\n"));
+               return WERR_BADFILE;
+       }
+
+       if (!strncmp((char *)data.data, "li", 2)) {
+               struct tdr_pull pull;
+               struct li_block li;
+       
+               ZERO_STRUCT(pull);
+               pull.data = data;
+
+               if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, regf, &li))) {
+                       DEBUG(0, ("Error parsing LI list\n"));
+                       return WERR_BADFILE;
+               }
+
+               if (strncmp(li.header, "li", 2) != 0) {
+                       abort();
+                       DEBUG(0, ("LI header corrupt\n"));
+                       return WERR_BADFILE;
+               }
+               
+               li.nk_offset = talloc_realloc(regf, li.nk_offset, uint32_t, li.key_count+1);
+               W_ERROR_HAVE_NO_MEMORY(li.nk_offset);
+               li.nk_offset[li.key_count] = key_offset;
+               li.key_count++;
+               *ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t)tdr_push_li_block, list_offset, &li);
+               
+               talloc_free(li.nk_offset);
+       } else if (!strncmp((char *)data.data, "lf", 2)) {
+               struct tdr_pull pull;
+               struct lf_block lf;
+
+               ZERO_STRUCT(pull);
+               pull.data = data;
+
+               if (NT_STATUS_IS_ERR(tdr_pull_lf_block(&pull, regf, &lf))) {
+                       DEBUG(0, ("Error parsing LF list\n"));
+                       return WERR_BADFILE;
+               }
+               SMB_ASSERT(!strncmp(lf.header, "lf", 2));
+               
+               lf.hr = talloc_realloc(regf, lf.hr, struct hash_record, lf.key_count+1);
+               W_ERROR_HAVE_NO_MEMORY(lf.hr);
+               lf.hr[lf.key_count].nk_offset = key_offset;
+               lf.hr[lf.key_count].hash = talloc_strndup(lf.hr, name, 4);
+               W_ERROR_HAVE_NO_MEMORY(lf.hr[lf.key_count].hash);
+               lf.key_count++;
+               *ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t)tdr_push_lf_block, list_offset, &lf);
+
+               talloc_free(lf.hr);
+       } else if (!strncmp((char *)data.data, "lh", 2)) {
+               struct tdr_pull pull;
+               struct lh_block lh;
+
+               ZERO_STRUCT(pull);
+               pull.data = data;
+
+               if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, regf, &lh))) {
+                       DEBUG(0, ("Error parsing LH list\n"));
+                       return WERR_BADFILE;
+               }
+               SMB_ASSERT(!strncmp(lh.header, "lh", 2));
+               
+               lh.hr = talloc_realloc(regf, lh.hr, struct lh_hash, lh.key_count+1);
+               W_ERROR_HAVE_NO_MEMORY(lh.hr);
+               lh.hr[lh.key_count].nk_offset = key_offset;
+               lh.hr[lh.key_count].base37 = regf_create_lh_hash(name);
+               lh.key_count++;
+               *ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t)tdr_push_lh_block, list_offset, &lh);
+
+               talloc_free(lh.hr);
+       } else if (!strncmp((char *)data.data, "ri", 2)) {
+               /* FIXME */
+               DEBUG(0, ("Adding to 'ri' subkey list is not supported yet.\n"));
+               return WERR_NOT_SUPPORTED;
+       } else {
+               DEBUG(0, ("Cannot add to unknown subkey list\n"));
+               return WERR_BADFILE;
+       }
+       
+       return WERR_OK;
+}
+
+static WERROR regf_sl_del_entry(struct regf_data *regf, uint32_t list_offset, 
+                                                               uint32_t key_offset, uint32_t *ret) 
+{
+       DATA_BLOB data;
+
+       data = hbin_get(regf, list_offset);
+       if (!data.data) {
+               DEBUG(0, ("Unable to find subkey list\n"));
+               return WERR_BADFILE;
+       }
+
+       if (strncmp((char *)data.data, "li", 2) == 0) {
+               struct li_block li;
+               struct tdr_pull pull;
+               uint16_t i;
+               bool found_offset = false;
+       
+               DEBUG(10, ("Subkeys in LI list\n"));
+               
+               ZERO_STRUCT(pull);
+               pull.data = data;       
+               
+               if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, regf, &li))) {
+                       DEBUG(0, ("Error parsing LI list\n"));
+                       return WERR_BADFILE;
+               }
+               
+               SMB_ASSERT(!strncmp(li.header, "li", 2));
+
+               for (i = 0; i < li.key_count; i++) {
+                       if (found_offset) {
+                               li.nk_offset[i-1] = li.nk_offset[i];
+                       }
+                       if (li.nk_offset[i] == key_offset) {
+                               found_offset = true;
+                               continue;
+                       }
+               }
+               if (!found_offset) {
+                       DEBUG(0, ("Subkey not found\n"));
+                       return WERR_NOT_FOUND;
+               }
+               li.key_count--;
+
+               /* If the there are no entries left, free the subkey list */
+               if (li.key_count == 0) {
+                       hbin_free(regf, list_offset);
+                       *ret = -1;
+               }
+
+               /* Store li block */
+               *ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_li_block, list_offset, &li);
+       } else if (strncmp((char *)data.data, "lf", 2) == 0) {
+               struct lf_block lf;
+               struct tdr_pull pull;
+               uint16_t i;
+               bool found_offset = false;
+               
+               DEBUG(10, ("Subkeys in LF list\n"));
+               
+               ZERO_STRUCT(pull);
+               pull.data = data;       
+               
+               if (NT_STATUS_IS_ERR(tdr_pull_lf_block(&pull, regf, &lf))) {
+                       DEBUG(0, ("Error parsing LF list\n"));
+                       return WERR_BADFILE;
+               }
+               
+               SMB_ASSERT(!strncmp(lf.header, "lf", 2));
+
+               for (i = 0; i < lf.key_count; i++) {
+                       if (found_offset) {
+                               lf.hr[i-1] = lf.hr[i];
+                               continue;
+                       }
+                       if (lf.hr[i].nk_offset == key_offset) {
+                               found_offset = 1;
+                               continue;
+                       }
+               }
+               if (!found_offset) {
+                       DEBUG(0, ("Subkey not found\n"));
+                       return WERR_NOT_FOUND;
+               }
+               lf.key_count--;
+               
+               /* If the there are no entries left, free the subkey list */
+               if (lf.key_count == 0) {
+                       hbin_free(regf, list_offset);
+                       *ret = -1;
+                       return WERR_OK;
+               }
+
+               /* Store lf block */
+               *ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_lf_block, list_offset, &lf);
+       } else if (strncmp((char *)data.data, "lh", 2) == 0) {
+               struct lh_block lh;
+               struct tdr_pull pull;
+               uint16_t i;
+               bool found_offset = false;
+               
+               DEBUG(10, ("Subkeys in LH list\n"));
+               
+               ZERO_STRUCT(pull);
+               pull.data = data;       
+               
+               if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, regf, &lh))) {
+                       DEBUG(0, ("Error parsing LF list\n"));
+                       return WERR_BADFILE;
+               }
+               
+               SMB_ASSERT(!strncmp(lh.header, "lh", 2));
+
+               for (i = 0; i < lh.key_count; i++) {
+                       if (found_offset) {
+                               lh.hr[i-1] = lh.hr[i];
+                               continue;
+                       }
+                       if (lh.hr[i].nk_offset == key_offset) {
+                               found_offset = 1;
+                               continue;
+                       }
+               }
+               if (!found_offset) {
+                       DEBUG(0, ("Subkey not found\n"));
+                       return WERR_NOT_FOUND;
+               }
+               lh.key_count--;
+               
+               /* If the there are no entries left, free the subkey list */
+               if (lh.key_count == 0) {
+                       hbin_free(regf, list_offset);
+                       *ret = -1;
+                       return WERR_OK;
+               }
+
+               /* Store lh block */
+               *ret = hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_lh_block, list_offset, &lh);
+       } else if (strncmp((char *)data.data, "ri", 2) == 0) {
+               /* FIXME */
+               DEBUG(0, ("Sorry, deletion from ri block is not supported yet.\n"));
+               return WERR_NOT_SUPPORTED;
+       } else {
+               DEBUG (0, ("Unknown header found in subkey list.\n"));
+               return WERR_BADFILE;
+       }
+       return WERR_OK;
+}
+
+static WERROR regf_del_value (struct hive_key *key, const char *name)
+{
+       const struct regf_key_data *private_data = 
+               (const struct regf_key_data *)key;
+       struct regf_data *regf = private_data->hive;
+       struct nk_block *nk = private_data->nk;
+       struct vk_block vk;
+       uint32_t vk_offset;
+       bool found_offset = false;
+       DATA_BLOB values;
+       uint32_t i;
+
+       if (nk->values_offset == -1) {
+               return WERR_NOT_FOUND;
+       }
+
+       values = hbin_get(regf, nk->values_offset);
+
+       for (i = 0; i < nk->num_values; i++) {
+               if (found_offset) {
+                       ((uint32_t *)values.data)[i-1] = ((uint32_t *) values.data)[i];
+               } else {
+                       vk_offset = IVAL(values.data, i * 4);
+                       if (!hbin_get_tdr(regf, vk_offset, private_data, 
+                                                         (tdr_pull_fn_t)tdr_pull_vk_block, &vk)) {
+                               DEBUG(0, ("Unable to get VK block at %d\n", vk_offset));
+                               return WERR_BADFILE;
+                       } 
+                       if (strcmp(vk.data_name, name) == 0) {
+                               hbin_free(regf, vk_offset);
+                               found_offset = true;
+                       }
+               }
+       }
+       if (!found_offset) {
+               return WERR_NOT_FOUND;
+       } else {
+               nk->num_values--;
+               values.length = (nk->num_values)*4;
+       }
+
+       /* Store values list and nk */
+       if (nk->num_values == 0) {
+               hbin_free(regf, nk->values_offset);
+               nk->values_offset = -1;
+       } else {        
+               nk->values_offset = hbin_store_resize(regf, nk->values_offset, values);
+       }
+       hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block, private_data->offset, nk);
+
+       return regf_save_hbin(private_data->hive);
+}
+
+
+static WERROR regf_del_key(const struct hive_key *parent, const char *name)
+{
+       const struct regf_key_data *private_data = 
+               (const struct regf_key_data *)parent;
+       struct regf_key_data *key;
+       struct nk_block *parent_nk;
+       WERROR error;
+
+       SMB_ASSERT(private_data);
+       
+       parent_nk = private_data->nk;
+
+       if (parent_nk->subkeys_offset == -1) {
+               DEBUG(4, ("Subkey list is empty, this key cannot contain subkeys.\n"));
+               return WERR_NOT_FOUND;
+       }
+
+       /* Find the key */
+       if (!W_ERROR_IS_OK(regf_get_subkey_by_name(parent_nk, parent, name, 
+                                                                          (struct hive_key **)&key))) {
+               DEBUG(0, ("Key '%s' not found\n", name));
+               return WERR_NOT_FOUND;
+       }
+       
+       if (key->nk->subkeys_offset != -1 || 
+               key->nk->values_offset != -1) {
+               DEBUG(0, ("Key '%s' is not empty.\n", name));
+               return WERR_FILE_EXISTS;
+       }
+       
+       /* Delete it from the subkey list. */
+       error = regf_sl_del_entry(private_data->hive, parent_nk->subkeys_offset, 
+                                                         key->offset, &parent_nk->subkeys_offset);
+       if (!W_ERROR_IS_OK(error)) {
+               DEBUG(0, ("Can't store new subkey list for parent key. Won't delete.\n"));
+               return error;
+       }
+
+       /* Re-store parent key */
+       parent_nk->num_subkeys--;
+       hbin_store_tdr_resize(private_data->hive, 
+                                                 (tdr_push_fn_t) tdr_push_nk_block, 
+                                                 private_data->offset, parent_nk);
+
+       if (key->nk->clsname_offset != -1) {
+               hbin_free(private_data->hive, key->nk->clsname_offset);
+       }
+       hbin_free(private_data->hive, key->offset);
+
+       return regf_save_hbin(private_data->hive);
+}
+
+static WERROR regf_add_key(TALLOC_CTX *ctx, const struct hive_key *parent, 
+                                                  const char *name, const char *classname,
+                                                  struct security_descriptor *sec_desc, 
+                                                  struct hive_key **ret)
+{
+       const struct regf_key_data *private_data = 
+               (const struct regf_key_data *)parent;
+       struct nk_block *parent_nk = private_data->nk, nk;
+       struct nk_block *root;
+       struct regf_data *regf = private_data->hive;
+       uint32_t offset;
+       WERROR error;
+
+       nk.header = "nk";
+       nk.type = REG_SUB_KEY;
+       unix_to_nt_time(&nk.last_change, time(NULL));
+       nk.uk1 = 0;
+       nk.parent_offset = private_data->offset;
+       nk.num_subkeys = 0;
+       nk.uk2 = 0;
+       nk.subkeys_offset = -1;
+       nk.unknown_offset = -1;
+       nk.num_values = 0;
+       nk.values_offset = -1;
+       memset(nk.unk3, 0, 5);
+       nk.clsname_offset = -1; /* FIXME: fill in */
+       nk.clsname_length = 0;
+       nk.key_name = name;
+       
+       /* Get the security descriptor of the root key */
+       root = talloc_zero(ctx, struct nk_block);
+       W_ERROR_HAVE_NO_MEMORY(root);
+
+       if (!hbin_get_tdr(regf, regf->header->data_offset, root, 
+                                         (tdr_pull_fn_t)tdr_pull_nk_block, root)) {
+               DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset));
+               return WERR_GENERAL_FAILURE;
+       }
+       nk.sk_offset = root->sk_offset;
+       talloc_free(root);
+       
+       /* Store the new nk key */
+       offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_nk_block, &nk);
+       
+       error = regf_sl_add_entry(regf, parent_nk->subkeys_offset, name, offset, &parent_nk->subkeys_offset);
+       if (!W_ERROR_IS_OK(error)) {
+               hbin_free(regf, offset);
+               return error;
+       }
+       
+       parent_nk->num_subkeys++;
+
+       /* Since the subkey offset of the parent can change, store it again */
+       hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block, 
+                                                 nk.parent_offset, parent_nk);
+
+       *ret = (struct hive_key *)regf_get_key(ctx, regf, offset);
+
+       return regf_save_hbin(private_data->hive);
+}
+
+static WERROR regf_set_value(struct hive_key *key, const char *name, 
+                                                        uint32_t type, const DATA_BLOB data)
+{
+       const struct regf_key_data *private_data = 
+               (const struct regf_key_data *)key;
+       struct regf_data *regf = private_data->hive;
+       struct nk_block *nk = private_data->nk;
+       struct vk_block vk;
+       uint32_t i;
+       uint32_t tmp_vk_offset, vk_offset, old_vk_offset = -1;
+       DATA_BLOB values;
+
+       ZERO_STRUCT(vk);
+
+       /* find the value offset, if it exists */
+       if (nk->values_offset != -1) {
+               values = hbin_get(regf, nk->values_offset);
+
+               for (i = 0; i < nk->num_values; i++) {
+                       tmp_vk_offset = IVAL(values.data, i * 4);
+                       if (!hbin_get_tdr(regf, tmp_vk_offset, private_data, 
+                                                         (tdr_pull_fn_t)tdr_pull_vk_block, &vk)) {
+                               DEBUG(0, ("Unable to get VK block at %d\n", tmp_vk_offset));
+                               return WERR_GENERAL_FAILURE;
+                       }
+                       if (strcmp(vk.data_name, name) == 0) {
+                               old_vk_offset = tmp_vk_offset;
+                               break;
+                       }
+               }
+               /* Free data, if any */
+               if (!(vk.data_length & 0x80000000)) {
+                       hbin_free(regf, vk.data_offset);        
+               }
+       }
+       if (old_vk_offset == -1) {
+               vk.header = "vk";
+               vk.name_length = strlen(name);
+               if (name != NULL && name[0] != 0) {
+                       vk.flag = 1;
+                       vk.data_name = name;
+               } else {
+                       vk.data_name = NULL;
+                       vk.flag = 0;
+               }
+       }
+       /* Set the type and data */
+       vk.data_length = data.length;
+       vk.data_type = type;
+       if (type == REG_DWORD) {
+               vk.data_length |= 0x80000000;
+               vk.data_offset = *(uint32_t *)data.data;
+       } else {
+               /* Store data somewhere */
+               vk.data_offset = hbin_store(regf, data);
+       }
+       if (old_vk_offset == -1) {
+               /* Store new vk */
+               vk_offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_vk_block, &vk);
+       } else {
+               /* Store vk at offset */
+               vk_offset = hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_vk_block, old_vk_offset ,&vk);
+       }
+
+       /* Re-allocate the value list */
+       if (nk->values_offset == -1) {
+               nk->values_offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_uint32, &vk_offset);
+               nk->num_values = 1;
+       } else {
+
+               /* Change if we're changing, otherwise we're adding the value */
+               if (old_vk_offset != -1) {
+                       /* Find and overwrite the offset. */
+                       for (i = 0; i < nk->num_values; i++) {
+                               if (IVAL(values.data, i * 4) == old_vk_offset) {
+                                       SIVAL(values.data, i * 4, vk_offset);
+                                       break;
+                               }
+                       }
+               } else {
+                       /* Create a new value list */
+                       DATA_BLOB value_list;
+
+                       value_list.length = (nk->num_values+1)*4;
+                       value_list.data = (void *)talloc_array(private_data, uint32_t, nk->num_values+1);
+                       W_ERROR_HAVE_NO_MEMORY(value_list.data);
+                       memcpy(value_list.data, values.data, nk->num_values * 4);
+
+                       SIVAL(value_list.data, nk->num_values * 4, vk_offset);
+                       nk->num_values++;
+                       nk->values_offset = hbin_store_resize(regf, nk->values_offset, value_list);
+               }
+               
+       }
+       hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block, private_data->offset, nk);
+       return regf_save_hbin(private_data->hive);
+}
+
+static WERROR regf_save_hbin(struct regf_data *regf)
+{
+       struct tdr_push *push = talloc_zero(regf, struct tdr_push);
+       int i;
+
+       W_ERROR_HAVE_NO_MEMORY(push);
+
+       if (lseek(regf->fd, 0, SEEK_SET) == -1) {
+               DEBUG(0, ("Error lseeking in regf file\n"));
+               return WERR_GENERAL_FAILURE;
+       }
+
+       /* Recompute checksum */
+       if (NT_STATUS_IS_ERR(tdr_push_regf_hdr(push, regf->header))) {
+               DEBUG(0, ("Failed to push regf header\n"));
+               return WERR_GENERAL_FAILURE;
+       }
+       regf->header->chksum = regf_hdr_checksum(push->data.data);
+       talloc_free(push);
+
+       if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd, 
+                                               (tdr_push_fn_t)tdr_push_regf_hdr, regf->header))) {
+               DEBUG(0, ("Error writing registry file header\n"));
+               return WERR_GENERAL_FAILURE;
+       }
+
+       if (lseek(regf->fd, 0x1000, SEEK_SET) == -1) {
+               DEBUG(0, ("Error lseeking to 0x1000 in regf file\n"));
+               return WERR_GENERAL_FAILURE;
+       }       
+
+       for (i = 0; regf->hbins[i]; i++) {
+               if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd, 
+                                                                                       (tdr_push_fn_t)tdr_push_hbin_block, 
+                                                                                       regf->hbins[i]))) {
+                       DEBUG(0, ("Error writing HBIN block\n"));       
+                       return WERR_GENERAL_FAILURE;
+               }
+       }
+
+       return WERR_OK;
+}
+
+WERROR reg_create_regf_file(TALLOC_CTX *parent_ctx, const char *location, 
+                                                        int minor_version, struct hive_key **key)
+{
+       struct regf_data *regf;
+       struct regf_hdr *regf_hdr;
+       struct tdr_pull pull;
+       int i;
+       struct nk_block nk;
+       WERROR error;
+
+       regf = (struct regf_data *)talloc_zero(NULL, struct regf_data);
+
+       W_ERROR_HAVE_NO_MEMORY(regf);
+
+       DEBUG(5, ("Attempting to create registry file\n"));
+
+       /* Get the header */
+       regf->fd = creat(location, 0644);
+
+       if (regf->fd == -1) {
+               DEBUG(0,("Could not create file: %s, %s\n", location,
+                                strerror(errno)));
+               talloc_free(regf);
+               return WERR_GENERAL_FAILURE;
+       }
+
+       regf_hdr = talloc_zero(regf, struct regf_hdr);
+       W_ERROR_HAVE_NO_MEMORY(regf_hdr);
+       regf_hdr->REGF_ID = "regf";
+       unix_to_nt_time(&regf_hdr->modtime, time(NULL));
+       regf_hdr->version.major = 1;
+       regf_hdr->version.minor = minor_version;
+       regf_hdr->last_block = 0x1000; /* Block size */
+       regf_hdr->description = talloc_strdup(regf_hdr, "registry created by Samba 4");
+       W_ERROR_HAVE_NO_MEMORY(regf_hdr->description);
+       regf_hdr->chksum = 0;
+
+       regf->header = regf_hdr;
+
+       pull.offset = 0x1000;
+
+       i = 0;
+       /* Create all hbin blocks */
+       regf->hbins = talloc_array(regf, struct hbin_block *, 1);
+       W_ERROR_HAVE_NO_MEMORY(regf->hbins);
+       regf->hbins[0] = NULL;
+
+       regf_hdr->data_offset = -1; /* FIXME */
+
+       nk.header = "nk";
+       nk.type = REG_SUB_KEY;
+       unix_to_nt_time(&nk.last_change, time(NULL));
+       nk.uk1 = 0;
+       nk.parent_offset = -1;
+       nk.num_subkeys = 0;
+       nk.uk2 = 0;
+       nk.subkeys_offset = -1;
+       nk.unknown_offset = -1;
+       nk.num_values = 0;
+       nk.values_offset = -1;
+       memset(nk.unk3, 0, 5);
+       nk.clsname_offset = -1; /* FIXME: fill in */
+       nk.clsname_length = 0;
+       nk.key_name = "";
+       
+       nk.sk_offset = -1; /* FIXME: fill in */
+       
+       /* Store the new nk key */
+       regf->header->data_offset = hbin_store_tdr(regf, 
+                                                                       (tdr_push_fn_t)tdr_push_nk_block, &nk);
+       
+       *key = (struct hive_key *)regf_get_key(parent_ctx, regf, regf->header->data_offset);
+
+       /* We can drop our own reference now that *key will have created one */
+       talloc_free(regf);
+
+       error = regf_save_hbin(regf);
+       if (!W_ERROR_IS_OK(error)) {
+               return error;
+       }
+
+       return WERR_OK;
+}
+
+WERROR reg_open_regf_file(TALLOC_CTX *parent_ctx, 
+                                                 const char *location, struct hive_key **key)
+{
+       struct regf_data *regf;
+       struct regf_hdr *regf_hdr;
+       struct tdr_pull pull;
+       int i;
+
+       regf = (struct regf_data *)talloc_zero(NULL, struct regf_data);
+
+       W_ERROR_HAVE_NO_MEMORY(regf);
+
+       DEBUG(5, ("Attempting to load registry file\n"));
+
+       /* Get the header */
+       regf->fd = open(location, O_RDWR);
+
+       if (regf->fd == -1) {
+               DEBUG(0,("Could not load file: %s, %s\n", location,
+                                strerror(errno)));
+               talloc_free(regf);
+               return WERR_GENERAL_FAILURE;
+       }
+
+       ZERO_STRUCT(pull);
+       pull.data.data = (uint8_t*)fd_load(regf->fd, &pull.data.length, regf);
+
+       if (pull.data.data == NULL) {
+               DEBUG(0, ("Error reading data\n"));
+               talloc_free(regf);
+               return WERR_GENERAL_FAILURE;
+       }
+
+       regf_hdr = talloc(regf, struct regf_hdr);
+       W_ERROR_HAVE_NO_MEMORY(regf_hdr);
+
+       if (NT_STATUS_IS_ERR(tdr_pull_regf_hdr(&pull, regf_hdr, regf_hdr))) {
+               talloc_free(regf);
+               return WERR_GENERAL_FAILURE;
+       }
+
+       regf->header = regf_hdr;
+
+       if (strcmp(regf_hdr->REGF_ID, "regf") != 0) {
+               DEBUG(0, ("Unrecognized NT registry header id: %s, %s\n",
+                                 regf_hdr->REGF_ID, location));
+               talloc_free(regf);
+               return WERR_GENERAL_FAILURE;
+       }
+
+       /* Validate the header ... */
+       if (regf_hdr_checksum(pull.data.data) != regf_hdr->chksum) {
+               DEBUG(0, ("Registry file checksum error: %s: %d,%d\n",
+                                 location, regf_hdr->chksum, 
+                                 regf_hdr_checksum(pull.data.data)));
+               talloc_free(regf);
+               return WERR_GENERAL_FAILURE;
+       }
+
+       pull.offset = 0x1000;
+
+       i = 0;
+       /* Read in all hbin blocks */
+       regf->hbins = talloc_array(regf, struct hbin_block *, 1);
+       W_ERROR_HAVE_NO_MEMORY(regf->hbins);
+
+       regf->hbins[0] = NULL;
+
+       while (pull.offset < pull.data.length && pull.offset <= regf->header->last_block) {
+               struct hbin_block *hbin = talloc(regf->hbins, struct hbin_block);
+
+               W_ERROR_HAVE_NO_MEMORY(hbin);
+
+               if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(&pull, hbin, hbin))) {
+                       DEBUG(0, ("[%d] Error parsing HBIN block\n", i));
+                       talloc_free(regf);
+                       return WERR_FOOBAR;
+               }
+
+               if (strcmp(hbin->HBIN_ID, "hbin") != 0) {
+                       DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n", i, hbin->HBIN_ID));
+                       talloc_free(regf);
+                       return WERR_FOOBAR;
+               }
+
+               regf->hbins[i] = hbin;
+               i++;
+               regf->hbins = talloc_realloc(regf, regf->hbins, struct hbin_block *, i+2);
+               regf->hbins[i] = NULL;
+       } 
+
+       DEBUG(1, ("%d HBIN blocks read\n", i));
+
+       *key = (struct hive_key *)regf_get_key(parent_ctx, regf, 
+                                                                                               regf->header->data_offset);
+
+       /* We can drop our own reference now that *key will have created one */
+       talloc_free(regf);
+
+       return WERR_OK;
+}
+
+static struct hive_operations reg_backend_regf = {
+       .name = "regf",
+       .get_key_info = regf_get_info,
+       .enum_key = regf_get_subkey_by_index,
+       .get_key_by_name = regf_get_subkey_by_name,
+       .get_value_by_name = regf_get_value_by_name,
+       .enum_value = regf_get_value,
+       .get_sec_desc = regf_get_sec_desc,
+       .set_sec_desc = regf_set_sec_desc,
+       .add_key = regf_add_key,
+       .set_value = regf_set_value,
+       .del_key = regf_del_key,
+       .delete_value = regf_del_value,
+};
index 46af4ffdc51ed14b964db3f754bfd19eb0685dbf..ffd7072b7ab427e58af1cc0af6721395294065df 100644 (file)
@@ -45,8 +45,8 @@ interface regf
                uint32 data_offset;       
                uint32 last_block;
                [value(1)] uint32 uk7;                  /* 1 */
-               [charset(UTF16)] uint16 description[0x40];
-               uint32 padding[83];                                     /* Padding */
+               [charset(UTF16)] uint16 description[0x20];
+               uint32 padding[99];                                     /* Padding */
                /* Checksum of first 0x200 bytes XOR-ed */
                uint32 chksum;  
        };
@@ -66,7 +66,7 @@ interface regf
                uint8 data[offset_to_next-0x20]; 
                /* data is filled with:
                        uint32 length;                  
-                               Negative if in used, positive otherwise
+                               Negative if in use, positive otherwise
                                Always a multiple of 8
                        uint8_t data[length];  
                                Free space marker if 0xffffffff
index 09d61c6b4f978e2d7ba4cfb9a7f01ab3ad31f87e..acfe056616448fa085de7b4510cfb056d0ed0d8a 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/CIFS implementation.
    Registry interface
    Copyright (C) Gerald Carter                        2002.
-   Copyright (C) Jelmer Vernooij                                         2003-2004.
+   Copyright (C) Jelmer Vernooij                                         2003-2007.
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #ifndef _REGISTRY_H /* _REGISTRY_H */
 #define _REGISTRY_H 
 
+struct registry_context;
+
 #include "core.h"
 #include "talloc/talloc.h"
 #include "librpc/gen_ndr/security.h"
+#include "lib/registry/hive.h"
 
 /* Handles for the predefined keys */
 #define HKEY_CLASSES_ROOT               0x80000000
@@ -36,6 +39,9 @@
 #define HKEY_PERFORMANCE_TEXT   0x80000050
 #define HKEY_PERFORMANCE_NLSTEXT 0x80000060
 
+#define HKEY_FIRST             HKEY_CLASSES_ROOT
+#define HKEY_LAST              HKEY_PERFORMANCE_NLSTEXT
+
 struct reg_predefined_key {
        uint32_t handle;
        const char *name;
@@ -52,17 +58,16 @@ extern const struct reg_predefined_key reg_predefined_keys[];
 
 #define REGISTRY_INTERFACE_VERSION 1
 
+struct reg_key_operations;
+
 /* structure to store the registry handles */
 struct registry_key 
 {
-  const char *name;       
-  const char *path;    
-  const char *class_name; 
-  NTTIME last_mod; 
-  struct registry_hive *hive;
-  void *backend_data;
+       struct registry_context *context;
 };
 
+#include "lib/registry/patchfile.h"
+
 struct registry_value 
 {
   const char *name;
@@ -74,109 +79,87 @@ struct registry_value
 typedef void (*reg_key_notification_function) (void);
 typedef void (*reg_value_notification_function) (void);
 
-/* 
- * Container for function pointers to enumeration routines
- * for virtual registry view 
- *
- * Backends can provide :
- *  - just one hive (example: nt4, w95)
- *  - several hives (example: rpc).
- * 
- * Backends should always do case-insensitive compares 
- * (everything is case-insensitive but case-preserving, 
- * just like the FS)
- *
- * There is no save function as all operations are expected to 
- * be atomic.
- */ 
-
-struct hive_operations {
-       const char *name;
-
-       /* Implement this one */
-       WERROR (*open_hive) (struct registry_hive *, struct registry_key **);
-
-       /* Or this one */
-       WERROR (*open_key) (TALLOC_CTX *, const struct registry_key *, const char *name, struct registry_key **);
-
-       WERROR (*num_subkeys) (const struct registry_key *, uint32_t *count);
-       WERROR (*num_values) (const struct registry_key *, uint32_t *count);
-       WERROR (*get_subkey_by_index) (TALLOC_CTX *, const struct registry_key *, int idx, struct registry_key **);
-
-       /* Can not contain more than one level */
-       WERROR (*get_subkey_by_name) (TALLOC_CTX *, const struct registry_key *, const char *name, struct registry_key **);
-       WERROR (*get_value_by_index) (TALLOC_CTX *, const struct registry_key *, int idx, struct registry_value **);
-
-       /* Can not contain more than one level */
-       WERROR (*get_value_by_name) (TALLOC_CTX *, const struct registry_key *, const char *name, struct registry_value **);
-
-       /* Security control */
-       WERROR (*key_get_sec_desc) (TALLOC_CTX *, const struct registry_key *, struct security_descriptor **);
-       WERROR (*key_set_sec_desc) (const struct registry_key *, const struct security_descriptor *);
-
-       /* Notification */
-       WERROR (*request_key_change_notify) (const struct registry_key *, reg_key_notification_function);
-       WERROR (*request_value_change_notify) (const struct registry_value *, reg_value_notification_function);
-
-       /* Key management */
-       WERROR (*add_key)(TALLOC_CTX *, const struct registry_key *, const char *name, uint32_t access_mask, struct security_descriptor *, struct registry_key **);
-       WERROR (*del_key)(const struct registry_key *, const char *name);
-       WERROR (*flush_key) (const struct registry_key *);
-
-       /* Value management */
-       WERROR (*set_value)(const struct registry_key *, const char *name, uint32_t type, const DATA_BLOB data); 
-       WERROR (*del_value)(const struct registry_key *, const char *valname);
-};
-
 struct cli_credentials;
+struct registry_context;
 
-struct registry_hive
-{
-       const struct hive_operations *functions;
-       struct registry_key *root;
-       struct auth_session_info *session_info;
-       struct cli_credentials *credentials;
-       void *backend_data;
-       const char *location;
-};
-
-/* Handle to a full registry
- * contains zero or more hives */
-struct registry_context {
-    void *backend_data;
-       struct cli_credentials *credentials;
-       struct auth_session_info *session_info;
-       WERROR (*get_predefined_key) (struct registry_context *, uint32_t hkey, struct registry_key **);
-};
-
-struct reg_init_function_entry {
-       const struct hive_operations *hive_functions;
-       struct reg_init_function_entry *prev, *next;
-};
-
-/* Representing differences between registry files */
-
-struct reg_diff_value
-{
+struct registry_operations {
        const char *name;
-       enum { REG_DIFF_DEL_VAL, REG_DIFF_SET_VAL } changetype;
-       uint32_t type;
-       DATA_BLOB data;
-};
 
-struct reg_diff_key
-{
-       const char *name;
-       enum { REG_DIFF_CHANGE_KEY, REG_DIFF_DEL_KEY } changetype;
-       uint32_t numvalues;
-       struct reg_diff_value *values;
-};
-
-struct reg_diff
-{
-       const char *format;
-       uint32_t numkeys;
-       struct reg_diff_key *keys;
+       WERROR (*get_key_info) (TALLOC_CTX *mem_ctx,
+                                                       const struct registry_key *key,
+                                                       const char **classname,
+                                                       uint32_t *numsubkeys,
+                                                       uint32_t *numvalues,
+                                                       NTTIME *last_change_time);
+
+       WERROR (*flush_key) (struct registry_key *key);
+
+       WERROR (*get_predefined_key) (const struct registry_context *ctx, 
+                                                         uint32_t key_id,
+                                                         struct registry_key **key);
+
+       WERROR (*open_key) (TALLOC_CTX *mem_ctx,
+                                               struct registry_key *parent,
+                                               const char *path,
+                                               struct registry_key **key);
+
+       WERROR (*create_key) (TALLOC_CTX *mem_ctx, 
+                                                 struct registry_key *parent,
+                                                 const char *name,
+                                                 const char *key_class,
+                                                 struct security_descriptor *security,
+                                                 struct registry_key **key);
+
+       WERROR (*delete_key) (struct registry_key *key, const char *name);
+
+       WERROR (*delete_value) (struct registry_key *key, const char *name);
+
+       WERROR (*enum_key) (TALLOC_CTX *mem_ctx,
+                                               const struct registry_key *key, uint32_t idx,
+                                               const char **name,
+                                               const char **keyclass,
+                                               NTTIME *last_changed_time);
+
+       WERROR (*enum_value) (TALLOC_CTX *mem_ctx,
+                                                 const struct registry_key *key, uint32_t idx,
+                                                 const char **name,
+                                                 uint32_t *type,
+                                                 DATA_BLOB *data);
+
+       WERROR (*get_security) (TALLOC_CTX *mem_ctx,
+                                                       const struct registry_key *key, 
+                                                       struct security_descriptor **security);
+
+       WERROR (*set_security) (struct registry_key *key,
+                                                       const struct security_descriptor *security);
+
+       WERROR (*load_key) (struct registry_key *key,
+                                               const char *key_name,
+                                               const char *path);
+
+       WERROR (*unload_key) (struct registry_key *key, const char *name);
+
+       WERROR (*notify_value_change) (struct registry_key *key,
+                                                                       reg_value_notification_function fn);
+
+       WERROR (*get_value) (TALLOC_CTX *mem_ctx,
+                                                const struct registry_key *key,
+                                                const char *name,
+                                                uint32_t *type,
+                                                DATA_BLOB *data);
+
+       WERROR (*set_value) (struct registry_key *key,
+                                                const char *name,
+                                                uint32_t type,
+                                                const DATA_BLOB data);
+}; 
+
+/**
+ * Handle to a full registry
+ * contains zero or more hives 
+ */
+struct registry_context {
+       const struct registry_operations *ops;
 };
 
 struct auth_session_info;
@@ -186,60 +169,110 @@ struct event_context;
 #define _PUBLIC_
 #endif
 
+/**
+ * Open the locally defined registry.
+ */
 _PUBLIC_ WERROR reg_open_local (TALLOC_CTX *mem_ctx, 
                                struct registry_context **ctx, 
                                struct auth_session_info *session_info, 
                                struct cli_credentials *credentials);
 
+_PUBLIC_ WERROR reg_open_samba (TALLOC_CTX *mem_ctx,
+                                                               struct registry_context **ctx,
+                                                               struct auth_session_info *session_info,
+                                                               struct cli_credentials *credentials);
+
+/**
+ * Open the registry on a remote machine.
+ */
 _PUBLIC_ WERROR reg_open_remote(struct registry_context **ctx, 
                                                                struct auth_session_info *session_info, 
                                                                struct cli_credentials *credentials, 
                                                                const char *location, struct event_context *ev);
 
-_PUBLIC_ NTSTATUS registry_register(const void *_hive_ops);
-_PUBLIC_ NTSTATUS registry_init(void);
-_PUBLIC_ BOOL reg_has_backend(const char *backend);
-_PUBLIC_ int reg_list_predefs(TALLOC_CTX *mem_ctx, char ***predefs, uint32_t **hkeys);
+_PUBLIC_ WERROR reg_open_wine(struct registry_context **ctx, const char *path);
+
 _PUBLIC_ const char *reg_get_predef_name(uint32_t hkey);
-_PUBLIC_ WERROR reg_get_predefined_key_by_name(struct registry_context *ctx, const char *name, struct registry_key **key);
-_PUBLIC_ WERROR reg_get_predefined_key(struct registry_context *ctx, uint32_t hkey, struct registry_key **key);
-_PUBLIC_ WERROR reg_open_hive(TALLOC_CTX *parent_ctx, const char *backend, const char *location, struct auth_session_info *session_info, struct cli_credentials *credentials, struct registry_key **root);
-_PUBLIC_ WERROR reg_open_key(TALLOC_CTX *mem_ctx, struct registry_key *parent, const char *name, struct registry_key **result);
-_PUBLIC_ WERROR reg_key_get_value_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *key, int idx, struct registry_value **val);
-_PUBLIC_ WERROR reg_key_num_subkeys(const struct registry_key *key, uint32_t *count);
-_PUBLIC_ WERROR reg_key_num_values(const struct registry_key *key, uint32_t *count);
-_PUBLIC_ WERROR reg_key_get_subkey_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *key, int idx, struct registry_key **subkey);
-WERROR reg_key_get_subkey_by_name(TALLOC_CTX *mem_ctx, const struct registry_key *key, const char *name, struct registry_key **subkey);
-_PUBLIC_ WERROR reg_key_get_value_by_name(TALLOC_CTX *mem_ctx, const struct registry_key *key, const char *name, struct registry_value **val);
+_PUBLIC_ WERROR reg_get_predefined_key_by_name(struct registry_context *ctx, 
+                                                                                          const char *name, 
+                                                                                          struct registry_key **key);
+_PUBLIC_ WERROR reg_get_predefined_key(const struct registry_context *ctx, 
+                                                                          uint32_t hkey, 
+                                                                          struct registry_key **key);
+
+_PUBLIC_ WERROR reg_open_key(TALLOC_CTX *mem_ctx, struct registry_key *parent, 
+                                                        const char *name, struct registry_key **result);
+
+_PUBLIC_ WERROR reg_key_get_value_by_index(TALLOC_CTX *mem_ctx, 
+                                  const struct registry_key *key, uint32_t idx, 
+                                  const char **name,
+                                  uint32_t *type,
+                                  DATA_BLOB *data);
+_PUBLIC_ WERROR reg_key_get_info(TALLOC_CTX *mem_ctx,
+                                                                const struct registry_key *key, 
+                                                                       const char **class_name,
+                                                                       uint32_t *num_subkeys,
+                                                                       uint32_t *num_values,
+                                                                       NTTIME *last_change_time);
+_PUBLIC_ WERROR reg_key_get_subkey_by_index(TALLOC_CTX *mem_ctx, 
+                                                                                       const struct registry_key *key, 
+                                                                                       int idx, 
+                                                                                       const char **name,
+                                                                                       const char **classname,
+                                                                                       NTTIME *last_mod_time);
+WERROR reg_key_get_subkey_by_name(TALLOC_CTX *mem_ctx, 
+                                                                 const struct registry_key *key, 
+                                                                 const char *name, 
+                                                                 struct registry_key **subkey);
+_PUBLIC_ WERROR reg_key_get_value_by_name(TALLOC_CTX *mem_ctx, 
+                                                                                 const struct registry_key *key, 
+                                                                                 const char *name, 
+                                                                                 uint32_t *type,
+                                                                                 DATA_BLOB *data);
 _PUBLIC_ WERROR reg_key_del(struct registry_key *parent, const char *name);
-_PUBLIC_ WERROR reg_key_add_name(TALLOC_CTX *mem_ctx, const struct registry_key *parent, const char *name, uint32_t access_mask, struct security_descriptor *desc, struct registry_key **newkey);
-_PUBLIC_ WERROR reg_val_set(struct registry_key *key, const char *value, uint32_t type, DATA_BLOB data);
+_PUBLIC_ WERROR reg_key_add_name(TALLOC_CTX *mem_ctx, 
+                                                                struct registry_key *parent, const char *name, 
+                                                                const char *classname, 
+                                                                struct security_descriptor *desc, 
+                                                                struct registry_key **newkey);
+_PUBLIC_ WERROR reg_val_set(struct registry_key *key, const char *value, 
+                                                       uint32_t type, DATA_BLOB data);
 _PUBLIC_ WERROR reg_get_sec_desc(TALLOC_CTX *ctx, const struct registry_key *key, struct security_descriptor **secdesc);
-_PUBLIC_ WERROR reg_del_value(const struct registry_key *key, const char *valname);
-_PUBLIC_ WERROR reg_key_flush(const struct registry_key *key);
-_PUBLIC_ WERROR reg_key_subkeysizes(const struct registry_key *key, uint32_t *max_subkeylen, uint32_t *max_subkeysize);
-_PUBLIC_ WERROR reg_key_valuesizes(const struct registry_key *key, uint32_t *max_valnamelen, uint32_t *max_valbufsize);
+_PUBLIC_ WERROR reg_del_value(struct registry_key *key, const char *valname);
+_PUBLIC_ WERROR reg_key_flush(struct registry_key *key);
+WERROR reg_create_key (TALLOC_CTX *mem_ctx, 
+                                               struct registry_key *parent,
 
-/* Utility functions */
+                                                 const char *name,
+                                                 const char *key_class,
+                                                 struct security_descriptor *security,
+                                                 struct registry_key **key);
 
+
+
+
+/* Utility functions */
 _PUBLIC_ const char *str_regtype(int type);
-_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type, DATA_BLOB *data);
-_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, struct registry_value *val) ;
+_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type, 
+                                                                  const DATA_BLOB data);
+_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, const char *name,
+                                                                  uint32_t type, const DATA_BLOB data);
 _PUBLIC_ BOOL reg_string_to_val(TALLOC_CTX *mem_ctx, const char *type_str, const char *data_str, uint32_t *type, DATA_BLOB *data);
-char *reg_path_win2unix(char *path) ;
-char *reg_path_unix2win(char *path) ;
 WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, const char *name, struct registry_key **result);
 WERROR reg_key_del_abs(struct registry_context *ctx, const char *path);
 WERROR reg_key_add_abs(TALLOC_CTX *mem_ctx, struct registry_context *ctx, const char *path, uint32_t access_mask, struct security_descriptor *sec_desc, struct registry_key **result);
+WERROR reg_load_key(struct registry_context *ctx, struct registry_key *key, 
+                                       const char *name, const char *filename);
 
+WERROR reg_mount_hive(struct registry_context *rctx, 
+                                         struct hive_key *hive_key,
+                                         uint32_t key_id,
+                                         const char **elements);
 
-/* Patch files */
-
-_PUBLIC_ struct reg_diff *reg_generate_diff(TALLOC_CTX *mem_ctx, struct registry_context *ctx1, struct registry_context *ctx2);
-_PUBLIC_ WERROR reg_diff_save(const struct reg_diff *diff, const char *filename);
-_PUBLIC_ struct reg_diff *reg_diff_load(TALLOC_CTX *ctx, const char *fn);
-_PUBLIC_ BOOL reg_diff_apply (const struct reg_diff *diff, struct registry_context *ctx);
+struct registry_key *reg_import_hive_key(struct registry_context *ctx,
+                                                                            struct hive_key *hive, 
+                                                                            uint32_t predef_key,
+                                                                                const char **elements);
 
-NTSTATUS registry_rpc_init(void);
 
 #endif /* _REGISTRY_H */
similarity index 57%
rename from source/lib/registry/reg_backend_rpc.c
rename to source/lib/registry/rpc.c
index 50489aced2104ad2bfb8a8883d3a4dd39186763e..59d41d591a0f585e4f64aa5518c9da2a6deecaff 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Samba Unix/Linux SMB implementation
    RPC backend for the registry library
-   Copyright (C) 2003-2004 Jelmer Vernooij, jelmer@samba.org
+   Copyright (C) 2003-2007 Jelmer Vernooij, jelmer@samba.org
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include "registry.h"
 #include "librpc/gen_ndr/ndr_winreg_c.h"
 
-static struct hive_operations reg_backend_rpc;
+struct rpc_key {
+       struct registry_key key;
+       struct policy_handle pol;
+       struct dcerpc_pipe *pipe;
+
+       uint32_t num_values;
+       uint32_t num_subkeys;
+       uint32_t max_valnamelen;
+       uint32_t max_valdatalen;
+};
+
+struct rpc_registry_context {
+       struct registry_context context;
+       struct dcerpc_pipe *pipe;
+};
+
+static struct registry_operations reg_backend_rpc;
 
 /**
  * This is the RPC backend for the registry library.
@@ -58,57 +74,46 @@ openhive(HKCR)
 openhive(HKDD)
 openhive(HKCC)
 
-struct rpc_key_data {
-       struct policy_handle pol;
-       int num_subkeys;
-       int num_values;
-       int max_valnamelen;
-       int max_valdatalen;
-};
-
 static struct {
        uint32_t hkey;
        WERROR (*open) (struct dcerpc_pipe *p, TALLOC_CTX *, struct policy_handle *h);
 } known_hives[] = {
-{ HKEY_LOCAL_MACHINE, open_HKLM },
-{ HKEY_CURRENT_USER, open_HKCU },
-{ HKEY_CLASSES_ROOT, open_HKCR },
-{ HKEY_PERFORMANCE_DATA, open_HKPD },
-{ HKEY_USERS, open_HKU },
-{ HKEY_DYN_DATA, open_HKDD },
-{ HKEY_CURRENT_CONFIG, open_HKCC },
-{ 0, NULL }
+       { HKEY_LOCAL_MACHINE, open_HKLM },
+       { HKEY_CURRENT_USER, open_HKCU },
+       { HKEY_CLASSES_ROOT, open_HKCR },
+       { HKEY_PERFORMANCE_DATA, open_HKPD },
+       { HKEY_USERS, open_HKU },
+       { HKEY_DYN_DATA, open_HKDD },
+       { HKEY_CURRENT_CONFIG, open_HKCC },
+       { 0, NULL }
 };
 
 static WERROR rpc_query_key(const struct registry_key *k);
 
-static WERROR rpc_get_predefined_key (struct registry_context *ctx, uint32_t hkey_type, struct registry_key **k)
+static WERROR rpc_get_predefined_key(struct registry_context *ctx, 
+                                                                        uint32_t hkey_type, 
+                                                                        struct registry_key **k)
 {
        int n;
-       struct registry_hive *h;
-       struct rpc_key_data *mykeydata;
+       struct rpc_registry_context *rctx = talloc_get_type(ctx, 
+                                                                                               struct rpc_registry_context);
+       struct rpc_key *mykeydata;
 
-       for(n = 0; known_hives[n].hkey; n++) 
-       {
-               if(known_hives[n].hkey == hkey_type) break;
+       for(n = 0; known_hives[n].hkey; n++) {
+               if(known_hives[n].hkey == hkey_type) 
+                       break;
        }
        
-       if(!known_hives[n].open)  {
+       if (known_hives[n].open == NULL)  {
                DEBUG(1, ("No such hive %d\n", hkey_type));
                return WERR_NO_MORE_ITEMS;
        }
 
-       h = talloc(ctx, struct registry_hive);
-       h->functions = &reg_backend_rpc;
-       h->location = NULL;
-       h->backend_data = ctx->backend_data;
-       
-       (*k) = h->root = talloc(h, struct registry_key);
-       (*k)->hive = h;
-       (*k)->backend_data = mykeydata = talloc(*k, struct rpc_key_data);
+       mykeydata = talloc(ctx, struct rpc_key);
+       mykeydata->pipe = rctx->pipe;
        mykeydata->num_values = -1;
        mykeydata->num_subkeys = -1;
-       return known_hives[n].open((struct dcerpc_pipe *)ctx->backend_data, *k, &(mykeydata->pol));
+       return known_hives[n].open(mykeydata->pipe, *k, &(mykeydata->pol));
 }
 
 #if 0
@@ -136,44 +141,44 @@ static WERROR rpc_key_put_rpc_data(TALLOC_CTX *mem_ctx, struct registry_key *k)
 }
 #endif
 
-static WERROR rpc_open_key(TALLOC_CTX *mem_ctx, const struct registry_key *h, const char *name, struct registry_key **key)
+static WERROR rpc_open_key(TALLOC_CTX *mem_ctx, struct registry_key *h, 
+                                                  const char *name, struct registry_key **key)
 {
-       struct rpc_key_data *mykeydata;
+       struct rpc_key *mykeydata = talloc_get_type(h, struct rpc_key),
+                                  *newkeydata;
     struct winreg_OpenKey r;
 
-       *key = talloc(mem_ctx, struct registry_key);
-       (*key)->name = talloc_strdup(mem_ctx, name);
-
-       (*key)->backend_data = mykeydata = talloc(mem_ctx, struct rpc_key_data);
-       mykeydata->num_values = -1;
-       mykeydata->num_subkeys = -1;
+       mykeydata = talloc(mem_ctx, struct rpc_key);
 
        /* Then, open the handle using the hive */
-
        memset(&r, 0, sizeof(struct winreg_OpenKey));
-    r.in.parent_handle = &(((struct rpc_key_data *)h->backend_data)->pol);
+    r.in.parent_handle = &mykeydata->pol;
     init_winreg_String(&r.in.keyname, name);
     r.in.unknown = 0x00000000;
     r.in.access_mask = 0x02000000;
-    r.out.handle = &mykeydata->pol;
+    r.out.handle = &newkeydata->pol;
 
-    dcerpc_winreg_OpenKey((struct dcerpc_pipe *)(h->hive->backend_data), mem_ctx, &r);
+    dcerpc_winreg_OpenKey(mykeydata->pipe, mem_ctx, &r);
 
        return r.out.result;
 }
 
-static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *parent, int n, struct registry_value **value)  
+static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, 
+                                                                        const struct registry_key *parent, 
+                                                                        uint32_t n, 
+                                                                        const char **value_name,
+                                                                        uint32_t *type,
+                                                                        DATA_BLOB *data)
 {
-       struct rpc_key_data *mykeydata = parent->backend_data;
+       struct rpc_key *mykeydata = talloc_get_type(parent, struct rpc_key);
        WERROR error;
        struct winreg_EnumValue r;
        uint32_t len1, zero = 0;
-       enum winreg_Type type;
        NTSTATUS status;
        struct winreg_StringBuf name;
        uint8_t u8;
        
-       if(mykeydata->num_values == -1) {
+       if (mykeydata->num_values == -1) {
                error = rpc_query_key(parent);
                if(!W_ERROR_IS_OK(error)) return error;
        }
@@ -187,13 +192,13 @@ static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, const struct registry_
        r.in.handle = &mykeydata->pol;
        r.in.enum_index = n;
        r.in.name = &name;
-       r.in.type = &type;
+       r.in.type = type;
        r.in.value = &u8;
        r.in.length = &zero;
        r.in.size = &len1;
        r.out.name = &name;
        
-       status = dcerpc_winreg_EnumValue((struct dcerpc_pipe *)parent->hive->backend_data, mem_ctx, &r);
+       status = dcerpc_winreg_EnumValue(mykeydata->pipe, mem_ctx, &r);
        if(NT_STATUS_IS_ERR(status)) {
                DEBUG(0, ("Error in EnumValue: %s\n", nt_errstr(status)));
                return WERR_GENERAL_FAILURE;
@@ -201,20 +206,23 @@ static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, const struct registry_
        
        if(NT_STATUS_IS_OK(status) && 
           W_ERROR_IS_OK(r.out.result) && r.out.length) {
-               *value = talloc(mem_ctx, struct registry_value);
-               (*value)->name = talloc_strdup(mem_ctx, r.out.name->name);
-               (*value)->data_type = type;
-               (*value)->data = data_blob_talloc(mem_ctx, r.out.value, *r.out.length);
+               *value_name = talloc_strdup(mem_ctx, r.out.name->name);
+               *data = data_blob_talloc(mem_ctx, r.out.value, *r.out.length);
                return WERR_OK;
        }
        
        return r.out.result;
 }
 
-static WERROR rpc_get_subkey_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *parent, int n, struct registry_key **subkey) 
+static WERROR rpc_get_subkey_by_index(TALLOC_CTX *mem_ctx, 
+                                                                         const struct registry_key *parent, 
+                                                                         uint32_t n, 
+                                                                         const char **name,
+                                                                         const char **keyclass,
+                                                                         NTTIME *last_changed_time)
 {
        struct winreg_EnumKey r;
-       struct rpc_key_data *mykeydata = parent->backend_data;
+       struct rpc_key *mykeydata = talloc_get_type(parent, struct rpc_key);
        NTSTATUS status;
        struct winreg_StringBuf namebuf, classbuf;
        NTTIME change_time = 0;
@@ -233,40 +241,47 @@ static WERROR rpc_get_subkey_by_index(TALLOC_CTX *mem_ctx, const struct registry
        r.in.last_changed_time = &change_time;
        r.out.name = &namebuf;
 
-       status = dcerpc_winreg_EnumKey((struct dcerpc_pipe *)parent->hive->backend_data, mem_ctx, &r);
+       status = dcerpc_winreg_EnumKey(mykeydata->pipe, mem_ctx, &r);
        if(NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(r.out.result)) {
-               char *name = talloc_strdup(mem_ctx, r.out.name->name);
-               return rpc_open_key(mem_ctx, parent, name, subkey);
+               *name = talloc_strdup(mem_ctx, r.out.name->name);
+               *keyclass = talloc_strdup(mem_ctx, r.out.keyclass->name);
+               *last_changed_time = *r.out.last_changed_time;
        }
 
        return r.out.result;
 }
 
-static WERROR rpc_add_key(TALLOC_CTX *mem_ctx, const struct registry_key *parent, const char *name, uint32_t access_mask, struct security_descriptor *sec, struct registry_key **key)
+static WERROR rpc_add_key(TALLOC_CTX *mem_ctx, 
+                                                 struct registry_key *parent, const char *name, 
+                                                 const char *key_class,
+                                                 struct security_descriptor *sec, 
+                                                 struct registry_key **key)
 {
        NTSTATUS status;
        struct winreg_CreateKey r;
+       struct rpc_key *parentkd = talloc_get_type(parent, struct rpc_key);
+       struct rpc_key *rpck = talloc(mem_ctx, struct rpc_key);
 
        init_winreg_String(&r.in.name, name);
        init_winreg_String(&r.in.keyclass, NULL);
 
-       r.in.handle = parent->backend_data;
-       r.out.new_handle = talloc(mem_ctx, struct policy_handle);       
+       r.in.handle = &parentkd->pol;
+       r.out.new_handle = &rpck->pol;
        r.in.options = 0;
-       r.in.access_mask = access_mask;
+       r.in.access_mask = SEC_STD_ALL;
        r.in.secdesc = NULL;
 
-       status = dcerpc_winreg_CreateKey((struct dcerpc_pipe *)(parent->hive->backend_data), mem_ctx, &r);
+       status = dcerpc_winreg_CreateKey(parentkd->pipe, mem_ctx, &r);
 
     if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(rpck);
         DEBUG(1, ("CreateKey failed - %s\n", nt_errstr(status)));
         return ntstatus_to_werror(status);
     }
 
        if (W_ERROR_IS_OK(r.out.result)) {
-               *key = talloc(mem_ctx, struct registry_key);
-               (*key)->name = talloc_strdup(*key, name);
-               (*key)->backend_data = r.out.new_handle;
+               rpck->pipe = talloc_reference(rpck, parentkd->pipe);
+               *key = (struct registry_key *)rpck;
        }
 
        return r.out.result;
@@ -276,14 +291,14 @@ static WERROR rpc_query_key(const struct registry_key *k)
 {
     NTSTATUS status;
     struct winreg_QueryInfoKey r;
-    struct rpc_key_data *mykeydata = k->backend_data;
+    struct rpc_key *mykeydata = talloc_get_type(k, struct rpc_key);
        TALLOC_CTX *mem_ctx = talloc_init("query_key");
 
        r.in.classname = talloc(mem_ctx, struct winreg_String);
     init_winreg_String(r.in.classname, NULL);
     r.in.handle = &mykeydata->pol;
        
-    status = dcerpc_winreg_QueryInfoKey((struct dcerpc_pipe *)(k->hive->backend_data), mem_ctx, &r);
+    status = dcerpc_winreg_QueryInfoKey(mykeydata->pipe, mem_ctx, &r);
        talloc_free(mem_ctx);
 
     if (!NT_STATUS_IS_OK(status)) {
@@ -301,26 +316,29 @@ static WERROR rpc_query_key(const struct registry_key *k)
        return r.out.result;
 }
 
-static WERROR rpc_del_key(const struct registry_key *parent, const char *name)
+static WERROR rpc_del_key(struct registry_key *parent, const char *name)
 {
        NTSTATUS status;
-       struct rpc_key_data *mykeydata = parent->backend_data;
+       struct rpc_key *mykeydata = talloc_get_type(parent, struct rpc_key);
        struct winreg_DeleteKey r;
        TALLOC_CTX *mem_ctx = talloc_init("del_key");
        
     r.in.handle = &mykeydata->pol;
     init_winreg_String(&r.in.key, name);
  
-    status = dcerpc_winreg_DeleteKey((struct dcerpc_pipe *)parent->hive->backend_data, mem_ctx, &r);
+    status = dcerpc_winreg_DeleteKey(mykeydata->pipe, mem_ctx, &r);
 
        talloc_free(mem_ctx);
 
        return r.out.result;
 }
 
-static WERROR rpc_num_values(const struct registry_key *key, uint32_t *count) 
+static WERROR rpc_get_info(TALLOC_CTX *mem_ctx, const struct registry_key *key,
+                                                  const char **classname, 
+                                                  uint32_t *numsubkeys,
+                                                  uint32_t *numvalue)
 {
-       struct rpc_key_data *mykeydata = key->backend_data;
+       struct rpc_key *mykeydata = talloc_get_type(key, struct rpc_key);
        WERROR error;
                
        if(mykeydata->num_values == -1) {
@@ -328,42 +346,34 @@ static WERROR rpc_num_values(const struct registry_key *key, uint32_t *count)
                if(!W_ERROR_IS_OK(error)) return error;
        }
                        
-       *count = mykeydata->num_values;
+       /* FIXME: *classname = talloc_strdup(mem_ctx, mykeydata->classname); */
+       *numvalue = mykeydata->num_values;
+       *numsubkeys = mykeydata->num_subkeys;
        return WERR_OK;
 }
 
-static WERROR rpc_num_subkeys(const struct registry_key *key, uint32_t *count) 
-{
-       struct rpc_key_data *mykeydata = key->backend_data;
-       WERROR error;
-
-       if(mykeydata->num_subkeys == -1) {
-               error = rpc_query_key(key);
-               if(!W_ERROR_IS_OK(error)) return error;
-       }
-                       
-       *count = mykeydata->num_subkeys;
-       return WERR_OK;
-}
-
-static struct hive_operations reg_backend_rpc = {
+static struct registry_operations reg_backend_rpc = {
        .name = "rpc",
        .open_key = rpc_open_key,
-       .get_subkey_by_index = rpc_get_subkey_by_index,
-       .get_value_by_index = rpc_get_value_by_index,
-       .add_key = rpc_add_key,
-       .del_key = rpc_del_key,
-       .num_subkeys = rpc_num_subkeys,
-       .num_values = rpc_num_values,
+       .enum_key = rpc_get_subkey_by_index,
+       .enum_value = rpc_get_value_by_index,
+       .create_key = rpc_add_key,
+       .delete_key = rpc_del_key,
+       .get_key_info = rpc_get_info,
 };
 
-_PUBLIC_ WERROR reg_open_remote(struct registry_context **ctx, struct auth_session_info *session_info, struct cli_credentials *credentials, 
-                      const char *location, struct event_context *ev)
+_PUBLIC_ WERROR reg_open_remote(struct registry_context **ctx, 
+                                                               struct auth_session_info *session_info, 
+                                                               struct cli_credentials *credentials, 
+                                                               const char *location, struct event_context *ev)
 {
        NTSTATUS status;
        struct dcerpc_pipe *p;
+       struct rpc_registry_context *rctx;
+
+       dcerpc_init();
 
-       *ctx = talloc(NULL, struct registry_context);
+       rctx = talloc(NULL, struct rpc_registry_context);
 
        /* Default to local smbd if no connection is specified */
        if (!location) {
@@ -374,7 +384,7 @@ _PUBLIC_ WERROR reg_open_remote(struct registry_context **ctx, struct auth_sessi
                                     &p, location, 
                                         &ndr_table_winreg,
                                     credentials, ev);
-       (*ctx)->backend_data = p;
+       rctx->pipe = p;
 
        if(NT_STATUS_IS_ERR(status)) {
                DEBUG(1, ("Unable to open '%s': %s\n", location, nt_errstr(status)));
@@ -383,13 +393,7 @@ _PUBLIC_ WERROR reg_open_remote(struct registry_context **ctx, struct auth_sessi
                return ntstatus_to_werror(status);
        }
 
-       (*ctx)->get_predefined_key = rpc_get_predefined_key;
+       *ctx = (struct registry_context *)rctx;
 
        return WERR_OK;
 }
-
-NTSTATUS registry_rpc_init(void)
-{
-       dcerpc_init();
-       return registry_register(&reg_backend_rpc);
-}
similarity index 57%
rename from source/lib/registry/reg_samba.c
rename to source/lib/registry/samba.c
index 560e1ded31c6769a63d9dd15db27fb35aca5bf8c..244c467a2cd4ee1e5966182a0281694cad295ee9 100644 (file)
@@ -1,6 +1,6 @@
 /* 
    Unix SMB/CIFS implementation.
-   Copyright (C) Jelmer Vernooij                       2004.
+   Copyright (C) Jelmer Vernooij                       2004-2007.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
  * @brief Samba-specific registry functions
  */
 
-static WERROR reg_samba_get_predef (struct registry_context *ctx, uint32_t hkey, struct registry_key **k)
+WERROR mount_samba_hive(struct registry_context *ctx,
+                                               struct auth_session_info *auth_info,
+                                               struct cli_credentials *creds,
+                                               const char *name, 
+                                               uint32_t hive_id)
 {
        WERROR error;
-       const char *conf;
-       char *backend;
+       struct hive_key *hive;
        const char *location;
-       const char *hivename = reg_get_predef_name(hkey);
 
-       *k = NULL;
+       location = talloc_asprintf(ctx, "%s/%s.ldb", lp_private_dir(), name);
 
-       conf = lp_parm_string(-1, "registry", hivename);
-       
-       if (!conf) {
-               return WERR_NOT_SUPPORTED;
-       }
+       error = reg_open_hive(ctx, location, auth_info, creds, &hive);
+       if (!W_ERROR_IS_OK(error))
+               return error;
+
+       return reg_mount_hive(ctx, hive, hive_id, NULL);
+}
+
+
+_PUBLIC_ WERROR reg_open_samba (TALLOC_CTX *mem_ctx, 
+                               struct registry_context **ctx, 
+                               struct auth_session_info *session_info, 
+                               struct cli_credentials *credentials)
+{
+       WERROR result;
 
-       location = strchr(conf, ':');
-       if (location) {
-               backend = talloc_strndup(ctx, conf, (int)(location - conf));
-               location++;
-       } else {
-               backend = talloc_strdup(ctx, "ldb");
-               location = conf;
+       result = reg_open_local(mem_ctx, ctx, session_info, credentials);
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
        }
 
+       mount_samba_hive(*ctx, session_info, credentials, 
+                                        "hklm", HKEY_LOCAL_MACHINE);
+
+       mount_samba_hive(*ctx, session_info, credentials, 
+                                        "hkcr", HKEY_CLASSES_ROOT);
+
+       /* FIXME: Should be mounted from NTUSER.DAT in the home directory of the 
+        * current user */
+       mount_samba_hive(*ctx, session_info, credentials, 
+                                        "hkcu", HKEY_CURRENT_USER);
+
+       mount_samba_hive(*ctx, session_info, credentials, 
+                                        "hku", HKEY_USERS);
+
        /* FIXME: Different hive backend for HKEY_CLASSES_ROOT: merged view of HKEY_LOCAL_MACHINE\Software\Classes
         * and HKEY_CURRENT_USER\Software\Classes */
 
@@ -59,23 +80,6 @@ static WERROR reg_samba_get_predef (struct registry_context *ctx, uint32_t hkey,
        /* FIXME: HKEY_LOCAL_MACHINE\Hardware is autogenerated */
 
        /* FIXME: HKEY_LOCAL_MACHINE\Security\SAM is an alias for HKEY_LOCAL_MACHINE\SAM */
-
-       error = reg_open_hive(ctx, backend, location, ctx->session_info, ctx->credentials, k);
-
-       talloc_free(backend);
-
-       return error;
-}
-
-_PUBLIC_ WERROR reg_open_local (TALLOC_CTX *mem_ctx, 
-                               struct registry_context **ctx, 
-                               struct auth_session_info *session_info, 
-                               struct cli_credentials *credentials)
-{
-       *ctx = talloc(mem_ctx, struct registry_context);
-       (*ctx)->credentials = talloc_reference(*ctx, credentials);
-       (*ctx)->session_info = talloc_reference(*ctx, session_info);
-       (*ctx)->get_predefined_key = reg_samba_get_predef;
        
        return WERR_OK;
 }
diff --git a/source/lib/registry/tests/diff.c b/source/lib/registry/tests/diff.c
new file mode 100644 (file)
index 0000000..220da88
--- /dev/null
@@ -0,0 +1,105 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   local testing of registry diff functionality
+
+   Copyright (C) Jelmer Vernooij 2007
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/registry/registry.h"
+#include "lib/cmdline/popt_common.h"
+#include "torture/torture.h"
+#include "librpc/gen_ndr/winreg.h"
+
+static bool test_generate_diff(struct torture_context *test)
+{
+       /* WERROR reg_generate_diff(struct registry_context *ctx1, 
+                                 struct registry_context *ctx2, 
+                                 const struct reg_diff_callbacks *callbacks,
+                                 void *callback_data)
+                                 */
+       return true;
+}
+
+
+static bool test_diff_load(struct torture_context *test)
+{
+       /* WERROR reg_diff_load(const char *filename, const struct reg_diff_callbacks *callbacks, void *callback_data) */
+
+       return true;
+}
+
+static bool test_diff_apply(struct torture_context *test)
+{
+       /*
+_PUBLIC_ WERROR reg_diff_apply (const char *filename, struct registry_context *ctx)
+       */
+
+       return true;
+}
+
+static const char *added_key = NULL;
+
+static WERROR test_add_key (void *callback_data, const char *key_name)
+{
+       added_key = talloc_strdup(callback_data, key_name);
+
+       return WERR_OK;
+}
+
+static bool test_generate_diff_key_add(struct torture_context *test)
+{
+       struct reg_diff_callbacks cb;
+       struct registry_key rk;
+
+       return true;
+
+       ZERO_STRUCT(cb);
+
+       cb.add_key = test_add_key;
+
+       if (W_ERROR_IS_OK(reg_generate_diff_key(&rk, NULL, "bla", &cb, test)))
+               return false;
+
+       torture_assert_str_equal(test, added_key, "bla", "key added");
+
+       return true;
+}
+
+static bool test_generate_diff_key_null(struct torture_context *test)
+{
+       struct reg_diff_callbacks cb;
+
+       ZERO_STRUCT(cb);
+
+       if (!W_ERROR_IS_OK(reg_generate_diff_key(NULL, NULL, "", &cb, NULL)))
+               return false;
+
+       return true;
+}
+
+struct torture_suite *torture_registry_diff(TALLOC_CTX *mem_ctx) 
+{
+       struct torture_suite *suite = torture_suite_create(mem_ctx, 
+                                                                                                          "DIFF");
+       torture_suite_add_simple_test(suite, "test_generate_diff_key_add", test_generate_diff_key_add);
+       torture_suite_add_simple_test(suite, "test_generate_diff_key_null", test_generate_diff_key_null);
+       torture_suite_add_simple_test(suite, "test_diff_apply", test_diff_apply);
+       torture_suite_add_simple_test(suite, "test_generate_diff", test_generate_diff);
+       torture_suite_add_simple_test(suite, "test_diff_load", test_diff_load);
+       return suite;
+}
index 1f0c89e058f3a8fda7b05b64ca94aeae345f5113..6595f86b18781a84bdfe832b2d09990f6398caaa 100644 (file)
@@ -3,7 +3,7 @@
 
    local testing of registry library
 
-   Copyright (C) Jelmer Vernooij 2005
+   Copyright (C) Jelmer Vernooij 2005-2007
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include "torture/torture.h"
 #include "librpc/gen_ndr/winreg.h"
 
+struct torture_suite *torture_registry_hive(TALLOC_CTX *mem_ctx);
+struct torture_suite *torture_registry_registry(TALLOC_CTX *mem_ctx);
+struct torture_suite *torture_registry_diff(TALLOC_CTX *mem_ctx);
+
 static bool test_str_regtype(struct torture_context *ctx)
 {
        torture_assert_str_equal(ctx, str_regtype(1), "REG_SZ", "REG_SZ failed");
@@ -38,7 +42,8 @@ static bool test_reg_val_data_string_dword(struct torture_context *ctx)
 {
        uint32_t d = 0x20;
        DATA_BLOB db = { (uint8_t *)&d, sizeof(d) };
-       torture_assert_str_equal(ctx, "0x20", reg_val_data_string(ctx, REG_DWORD, &db), "dword failed");
+       torture_assert_str_equal(ctx, "0x20", 
+                                       reg_val_data_string(ctx, REG_DWORD, db), "dword failed");
        return true;
 }
 
@@ -46,9 +51,9 @@ static bool test_reg_val_data_string_sz(struct torture_context *ctx)
 {
        DATA_BLOB db;
        db.length = convert_string_talloc(ctx, CH_UNIX, CH_UTF16, "bla", 3, (void **)&db.data);
-       torture_assert_str_equal(ctx, "bla", reg_val_data_string(ctx, REG_SZ, &db), "sz failed");
+       torture_assert_str_equal(ctx, "bla", reg_val_data_string(ctx, REG_SZ, db), "sz failed");
        db.length = 4;
-       torture_assert_str_equal(ctx, "bl", reg_val_data_string(ctx, REG_SZ, &db), "sz failed");
+       torture_assert_str_equal(ctx, "bl", reg_val_data_string(ctx, REG_SZ, db), "sz failed");
        return true;
 }
 
@@ -56,7 +61,9 @@ static bool test_reg_val_data_string_binary(struct torture_context *ctx)
 {
        uint8_t x[] = { 0x1, 0x2, 0x3, 0x4 };
        DATA_BLOB db = { x, 4 };
-       torture_assert_str_equal(ctx, "01020304", reg_val_data_string(ctx, REG_BINARY, &db), "binary failed");
+       torture_assert_str_equal(ctx, "01020304", 
+                                                        reg_val_data_string(ctx, REG_BINARY, db), 
+                                                        "binary failed");
        return true;
 }
 
@@ -64,18 +71,20 @@ static bool test_reg_val_data_string_binary(struct torture_context *ctx)
 static bool test_reg_val_data_string_empty(struct torture_context *ctx)
 {
        DATA_BLOB db = { NULL, 0 };
-       torture_assert_str_equal(ctx, "", reg_val_data_string(ctx, REG_BINARY, &db), "empty failed");
+       torture_assert_str_equal(ctx, "", 
+                                       reg_val_data_string(ctx, REG_BINARY, db), "empty failed");
        return true;
 }
 
 static bool test_reg_val_description(struct torture_context *ctx)
 {
-       struct registry_value val;
-       val.name = "camel";
-       val.data_type = REG_SZ;
-       val.data.length = convert_string_talloc(ctx, CH_UNIX, CH_UTF16, "stationary traveller", 
-                                                                                       strlen("stationary traveller"), (void **)&val.data.data);
-       torture_assert_str_equal(ctx, "camel = REG_SZ : stationary traveller", reg_val_description(ctx, &val),
+       DATA_BLOB data;
+       data.length = convert_string_talloc(ctx, CH_UNIX, CH_UTF16, 
+                                                                               "stationary traveller", 
+                                                                           strlen("stationary traveller"), 
+                                                                               (void **)&data.data);
+       torture_assert_str_equal(ctx, "camel = REG_SZ : stationary traveller", 
+                                                        reg_val_description(ctx, "camel", REG_SZ, data),
                                                         "reg_val_description failed");
        return true;
 }
@@ -83,12 +92,11 @@ static bool test_reg_val_description(struct torture_context *ctx)
 
 static bool test_reg_val_description_nullname(struct torture_context *ctx)
 {
-       struct registry_value val;
-       val.name = NULL;
-       val.data_type = REG_SZ;
-       val.data.length = convert_string_talloc(ctx, CH_UNIX, CH_UTF16, "west berlin", 
-                                                                                       strlen("west berlin"), (void **)&val.data.data);
-       torture_assert_str_equal(ctx, "<No Name> = REG_SZ : west berlin", reg_val_description(ctx, &val),
+       DATA_BLOB data;
+       data.length = convert_string_talloc(ctx, CH_UNIX, CH_UTF16, "west berlin", 
+                                                               strlen("west berlin"), (void **)&data.data);
+       torture_assert_str_equal(ctx, "<No Name> = REG_SZ : west berlin", 
+                                                        reg_val_description(ctx, NULL, REG_SZ, data),
                                                         "description with null name failed");
        return true;
 }
@@ -98,12 +106,22 @@ struct torture_suite *torture_registry(TALLOC_CTX *mem_ctx)
        struct torture_suite *suite = torture_suite_create(mem_ctx, 
                                                                                                           "REGISTRY");
        torture_suite_add_simple_test(suite, "str_regtype", test_str_regtype);
-       torture_suite_add_simple_test(suite, "reg_val_data_string dword", test_reg_val_data_string_dword);
-       torture_suite_add_simple_test(suite, "reg_val_data_string sz", test_reg_val_data_string_sz);
-       torture_suite_add_simple_test(suite, "reg_val_data_string binary", test_reg_val_data_string_binary);
-       torture_suite_add_simple_test(suite, "reg_val_data_string empty", test_reg_val_data_string_empty);
-       torture_suite_add_simple_test(suite, "reg_val_description", test_reg_val_description);
-       torture_suite_add_simple_test(suite, "reg_val_description null", test_reg_val_description_nullname);
+       torture_suite_add_simple_test(suite, "reg_val_data_string dword", 
+                                                                 test_reg_val_data_string_dword);
+       torture_suite_add_simple_test(suite, "reg_val_data_string sz", 
+                                                                 test_reg_val_data_string_sz);
+       torture_suite_add_simple_test(suite, "reg_val_data_string binary", 
+                                                                 test_reg_val_data_string_binary);
+       torture_suite_add_simple_test(suite, "reg_val_data_string empty", 
+                                                                 test_reg_val_data_string_empty);
+       torture_suite_add_simple_test(suite, "reg_val_description", 
+                                                                 test_reg_val_description);
+       torture_suite_add_simple_test(suite, "reg_val_description null", 
+                                                                 test_reg_val_description_nullname);
+
+       torture_suite_add_suite(suite, torture_registry_hive(mem_ctx));
+       torture_suite_add_suite(suite, torture_registry_registry(mem_ctx));
+       torture_suite_add_suite(suite, torture_registry_diff(mem_ctx));
 
        return suite;
 }
diff --git a/source/lib/registry/tests/hive.c b/source/lib/registry/tests/hive.c
new file mode 100644 (file)
index 0000000..a04bc11
--- /dev/null
@@ -0,0 +1,383 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   local testing of registry library - hives
+
+   Copyright (C) Jelmer Vernooij 2005-2007
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "lib/registry/registry.h"
+#include "lib/cmdline/popt_common.h"
+#include "torture/torture.h"
+#include "librpc/gen_ndr/winreg.h"
+#include "system/filesys.h"
+
+NTSTATUS torture_temp_dir(struct torture_context *tctx, const char *prefix, 
+                                                                  const char **tempdir);
+
+static bool test_del_nonexistant_key(struct torture_context *tctx,
+                                                                        const void *test_data)
+{
+       const struct hive_key *root = test_data;
+       WERROR error = hive_key_del(root, "bla");
+       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, 
+                                                         "invalid return code");
+
+       return true;
+}
+
+static bool test_keyinfo_root(struct torture_context *tctx,
+                                                const void *test_data)
+{
+       uint32_t num_subkeys, num_values;
+       const struct hive_key *root = test_data;
+       WERROR error;
+
+       /* This is a new backend. There should be no subkeys and no 
+        * values */
+       error = hive_key_get_info(tctx, root, NULL, &num_subkeys, &num_values, 
+                                                         NULL);
+       torture_assert_werr_ok(tctx, error, "reg_key_num_subkeys()");
+
+       torture_assert_int_equal(tctx, num_subkeys, 0, "New key has non-zero subkey count");
+
+       torture_assert_werr_ok(tctx, error, "reg_key_num_values");
+
+       torture_assert_int_equal(tctx, num_values, 0, "New key has non-zero value count");
+
+       return true;
+}
+
+static bool test_keyinfo_nums(struct torture_context *tctx,
+                                                const void *test_data)
+{
+       uint32_t num_subkeys, num_values;
+       const struct hive_key *root = test_data;
+       WERROR error;
+       struct hive_key *subkey;
+       uint32_t data = 42;
+
+       error = hive_key_add_name(tctx, root, "Nested Keyll", NULL, 
+                                                        NULL, &subkey);
+       torture_assert_werr_ok(tctx, error, "hive_key_add_name");
+
+       error = hive_set_value(root, "Answer", REG_DWORD, 
+                                  data_blob_talloc(tctx, &data, sizeof(data)));
+       torture_assert_werr_ok(tctx, error, "hive_set_value");
+
+       /* This is a new backend. There should be no subkeys and no 
+        * values */
+       error = hive_key_get_info(tctx, root, NULL, &num_subkeys, &num_values, 
+                                                         NULL);
+       torture_assert_werr_ok(tctx, error, "reg_key_num_subkeys()");
+
+       torture_assert_int_equal(tctx, num_subkeys, 1, "subkey count");
+
+       torture_assert_werr_ok(tctx, error, "reg_key_num_values");
+
+       torture_assert_int_equal(tctx, num_values, 1, "value count");
+
+       return true;
+}
+
+static bool test_add_subkey(struct torture_context *tctx,
+                                         const void *test_data)
+{
+       WERROR error;
+       struct hive_key *subkey;
+       const struct hive_key *root = test_data;
+       TALLOC_CTX *mem_ctx = tctx;
+
+       error = hive_key_add_name(mem_ctx, root, "Nested Key", NULL, 
+                                                        NULL, &subkey);
+       torture_assert_werr_ok(tctx, error, "hive_key_add_name");
+
+       error = hive_key_del(root, "Nested Key");
+       torture_assert_werr_ok(tctx, error, "reg_key_del");
+
+       return true;
+}
+
+static bool test_flush_key(struct torture_context *tctx,
+                                         const void *test_data)
+{
+       const struct hive_key *root = test_data;
+
+       torture_assert_werr_ok(tctx, hive_key_flush(root), "flush key");
+
+       return true;
+}
+
+static bool test_del_key(struct torture_context *tctx, const void *test_data)
+{
+       WERROR error;
+       struct hive_key *subkey;
+       const struct hive_key *root = test_data;
+       TALLOC_CTX *mem_ctx = tctx;
+
+       error = hive_key_add_name(mem_ctx, root, "Nested Key", NULL, 
+                                                        NULL, &subkey);
+       torture_assert_werr_ok(tctx, error, "hive_key_add_name");
+
+       error = hive_key_del(root, "Nested Key");
+       torture_assert_werr_ok(tctx, error, "reg_key_del");
+
+       error = hive_key_del(root, "Nested Key");
+       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, "reg_key_del");
+
+       return true;
+}
+
+static bool test_set_value(struct torture_context *tctx,
+                                         const void *test_data)
+{
+       WERROR error;
+       struct hive_key *subkey;
+       const struct hive_key *root = test_data;
+       TALLOC_CTX *mem_ctx = tctx;
+       uint32_t data = 42;
+
+       error = hive_key_add_name(mem_ctx, root, "YA Nested Key", NULL, 
+                                                        NULL, &subkey);
+       torture_assert_werr_ok(tctx, error, "hive_key_add_name");
+
+       error = hive_set_value(subkey, "Answer", REG_DWORD, 
+                                  data_blob_talloc(mem_ctx, &data, sizeof(data)));
+       torture_assert_werr_ok(tctx, error, "hive_set_value");
+
+       return true;
+}
+
+static bool test_get_value(struct torture_context *tctx, const void *test_data)
+{
+       WERROR error;
+       struct hive_key *subkey;
+       const struct hive_key *root = test_data;
+       TALLOC_CTX *mem_ctx = tctx;
+       uint32_t data = 42;
+       uint32_t type;
+       DATA_BLOB value;
+
+       error = hive_key_add_name(mem_ctx, root, "EYA Nested Key", NULL, 
+                                                        NULL, &subkey);
+       torture_assert_werr_ok(tctx, error, "hive_key_add_name");
+
+       error = hive_get_value(mem_ctx, subkey, "Answer", &type, &value);
+       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, 
+                                                         "getting missing value");
+
+       error = hive_set_value(subkey, "Answer", REG_DWORD, 
+                                  data_blob_talloc(mem_ctx, &data, sizeof(data)));
+       torture_assert_werr_ok(tctx, error, "hive_set_value");
+
+       error = hive_get_value(mem_ctx, subkey, "Answer", &type, &value);
+       torture_assert_werr_ok(tctx, error, "getting value");
+
+       torture_assert(tctx, memcmp(value.data, &data, 4) == 0, "value data");
+
+       torture_assert_int_equal(tctx, value.length, 4, "value length");
+       torture_assert_int_equal(tctx, type, REG_DWORD, "value type");
+
+       return true;
+}
+
+static bool test_del_value(struct torture_context *tctx, const void *test_data)
+{
+       WERROR error;
+       struct hive_key *subkey;
+       const struct hive_key *root = test_data;
+       TALLOC_CTX *mem_ctx = tctx;
+       uint32_t data = 42;
+       uint32_t type;
+       DATA_BLOB value;
+
+       error = hive_key_add_name(mem_ctx, root, "EEYA Nested Key", NULL, 
+                                                        NULL, &subkey);
+       torture_assert_werr_ok(tctx, error, "hive_key_add_name");
+
+       error = hive_set_value(subkey, "Answer", REG_DWORD, 
+                                  data_blob_talloc(mem_ctx, &data, sizeof(data)));
+       torture_assert_werr_ok(tctx, error, "hive_set_value");
+
+       error = hive_del_value(subkey, "Answer");
+       torture_assert_werr_ok(tctx, error, "deleting value");
+
+       error = hive_get_value(mem_ctx, subkey, "Answer", &type, &value);
+       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, "getting value");
+
+       error = hive_del_value(subkey, "Answer");
+       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, "deleting value");
+
+       return true;
+}
+
+static bool test_list_values(struct torture_context *tctx, 
+                                                        const void *test_data)
+{
+       WERROR error;
+       struct hive_key *subkey;
+       const struct hive_key *root = test_data;
+       TALLOC_CTX *mem_ctx = tctx;
+       uint32_t data = 42;
+       uint32_t type;
+       DATA_BLOB value;
+       const char *name;
+
+       error = hive_key_add_name(mem_ctx, root, "AYAYA Nested Key", NULL, 
+                                                        NULL, &subkey);
+       torture_assert_werr_ok(tctx, error, "hive_key_add_name");
+
+       error = hive_set_value(subkey, "Answer", REG_DWORD, 
+                                  data_blob_talloc(mem_ctx, &data, sizeof(data)));
+       torture_assert_werr_ok(tctx, error, "hive_set_value");
+
+       error = hive_get_value_by_index(mem_ctx, subkey, 0, &name, &type, &value);
+       torture_assert_werr_ok(tctx, error, "getting value");
+
+       torture_assert_str_equal(tctx, name, "Answer", "value name");
+       torture_assert(tctx, memcmp(value.data, &data, 4) == 0, "value data");
+
+       torture_assert_int_equal(tctx, value.length, 4, "value length");
+       torture_assert_int_equal(tctx, type, REG_DWORD, "value type");
+
+       error = hive_get_value_by_index(mem_ctx, subkey, 1, &name, &type, &value);
+       torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS, 
+                                                         "getting missing value");
+
+       return true;
+}
+
+static void tcase_add_tests(struct torture_tcase *tcase) 
+{
+       torture_tcase_add_simple_test(tcase, "del_nonexistant_key", 
+                                                                 test_del_nonexistant_key);
+       torture_tcase_add_simple_test(tcase, "add_subkey", test_add_subkey);
+       torture_tcase_add_simple_test(tcase, "flush_key", test_flush_key);
+       torture_tcase_add_simple_test(tcase, "get_info", test_keyinfo_root);
+       torture_tcase_add_simple_test(tcase, "get_info_nums", test_keyinfo_nums);
+       torture_tcase_add_simple_test(tcase, "set_value", test_set_value);
+       torture_tcase_add_simple_test(tcase, "get_value", test_get_value);
+       torture_tcase_add_simple_test(tcase, "list_values", test_list_values);
+       torture_tcase_add_simple_test(tcase, "del_key", test_del_key);
+       torture_tcase_add_simple_test(tcase, "del_value", test_del_value);
+}
+
+static bool hive_setup_dir(struct torture_context *tctx, void **data)
+{
+       struct hive_key *key;
+       WERROR error;
+       const char *dirname;
+       NTSTATUS status;
+
+       status = torture_temp_dir(tctx, "hive-dir", &dirname);
+       if (!NT_STATUS_IS_OK(status))
+               return false;
+
+       rmdir(dirname);
+
+       error = reg_create_directory(tctx, dirname, &key);
+       if (!W_ERROR_IS_OK(error)) {
+               fprintf(stderr, "Unable to initialize dir hive\n");
+               return false;
+       }
+
+       *data = key;
+
+       return true;
+}
+
+static bool hive_setup_ldb(struct torture_context *tctx, void **data)
+{
+       struct hive_key *key;
+       WERROR error;
+       const char *dirname;
+       NTSTATUS status;
+
+       status = torture_temp_dir(tctx, "hive-ldb", &dirname);
+       if (!NT_STATUS_IS_OK(status))
+               return false;
+
+       rmdir(dirname);
+
+       error = reg_open_ldb_file(tctx, dirname, NULL, NULL, &key);
+       if (!W_ERROR_IS_OK(error)) {
+               fprintf(stderr, "Unable to initialize ldb hive\n");
+               return false;
+       }
+
+       *data = key;
+
+       return true;
+}
+
+static bool hive_setup_regf(struct torture_context *tctx, void **data)
+{
+       struct hive_key *key;
+       WERROR error;
+       const char *dirname;
+       NTSTATUS status;
+
+       status = torture_temp_dir(tctx, "hive-dir", &dirname);
+       if (!NT_STATUS_IS_OK(status))
+               return false;
+
+       rmdir(dirname);
+
+       error = reg_create_regf_file(tctx, dirname, 5, &key);
+       if (!W_ERROR_IS_OK(error)) {
+               fprintf(stderr, "Unable to create new regf file\n");
+               return false;
+       }
+
+       *data = key;
+
+       return true;
+}
+
+static bool test_dir_refuses_null_location(struct torture_context *tctx)
+{
+       torture_assert_werr_equal(tctx, WERR_INVALID_PARAM, 
+                                                         reg_open_directory(NULL, NULL, NULL),
+                                                         "reg_open_directory accepts NULL location");
+       return true;
+}
+
+struct torture_suite *torture_registry_hive(TALLOC_CTX *mem_ctx) 
+{
+       struct torture_tcase *tcase;
+       struct torture_suite *suite = torture_suite_create(mem_ctx, 
+                                                                                                          "HIVE");
+
+       torture_suite_add_simple_test(suite, "dir-refuses-null-location", 
+                                                                 test_dir_refuses_null_location);
+
+
+       tcase = torture_suite_add_tcase(suite, "dir");
+       torture_tcase_set_fixture(tcase, hive_setup_dir, NULL);
+       tcase_add_tests(tcase);
+
+       tcase = torture_suite_add_tcase(suite, "ldb");
+       torture_tcase_set_fixture(tcase, hive_setup_ldb, NULL);
+       tcase_add_tests(tcase);
+
+       tcase = torture_suite_add_tcase(suite, "regf");
+       torture_tcase_set_fixture(tcase, hive_setup_regf, NULL);
+       tcase_add_tests(tcase);
+
+       return suite;
+}
diff --git a/source/lib/registry/tests/registry.c b/source/lib/registry/tests/registry.c
new file mode 100644 (file)
index 0000000..851f74f
--- /dev/null
@@ -0,0 +1,486 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   local testing of registry library - registry backend
+
+   Copyright (C) Jelmer Vernooij 2005-2007
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "lib/registry/registry.h"
+#include "lib/cmdline/popt_common.h"
+#include "torture/torture.h"
+#include "librpc/gen_ndr/winreg.h"
+#include "system/filesys.h"
+
+NTSTATUS torture_temp_dir(struct torture_context *tctx, const char *prefix, 
+                                                                  const char **tempdir);
+
+/**
+ * Test obtaining a predefined key.
+ */
+static bool test_get_predefined(struct torture_context *tctx,
+                                                               const void *_data)
+{
+       const struct registry_context *rctx = _data;
+       struct registry_key *root;
+       WERROR error;
+
+       error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root);
+       torture_assert_werr_ok(tctx, error, 
+                                                  "getting predefined key failed");
+       return true;
+}
+
+/**
+ * Test creating a new subkey
+ */
+static bool test_create_subkey(struct torture_context *tctx,
+                                                     const void *_data)
+{
+       const struct registry_context *rctx = _data;
+       struct registry_key *root, *newkey;
+       WERROR error;
+
+       error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root);
+       torture_assert_werr_ok(tctx, error, 
+                                                  "getting predefined key failed");
+
+       error = reg_key_add_name(rctx, root, "Bad Bentheim", NULL, NULL, &newkey);
+       torture_assert_werr_ok(tctx, error, "Creating key return code");
+       torture_assert(tctx, newkey != NULL, "Creating new key");
+
+       return true;
+}
+
+/**
+ * Test creating a new nested subkey
+ */
+static bool test_create_nested_subkey(struct torture_context *tctx,
+                                                     const void *_data)
+{
+       const struct registry_context *rctx = _data;
+       struct registry_key *root, *newkey1, *newkey2;
+       WERROR error;
+
+       error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root);
+       torture_assert_werr_ok(tctx, error, 
+                                                  "getting predefined key failed");
+
+       error = reg_key_add_name(rctx, root, "Hamburg", NULL, NULL, 
+                                                        &newkey1);
+       torture_assert_werr_ok(tctx, error, "Creating key return code");
+       torture_assert(tctx, newkey2 != NULL, "Creating new key");
+
+       error = reg_key_add_name(rctx, root, "Hamburg\\Hamburg", NULL, NULL, 
+                                                        &newkey2);
+       torture_assert_werr_ok(tctx, error, "Creating key return code");
+       torture_assert(tctx, newkey2 != NULL, "Creating new key");
+
+       return true;
+}
+
+/**
+ * Test creating a new subkey
+ */
+static bool test_key_add_abs_top(struct torture_context *tctx,
+                                                        const void *_data)
+{
+       const struct registry_context *rctx = _data;
+       struct registry_key *root;
+       WERROR error;
+
+       error = reg_key_add_abs(tctx, rctx, "HKEY_CLASSES_ROOT", 0, NULL, &root);
+       torture_assert_werr_equal(tctx, error, WERR_ALREADY_EXISTS, "create top level");
+
+       return true;
+}
+
+/**
+ * Test creating a new subkey
+ */
+static bool test_key_add_abs(struct torture_context *tctx,
+                                                        const void *_data)
+{
+       WERROR error;
+       const struct registry_context *rctx = _data;
+       struct registry_key *root, *result1, *result2;
+
+       error = reg_key_add_abs(tctx, rctx,  "HKEY_CLASSES_ROOT\\bloe", 0, NULL, &result1);
+       torture_assert_werr_ok(tctx, error, "create lowest");
+
+       error = reg_key_add_abs(tctx, rctx,  "HKEY_CLASSES_ROOT\\bloe\\bla", 0, NULL, &result1);
+       torture_assert_werr_ok(tctx, error, "create nested");
+
+       error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root);
+       torture_assert_werr_ok(tctx, error, 
+                                                  "getting predefined key failed");
+
+       error = reg_open_key(tctx, root, "bloe", &result2);
+       torture_assert_werr_ok(tctx, error, "opening key");
+
+       error = reg_open_key(tctx, root, "bloe\\bla", &result2);
+       torture_assert_werr_ok(tctx, error, "opening key");
+
+       return true;
+}
+
+
+static bool test_del_key(struct torture_context *tctx, const void *_data)
+{
+       const struct registry_context *rctx = _data;
+       struct registry_key *root, *newkey;
+       WERROR error;
+
+       error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root);
+       torture_assert_werr_ok(tctx, error, 
+                                                  "getting predefined key failed");
+
+       error = reg_key_add_name(rctx, root, "Hamburg", NULL, NULL, &newkey);
+
+       torture_assert_werr_ok(tctx, error, "Creating key return code");
+       torture_assert(tctx, newkey != NULL, "Creating new key");
+
+       error = reg_key_del(root, "Hamburg");
+       torture_assert_werr_ok(tctx, error, "Delete key");
+
+       error = reg_key_del(root, "Hamburg");
+       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, 
+                                                         "Delete missing key");
+
+       return true;
+}
+
+/**
+ * Convenience function for opening the HKEY_CLASSES_ROOT hive and 
+ * creating a single key for testing purposes.
+ */
+static bool create_test_key(struct torture_context *tctx, 
+                                                       const struct registry_context *rctx,
+                                                       const char *name, 
+                                                       struct registry_key **root,
+                                                       struct registry_key **subkey)
+{
+       WERROR error;
+
+       error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, root);
+       torture_assert_werr_ok(tctx, error, 
+                                                  "getting predefined key failed");
+
+       error = reg_key_add_name(rctx, *root, name, NULL, NULL, subkey);
+       torture_assert_werr_ok(tctx, error, "Creating key return code");
+
+       return true;
+}
+
+
+static bool test_flush_key(struct torture_context *tctx, const void *_data)
+{
+       const struct registry_context *rctx = _data;
+       struct registry_key *root, *subkey;
+       WERROR error;
+
+       if (!create_test_key(tctx, rctx, "Munchen", &root, &subkey))
+               return false;
+
+       error = reg_key_flush(subkey);
+       torture_assert_werr_ok(tctx, error, "flush key");
+
+       return true;
+}
+
+static bool test_query_key(struct torture_context *tctx, const void *_data)
+{
+       const struct registry_context *rctx = _data;
+       struct registry_key *root, *subkey;
+       WERROR error;
+       NTTIME last_changed_time;
+       uint32_t num_subkeys, num_values;
+       const char *classname;
+
+       if (!create_test_key(tctx, rctx, "Munchen", &root, &subkey))
+               return false;
+
+       error = reg_key_get_info(tctx, subkey, &classname,
+                                                        &num_subkeys, &num_values,
+                                                        &last_changed_time);
+
+       torture_assert_werr_ok(tctx, error, "get info key");
+       torture_assert(tctx, classname == NULL, "classname");
+       torture_assert_int_equal(tctx, num_subkeys, 0, "num subkeys");
+       torture_assert_int_equal(tctx, num_values, 0, "num values");
+
+       return true;
+}
+
+static bool test_query_key_nums(struct torture_context *tctx, const void *_data)
+{
+       const struct registry_context *rctx = _data;
+       struct registry_key *root, *subkey1, *subkey2;
+       WERROR error;
+       uint32_t num_subkeys, num_values;
+       uint32_t data = 42;
+
+       if (!create_test_key(tctx, rctx, "Berlin", &root, &subkey1))
+               return false;
+
+       error = reg_key_add_name(rctx, subkey1, "Bentheim", NULL, NULL, &subkey2);
+       torture_assert_werr_ok(tctx, error, "Creating key return code");
+
+       error = reg_val_set(subkey1, "Answer", REG_DWORD, 
+                                               data_blob_talloc(tctx, &data, sizeof(data)));
+       torture_assert_werr_ok(tctx, error, "set value");
+
+       error = reg_key_get_info(tctx, subkey1, NULL, &num_subkeys,
+                                                        &num_values, NULL);
+
+       torture_assert_werr_ok(tctx, error, "get info key");
+       torture_assert_int_equal(tctx, num_subkeys, 1, "num subkeys");
+       torture_assert_int_equal(tctx, num_values, 1, "num values");
+
+       return true;
+}
+
+/**
+ * Test that the subkeys of a key can be enumerated, that 
+ * the returned parameters for get_subkey_by_index are optional and 
+ * that enumerating the parents of a non-top-level node works.
+ */
+static bool test_list_subkeys(struct torture_context *tctx, const void *_data)
+{
+       const struct registry_context *rctx = _data;
+       struct registry_key *subkey = NULL, *root;
+       WERROR error;
+       NTTIME last_mod_time;
+       const char *classname, *name;
+
+       if (!create_test_key(tctx, rctx, "Goettingen", &root, &subkey))
+               return false;
+
+       error = reg_key_get_subkey_by_index(tctx, root, 0, &name, &classname, 
+                                                               &last_mod_time);
+
+       torture_assert_werr_ok(tctx, error, "Enum keys return code");
+       torture_assert_str_equal(tctx, name, "Goettingen", "Enum keys data");
+
+
+       error = reg_key_get_subkey_by_index(tctx, root, 0, NULL, NULL, NULL);
+
+       torture_assert_werr_ok(tctx, error, "Enum keys with NULL arguments return code");
+
+       error = reg_key_get_subkey_by_index(tctx, root, 1, NULL, NULL, NULL);
+       
+       torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS, 
+                                                         "Invalid error for no more items");
+
+       error = reg_key_get_subkey_by_index(tctx, subkey, 0, NULL, NULL, NULL);
+       
+       torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS, 
+                                                         "Invalid error for no more items");
+
+       return true;
+}
+
+/**
+ * Test setting a value
+ */
+static bool test_set_value(struct torture_context *tctx, const void *_data)
+{
+       const struct registry_context *rctx = _data;
+       struct registry_key *subkey = NULL, *root;
+       WERROR error;
+       uint32_t data = 42;
+
+       if (!create_test_key(tctx, rctx, "Dusseldorf", &root, &subkey))
+               return false;
+
+       error = reg_val_set(subkey, "Answer", REG_DWORD, 
+                                               data_blob_talloc(tctx, &data, sizeof(data)));
+       torture_assert_werr_ok (tctx, error, "setting value");
+
+       return true;
+}
+
+/**
+ * Test getting a value
+ */
+static bool test_get_value(struct torture_context *tctx, const void *_data)
+{
+       const struct registry_context *rctx = _data;
+       struct registry_key *subkey = NULL, *root;
+       WERROR error;
+       DATA_BLOB data;
+       uint32_t value = 42;
+       uint32_t type;
+
+       if (!create_test_key(tctx, rctx, "Duisburg", &root, &subkey))
+               return false;
+
+       error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type, 
+                                                                         &data);
+       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, 
+                                                         "getting missing value");
+
+       error = reg_val_set(subkey, __FUNCTION__, REG_DWORD, 
+                                               data_blob_talloc(tctx, &value, 4));
+       torture_assert_werr_ok (tctx, error, "setting value");
+
+       error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type, 
+                                                                         &data);
+       torture_assert_werr_ok(tctx, error, "getting value");
+
+       torture_assert_int_equal(tctx, 4, data.length, "value length ok");
+       torture_assert(tctx, memcmp(data.data, &value, 4) == 0, "value content ok");
+       torture_assert_int_equal(tctx, REG_DWORD, type, "value type");
+
+       return true;
+}
+
+/**
+ * Test unsetting a value
+ */
+static bool test_del_value(struct torture_context *tctx, const void *_data)
+{
+       const struct registry_context *rctx = _data;
+       struct registry_key *subkey = NULL, *root;
+       WERROR error;
+       DATA_BLOB data;
+       uint32_t value = 42;
+       uint32_t type;
+
+       if (!create_test_key(tctx, rctx, "Duisburg", &root, &subkey))
+               return false;
+
+       error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type, 
+                                                                         &data);
+       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, 
+                                                         "getting missing value");
+
+       error = reg_val_set(subkey, __FUNCTION__, REG_DWORD, 
+                                               data_blob_talloc(tctx, &value, 4));
+       torture_assert_werr_ok (tctx, error, "setting value");
+
+       error = reg_del_value(subkey, __FUNCTION__);
+       torture_assert_werr_ok (tctx, error, "unsetting value");
+
+       error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type, &data);
+       torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, 
+                                                         "getting missing value");
+
+       return true;
+}
+
+/**
+ * Test listing values
+ */
+static bool test_list_values(struct torture_context *tctx, const void *_data)
+{
+       const struct registry_context *rctx = _data;
+       struct registry_key *subkey = NULL, *root;
+       WERROR error;
+       DATA_BLOB data;
+       uint32_t value = 42;
+       uint32_t type;
+       const char *name;
+
+       if (!create_test_key(tctx, rctx, "Bonn", &root, &subkey))
+               return false;
+
+       error = reg_val_set(subkey, "bar", REG_DWORD, 
+                                               data_blob_talloc(tctx, &value, 4));
+       torture_assert_werr_ok (tctx, error, "setting value");
+
+       error = reg_key_get_value_by_index(tctx, subkey, 0, &name, &type, &data);
+       torture_assert_werr_ok(tctx, error, "getting value");
+
+       torture_assert_str_equal(tctx, name, "bar", "value name");
+       torture_assert_int_equal(tctx, 4, data.length, "value length");
+       torture_assert(tctx, memcmp(data.data, &value, 4) == 0, "value content");
+       torture_assert_int_equal(tctx, REG_DWORD, type, "value type");
+
+       error = reg_key_get_value_by_index(tctx, subkey, 1, &name, &type, &data);
+       torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS, 
+                                                         "getting missing value");
+
+       return true;
+}
+
+static bool setup_local_registry(struct torture_context *tctx, void **data)
+{
+       struct registry_context *rctx;
+       WERROR error;
+       const char *tempdir;
+       NTSTATUS status;
+       struct hive_key *hive_key;
+
+       error = reg_open_local(tctx, &rctx, NULL, NULL);
+       if (!W_ERROR_IS_OK(error))
+               return false;
+
+       status = torture_temp_dir(tctx, "registry-local", &tempdir);
+       if (!NT_STATUS_IS_OK(status))
+               return false;
+
+       error = reg_open_ldb_file(tctx, 
+                                         talloc_asprintf(tctx, "%s/classes_root.ldb", tempdir),
+                                         NULL,
+                                         NULL,
+                                         &hive_key);
+       if (!W_ERROR_IS_OK(error))
+               return false;
+
+       error = reg_mount_hive(rctx, hive_key, HKEY_CLASSES_ROOT, NULL);
+       if (!W_ERROR_IS_OK(error))
+               return false;
+
+       *data = rctx;
+
+       return true;
+}
+
+static void tcase_add_tests(struct torture_tcase *tcase)
+{
+       torture_tcase_add_simple_test(tcase, "list_subkeys", test_list_subkeys);
+       torture_tcase_add_simple_test(tcase, "get_predefined_key",
+                                                                       test_get_predefined);
+       torture_tcase_add_simple_test(tcase, "create_key", test_create_subkey);
+       torture_tcase_add_simple_test(tcase, "create_key", 
+                                                                 test_create_nested_subkey);
+       torture_tcase_add_simple_test(tcase, "key_add_abs", test_key_add_abs);
+       torture_tcase_add_simple_test(tcase, "key_add_abs_top", test_key_add_abs_top);
+       torture_tcase_add_simple_test(tcase, "set_value", test_set_value);
+       torture_tcase_add_simple_test(tcase, "get_value", test_get_value);
+       torture_tcase_add_simple_test(tcase, "list_values", test_list_values);
+       torture_tcase_add_simple_test(tcase, "del_key", test_del_key);
+       torture_tcase_add_simple_test(tcase, "del_value", test_del_value);
+       torture_tcase_add_simple_test(tcase, "flush_key", test_flush_key);
+       torture_tcase_add_simple_test(tcase, "query_key", test_query_key);
+       torture_tcase_add_simple_test(tcase, "query_key_nums", test_query_key_nums);
+}
+
+struct torture_suite *torture_registry_registry(TALLOC_CTX *mem_ctx) 
+{
+       struct torture_tcase *tcase;
+       struct torture_suite *suite = torture_suite_create(mem_ctx, 
+                                                                                                          "REGISTRY");
+       
+       tcase = torture_suite_add_tcase(suite, "local");
+       torture_tcase_set_fixture(tcase, setup_local_registry, NULL);
+       tcase_add_tests(tcase);
+
+       return suite;
+}
diff --git a/source/lib/registry/tools/common.c b/source/lib/registry/tools/common.c
new file mode 100644 (file)
index 0000000..c8b0945
--- /dev/null
@@ -0,0 +1,75 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Popt routines specifically for registry
+
+   Copyright (C) Jelmer Vernooij 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "auth/credentials/credentials.h"
+#include "lib/registry/registry.h"
+
+struct registry_context *reg_common_open_remote(const char *remote, struct cli_credentials *creds)
+{
+       struct registry_context *h;
+       WERROR error;
+       
+       error = reg_open_remote(&h, NULL, creds, remote, NULL);
+
+       if (!W_ERROR_IS_OK(error)) {
+               fprintf(stderr, "Unable to open remote registry at %s:%s \n", remote, win_errstr(error));
+               return NULL;
+       }
+
+       return h;
+}
+
+struct registry_key *reg_common_open_file(const char *path, struct cli_credentials *creds)
+{
+       struct hive_key *hive_root;
+       struct registry_context *h;
+       WERROR error;
+
+       error = reg_open_hive(NULL, path, NULL, creds, &hive_root);
+
+       if(!W_ERROR_IS_OK(error)) {
+               fprintf(stderr, "Unable to open '%s': %s \n", path, win_errstr(error));
+               return NULL;
+       }
+
+       error = reg_open_local(NULL, &h, NULL, creds);
+       if (!W_ERROR_IS_OK(error)) {
+               fprintf(stderr, "Unable to initialize local registry: %s\n", win_errstr(error));
+               return NULL;
+       }
+
+       return reg_import_hive_key(h, hive_root, -1, NULL);
+}
+
+struct registry_context *reg_common_open_local(struct cli_credentials *creds)
+{
+       WERROR error;
+       struct registry_context *h;
+       
+       error = reg_open_samba(NULL, &h, NULL, creds);
+
+       if(!W_ERROR_IS_OK(error)) {
+               fprintf(stderr, "Unable to open local registry:%s \n", win_errstr(error));
+               return NULL;
+       }
+
+       return h;
+}
index 6eb8a78cafc0e1ad78ff55562bc8d8f425c9bb2e..8030457f5c72d2b930442fd045b87a3a3eaf62c8 100644 (file)
@@ -2,7 +2,8 @@
    Unix SMB/CIFS implementation.
    simple registry frontend
    
-   Copyright (C) Jelmer Vernooij 2004-2005
+   Copyright (C) Jelmer Vernooij 2004-2007
+   Copyright (C) Wilco Baan Hofman 2006
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include "lib/registry/registry.h"
 #include "lib/events/events.h"
 #include "lib/cmdline/popt_common.h"
+#include "lib/registry/tools/common.h"
 
-int main(int argc, char **argv)
+enum reg_backend { REG_UNKNOWN, REG_LOCAL, REG_REMOTE, REG_NULL };
+
+static struct registry_context *open_backend(poptContext pc, enum reg_backend backend, const char *remote_host)
+{
+       WERROR error;
+       struct registry_context *ctx;
+       
+       switch (backend) {
+       case REG_UNKNOWN:
+               poptPrintUsage(pc, stderr, 0);
+               return NULL;
+       case REG_LOCAL:
+               error = reg_open_samba(NULL, &ctx, NULL, cmdline_credentials);
+               break;
+       case REG_REMOTE:
+               error = reg_open_remote(&ctx, NULL, cmdline_credentials, remote_host, NULL);
+               break;
+       case REG_NULL:
+               error = reg_open_local(NULL, &ctx, NULL, cmdline_credentials);
+               break;
+       }
+
+       if (!W_ERROR_IS_OK(error)) {
+               fprintf(stderr, "Error: %s\n", win_errstr(error));
+               return NULL;
+       }
+
+       return ctx;
+}
+
+int main(int argc, const char **argv)
 {
        int opt;
        poptContext pc;
        char *outputfile = NULL;
+       enum reg_backend backend1 = REG_UNKNOWN, backend2 = REG_UNKNOWN;
+       const char *remote1 = NULL, *remote2 = NULL;
        struct registry_context *h1 = NULL, *h2 = NULL;
-       int from_null = 0;
        WERROR error;
-       struct reg_diff *diff;
        struct poptOption long_options[] = {
                POPT_AUTOHELP
-               {"output", 'o', POPT_ARG_STRING, &outputfile, 'o', "output file to use", NULL },
-               {"null", 'n', POPT_ARG_NONE, &from_null, 'n', "Diff from NULL", NULL },
-               {"remote", 'R', POPT_ARG_STRING, NULL, 0, "Connect to remote server" , NULL },
-               {"local", 'L', POPT_ARG_NONE, NULL, 0, "Open local registry", NULL },
+               {"output", 'o', POPT_ARG_STRING, &outputfile, 0, "output file to use", NULL },
+               {"null", 'n', POPT_ARG_NONE, NULL, 'n', "Diff from NULL", NULL },
+               {"remote", 'R', POPT_ARG_STRING, NULL, 'R', "Connect to remote server" , NULL },
+               {"local", 'L', POPT_ARG_NONE, NULL, 'L', "Open local registry", NULL },
                POPT_COMMON_SAMBA
                POPT_COMMON_CREDENTIALS
                POPT_COMMON_VERSION
                { NULL }
        };
+       TALLOC_CTX *ctx;
+       void *callback_data;
+       struct reg_diff_callbacks *callbacks;
 
-       registry_init();
+       ctx = talloc_init("regdiff");
 
-       pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
+       pc = poptGetContext(argv[0], argc, argv, long_options,0);
 
        while((opt = poptGetNextOpt(pc)) != -1) {
                error = WERR_OK;
                switch(opt)     {
                case 'L':
-                       if (!h1 && !from_null) error = reg_open_local(NULL, &h1, NULL, cmdline_credentials);
-                       else if (!h2) error = reg_open_local(NULL, &h2, NULL, cmdline_credentials);
+                       if (backend1 == REG_UNKNOWN)
+                               backend1 = REG_LOCAL;
+                       else if (backend2 == REG_UNKNOWN)
+                               backend2 = REG_LOCAL;
+                       break;
+               case 'n':
+                       if (backend1 == REG_UNKNOWN)
+                               backend1 = REG_NULL;
+                       else if (backend2 == REG_UNKNOWN)
+                               backend2 = REG_NULL;
                        break;
                case 'R':
-                       if (!h1 && !from_null) 
-                               error = reg_open_remote(&h1, NULL, cmdline_credentials, 
-                                                       poptGetOptArg(pc), NULL);
-                       else if (!h2) error = reg_open_remote(&h2, NULL, cmdline_credentials, 
-                                                             poptGetOptArg(pc), NULL);
+                       if (backend1 == REG_UNKNOWN) {
+                               backend1 = REG_REMOTE;
+                               remote1 = poptGetOptArg(pc);
+                       } else if (backend2 == REG_UNKNOWN) {
+                               backend2 = REG_REMOTE;
+                               remote2 = poptGetOptArg(pc);
+                       }
                        break;
                }
 
-               if (!W_ERROR_IS_OK(error)) {
-                       fprintf(stderr, "Error: %s\n", win_errstr(error));
-                       return 1;
-               }
        }
 
+       h1 = open_backend(pc, backend1, remote1);
+       if (h1 == NULL)
+               return 1;
+
+       h2 = open_backend(pc, backend2, remote2);
+       if (h2 == NULL)
+               return 1;
+
        poptFreeContext(pc);
 
-       diff = reg_generate_diff(NULL, h1, h2);
-       if (!diff) {
-               fprintf(stderr, "Unable to generate diff between keys\n");
+       error = reg_dotreg_diff_save(ctx, outputfile, &callbacks, &callback_data);
+       if (!W_ERROR_IS_OK(error)) {
+               fprintf(stderr, "Problem saving registry diff to '%s': %s\n", outputfile, win_errstr(error));
                return -1;
        }
 
-       reg_diff_save(diff, outputfile);
+       error = reg_generate_diff(h1, h2, callbacks, callback_data);
+       if (!W_ERROR_IS_OK(error)) {
+               fprintf(stderr, "Unable to generate diff between keys: %s\n", win_errstr(error));
+               return -1;
+       }
 
        return 0;
 }
index 83ad5575ef051cb7f1c6b44ff228d8400a99808b..1e6d15a7af9716678169e7e13e6163f1bc44504a 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/CIFS implementation.
    simple registry frontend
    
-   Copyright (C) 2004-2005 Jelmer Vernooij, jelmer@samba.org
+   Copyright (C) 2004-2007 Jelmer Vernooij, jelmer@samba.org
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -22,6 +22,8 @@
 #include "lib/events/events.h"
 #include "lib/registry/registry.h"
 #include "lib/cmdline/popt_common.h"
+#include "lib/registry/tools/common.h"
+#include "lib/registry/patchfile.h"
 
 int main(int argc, char **argv)
 {
@@ -29,12 +31,12 @@ int main(int argc, char **argv)
        poptContext pc;
        const char *patch;
        struct registry_context *h;
+       const char *file = NULL;
        const char *remote = NULL;
-       struct reg_diff *diff;
-       WERROR error;
        struct poptOption long_options[] = {
                POPT_AUTOHELP
                {"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL},
+               {"file", 'F', POPT_ARG_STRING, &file, 0, "file path", NULL },
                POPT_COMMON_SAMBA
                POPT_COMMON_CREDENTIALS
                { NULL }
@@ -45,29 +47,24 @@ int main(int argc, char **argv)
        while((opt = poptGetNextOpt(pc)) != -1) {
        }
 
-       registry_init();
-
        if (remote) {
-               error = reg_open_remote (&h, NULL, cmdline_credentials, remote, NULL);
+               h = reg_common_open_remote (remote, cmdline_credentials);
        } else {
-               error = reg_open_local (NULL, &h, NULL, cmdline_credentials);
+               h = reg_common_open_local (cmdline_credentials);
        }
-
-       if (W_ERROR_IS_OK(error)) {
-               fprintf(stderr, "Error: %s\n", win_errstr(error));
+       
+       if (h == NULL)
                return 1;
-       }
                
        patch = poptGetArg(pc);
-       poptFreeContext(pc);
-
-       diff = reg_diff_load(NULL, patch);
-       if (!diff) {
-               fprintf(stderr, "Unable to load registry patch from `%s'\n", patch);
+       if (patch == NULL) {
+               poptPrintUsage(pc, stderr, 0);
                return 1;
        }
 
-       reg_diff_apply(diff, h);
+       poptFreeContext(pc);
+
+       reg_diff_apply(patch, h);
 
        return 0;
 }
index f431c81bf8dc19fb8f6a4dc9987aff6808d55095..0887bc91f3d0304f3147a34d0c6ae1bc62ecab3d 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/CIFS implementation.
    simple registry frontend
    
-   Copyright (C) Jelmer Vernooij 2004
+   Copyright (C) Jelmer Vernooij 2004-2007
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include "system/time.h"
 #include "lib/smbreadline/smbreadline.h"
 #include "librpc/gen_ndr/ndr_security.h"
+#include "lib/registry/tools/common.h"
 
-/* 
+struct regshell_context {
+       struct registry_context *registry;
+       const char *path;
+       struct registry_key *current;
+};
+
+/* *
  * ck/cd - change key
  * ls - list values/keys
  * rmval/rm - remove value
  * exit
  */
 
-static struct registry_key *cmd_info(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_info(struct regshell_context *ctx, int argc, char **argv)
 {
        struct security_descriptor *sec_desc = NULL;
        time_t last_mod;
        WERROR error;
+       const char *classname;
+       NTTIME last_change;
+
+       error = reg_key_get_info(ctx, ctx->current, &classname, NULL, NULL, &last_change);
+       if (!W_ERROR_IS_OK(error)) {
+               printf("Error getting key info: %s\n", win_errstr(error));
+               return error;
+       }
+
        
-       printf("Name: %s\n", cur->name);
-       printf("Full path: %s\n", cur->path);
-       printf("Key Class: %s\n", cur->class_name);
-       last_mod = nt_time_to_unix(cur->last_mod);
+       printf("Name: %s\n", strchr(ctx->path, '\\')?strrchr(ctx->path, '\\')+1: 
+                  ctx->path);
+       printf("Full path: %s\n", ctx->path);
+       printf("Key Class: %s\n", classname);
+       last_mod = nt_time_to_unix(last_change);
        printf("Time Last Modified: %s\n", ctime(&last_mod));
 
-       error = reg_get_sec_desc(mem_ctx, cur, &sec_desc);
+       error = reg_get_sec_desc(ctx, ctx->current, &sec_desc);
        if (!W_ERROR_IS_OK(error)) {
                printf("Error getting security descriptor\n");
-       } else {
-               ndr_print_debug((ndr_print_fn_t)ndr_print_security_descriptor, "Security", sec_desc);
-       }
+               return error;
+       } 
+       ndr_print_debug((ndr_print_fn_t)ndr_print_security_descriptor, "Security", sec_desc);
        talloc_free(sec_desc);
-       return cur;
+
+       return WERR_OK;
 }
 
-static struct registry_key *cmd_predef(TALLOC_CTX *mem_ctx, struct registry_context *ctx, struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_predef(struct regshell_context *ctx, int argc, char **argv)
 {
        struct registry_key *ret = NULL;
        if (argc < 2) {
@@ -70,165 +88,195 @@ static struct registry_key *cmd_predef(TALLOC_CTX *mem_ctx, struct registry_cont
        } else if (!ctx) {
                fprintf(stderr, "No full registry loaded, no predefined keys defined\n");
        } else {
-               WERROR error = reg_get_predefined_key_by_name(ctx, argv[1], &ret);
+               WERROR error = reg_get_predefined_key_by_name(ctx->registry, argv[1], &ret);
 
                if (!W_ERROR_IS_OK(error)) {
                        fprintf(stderr, "Error opening predefined key %s: %s\n", argv[1], win_errstr(error));
-                       ret = NULL;
+                       return error;
                }
        }
-       return ret;
+
+       return WERR_OK;
 }
 
-static struct registry_key *cmd_pwd(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_pwd(struct regshell_context *ctx,
+                                                                       int argc, char **argv)
 {
-       printf("%s\n", cur->path);
-       return cur;
+       printf("%s\n", ctx->path);
+       return WERR_OK;
 }
 
-static struct registry_key *cmd_set(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_set(struct regshell_context *ctx, int argc, char **argv)
 {
        struct registry_value val;
        WERROR error;
 
        if (argc < 4) {
                fprintf(stderr, "Usage: set value-name type value\n");
-               return cur;
+               return WERR_INVALID_PARAM;
        } 
 
-       if (!reg_string_to_val(mem_ctx, argv[2], argv[3], &val.data_type, &val.data)) {
+       if (!reg_string_to_val(ctx, argv[2], argv[3], &val.data_type, 
+                                                  &val.data)) {
                fprintf(stderr, "Unable to interpret data\n");
-               return cur;
+               return WERR_INVALID_PARAM;
        }
 
-       error = reg_val_set(cur, argv[1], val.data_type, val.data);
+       error = reg_val_set(ctx->current, argv[1], val.data_type, val.data);
        if (!W_ERROR_IS_OK(error)) {
                fprintf(stderr, "Error setting value: %s\n", win_errstr(error));
-               return NULL;
+               return error;
        }
-       return cur;
+
+       return WERR_OK;
 }
 
-static struct registry_key *cmd_ck(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_ck(struct regshell_context *ctx, int argc, char **argv)
 { 
        struct registry_key *new = NULL;
        WERROR error;
+
        if(argc < 2) {
-               new = cur;
+               new = ctx->current;
        } else {
-               error = reg_open_key(mem_ctx, cur, argv[1], &new);
+               error = reg_open_key(ctx->registry, ctx->current, argv[1], &new);
                if(!W_ERROR_IS_OK(error)) {
                        DEBUG(0, ("Error opening specified key: %s\n", win_errstr(error)));
-                       return NULL;
+                       return error;
                }
        } 
 
-       printf("Current path is: %s\n", new->path);
+       ctx->path = talloc_asprintf(ctx, "%s\\%s", ctx->path, argv[1]);
+       printf("Current path is: %s\n", ctx->path);
+       ctx->current = new;
        
-       return new;
+       return WERR_OK;
 }
 
-static struct registry_key *cmd_print(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_print(struct regshell_context *ctx, int argc, char **argv)
 {
-       struct registry_value *value;
+       uint32_t value_type;
+       DATA_BLOB value_data;
        WERROR error;
 
        if (argc != 2) {
                fprintf(stderr, "Usage: print <valuename>");
-               return NULL;
+               return WERR_INVALID_PARAM;
        }
        
-       error = reg_key_get_value_by_name(mem_ctx, cur, argv[1], &value);
+       error = reg_key_get_value_by_name(ctx, ctx->current, argv[1], 
+                                                                         &value_type, &value_data);
        if (!W_ERROR_IS_OK(error)) {
                fprintf(stderr, "No such value '%s'\n", argv[1]);
-               return NULL;
+               return error;
        }
 
-       printf("%s\n%s\n", str_regtype(value->data_type), reg_val_data_string(mem_ctx, value->data_type, &value->data));
-       return NULL;
+       printf("%s\n%s\n", str_regtype(value_type), 
+                  reg_val_data_string(ctx, value_type, value_data));
+
+       return WERR_OK;
 }
 
-static struct registry_key *cmd_ls(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_ls(struct regshell_context *ctx, int argc, char **argv)
 {
        int i;
        WERROR error;
        struct registry_value *value;
-       struct registry_key *sub;
-       for(i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(mem_ctx, cur, i, &sub)); i++) {
-               printf("K %s\n", sub->name);
+       uint32_t data_type;
+       DATA_BLOB data;
+       const char *name;
+
+       for (i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(ctx, ctx->current, i, &name, NULL, NULL)); i++) {
+               printf("K %s\n", name);
        }
 
-       if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
+       if (!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
                DEBUG(0, ("Error occured while browsing thru keys: %s\n", win_errstr(error)));
        }
 
-       for(i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(mem_ctx, cur, i, &value)); i++) {
-               printf("V \"%s\" %s %s\n", value->name, str_regtype(value->data_type), reg_val_data_string(mem_ctx, value->data_type, &value->data));
+       for (i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(ctx, ctx->current, i, &name, &data_type, &data)); i++) {
+               printf("V \"%s\" %s %s\n", value->name, str_regtype(data_type), 
+                          reg_val_data_string(ctx, data_type, data));
        }
        
-       return NULL
+       return WERR_OK
 }
-static struct registry_key *cmd_mkkey(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_mkkey(struct regshell_context *ctx, int argc, char **argv)
 { 
        struct registry_key *tmp;
+       WERROR error;
+
        if(argc < 2) {
                fprintf(stderr, "Usage: mkkey <keyname>\n");
-               return NULL;
+               return WERR_INVALID_PARAM;
        }
+
+       error = reg_key_add_name(ctx, ctx->current, argv[1], 0, NULL, &tmp);
        
-       if(!W_ERROR_IS_OK(reg_key_add_name(mem_ctx, cur, argv[1], 0, NULL, &tmp))) {
+       if (!W_ERROR_IS_OK(error)) {
                fprintf(stderr, "Error adding new subkey '%s'\n", argv[1]);
-               return NULL;
+               return error;
        }
 
-       return NULL
+       return WERR_OK
 }
 
-static struct registry_key *cmd_rmkey(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_rmkey(struct regshell_context *ctx,
+                                                                         int argc, char **argv)
 { 
+       WERROR error;
+
        if(argc < 2) {
                fprintf(stderr, "Usage: rmkey <name>\n");
-               return NULL;
+               return WERR_INVALID_PARAM;
        }
 
-       if(!W_ERROR_IS_OK(reg_key_del(cur, argv[1]))) {
+       error = reg_key_del(ctx->current, argv[1]);
+       if(!W_ERROR_IS_OK(error)) {
                fprintf(stderr, "Error deleting '%s'\n", argv[1]);
+               return error;
        } else {
                fprintf(stderr, "Successfully deleted '%s'\n", argv[1]);
        }
        
-       return NULL; 
+       return WERR_OK;
 }
 
-static struct registry_key *cmd_rmval(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_rmval(struct regshell_context *ctx, int argc, char **argv)
 { 
+       WERROR error;
+
        if(argc < 2) {
                fprintf(stderr, "Usage: rmval <valuename>\n");
-               return NULL;
+               return WERR_INVALID_PARAM;
        }
 
-       if(!W_ERROR_IS_OK(reg_del_value(cur, argv[1]))) {
+       error = reg_del_value(ctx->current, argv[1]);
+       if(!W_ERROR_IS_OK(error)) {
                fprintf(stderr, "Error deleting value '%s'\n", argv[1]);
+               return error;
        } else {
                fprintf(stderr, "Successfully deleted value '%s'\n", argv[1]);
        }
 
-       return NULL
+       return WERR_OK
 }
 
-static struct registry_key *cmd_exit(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_exit(struct regshell_context *ctx,
+                                                                        int argc, char **argv)
 {
        exit(0);
-       return NULL; 
+       return WERR_OK;
 }
 
-static struct registry_key *cmd_help(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *, int, char **);
+static WERROR cmd_help(struct regshell_context *ctx, int, char **);
 
 static struct {
        const char *name;
        const char *alias;
        const char *help;
-       struct registry_key *(*handle)(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *, int argc, char **argv);
+       WERROR (*handle)(struct regshell_context *ctx,
+                                                                  int argc, char **argv);
 } regshell_cmds[] = {
        {"ck", "cd", "Change current key", cmd_ck },
        {"info", "i", "Show detailed information of a key", cmd_info },
@@ -245,17 +293,19 @@ static struct {
        {NULL }
 };
 
-static struct registry_key *cmd_help(TALLOC_CTX *mem_ctx, struct registry_context *ctx, struct registry_key *cur, int argc, char **argv)
+static WERROR cmd_help(struct regshell_context *ctx,
+                                                                        int argc, char **argv)
 {
        int i;
        printf("Available commands:\n");
        for(i = 0; regshell_cmds[i].name; i++) {
                printf("%s - %s\n", regshell_cmds[i].name, regshell_cmds[i].help);
        }
-       return NULL;
+       return WERR_OK;
 } 
 
-static struct registry_key *process_cmd(TALLOC_CTX *mem_ctx, struct registry_context *ctx, struct registry_key *k, char *line)
+static WERROR process_cmd(struct regshell_context *ctx,
+                                                                               char *line)
 {
        int argc;
        char **argv = NULL;
@@ -263,19 +313,19 @@ static struct registry_key *process_cmd(TALLOC_CTX *mem_ctx, struct registry_con
 
        if ((ret = poptParseArgvString(line, &argc, (const char ***) &argv)) != 0) {
                fprintf(stderr, "regshell: %s\n", poptStrerror(ret));
-               return k;
+               return WERR_INVALID_PARAM;
        }
 
        for(i = 0; regshell_cmds[i].name; i++) {
                if(!strcmp(regshell_cmds[i].name, argv[0]) || 
                   (regshell_cmds[i].alias && !strcmp(regshell_cmds[i].alias, argv[0]))) {
-                       return regshell_cmds[i].handle(mem_ctx, ctx, k, argc, argv);
+                       return regshell_cmds[i].handle(ctx, argc, argv);
                }
        }
 
        fprintf(stderr, "No such command '%s'\n", argv[0]);
        
-       return k;
+       return WERR_INVALID_PARAM;
 }
 
 #define MAX_COMPLETIONS 100
@@ -333,7 +383,7 @@ cleanup:
 static char **reg_complete_key(const char *text, int start, int end)
 {
        struct registry_key *base;
-       struct registry_key *subkey;
+       const char *subkeyname;
        int i, j = 1;
        int samelen = 0;
        int len;
@@ -351,10 +401,11 @@ static char **reg_complete_key(const char *text, int start, int end)
 
        len = strlen(text);
        for(i = 0; j < MAX_COMPLETIONS-1; i++) {
-               status = reg_key_get_subkey_by_index(mem_ctx, base, i, &subkey);
+               status = reg_key_get_subkey_by_index(mem_ctx, base, i, &subkeyname, 
+                                                                                        NULL, NULL);
                if(W_ERROR_IS_OK(status)) {
-                       if(!strncmp(text, subkey->name, len)) {
-                               matches[j] = strdup(subkey->name);
+                       if(!strncmp(text, subkeyname, len)) {
+                               matches[j] = strdup(subkeyname);
                                j++;
 
                                if (j == 1)
@@ -381,7 +432,8 @@ static char **reg_complete_key(const char *text, int start, int end)
        if (j == 2) { /* Exact match */
                asprintf(&matches[0], "%s%s", base_n, matches[1]);
        } else {
-               asprintf(&matches[0], "%s%s", base_n, talloc_strndup(mem_ctx, matches[1], samelen));
+               asprintf(&matches[0], "%s%s", base_n, 
+                               talloc_strndup(mem_ctx, matches[1], samelen));
        }               
        talloc_free(mem_ctx);
 
@@ -400,19 +452,17 @@ static char **reg_completion(const char *text, int start, int end)
        }
 }
 
- int main(int argc, char **argv)
+int main(int argc, char **argv)
 {
        int opt;
-       const char *backend = NULL;
-       struct registry_key *curkey = NULL;
+       const char *file = NULL;
        poptContext pc;
-       WERROR error;
-       TALLOC_CTX *mem_ctx = talloc_init("cmd");
        const char *remote = NULL;
-       struct registry_context *h = NULL;
+       struct regshell_context *ctx;
+       bool ret = true;
        struct poptOption long_options[] = {
                POPT_AUTOHELP
-               {"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL},
+               {"file", 'F', POPT_ARG_STRING, &file, 0, "open hive file", NULL },
                {"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL},
                POPT_COMMON_SAMBA
                POPT_COMMON_CREDENTIALS
@@ -425,64 +475,62 @@ static char **reg_completion(const char *text, int start, int end)
        while((opt = poptGetNextOpt(pc)) != -1) {
        }
 
-       registry_init();
+       ctx = talloc_zero(NULL, struct regshell_context);
 
-       if (remote) {
-               error = reg_open_remote (&h, NULL, cmdline_credentials, remote, NULL); 
-       } else if (backend) {
-               error = reg_open_hive(NULL, backend, poptGetArg(pc), NULL, cmdline_credentials, &curkey);
+       if (remote != NULL) {
+               ctx->registry = reg_common_open_remote(remote, cmdline_credentials);
+       } else if (file != NULL) {
+               ctx->current = reg_common_open_file(file, cmdline_credentials);
+               ctx->registry = ctx->current->context;
+               ctx->path = talloc_strdup(ctx, "");
        } else {
-               error = reg_open_local(NULL, &h, NULL, cmdline_credentials);
+               ctx->registry = reg_common_open_local(cmdline_credentials);
        }
 
-       if(!W_ERROR_IS_OK(error)) {
-               fprintf(stderr, "Unable to open registry\n");
+       if (ctx->registry == NULL)
                return 1;
-       }
 
-       if (h) {
+       if (ctx->current == NULL) {
                int i;
 
                for (i = 0; reg_predefined_keys[i].handle; i++) {
                        WERROR err;
-                       err = reg_get_predefined_key(h, reg_predefined_keys[i].handle, &curkey);
+                       err = reg_get_predefined_key(ctx->registry, 
+                                                                                reg_predefined_keys[i].handle, 
+                                                                                &ctx->current);
                        if (W_ERROR_IS_OK(err)) {
+                               ctx->path = talloc_strdup(ctx, reg_predefined_keys[i].name);
                                break;
                        } else {
-                               curkey = NULL;
+                               ctx->current = NULL;
                        }
                }
        }
 
-       if (!curkey) {
+       if (ctx->current == NULL) {
                fprintf(stderr, "Unable to access any of the predefined keys\n");
                return -1;
        }
        
        poptFreeContext(pc);
        
-       while(True) {
+       while (true) {
                char *line, *prompt;
                
-               if(curkey->hive->root->name) {
-                       asprintf(&prompt, "%s:%s> ", curkey->hive->root->name, curkey->path);
-               } else {
-                       asprintf(&prompt, "%s> ", curkey->path);
-               }
+               asprintf(&prompt, "%s> ", ctx->path);
                
-               current_key = curkey;           /* No way to pass a void * pointer 
-                                                                          via readline :-( */
+               current_key = ctx->current;             /* No way to pass a void * pointer 
+                                                                                          via readline :-( */
                line = smb_readline(prompt, NULL, reg_completion);
 
-               if(!line)
+               if (line == NULL)
                        break;
 
-               if(line[0] != '\n') {
-                       struct registry_key *new = process_cmd(mem_ctx, h, curkey, line);
-                       if(new)curkey = new;
+               if (line[0] != '\n') {
+                       ret = W_ERROR_IS_OK(process_cmd(ctx, line));
                }
        }
-       talloc_free(mem_ctx);
+       talloc_free(ctx);
 
-       return 0;
+       return (ret?0:1);
 }
index d026d2824f55a37a9ca1908bfc7841737e82bba4..8d2460a93efd9f0300ec96c5a45e8c385fb83270 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/CIFS implementation.
    simple registry frontend
    
-   Copyright (C) Jelmer Vernooij 2004
+   Copyright (C) Jelmer Vernooij 2004-2007
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 #include "includes.h"
 #include "lib/registry/registry.h"
+#include "lib/registry/tools/common.h"
 #include "lib/events/events.h"
 #include "lib/cmdline/popt_common.h"
 
-static void print_tree(int l, struct registry_key *p, int fullpath, int novals)
+/**
+ * Print a registry key recursively 
+ * 
+ * @param level Level at which to print
+ * @param p Key to print
+ * @param fullpath Whether the full pat hshould be printed or just the last bit
+ * @param novals Whether values should not be printed
+ */
+static void print_tree(int level, struct registry_key *p, 
+                                          const char *name,
+                                          bool fullpath, bool novals)
 {
        struct registry_key *subkey;
-       struct registry_value *value;
+       const char *valuename;
+       const char *keyname;
+       uint32_t value_type;
+       DATA_BLOB value_data;
        struct security_descriptor *sec_desc;
        WERROR error;
        int i;
        TALLOC_CTX *mem_ctx;
 
-       for(i = 0; i < l; i++) putchar(' ');
-       
-       /* Hive name */
-       if(p->hive->root == p) {
-               if(p->hive->root->name) printf("%s\n", p->hive->root->name); else printf("<No Name>\n");
-       } else {
-               if(!p->name) printf("<No Name>\n");
-               if(fullpath) printf("%s\n", p->path);
-               else printf("%s\n", p->name?p->name:"(NULL)");
-       }
+       for(i = 0; i < level; i++) putchar(' '); puts(name);
 
        mem_ctx = talloc_init("print_tree");
-       for(i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(mem_ctx, p, i, &subkey)); i++) {
-               print_tree(l+1, subkey, fullpath, novals);
+       for (i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(mem_ctx, p, i, &keyname, NULL, NULL)); i++) {
+               SMB_ASSERT(strlen(keyname) > 0);
+               if (!W_ERROR_IS_OK(reg_open_key(mem_ctx, p, keyname, &subkey))) 
+                       continue;
+               print_tree(level+1, subkey, (fullpath && strlen(name))?
+                                               talloc_asprintf(mem_ctx, "%s\\%s", name, keyname):
+                                               keyname, fullpath, novals);
        }
        talloc_free(mem_ctx);
 
        if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
-               DEBUG(0, ("Error occured while fetching subkeys for '%s': %s\n", p->path, win_errstr(error)));
+               DEBUG(0, ("Error occured while fetching subkeys for '%s': %s\n", 
+                                 name, win_errstr(error)));
        }
 
-       if(!novals) {
+       if (!novals) {
                mem_ctx = talloc_init("print_tree");
-               for(i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(mem_ctx, p, i, &value)); i++) {
+               for(i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(mem_ctx, 
+                                               p, i, &valuename, &value_type, &value_data)); i++) {
                        int j;
                        char *desc;
-                       for(j = 0; j < l+1; j++) putchar(' ');
-                       desc = reg_val_description(mem_ctx, value);
+                       for(j = 0; j < level+1; j++) putchar(' ');
+                       desc = reg_val_description(mem_ctx, valuename, value_type, 
+                                                                          value_data);
                        printf("%s\n", desc);
                }
                talloc_free(mem_ctx);
 
                if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
-                       DEBUG(0, ("Error occured while fetching values for '%s': %s\n", p->path, win_errstr(error)));
+                       DEBUG(0, ("Error occured while fetching values for '%s': %s\n", 
+                                         name, win_errstr(error)));
                }
        }
 
@@ -79,21 +93,22 @@ static void print_tree(int l, struct registry_key *p, int fullpath, int novals)
 int main(int argc, char **argv)
 {
        int opt, i;
-       const char *backend = NULL;
+       const char *file = NULL;
        const char *remote = NULL;
        poptContext pc;
        struct registry_context *h = NULL;
-       struct registry_key *root = NULL;
+       struct registry_key *start_key = NULL;
        WERROR error;
-       int fullpath = 0, no_values = 0;
+       bool fullpath = false, no_values = false;
        struct poptOption long_options[] = {
                POPT_AUTOHELP
-               {"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL},
-               {"fullpath", 'f', POPT_ARG_NONE, &fullpath, 0, "show full paths", NULL},
+               {"file", 'F', POPT_ARG_STRING, &file, 0, "file path", NULL },
                {"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL },
+               {"fullpath", 'f', POPT_ARG_NONE, &fullpath, 0, "show full paths", NULL},
                {"no-values", 'V', POPT_ARG_NONE, &no_values, 0, "don't show values", NULL},
                POPT_COMMON_SAMBA       
                POPT_COMMON_CREDENTIALS 
+               POPT_COMMON_VERSION
                { NULL }
        };
 
@@ -102,48 +117,35 @@ int main(int argc, char **argv)
        while((opt = poptGetNextOpt(pc)) != -1) {
        }
 
-       registry_init();
-
-       if (remote) {
-               error = reg_open_remote(&h, NULL, cmdline_credentials, remote, NULL);
-
-               if(!W_ERROR_IS_OK(error)) {
-                       fprintf(stderr, "Unable to open remote registry at %s:%s \n", remote, win_errstr(error));
-                       return 1;
-               }
-
-       } else if (backend) {
-           error = reg_open_hive(NULL, backend, poptGetArg(pc), NULL, cmdline_credentials, &root);
-       
-               if(!W_ERROR_IS_OK(error)) {
-                       fprintf(stderr, "Unable to open '%s' with backend '%s':%s \n", poptGetArg(pc), backend, win_errstr(error));
-                       return 1;
-               }
+       if (remote != NULL) {
+               h = reg_common_open_remote(remote, cmdline_credentials);
+       } else if (file != NULL) {
+               start_key = reg_common_open_file(file, cmdline_credentials);
        } else {
-               error = reg_open_local (NULL, &h, NULL, cmdline_credentials);
-
-               if(!W_ERROR_IS_OK(error)) {
-                       fprintf(stderr, "Unable to open local registry:%s \n", win_errstr(error));
-                       return 1;
-               }
-
+               h = reg_common_open_local(cmdline_credentials);
        }
 
+       if (h == NULL && start_key == NULL)
+               return 1;
+
        poptFreeContext(pc);
 
        error = WERR_OK;
        
-       if (root != NULL) {
-               print_tree(0, root, fullpath, no_values);
+       if (start_key != NULL) {
+               print_tree(0, start_key, "", fullpath, no_values);
        } else {
                for(i = 0; reg_predefined_keys[i].handle; i++) {
-                       error = reg_get_predefined_key(h, reg_predefined_keys[i].handle, &root);
+                       error = reg_get_predefined_key(h, reg_predefined_keys[i].handle, 
+                                                                                  &start_key);
                        if (!W_ERROR_IS_OK(error)) {
-                               fprintf(stderr, "Skipping %s\n", reg_predefined_keys[i].name);
+                               fprintf(stderr, "Skipping %s: %s\n", reg_predefined_keys[i].name, 
+                                               win_errstr(error));
                                continue;
                        }
-                       SMB_ASSERT(root);
-                       print_tree(0, root, fullpath, no_values);
+                       SMB_ASSERT(start_key != NULL);
+                       print_tree(0, start_key, reg_predefined_keys[i].name, fullpath, 
+                                          no_values);
                }
        }
 
similarity index 74%
rename from source/lib/registry/common/reg_util.c
rename to source/lib/registry/util.c
index 696336161eca4a36ebe1998f10b88ea6b7846e25..47716f89cf618bb58d6bb4ef6441374917d448bb 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    Unix SMB/CIFS implementation.
    Transparent registry backend handling
-   Copyright (C) Jelmer Vernooij                       2003-2004.
+   Copyright (C) Jelmer Vernooij                       2003-2007.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -50,27 +50,30 @@ _PUBLIC_ const char *str_regtype(int type)
        return "Unknown";
 }
 
-_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type, DATA_BLOB *data)
+_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type, 
+                                                                  const DATA_BLOB data)
 { 
   char *ret = NULL;
 
-  if(data->length == 0) return talloc_strdup(mem_ctx, "");
+  if (data.length == 0) 
+         return talloc_strdup(mem_ctx, "");
 
   switch (type) {
   case REG_EXPAND_SZ:
   case REG_SZ:
-      convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, data->data, data->length, (void **)&ret);
+      convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, data.data, data.length, 
+                                                       (void **)&ret);
          return ret;
 
   case REG_BINARY:
-         ret = data_blob_hex_string(mem_ctx, data);
+         ret = data_blob_hex_string(mem_ctx, &data);
          return ret;
 
   case REG_DWORD:
-         if (*(int *)data->data == 0)
+         if (*(int *)data.data == 0)
                  return talloc_strdup(mem_ctx, "0");
 
-         return talloc_asprintf(mem_ctx, "0x%x", *(int *)data->data);
+         return talloc_asprintf(mem_ctx, "0x%x", *(int *)data.data);
 
   case REG_MULTI_SZ:
        /* FIXME */
@@ -84,9 +87,13 @@ _PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type, DATA_BLOB
 }
 
 /** Generate a string that describes a registry value */
-_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, struct registry_value *val) 
+_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, const char *name, 
+                                                                  uint32_t data_type,
+                                                                  const DATA_BLOB data)
 {
-       return talloc_asprintf(mem_ctx, "%s = %s : %s", val->name?val->name:"<No Name>", str_regtype(val->data_type), reg_val_data_string(mem_ctx, val->data_type, &val->data));
+       return talloc_asprintf(mem_ctx, "%s = %s : %s", name?name:"<No Name>", 
+                                                  str_regtype(data_type), 
+                                       reg_val_data_string(mem_ctx, data_type, data));
 }
 
 _PUBLIC_ BOOL reg_string_to_val(TALLOC_CTX *mem_ctx, const char *type_str, const char *data_str, uint32_t *type, DATA_BLOB *data)
@@ -136,29 +143,6 @@ _PUBLIC_ BOOL reg_string_to_val(TALLOC_CTX *mem_ctx, const char *type_str, const
        return True;
 }
 
-/**
- * Replace all \'s with /'s
- */
-char *reg_path_win2unix(char *path) 
-{
-       int i;
-       for(i = 0; path[i]; i++) {
-               if(path[i] == '\\') path[i] = '/';
-       }
-       return path;
-}
-/**
- * Replace all /'s with \'s
- */
-char *reg_path_unix2win(char *path) 
-{
-       int i;
-       for(i = 0; path[i]; i++) {
-               if(path[i] == '/') path[i] = '\\';
-       }
-       return path;
-}
-
 /** Open a key by name (including the predefined key name!) */
 WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, const char *name, struct registry_key **result)
 {
@@ -167,14 +151,16 @@ WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, co
        int predeflength;
        char *predefname;
 
-       if(strchr(name, '\\')) predeflength = strchr(name, '\\')-name;
-       else predeflength = strlen(name);
+       if (strchr(name, '\\') != NULL) 
+               predeflength = strchr(name, '\\')-name;
+       else 
+               predeflength = strlen(name);
 
        predefname = talloc_strndup(mem_ctx, name, predeflength);
        error = reg_get_predefined_key_by_name(handle, predefname, &predef);
        talloc_free(predefname);
 
-       if(!W_ERROR_IS_OK(error)) {
+       if (!W_ERROR_IS_OK(error)) {
                return error;
        }
 
@@ -186,7 +172,9 @@ WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, co
        }
 }
 
-static WERROR get_abs_parent(TALLOC_CTX *mem_ctx, struct registry_context *ctx, const char *path, struct registry_key **parent, const char **name)
+static WERROR get_abs_parent(TALLOC_CTX *mem_ctx, struct registry_context *ctx, 
+                                                        const char *path, struct registry_key **parent, 
+                                                        const char **name)
 {
        char *parent_name;
        WERROR error;
@@ -195,14 +183,14 @@ static WERROR get_abs_parent(TALLOC_CTX *mem_ctx, struct registry_context *ctx,
                return WERR_FOOBAR;
        }
        
-       parent_name = talloc_strndup(mem_ctx, path, strrchr(path, '\\')-1-path);
+       parent_name = talloc_strndup(mem_ctx, path, strrchr(path, '\\')-path);
 
        error = reg_open_key_abs(mem_ctx, ctx, parent_name, parent);
        if (!W_ERROR_IS_OK(error)) {
                return error;
        }
        
-       *name = talloc_strdup(mem_ctx, strchr(path, '\\')+1);
+       *name = talloc_strdup(mem_ctx, strrchr(path, '\\')+1);
 
        return WERR_OK;
 }
@@ -228,20 +216,27 @@ WERROR reg_key_del_abs(struct registry_context *ctx, const char *path)
        return error;
 }
 
-WERROR reg_key_add_abs(TALLOC_CTX *mem_ctx, struct registry_context *ctx, const char *path, uint32_t access_mask, struct security_descriptor *sec_desc, struct registry_key **result)
+WERROR reg_key_add_abs(TALLOC_CTX *mem_ctx, struct registry_context *ctx, 
+                                          const char *path, uint32_t access_mask, 
+                                          struct security_descriptor *sec_desc, 
+                                          struct registry_key **result)
 {
        struct registry_key *parent;
        const char *n;
        WERROR error;
        
        if (!strchr(path, '\\')) {
-               return WERR_FOOBAR;
+               return WERR_ALREADY_EXISTS;
        }
        
        error = get_abs_parent(mem_ctx, ctx, path, &parent, &n);
-       if (W_ERROR_IS_OK(error)) {
-               error = reg_key_add_name(mem_ctx, parent, n, access_mask, sec_desc, result);
+       if (!W_ERROR_IS_OK(error)) {
+               DEBUG(2, ("Opening parent of %s failed with %s\n", path, 
+                                 win_errstr(error)));
+               return error;
        }
 
+       error = reg_key_add_name(mem_ctx, parent, n, NULL, sec_desc, result);
+
        return error;
 }
similarity index 96%
rename from source/lib/registry/reg_backend_wine.c
rename to source/lib/registry/wine.c
index 7184a602d156597203a240b049acd3e744e29929..2cb0b9955ebeee54a124fae14c2ba7bd477a18d6 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    Unix SMB/CIFS implementation.
    Registry interface
-   Copyright (C) Jelmer Vernooij                                         2004.
+   Copyright (C) Jelmer Vernooij                                         2007.
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -26,8 +26,6 @@ static WERROR wine_open_reg (struct registry_hive *h, struct registry_key **key)
        /* FIXME: Open h->location and mmap it */
 }
 
-
-
 static REG_OPS reg_backend_wine = {
        .name = "wine",
        .open_hive = wine_open_reg,
index 2a01cea286bb883df42e611099c52ba98f2bb269..034114eadedafa031b79f3284fb9843d85fb552a 100644 (file)
@@ -28,7 +28,7 @@
 /*******************************************************************
  Close the low 3 fd's and open dev/null in their place.
 ********************************************************************/
-static void close_low_fds(BOOL stderr_too)
+static void close_low_fds(bool stderr_too)
 {
 #ifndef VALGRIND
        int fd;
@@ -65,7 +65,7 @@ static void close_low_fds(BOOL stderr_too)
  Become a daemon, discarding the controlling terminal.
 **/
 
-_PUBLIC_ void become_daemon(BOOL Fork)
+_PUBLIC_ void become_daemon(bool Fork)
 {
        if (Fork) {
                if (fork()) {
@@ -87,7 +87,7 @@ _PUBLIC_ void become_daemon(BOOL Fork)
 #endif /* HAVE_SETSID */
 
        /* Close fd's 0,1,2. Needed if started by rsh */
-       close_low_fds(False);  /* Don't close stderr, let the debug system
+       close_low_fds(false);  /* Don't close stderr, let the debug system
                                  attach it to the logfile */
 }
 
index 03c9055e84d2877a67002db4cc77d7cc7d5b9f14..47174b6eeb8b942eb253596eb8eb029a3ecf83f7 100644 (file)
@@ -59,11 +59,12 @@ _PUBLIC_ struct dcesrv_handle *dcesrv_handle_new(struct dcesrv_connection_contex
        return h;
 }
 
-/*
+/**
   find an internal handle given a wire handle. If the wire handle is NULL then
   allocate a new handle
 */
-_PUBLIC_ struct dcesrv_handle *dcesrv_handle_fetch(struct dcesrv_connection_context *context, 
+_PUBLIC_ struct dcesrv_handle *dcesrv_handle_fetch(
+                                         struct dcesrv_connection_context *context, 
                                          struct policy_handle *p,
                                          uint8_t handle_type)
 {
index a71439e7c9496e5d0994dbb8cca171c5e93bc9e2..11c366fcb71ed392053e91f05bb02aaf7aae242f 100644 (file)
 
 enum handle_types { HTYPE_REGVAL, HTYPE_REGKEY };
 
-static NTSTATUS dcerpc_winreg_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
+static NTSTATUS dcerpc_winreg_bind(struct dcesrv_call_state *dce_call, 
+                                                                  const struct dcesrv_interface *iface)
 {
        struct registry_context *ctx;
        WERROR err;
 
-       err = reg_open_local(dce_call->context,
+       err = reg_open_samba(dce_call->context,
                             &ctx, dce_call->conn->auth_state.session_info, NULL);
 
+       if (!W_ERROR_IS_OK(err)) {
+               DEBUG(0, ("Error opening registry: %s\n", win_errstr(err)));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
        dce_call->context->private = ctx;
 
        return NT_STATUS_OK;
@@ -43,7 +49,9 @@ static NTSTATUS dcerpc_winreg_bind(struct dcesrv_call_state *dce_call, const str
 
 #define DCESRV_INTERFACE_WINREG_BIND dcerpc_winreg_bind
 
-static WERROR dcesrv_winreg_openhive (struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, uint32_t hkey, struct policy_handle **outh)
+static WERROR dcesrv_winreg_openhive(struct dcesrv_call_state *dce_call, 
+                                                                        TALLOC_CTX *mem_ctx, uint32_t hkey, 
+                                                                        struct policy_handle **outh)
 {
        struct registry_context *ctx = dce_call->context->private;
        struct dcesrv_handle *h; 
@@ -79,8 +87,9 @@ func_winreg_OpenHive(HKPN,HKEY_PERFORMANCE_NLSTEXT)
 /* 
   winreg_CloseKey 
 */
-static WERROR dcesrv_winreg_CloseKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                             struct winreg_CloseKey *r)
+static WERROR dcesrv_winreg_CloseKey(struct dcesrv_call_state *dce_call, 
+                                                                        TALLOC_CTX *mem_ctx,
+                                                                        struct winreg_CloseKey *r)
 {
        struct dcesrv_handle *h; 
 
@@ -93,12 +102,12 @@ static WERROR dcesrv_winreg_CloseKey(struct dcesrv_call_state *dce_call, TALLOC_
        return WERR_OK;
 }
 
-
 /* 
   winreg_CreateKey 
 */
-static WERROR dcesrv_winreg_CreateKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                              struct winreg_CreateKey *r)
+static WERROR dcesrv_winreg_CreateKey(struct dcesrv_call_state *dce_call, 
+                                                                         TALLOC_CTX *mem_ctx, 
+                                                                         struct winreg_CreateKey *r)
 {
        struct dcesrv_handle *h, *newh;
        WERROR error;
@@ -124,10 +133,9 @@ static WERROR dcesrv_winreg_CreateKey(struct dcesrv_call_state *dce_call, TALLOC
                }
        }
 
-       error = reg_key_add_name(newh, (struct registry_key *)h->data, r->in.name.name, 
-                                r->in.access_mask, 
-                                r->in.secdesc?&sd:NULL, 
-                                (struct registry_key **)&newh->data);
+       error = reg_key_add_name(newh, (struct registry_key *)h->data, 
+                                                        r->in.name.name, NULL, r->in.secdesc?&sd:NULL, 
+                                                        (struct registry_key **)&newh->data);
        if (W_ERROR_IS_OK(error)) {
                r->out.new_handle = &newh->wire_handle;
        } else {
@@ -141,8 +149,9 @@ static WERROR dcesrv_winreg_CreateKey(struct dcesrv_call_state *dce_call, TALLOC
 /* 
   winreg_DeleteKey 
 */
-static WERROR dcesrv_winreg_DeleteKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_DeleteKey *r)
+static WERROR dcesrv_winreg_DeleteKey(struct dcesrv_call_state *dce_call, 
+                                                                         TALLOC_CTX *mem_ctx,
+                                                                         struct winreg_DeleteKey *r)
 {
        struct dcesrv_handle *h;
 
@@ -155,8 +164,9 @@ static WERROR dcesrv_winreg_DeleteKey(struct dcesrv_call_state *dce_call, TALLOC
 /* 
   winreg_DeleteValue 
 */
-static WERROR dcesrv_winreg_DeleteValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_DeleteValue *r)
+static WERROR dcesrv_winreg_DeleteValue(struct dcesrv_call_state *dce_call, 
+                                                                               TALLOC_CTX *mem_ctx,
+                                                                               struct winreg_DeleteValue *r)
 {
        struct dcesrv_handle *h;
        struct registry_key *key;
@@ -172,25 +182,29 @@ static WERROR dcesrv_winreg_DeleteValue(struct dcesrv_call_state *dce_call, TALL
 /* 
   winreg_EnumKey 
 */
-static WERROR dcesrv_winreg_EnumKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_EnumKey *r)
+static WERROR dcesrv_winreg_EnumKey(struct dcesrv_call_state *dce_call, 
+                                                                       TALLOC_CTX *mem_ctx,
+                                                                       struct winreg_EnumKey *r)
 {
        struct dcesrv_handle *h;
-       struct registry_key *key;
+       const char *name;
+       NTTIME last_mod;
 
        DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 
-       r->out.result = reg_key_get_subkey_by_index(mem_ctx, (struct registry_key *)h->data, r->in.enum_index, &key);
+       r->out.result = reg_key_get_subkey_by_index(mem_ctx, 
+                                               (struct registry_key *)h->data, r->in.enum_index, 
+                                               &name, NULL, &last_mod);
 
        if (W_ERROR_IS_OK(r->out.result)) {
-               if (2*strlen_m_term(key->name) > r->in.name->size) {
+               if (2*strlen_m_term(name) > r->in.name->size) {
                        return WERR_MORE_DATA;
                }
-               r->out.name->length = 2*strlen_m_term(key->name);
-               r->out.name->name = key->name;
+               r->out.name->length = 2*strlen_m_term(name);
+               r->out.name->name = name;
                r->out.keyclass = talloc_zero(mem_ctx, struct winreg_StringBuf);
                if (r->in.last_changed_time) {
-                       r->out.last_changed_time = &key->last_mod;
+                       r->out.last_changed_time = &last_mod;
                }
        }
        
@@ -201,19 +215,24 @@ static WERROR dcesrv_winreg_EnumKey(struct dcesrv_call_state *dce_call, TALLOC_C
 /* 
   winreg_EnumValue 
 */
-static WERROR dcesrv_winreg_EnumValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                              struct winreg_EnumValue *r)
+static WERROR dcesrv_winreg_EnumValue(struct dcesrv_call_state *dce_call, 
+                                                                         TALLOC_CTX *mem_ctx,
+                                                                         struct winreg_EnumValue *r)
 {
        struct dcesrv_handle *h;
        struct registry_key *key;
-       struct registry_value *value;
        WERROR result;
+       const char *data_name;
+       uint32_t data_type;
+       DATA_BLOB data;
 
        DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 
        key = h->data;
 
-       result = reg_key_get_value_by_index(mem_ctx, key, r->in.enum_index, &value);
+       result = reg_key_get_value_by_index(mem_ctx, key, r->in.enum_index, 
+                                                                               &data_name,
+                                                                               &data_type, &data);
        if (!W_ERROR_IS_OK(result)) {
                return result;
        }
@@ -222,32 +241,32 @@ static WERROR dcesrv_winreg_EnumValue(struct dcesrv_call_state *dce_call, TALLOC
           want that back */
        if (r->in.type != NULL) {
                r->out.type = talloc(mem_ctx, enum winreg_Type);
-               *r->out.type = value->data_type;
+               *r->out.type = data_type;
        }
 
        /* check the client has enough room for the value */
        if (r->in.value != NULL &&
            r->in.size != NULL && 
-           value->data.length > *r->in.size) {
+           data.length > *r->in.size) {
                return WERR_MORE_DATA;
        }
        
        /* and enough room for the name */
-       if (r->in.name->size < 2*strlen_m_term(value->name)) {
+       if (r->in.name->size < 2*strlen_m_term(data_name)) {
                return WERR_MORE_DATA;          
        }
 
-       r->out.name->name = value->name;
-       r->out.name->length = 2*strlen_m_term(value->name);
-       r->out.name->size = 2*strlen_m_term(value->name);
+       r->out.name->name = data_name;
+       r->out.name->length = 2*strlen_m_term(data_name);
+       r->out.name->size = 2*strlen_m_term(data_name);
 
        if (r->in.value) {
-               r->out.value = value->data.data;
+               r->out.value = data.data;
        }
 
        if (r->in.size) {
                r->out.size = talloc(mem_ctx, uint32_t);
-               *r->out.size = value->data.length;
+               *r->out.size = data.length;
                r->out.length = r->out.size;
        }
        
@@ -258,8 +277,9 @@ static WERROR dcesrv_winreg_EnumValue(struct dcesrv_call_state *dce_call, TALLOC
 /* 
   winreg_FlushKey 
 */
-static WERROR dcesrv_winreg_FlushKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_FlushKey *r)
+static WERROR dcesrv_winreg_FlushKey(struct dcesrv_call_state *dce_call, 
+                                                                        TALLOC_CTX *mem_ctx, 
+                                                                        struct winreg_FlushKey *r)
 {
        struct dcesrv_handle *h;
 
@@ -272,8 +292,9 @@ static WERROR dcesrv_winreg_FlushKey(struct dcesrv_call_state *dce_call, TALLOC_
 /* 
   winreg_GetKeySecurity 
 */
-static WERROR dcesrv_winreg_GetKeySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_GetKeySecurity *r)
+static WERROR dcesrv_winreg_GetKeySecurity(struct dcesrv_call_state *dce_call, 
+                                                                                  TALLOC_CTX *mem_ctx, 
+                                                                                  struct winreg_GetKeySecurity *r)
 {
        struct dcesrv_handle *h;
 
@@ -286,8 +307,9 @@ static WERROR dcesrv_winreg_GetKeySecurity(struct dcesrv_call_state *dce_call, T
 /* 
   winreg_LoadKey 
 */
-static WERROR dcesrv_winreg_LoadKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_LoadKey *r)
+static WERROR dcesrv_winreg_LoadKey(struct dcesrv_call_state *dce_call, 
+                                                                       TALLOC_CTX *mem_ctx, 
+                                                                       struct winreg_LoadKey *r)
 {
        return WERR_NOT_SUPPORTED;
 }
@@ -296,8 +318,9 @@ static WERROR dcesrv_winreg_LoadKey(struct dcesrv_call_state *dce_call, TALLOC_C
 /* 
   winreg_NotifyChangeKeyValue 
 */
-static WERROR dcesrv_winreg_NotifyChangeKeyValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_NotifyChangeKeyValue *r)
+static WERROR dcesrv_winreg_NotifyChangeKeyValue(
+                                       struct dcesrv_call_state *dce_call, 
+                                       TALLOC_CTX *mem_ctx, struct winreg_NotifyChangeKeyValue *r)
 {
        return WERR_NOT_SUPPORTED;
 }
@@ -306,8 +329,9 @@ static WERROR dcesrv_winreg_NotifyChangeKeyValue(struct dcesrv_call_state *dce_c
 /* 
   winreg_OpenKey 
 */
-static WERROR dcesrv_winreg_OpenKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_OpenKey *r)
+static WERROR dcesrv_winreg_OpenKey(struct dcesrv_call_state *dce_call, 
+                                                                       TALLOC_CTX *mem_ctx,
+                                                                       struct winreg_OpenKey *r)
 {
        struct dcesrv_handle *h, *newh;
        WERROR result;
@@ -336,82 +360,66 @@ static WERROR dcesrv_winreg_OpenKey(struct dcesrv_call_state *dce_call, TALLOC_C
 /* 
   winreg_QueryInfoKey 
 */
-static WERROR dcesrv_winreg_QueryInfoKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_QueryInfoKey *r)
+static WERROR dcesrv_winreg_QueryInfoKey(struct dcesrv_call_state *dce_call, 
+                                                                                TALLOC_CTX *mem_ctx,
+                                                                                struct winreg_QueryInfoKey *r)
 {
        struct dcesrv_handle *h;
        struct registry_key *k;
        WERROR ret;
+       const char *classname;
 
        DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 
        k = h->data;
 
-       ret = reg_key_num_subkeys(k, r->out.num_subkeys);
-       if (!W_ERROR_IS_OK(ret)) { 
-               return ret;
-       }
+       ret = reg_key_get_info(mem_ctx, k, &classname, r->out.num_subkeys, 
+                                                  r->out.num_values, r->out.last_changed_time);
 
-       ret = reg_key_num_values(k, r->out.num_values);
-       if (!W_ERROR_IS_OK(ret)) { 
-               return ret;
-       }
+       if (r->out.classname != NULL)
+               r->out.classname->name = classname;
 
-       ret = reg_key_subkeysizes(k, r->out.max_subkeysize, r->out.max_subkeylen);
-       if (!W_ERROR_IS_OK(ret)) { 
-               return ret;
-       }
-
-       ret = reg_key_valuesizes(k, r->out.max_valnamelen, r->out.max_valbufsize);
-       if (!W_ERROR_IS_OK(ret)) { 
-               return ret;
-       }
-
-       r->out.secdescsize = 0; /* FIXME */
-       ZERO_STRUCT(r->out.last_changed_time); /* FIXME */
-       if (!W_ERROR_IS_OK(ret)) { 
-               return ret;
-       }
-
-
-       return WERR_OK;
+       return ret;
 }
 
 
 /* 
   winreg_QueryValue 
 */
-static WERROR dcesrv_winreg_QueryValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_QueryValue *r)
+static WERROR dcesrv_winreg_QueryValue(struct dcesrv_call_state *dce_call, 
+                                                                          TALLOC_CTX *mem_ctx,
+                                                                          struct winreg_QueryValue *r)
 {
        struct dcesrv_handle *h;
        struct registry_key *key;
-       struct registry_value *val;
+       uint32_t value_type;
+       DATA_BLOB value_data;
        WERROR result;
 
        DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
 
        key = h->data;
        
-       result = reg_key_get_value_by_name(mem_ctx, key, r->in.value_name.name, &val);
+       result = reg_key_get_value_by_name(mem_ctx, key, r->in.value_name.name, 
+                                                                          &value_type, &value_data);
 
        if (!W_ERROR_IS_OK(result)) { 
                return result;
        }
 
        /* Just asking for the size of the buffer */
-       r->out.type = (enum winreg_Type *)&val->data_type;
+       r->out.type = &value_type;
        r->out.length = talloc(mem_ctx, uint32_t);
        if (!r->out.length) {
                return WERR_NOMEM;
        }
-       *r->out.length = val->data.length;
-       if (!r->in.data) {
+       *r->out.length = value_data.length;
+       if (r->in.data == NULL) {
                r->out.size = talloc(mem_ctx, uint32_t);
-               *r->out.size = val->data.length;
+               *r->out.size = value_data.length;
        } else {
                r->out.size = r->in.size;
-               r->out.data = val->data.data;
+               r->out.data = value_data.data;
        }
 
        return WERR_OK;
@@ -421,8 +429,9 @@ static WERROR dcesrv_winreg_QueryValue(struct dcesrv_call_state *dce_call, TALLO
 /* 
   winreg_ReplaceKey 
 */
-static WERROR dcesrv_winreg_ReplaceKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_ReplaceKey *r)
+static WERROR dcesrv_winreg_ReplaceKey(struct dcesrv_call_state *dce_call, 
+                                                                          TALLOC_CTX *mem_ctx,
+                                                                          struct winreg_ReplaceKey *r)
 {
        return WERR_NOT_SUPPORTED;
 }
@@ -431,8 +440,9 @@ static WERROR dcesrv_winreg_ReplaceKey(struct dcesrv_call_state *dce_call, TALLO
 /* 
   winreg_RestoreKey 
 */
-static WERROR dcesrv_winreg_RestoreKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_RestoreKey *r)
+static WERROR dcesrv_winreg_RestoreKey(struct dcesrv_call_state *dce_call, 
+                                                                          TALLOC_CTX *mem_ctx, 
+                                                                          struct winreg_RestoreKey *r)
 {
        return WERR_NOT_SUPPORTED;
 }
@@ -441,8 +451,9 @@ static WERROR dcesrv_winreg_RestoreKey(struct dcesrv_call_state *dce_call, TALLO
 /* 
   winreg_SaveKey 
 */
-static WERROR dcesrv_winreg_SaveKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_SaveKey *r)
+static WERROR dcesrv_winreg_SaveKey(struct dcesrv_call_state *dce_call, 
+                                                                       TALLOC_CTX *mem_ctx, 
+                                                                       struct winreg_SaveKey *r)
 {
        return WERR_NOT_SUPPORTED;
 }
@@ -451,8 +462,9 @@ static WERROR dcesrv_winreg_SaveKey(struct dcesrv_call_state *dce_call, TALLOC_C
 /* 
   winreg_SetKeySecurity 
 */
-static WERROR dcesrv_winreg_SetKeySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_SetKeySecurity *r)
+static WERROR dcesrv_winreg_SetKeySecurity(struct dcesrv_call_state *dce_call, 
+                                                                                  TALLOC_CTX *mem_ctx, 
+                                                                                  struct winreg_SetKeySecurity *r)
 {
        return WERR_NOT_SUPPORTED;
 }
@@ -461,8 +473,9 @@ static WERROR dcesrv_winreg_SetKeySecurity(struct dcesrv_call_state *dce_call, T
 /* 
   winreg_SetValue 
 */
-static WERROR dcesrv_winreg_SetValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_SetValue *r)
+static WERROR dcesrv_winreg_SetValue(struct dcesrv_call_state *dce_call, 
+                                                                        TALLOC_CTX *mem_ctx, 
+                                                                        struct winreg_SetValue *r)
 {
        struct dcesrv_handle *h;
        struct registry_key *key;
@@ -488,8 +501,9 @@ static WERROR dcesrv_winreg_SetValue(struct dcesrv_call_state *dce_call, TALLOC_
 /* 
   winreg_UnLoadKey 
 */
-static WERROR dcesrv_winreg_UnLoadKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_UnLoadKey *r)
+static WERROR dcesrv_winreg_UnLoadKey(struct dcesrv_call_state *dce_call, 
+                                                                         TALLOC_CTX *mem_ctx, 
+                                                                         struct winreg_UnLoadKey *r)
 {
        return WERR_NOT_SUPPORTED;
 }
@@ -498,8 +512,9 @@ static WERROR dcesrv_winreg_UnLoadKey(struct dcesrv_call_state *dce_call, TALLOC
 /* 
   winreg_InitiateSystemShutdown 
 */
-static WERROR dcesrv_winreg_InitiateSystemShutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_InitiateSystemShutdown *r)
+static WERROR dcesrv_winreg_InitiateSystemShutdown(
+                                               struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                                               struct winreg_InitiateSystemShutdown *r)
 {
        return WERR_NOT_SUPPORTED;
 }
@@ -508,8 +523,9 @@ static WERROR dcesrv_winreg_InitiateSystemShutdown(struct dcesrv_call_state *dce
 /* 
   winreg_AbortSystemShutdown 
 */
-static WERROR dcesrv_winreg_AbortSystemShutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_AbortSystemShutdown *r)
+static WERROR dcesrv_winreg_AbortSystemShutdown(
+               struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+               struct winreg_AbortSystemShutdown *r)
 {
        return WERR_NOT_SUPPORTED;
 }
@@ -518,8 +534,9 @@ static WERROR dcesrv_winreg_AbortSystemShutdown(struct dcesrv_call_state *dce_ca
 /* 
   winreg_GetVersion 
 */
-static WERROR dcesrv_winreg_GetVersion(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                               struct winreg_GetVersion *r)
+static WERROR dcesrv_winreg_GetVersion(struct dcesrv_call_state *dce_call, 
+                                                                          TALLOC_CTX *mem_ctx, 
+                                                                          struct winreg_GetVersion *r)
 {
        struct dcesrv_handle *h;
 
@@ -537,8 +554,9 @@ static WERROR dcesrv_winreg_GetVersion(struct dcesrv_call_state *dce_call, TALLO
 /* 
   winreg_QueryMultipleValues 
 */
-static WERROR dcesrv_winreg_QueryMultipleValues(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_QueryMultipleValues *r)
+static WERROR dcesrv_winreg_QueryMultipleValues(
+       struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+       struct winreg_QueryMultipleValues *r)
 {
        return WERR_NOT_SUPPORTED;
 }
@@ -547,8 +565,9 @@ static WERROR dcesrv_winreg_QueryMultipleValues(struct dcesrv_call_state *dce_ca
 /* 
   winreg_InitiateSystemShutdownEx 
 */
-static WERROR dcesrv_winreg_InitiateSystemShutdownEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_InitiateSystemShutdownEx *r)
+static WERROR dcesrv_winreg_InitiateSystemShutdownEx(
+               struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+               struct winreg_InitiateSystemShutdownEx *r)
 {
        return WERR_NOT_SUPPORTED;
 }
@@ -557,8 +576,9 @@ static WERROR dcesrv_winreg_InitiateSystemShutdownEx(struct dcesrv_call_state *d
 /* 
   winreg_SaveKeyEx 
 */
-static WERROR dcesrv_winreg_SaveKeyEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_SaveKeyEx *r)
+static WERROR dcesrv_winreg_SaveKeyEx(struct dcesrv_call_state *dce_call, 
+                                                                         TALLOC_CTX *mem_ctx,
+                                                                         struct winreg_SaveKeyEx *r)
 {
        return WERR_NOT_SUPPORTED;
 }
@@ -567,8 +587,9 @@ static WERROR dcesrv_winreg_SaveKeyEx(struct dcesrv_call_state *dce_call, TALLOC
 /* 
   winreg_QueryMultipleValues2 
 */
-static WERROR dcesrv_winreg_QueryMultipleValues2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct winreg_QueryMultipleValues2 *r)
+static WERROR dcesrv_winreg_QueryMultipleValues2(
+               struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+               struct winreg_QueryMultipleValues2 *r)
 {
        return WERR_NOT_SUPPORTED;
 }
index 978158e613f27e6fc1a4b586863eebc24390d02d..e189ad1105cf7788e089a9c70d5521b0d920bcc6 100644 (file)
@@ -46,5 +46,4 @@ RPC-SVCCTL
 RPC-DSSYNC
 RPC-EPMAPPER
 RPC-INITSHUTDOWN
-RPC-WINREG
 RPC-SAMSYNC
index 2f9498e5ac8535daa3bc905bb001bb675e6e811f..f655f81f2d5bc4235a237a29fe7c7ea5e0b6ae37 100755 (executable)
@@ -3,6 +3,8 @@
 LEX="$1"
 SRC="$2"
 DEST="$3"
+shift 3
+ARGS="$*"
 
 dir=`dirname $SRC`
 file=`basename $SRC`
@@ -29,12 +31,15 @@ if [ -r $DEST ]; then
        fi
 fi
 TOP=`pwd`
-if cd $dir && $LEX $file; then
+if cd $dir && $LEX $ARGS $file; then
        if [ -r $base.yy.c ];then
                # we must guarantee that config.h comes first
                echo "#include \"config.h\"" > $base.c
                sed '/^#/ s|$base.yy\.c|$DEST|' $base.yy.c >> $base.c
                rm -f $base.yy.c
+       elif [ ! -r base.c ]; then
+               echo "$base.c nor $base.yy.c generated."
+               exit 1
        fi
 fi
 cd $TOP
index 06384c8dbd494c0817c799c023ec2448cb070739..7b143ae4d93c41db8e583419b9ea8c8b7d7fec13 100644 (file)
@@ -575,8 +575,6 @@ static int ejs_ldb_attach_dsdb_schema_from_ldif(MprVarHandle eid, int argc, char
 {
        struct ldb_context *ldb;
        WERROR status;
-       char *pf_name;
-       char *df_name;
        const char *pf;
        const char *df;
 
diff --git a/source/setup/provision.reg b/source/setup/provision.reg
new file mode 100644 (file)
index 0000000..337d1fc
--- /dev/null
@@ -0,0 +1,17 @@
+REGEDIT4
+
+[HKEY_LOCAL_MACHINE]
+
+[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\ProductOptions]
+ProductType="LanmanNT"
+
+[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Print]
+
+[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Terminal Server]
+
+[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters]
+RefusePasswordChange=REG_DWORD:0
+
+[HKEY_USERS]
+
+[HKEY_CLASSES_ROOT]
index 7731db85f8732289f38717e14e09226d7970df69..1a90592fcd5860c9ffea03a28b1522707d5238a6 100644 (file)
@@ -262,7 +262,7 @@ static int binary_smbd_main(const char *binary_name, int argc, const char *argv[
 
        if (opt_daemon) {
                DEBUG(3,("Becoming a daemon.\n"));
-               become_daemon(True);
+               become_daemon(true);
        }
 
        cleanup_tmp_files();
@@ -286,9 +286,6 @@ static int binary_smbd_main(const char *binary_name, int argc, const char *argv[
 
        gensec_init(); /* FIXME: */
 
-       registry_init(); /* FIXME: maybe run this in the initialization function 
-                                               of the winreg RPC server instead? */
-
        ntptr_init();   /* FIXME: maybe run this in the initialization function 
                                                of the spoolss RPC server instead? */
 
index c089cfd887e9d2ded5cb2897083a8754837c10a1..1364028ab7e1c7f124282cefb66a71eed606d52d 100644 (file)
@@ -23,6 +23,9 @@ OBJ_FILES = \
                ../../lib/socket_wrapper/testsuite.o \
                irpc.o \
                ../../lib/registry/tests/generic.o \
+               ../../lib/registry/tests/hive.o \
+               ../../lib/registry/tests/diff.o \
+               ../../lib/registry/tests/registry.o \
                resolve.o \
                ../../lib/util/tests/strlist.o \
                ../../lib/util/tests/file.o \
index 226f016c5567d9e7b422a21ee9187f4563e9f646..d7c956efd6fdc25f993f18ce14c2c99d2bf96ee2 100644 (file)
@@ -457,7 +457,8 @@ static const uint8_t getkeysecurity_in_data[] = {
   0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-static bool getkeysecurity_in_check(struct torture_context *tctx, struct winreg_GetKeySecurity *r)
+static bool getkeysecurity_in_check(struct torture_context *tctx, 
+                                                                       struct winreg_GetKeySecurity *r)
 {
        /* FIXME: Handle */
        torture_assert_int_equal(tctx, r->in.sec_info, 2, "sec info");
@@ -474,7 +475,8 @@ static const uint8_t getkeysecurity_out_data[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-static bool getkeysecurity_out_check(struct torture_context *tctx, struct winreg_GetKeySecurity *r)
+static bool getkeysecurity_out_check(struct torture_context *tctx, 
+                                                                        struct winreg_GetKeySecurity *r)
 {
        torture_assert_int_equal(tctx, r->in.sd->size, 20, "sd size");
        torture_assert_int_equal(tctx, r->in.sd->len, 20, "sd len");
index b20d25d1ef6de4e565367894e56c37b720680868..83462d3328625de7fd38369933691f9647b11fdf 100644 (file)
@@ -575,11 +575,11 @@ static bool test_handles_drsuapi(struct torture_context *torture)
 }
 
 
-struct torture_suite *torture_rpc_handles(void)
+struct torture_suite *torture_rpc_handles(TALLOC_CTX *mem_ctx)
 {
        struct torture_suite *suite;
 
-       suite = torture_suite_create(talloc_autofree_context(), "HANDLES");
+       suite = torture_suite_create(mem_ctx, "HANDLES");
        torture_suite_add_simple_test(suite, "lsarpc", test_handles_lsa);
        torture_suite_add_simple_test(suite, "lsarpc-shared", test_handles_lsa_shared);
        torture_suite_add_simple_test(suite, "samr", test_handles_samr);
index 250945a8a2fc8f73791dba85f07c4e94667e8456..12ace3e7d2ab6520808cc53236df4f213c713377 100644 (file)
@@ -134,6 +134,17 @@ static bool torture_rpc_wrap_test(struct torture_context *tctx,
        return fn(tctx, (struct dcerpc_pipe *)tcase->data);
 }
 
+static bool torture_rpc_wrap_test_ex(struct torture_context *tctx, 
+                                                                 struct torture_tcase *tcase,
+                                                                 struct torture_test *test)
+{
+       bool (*fn) (struct torture_context *, struct dcerpc_pipe *, const void *);
+
+       fn = test->fn;
+
+       return fn(tctx, (struct dcerpc_pipe *)tcase->data, test->data);
+}
+
 _PUBLIC_ struct torture_test *torture_rpc_tcase_add_test(
                                        struct torture_tcase *tcase, 
                                        const char *name, 
@@ -155,6 +166,29 @@ _PUBLIC_ struct torture_test *torture_rpc_tcase_add_test(
        return test;
 }
 
+_PUBLIC_ struct torture_test *torture_rpc_tcase_add_test_ex(
+                                       struct torture_tcase *tcase, 
+                                       const char *name, 
+                                       bool (*fn) (struct torture_context *, struct dcerpc_pipe *,
+                                                               void *),
+                                       void *userdata)
+{
+       struct torture_test *test;
+
+       test = talloc(tcase, struct torture_test);
+
+       test->name = talloc_strdup(test, name);
+       test->description = NULL;
+       test->run = torture_rpc_wrap_test_ex;
+       test->dangerous = false;
+       test->data = userdata;
+       test->fn = fn;
+
+       DLIST_ADD(tcase->tests, test);
+
+       return test;
+}
+
 NTSTATUS torture_rpc_init(void)
 {
        struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "RPC");
@@ -173,7 +207,8 @@ NTSTATUS torture_rpc_init(void)
        torture_suite_add_suite(suite, torture_rpc_eventlog());
        torture_suite_add_suite(suite, torture_rpc_atsvc());
        torture_suite_add_suite(suite, torture_rpc_wkssvc());
-       torture_suite_add_suite(suite, torture_rpc_handles());
+       torture_suite_add_suite(suite, torture_rpc_handles(suite));
+       torture_suite_add_suite(suite, torture_rpc_winreg(suite));
        torture_suite_add_simple_test(suite, "SPOOLSS", torture_rpc_spoolss);
        torture_suite_add_simple_test(suite, "SAMR", torture_rpc_samr);
        torture_suite_add_simple_test(suite, "SAMR-USERS", torture_rpc_samr_users);
@@ -186,7 +221,6 @@ NTSTATUS torture_rpc_init(void)
        torture_suite_add_simple_test(suite, "SRVSVC", torture_rpc_srvsvc);
        torture_suite_add_simple_test(suite, "SVCCTL", torture_rpc_svcctl);
        torture_suite_add_simple_test(suite, "EPMAPPER", torture_rpc_epmapper);
-       torture_suite_add_simple_test(suite, "WINREG", torture_rpc_winreg);
        torture_suite_add_simple_test(suite, "INITSHUTDOWN", torture_rpc_initshutdown);
        torture_suite_add_simple_test(suite, "OXIDRESOLVE", torture_rpc_oxidresolve);
        torture_suite_add_simple_test(suite, "REMACT", torture_rpc_remact);
index ac5b39b1e652a88f0f836e92265b5940e8f97f30..d433406c58170b13c82373fcbe28f7c74df7ba20 100644 (file)
@@ -3,7 +3,7 @@
    test suite for winreg rpc operations
 
    Copyright (C) Tim Potter 2003
-   Copyright (C) Jelmer Vernooij 2004
+   Copyright (C) Jelmer Vernooij 2004-2007
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -32,7 +32,9 @@
 #define TEST_KEY3 TEST_KEY_BASE "\\with a subkey"
 #define TEST_SUBKEY TEST_KEY3 "\\subkey"
 
-static void init_initshutdown_String(TALLOC_CTX *mem_ctx, struct initshutdown_String *name, const char *s)
+static void init_initshutdown_String(TALLOC_CTX *mem_ctx, 
+                                                                        struct initshutdown_String *name, 
+                                                                        const char *s)
 {
        name->name = talloc(mem_ctx, struct initshutdown_String_sub);
        name->name->name = s;
@@ -50,40 +52,30 @@ static void init_winreg_String(struct winreg_String *name, const char *s)
        }
 }
 
-static bool test_GetVersion(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
+static bool test_GetVersion(struct dcerpc_pipe *p, 
+                               struct torture_context *tctx,
                            struct policy_handle *handle)
 {
-       NTSTATUS status;
        struct winreg_GetVersion r;
        uint32_t v;
-       printf("\ntesting GetVersion\n");
 
        ZERO_STRUCT(r);
        r.in.handle = handle;
        r.out.version = &v;
 
-       status = dcerpc_winreg_GetVersion(p, mem_ctx, &r);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("GetVersion failed - %s\n", nt_errstr(status));
-               return false;
-       }
+       torture_assert_ntstatus_ok(tctx, dcerpc_winreg_GetVersion(p, tctx, &r),
+                                                          "GetVersion failed");
 
-       if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("GetVersion failed - %s\n", win_errstr(r.out.result));
-               return false;
-       }
+       torture_assert_werr_ok(tctx, r.out.result, "GetVersion failed");
 
        return true;
 }
 
-static bool test_NotifyChangeKeyValue(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
+static bool test_NotifyChangeKeyValue(struct dcerpc_pipe *p, 
+                                                                         struct torture_context *tctx, 
                                                                          struct policy_handle *handle)
 {
        struct winreg_NotifyChangeKeyValue r;
-       NTSTATUS status;
-
-       printf("\ntesting NotifyChangeKeyValue\n");
 
        r.in.handle = handle;
        r.in.watch_subtree = 1;
@@ -92,32 +84,27 @@ static bool test_NotifyChangeKeyValue(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx
        init_winreg_String(&r.in.string1, NULL);
        init_winreg_String(&r.in.string2, NULL);
 
-       status = dcerpc_winreg_NotifyChangeKeyValue(p, mem_ctx, &r);
-       
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("NotifyChangeKeyValue failed - %s\n", nt_errstr(status));
-               return false;
-       }
+       torture_assert_ntstatus_ok(tctx, 
+                                                          dcerpc_winreg_NotifyChangeKeyValue(p, tctx, &r),
+                                                          "NotifyChangeKeyValue failed");
 
        if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("NotifyChangeKeyValue failed - %s - not considering\n", win_errstr(r.out.result));
+               torture_comment(tctx, 
+                                               "NotifyChangeKeyValue failed - %s - not considering\n", win_errstr(r.out.result));
                return true;
        }
 
        return true;
 }
 
-static bool test_CreateKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+static bool test_CreateKey(struct dcerpc_pipe *p, struct torture_context *tctx,
                          struct policy_handle *handle, const char *name, 
                           const char *class)
 {
        struct winreg_CreateKey r;
        struct policy_handle newhandle;
-       NTSTATUS status;
        enum winreg_CreateAction action_taken = 0;
 
-       printf("\ntesting CreateKey\n");
-
        r.in.handle = handle;
        r.out.new_handle = &newhandle;
        init_winreg_String(&r.in.name, name);   
@@ -127,17 +114,10 @@ static bool test_CreateKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        r.in.action_taken = r.out.action_taken = &action_taken;
        r.in.secdesc = NULL;
 
-       status = dcerpc_winreg_CreateKey(p, mem_ctx, &r);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("CreateKey failed - %s\n", nt_errstr(status));
-               return false;
-       }
+       torture_assert_ntstatus_ok(tctx, dcerpc_winreg_CreateKey(p, tctx, &r),
+               "CreateKey failed");
 
-       if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("CreateKey failed - %s\n", win_errstr(r.out.result));
-               return false;
-       }
+       torture_assert_werr_ok(tctx,  r.out.result, "CreateKey failed");
 
        return true;
 }
@@ -146,18 +126,18 @@ static bool test_CreateKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
 /*
   createkey testing with a SD
 */
-static bool test_CreateKey_sd(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+static bool test_CreateKey_sd(struct dcerpc_pipe *p, 
+                                                         struct torture_context *tctx,
                              struct policy_handle *handle, const char *name, 
                              const char *class, struct policy_handle *newhandle)
 {
        struct winreg_CreateKey r;
-       NTSTATUS status;
        enum winreg_CreateAction action_taken = 0;
        struct security_descriptor *sd;
        DATA_BLOB sdblob;
        struct winreg_SecBuf secbuf;
 
-       sd = security_descriptor_create(mem_ctx,
+       sd = security_descriptor_create(tctx,
                                        NULL, NULL,
                                        SID_NT_AUTHENTICATED_USERS,
                                        SEC_ACE_TYPE_ACCESS_ALLOWED,
@@ -165,12 +145,10 @@ static bool test_CreateKey_sd(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
                                        SEC_ACE_FLAG_OBJECT_INHERIT,
                                        NULL);
 
-       status = ndr_push_struct_blob(&sdblob, mem_ctx, sd, 
-                                     (ndr_push_flags_fn_t)ndr_push_security_descriptor);
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("Failed to push security_descriptor ?!\n");
-               return false;
-       }
+       torture_assert_ntstatus_ok(tctx, 
+               ndr_push_struct_blob(&sdblob, tctx, sd, 
+                                     (ndr_push_flags_fn_t)ndr_push_security_descriptor),
+                               "Failed to push security_descriptor ?!\n");
 
        secbuf.sd.data = sdblob.data;
        secbuf.sd.len = sdblob.length;
@@ -178,8 +156,6 @@ static bool test_CreateKey_sd(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        secbuf.length = sdblob.length-10;
        secbuf.inherit = 0;
 
-       printf("\ntesting CreateKey with sd\n");
-
        r.in.handle = handle;
        r.out.new_handle = newhandle;
        init_winreg_String(&r.in.name, name);   
@@ -189,59 +165,42 @@ static bool test_CreateKey_sd(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        r.in.action_taken = r.out.action_taken = &action_taken;
        r.in.secdesc = &secbuf;
 
-       status = dcerpc_winreg_CreateKey(p, mem_ctx, &r);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("CreateKey with sd failed - %s\n", nt_errstr(status));
-               return false;
-       }
+       torture_assert_ntstatus_ok(tctx, dcerpc_winreg_CreateKey(p, tctx, &r),
+               "CreateKey with sd failed");
 
-       if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("CreateKey with sd failed - %s\n", win_errstr(r.out.result));
-               return false;
-       }
+       torture_assert_werr_ok(tctx, r.out.result, "CreateKey with sd failed");
 
        return true;
 }
 
-static bool test_GetKeySecurity(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
+static bool test_GetKeySecurity(struct dcerpc_pipe *p, 
+                                                               struct torture_context *tctx,
                          struct policy_handle *handle)
 {
-       NTSTATUS status;
        struct winreg_GetKeySecurity r;
        struct security_descriptor sd;
        DATA_BLOB sdblob;
 
-       printf("\ntesting GetKeySecurity\n");
-
        ZERO_STRUCT(r);
 
        r.in.handle = handle;
-       r.in.sd = r.out.sd = talloc_zero(mem_ctx, struct KeySecurityData);
+       r.in.sd = r.out.sd = talloc_zero(tctx, struct KeySecurityData);
        r.in.sd->size = 0x1000;
        r.in.sec_info = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL;
 
-       status = dcerpc_winreg_GetKeySecurity(p, mem_ctx, &r);
+       torture_assert_ntstatus_ok(tctx, dcerpc_winreg_GetKeySecurity(p, tctx, &r),
+               "GetKeySecurity failed");
 
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("GetKeySecurity failed - %s\n", nt_errstr(status));
-               return false;
-       }
-
-       if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("GetKeySecurity failed - %s\n", win_errstr(r.out.result));
-               return false;
-       }
+       torture_assert_werr_ok(tctx, r.out.result, "GetKeySecurity failed");
 
        sdblob.data = r.out.sd->data;
        sdblob.length = r.out.sd->len;
 
-       status = ndr_pull_struct_blob(&sdblob, mem_ctx, &sd, 
-                                     (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("pull_security_descriptor failed - %s\n", nt_errstr(status));
-               return false;
-       }
+       torture_assert_ntstatus_ok(tctx, 
+               ndr_pull_struct_blob(&sdblob, tctx, &sd, 
+                                     (ndr_pull_flags_fn_t)ndr_pull_security_descriptor),
+                       "pull_security_descriptor failed");
+
        if (p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
                NDR_PRINT_DEBUG(security_descriptor, &sd);
        }
@@ -249,88 +208,57 @@ static bool test_GetKeySecurity(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        return true;
 }
 
-static bool test_CloseKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
+static bool test_CloseKey(struct dcerpc_pipe *p, struct torture_context *tctx, 
                          struct policy_handle *handle)
 {
-       NTSTATUS status;
        struct winreg_CloseKey r;
 
-       printf("\ntesting CloseKey\n");
-
        r.in.handle = r.out.handle = handle;
 
-       status = dcerpc_winreg_CloseKey(p, mem_ctx, &r);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("CloseKey failed - %s\n", nt_errstr(status));
-               return false;
-       }
+       torture_assert_ntstatus_ok(tctx, dcerpc_winreg_CloseKey(p, tctx, &r),
+                                                          "CloseKey failed");
 
-       if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("CloseKey failed - %s\n", win_errstr(r.out.result));
-               return false;
-       }
+       torture_assert_werr_ok(tctx, r.out.result, "CloseKey failed");
 
        return true;
 }
 
-static bool test_FlushKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
+static bool test_FlushKey(struct dcerpc_pipe *p, struct torture_context *tctx, 
                          struct policy_handle *handle)
 {
-       NTSTATUS status;
        struct winreg_FlushKey r;
 
-       printf("\ntesting FlushKey\n");
-
        r.in.handle = handle;
 
-       status = dcerpc_winreg_FlushKey(p, mem_ctx, &r);
+       torture_assert_ntstatus_ok(tctx, dcerpc_winreg_FlushKey(p, tctx, &r),
+                       "FlushKey failed");
 
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("FlushKey failed - %s\n", nt_errstr(status));
-               return false;
-       }
-
-       if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("FlushKey failed - %s\n", win_errstr(r.out.result));
-               return false;
-       }
+       torture_assert_werr_ok(tctx, r.out.result, "FlushKey failed");
 
        return true;
 }
 
-static bool test_OpenKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
+static bool test_OpenKey(struct dcerpc_pipe *p, struct torture_context *tctx,
                         struct policy_handle *hive_handle,
                         const char *keyname, struct policy_handle *key_handle)
 {
-       NTSTATUS status;
        struct winreg_OpenKey r;
 
-       printf("\ntesting OpenKey\n");
-
        r.in.parent_handle = hive_handle;
        init_winreg_String(&r.in.keyname, keyname);
        r.in.unknown = 0x00000000;
        r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
        r.out.handle = key_handle;
 
-       status = dcerpc_winreg_OpenKey(p, mem_ctx, &r);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("OpenKey failed - %s\n", nt_errstr(status));
-               return false;
-       }
-
-       if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("OpenKey failed - %s\n", win_errstr(r.out.result));
+       torture_assert_ntstatus_ok(tctx, dcerpc_winreg_OpenKey(p, tctx, &r),
+                               "OpenKey failed");
 
-               return false;
-       }
+       torture_assert_werr_ok(tctx, r.out.result, "OpenKey failed");
 
        return true;
 }
 
-static bool test_Cleanup(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
+static bool test_Cleanup(struct dcerpc_pipe *p, struct torture_context *tctx,
                         struct policy_handle *handle, const char *key)
 {
        struct winreg_DeleteKey r;
@@ -338,34 +266,25 @@ static bool test_Cleanup(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        r.in.handle = handle;
 
        init_winreg_String(&r.in.key, key);
-       dcerpc_winreg_DeleteKey(p, mem_ctx, &r);
+       dcerpc_winreg_DeleteKey(p, tctx, &r);
 
        return true;
 }
 
 
-static bool test_DeleteKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
+static bool test_DeleteKey(struct dcerpc_pipe *p, struct torture_context *tctx,
                           struct policy_handle *handle, const char *key)
 {
        NTSTATUS status;
        struct winreg_DeleteKey r;
 
-       printf("\ntesting DeleteKey\n");
-
        r.in.handle = handle;
        init_winreg_String(&r.in.key, key);     
 
-       status = dcerpc_winreg_DeleteKey(p, mem_ctx, &r);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("DeleteKey failed - %s\n", nt_errstr(status));
-               return false;
-       }
+       status = dcerpc_winreg_DeleteKey(p, tctx, &r);
 
-       if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("DeleteKey failed - %s\n", win_errstr(r.out.result));
-               return false;
-       }
+       torture_assert_ntstatus_ok(tctx, status, "DeleteKey failed");
+       torture_assert_werr_ok(tctx, r.out.result, "DeleteKey failed");
 
        return true;
 }
@@ -373,44 +292,33 @@ static bool test_DeleteKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
 /* DeleteKey on a key with subkey(s) should
  * return WERR_ACCESS_DENIED. */
 static bool test_DeleteKeyWithSubkey(struct dcerpc_pipe *p, 
-                                    TALLOC_CTX* mem_ctx,
+                                    struct torture_context *tctx,
                                     struct policy_handle *handle, const char *key)
 {
-       NTSTATUS status;
        struct winreg_DeleteKey r;
 
-       printf("\ntesting DeleteKeyWithSubkey\n");
-
        r.in.handle = handle;
        init_winreg_String(&r.in.key, key);
 
-       status = dcerpc_winreg_DeleteKey(p, mem_ctx, &r);
+       torture_assert_ntstatus_ok(tctx, dcerpc_winreg_DeleteKey(p, tctx, &r),
+                                                          "DeleteKeyWithSubkey failed");
 
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("DeleteKeyWithSubkey failed  - %s\n", nt_errstr(status));
-               return false;
-       }
-
-       if (!W_ERROR_EQUAL(r.out.result, WERR_ACCESS_DENIED)) {
-               printf("DeleteKeyWithSubkey failed - %s\n", win_errstr(r.out.result));
-               return false;
-       }
+       torture_assert_werr_equal(tctx, r.out.result, WERR_ACCESS_DENIED, 
+                       "DeleteKeyWithSubkey failed");
 
        return true;
 }
 
-static bool test_QueryInfoKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+static bool test_QueryInfoKey(struct dcerpc_pipe *p, 
+                                                         struct torture_context *tctx,
                              struct policy_handle *handle, char *class)
 {
-       NTSTATUS status;
        struct winreg_QueryInfoKey r;
        uint32_t num_subkeys, max_subkeylen, max_subkeysize,
                num_values, max_valnamelen, max_valbufsize,
                secdescsize;
        NTTIME last_changed_time;
 
-       printf("\ntesting QueryInfoKey\n");
-
        ZERO_STRUCT(r);
        r.in.handle = handle;
        r.out.num_subkeys = &num_subkeys;
@@ -422,30 +330,24 @@ static bool test_QueryInfoKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        r.out.secdescsize = &secdescsize;
        r.out.last_changed_time = &last_changed_time;
 
-       r.out.classname = talloc(mem_ctx, struct winreg_String);
+       r.out.classname = talloc(tctx, struct winreg_String);
        
-       r.in.classname = talloc(mem_ctx, struct winreg_String);
+       r.in.classname = talloc(tctx, struct winreg_String);
        init_winreg_String(r.in.classname, class);
        
-       status = dcerpc_winreg_QueryInfoKey(p, mem_ctx, &r);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("QueryInfoKey failed - %s\n", nt_errstr(status));
-               return false;
-       }
+       torture_assert_ntstatus_ok(tctx, 
+               dcerpc_winreg_QueryInfoKey(p, tctx, &r),
+               "QueryInfoKey failed");
 
-       if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("QueryInfoKey failed - %s\n", win_errstr(r.out.result));
-               return false;
-       }
+       torture_assert_werr_ok(tctx, r.out.result, "QueryInfoKey failed");
 
        return true;
 }
 
-static bool test_key(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
+static bool test_key(struct dcerpc_pipe *p, struct torture_context *tctx,
                     struct policy_handle *handle, int depth);
 
-static bool test_EnumKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
+static bool test_EnumKey(struct dcerpc_pipe *p, struct torture_context *tctx,
                         struct policy_handle *handle, int depth)
 {
        struct winreg_EnumKey r;
@@ -453,8 +355,6 @@ static bool test_EnumKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        NTSTATUS status;
        NTTIME t = 0;
 
-       printf("Testing EnumKey\n\n");
-
        class.name   = "";
        class.size   = 1024;
 
@@ -469,18 +369,19 @@ static bool test_EnumKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
                name.name   = NULL;
                name.size   = 1024;
 
-               status = dcerpc_winreg_EnumKey(p, mem_ctx, &r);
+               status = dcerpc_winreg_EnumKey(p, tctx, &r);
 
                if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(r.out.result)) {
                        struct policy_handle key_handle;
 
-                       printf("EnumKey: %d: %s\n", r.in.enum_index, r.out.name->name);
+                       torture_comment(tctx, "EnumKey: %d: %s\n", r.in.enum_index, 
+                                                       r.out.name->name);
 
                        if (!test_OpenKey(
-                                   p, mem_ctx, handle, r.out.name->name,
+                                   p, tctx, handle, r.out.name->name,
                                    &key_handle)) {
                        } else {
-                               test_key(p, mem_ctx, &key_handle, depth + 1);
+                               test_key(p, tctx, &key_handle, depth + 1);
                        }
                }
 
@@ -488,64 +389,59 @@ static bool test_EnumKey(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
 
        } while (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(r.out.result));
 
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("EnumKey failed - %s\n", nt_errstr(status));
-               return false;
-       }
+       torture_assert_ntstatus_ok(tctx, status, "EnumKey failed");
 
-       if (!W_ERROR_IS_OK(r.out.result) && !W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
-               printf("EnumKey failed - %s\n", win_errstr(r.out.result));
-               return false;
+       if (!W_ERROR_IS_OK(r.out.result) && 
+               !W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
+               torture_fail(tctx, "EnumKey failed");
        }
 
-
-
        return true;
 }
 
-static bool test_QueryMultipleValues(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *handle, const char *valuename)
+static bool test_QueryMultipleValues(struct dcerpc_pipe *p, 
+                                                                        struct torture_context *tctx, 
+                                                                        struct policy_handle *handle, 
+                                                                        const char *valuename)
 {
        struct winreg_QueryMultipleValues r;
        NTSTATUS status;
        uint32_t bufsize=0;
 
-       printf("Testing QueryMultipleValues\n");
-
        r.in.key_handle = handle;
-       r.in.values = r.out.values = talloc_array(mem_ctx, struct QueryMultipleValue, 1);
-       r.in.values[0].name = talloc(mem_ctx, struct winreg_String);
+       r.in.values = r.out.values = talloc_array(tctx, struct QueryMultipleValue, 1);
+       r.in.values[0].name = talloc(tctx, struct winreg_String);
        r.in.values[0].name->name = valuename;
        r.in.values[0].offset = 0;
        r.in.values[0].length = 0;
        r.in.values[0].type = 0;
 
        r.in.num_values = 1;
-       r.in.buffer_size = r.out.buffer_size = talloc(mem_ctx, uint32_t);
+       r.in.buffer_size = r.out.buffer_size = talloc(tctx, uint32_t);
        *r.in.buffer_size = bufsize;
        do { 
                *r.in.buffer_size = bufsize;
-               r.in.buffer = r.out.buffer = talloc_zero_array(mem_ctx, uint8_t, 
+               r.in.buffer = r.out.buffer = talloc_zero_array(tctx, uint8_t, 
                                                               *r.in.buffer_size);
 
-               status = dcerpc_winreg_QueryMultipleValues(p, mem_ctx, &r);
+               status = dcerpc_winreg_QueryMultipleValues(p, tctx, &r);
        
-               if(NT_STATUS_IS_ERR(status)) {
-                       printf("QueryMultipleValues failed - %s\n", nt_errstr(status));
-                       return false;
-               }
+               if(NT_STATUS_IS_ERR(status))
+                       torture_fail(tctx, "QueryMultipleValues failed");
+
                talloc_free(r.in.buffer);
                bufsize += 0x20;
        } while (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA));
 
-       if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("QueryMultipleValues failed - %s\n", win_errstr(r.out.result));
-               return false;
-       }
+       torture_assert_werr_ok(tctx, r.out.result, "QueryMultipleValues failed");
 
        return true;
 }
 
-static bool test_QueryValue(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *handle, const char *valuename)
+static bool test_QueryValue(struct dcerpc_pipe *p, 
+                                                       struct torture_context *tctx, 
+                                                       struct policy_handle *handle, 
+                                                       const char *valuename)
 {
        struct winreg_QueryValue r;
        NTSTATUS status;
@@ -553,8 +449,6 @@ static bool test_QueryValue(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct p
        uint32_t offered = 0xfff;
        uint32_t zero = 0;
 
-       printf("Testing QueryValue\n");
-
        r.in.handle = handle;
        r.in.data = NULL;
        r.in.value_name.name = valuename;
@@ -562,21 +456,17 @@ static bool test_QueryValue(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct p
        r.in.size = &offered;
        r.in.length = &zero;
 
-       status = dcerpc_winreg_QueryValue(p, mem_ctx, &r);
-       if(NT_STATUS_IS_ERR(status)) {
-               printf("QueryValue failed - %s\n", nt_errstr(status));
-               return false;
+       status = dcerpc_winreg_QueryValue(p, tctx, &r);
+       if (NT_STATUS_IS_ERR(status)) {
+               torture_fail(tctx, "QueryValue failed");
        }
 
-       if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("QueryValue failed - %s\n", win_errstr(r.out.result));
-               return false;
-       }
+       torture_assert_werr_ok(tctx, r.out.result, "QueryValue failed");
 
        return true;
 }
 
-static bool test_EnumValue(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
+static bool test_EnumValue(struct dcerpc_pipe *p, struct torture_context *tctx,
                           struct policy_handle *handle, int max_valnamelen, int max_valbufsize)
 {
        struct winreg_EnumValue r;
@@ -586,8 +476,6 @@ static bool test_EnumValue(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        uint8_t buf8;
        struct winreg_StringBuf name;
 
-       printf("testing EnumValue\n");
-
        name.name   = "";
        name.size   = 1024;
 
@@ -601,237 +489,219 @@ static bool test_EnumValue(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        r.in.size = &size;
        
        do {
-               NTSTATUS status = dcerpc_winreg_EnumValue(p, mem_ctx, &r);
-               if(NT_STATUS_IS_ERR(status)) {
-                       printf("EnumValue failed - %s\n", nt_errstr(status));
-                       return false;
-               }
+               torture_assert_ntstatus_ok(tctx, dcerpc_winreg_EnumValue(p, tctx, &r),
+                                                                  "EnumValue failed");
 
                if (W_ERROR_IS_OK(r.out.result)) {
-                       ret &= test_QueryValue(p, mem_ctx, handle, r.out.name->name);
-                       ret &= test_QueryMultipleValues(p, mem_ctx, handle, r.out.name->name);
+                       ret &= test_QueryValue(p, tctx, handle, r.out.name->name);
+                       ret &= test_QueryMultipleValues(p, tctx, handle, r.out.name->name);
                }
 
                r.in.enum_index++;
        } while (W_ERROR_IS_OK(r.out.result));
 
-       if(!W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) {
-               printf("EnumValue failed - %s\n", win_errstr(r.out.result));
-               return false;
-       }
+       torture_assert_werr_equal(tctx, r.out.result, WERR_NO_MORE_ITEMS,
+               "EnumValue failed");
 
        return ret;
 }
 
-static bool test_InitiateSystemShutdown(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
-                       const char *msg, uint32_t timeout)
+static bool test_AbortSystemShutdown(struct dcerpc_pipe *p, 
+                                                                        struct torture_context *tctx)
 {
-       struct winreg_InitiateSystemShutdown r;
-       NTSTATUS status;
-       uint16_t hostname = 0x0;
-       
-       r.in.hostname = &hostname;
-       r.in.message = talloc(mem_ctx, struct initshutdown_String);
-       init_initshutdown_String(mem_ctx, r.in.message, msg);
-       r.in.force_apps = 1;
-       r.in.timeout = timeout;
-       r.in.reboot = 1;
+       struct winreg_AbortSystemShutdown r;
+       uint16_t server = 0x0;
 
-       status = dcerpc_winreg_InitiateSystemShutdown(p, mem_ctx, &r);
+       r.in.server = &server;
+       
+       torture_assert_ntstatus_ok(tctx, 
+                                                          dcerpc_winreg_AbortSystemShutdown(p, tctx, &r),
+                                                          "AbortSystemShutdown failed");
 
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("InitiateSystemShutdown failed - %s\n", nt_errstr(status));
-               return false;
-       }
-
-       if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("InitiateSystemShutdown failed - %s\n", win_errstr(r.out.result));
-               return false;
-       }
+       torture_assert_werr_ok(tctx, r.out.result, "AbortSystemShutdown failed");
 
        return true;
 }
 
-static bool test_InitiateSystemShutdownEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
-                       const char *msg, uint32_t timeout)
+static bool test_InitiateSystemShutdown(struct torture_context *tctx,
+                                                                               struct dcerpc_pipe *p)
 {
-       struct winreg_InitiateSystemShutdownEx r;
-       NTSTATUS status;
+       struct winreg_InitiateSystemShutdown r;
        uint16_t hostname = 0x0;
-       
+
+       if (!torture_setting_bool(tctx, "dangerous", false))
+               torture_skip(tctx, 
+                  "winreg_InitiateShutdown disabled - enable dangerous tests to use");
+
+
        r.in.hostname = &hostname;
-       r.in.message = talloc(mem_ctx, struct initshutdown_String);
-       init_initshutdown_String(mem_ctx, r.in.message, msg);
+       r.in.message = talloc(tctx, struct initshutdown_String);
+       init_initshutdown_String(tctx, r.in.message, "spottyfood");
        r.in.force_apps = 1;
-       r.in.timeout = timeout;
+       r.in.timeout = 30;
        r.in.reboot = 1;
-       r.in.reason = 0;
-
-       status = dcerpc_winreg_InitiateSystemShutdownEx(p, mem_ctx, &r);
 
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("InitiateSystemShutdownEx failed - %s\n", nt_errstr(status));
-               return false;
-       }
+       torture_assert_ntstatus_ok(tctx, 
+                                                       dcerpc_winreg_InitiateSystemShutdown(p, tctx, &r),
+                                                       "InitiateSystemShutdown failed");
 
-       if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("InitiateSystemShutdownEx failed - %s\n", win_errstr(r.out.result));
-               return false;
-       }
+       torture_assert_werr_ok(tctx, r.out.result, "InitiateSystemShutdown failed");
 
-       return true;
+       return test_AbortSystemShutdown(p, tctx);
 }
 
-static bool test_AbortSystemShutdown(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
+
+static bool test_InitiateSystemShutdownEx(struct torture_context *tctx,
+                                                                                 struct dcerpc_pipe *p)
 {
-       struct winreg_AbortSystemShutdown r;
-       NTSTATUS status;
-       uint16_t server = 0x0;
+       struct winreg_InitiateSystemShutdownEx r;
+       uint16_t hostname = 0x0;
 
-       r.in.server = &server;
+       if (!torture_setting_bool(tctx, "dangerous", false))
+               torture_skip(tctx, 
+                  "winreg_InitiateShutdownEx disabled - enable dangerous tests to use");
        
-       status = dcerpc_winreg_AbortSystemShutdown(p, mem_ctx, &r);
+       r.in.hostname = &hostname;
+       r.in.message = talloc(tctx, struct initshutdown_String);
+       init_initshutdown_String(tctx, r.in.message, "spottyfood");
+       r.in.force_apps = 1;
+       r.in.timeout = 30;
+       r.in.reboot = 1;
+       r.in.reason = 0;
 
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("AbortSystemShutdown failed - %s\n", nt_errstr(status));
-               return false;
-       }
+       torture_assert_ntstatus_ok(tctx, 
+               dcerpc_winreg_InitiateSystemShutdownEx(p, tctx, &r),
+               "InitiateSystemShutdownEx failed");
 
-       if (!W_ERROR_IS_OK(r.out.result)) {
-               printf("AbortSystemShutdown failed - %s\n", win_errstr(r.out.result));
-               return false;
-       }
+       torture_assert_werr_ok(tctx, r.out.result, 
+                                                  "InitiateSystemShutdownEx failed");
 
-       return true;
+       return test_AbortSystemShutdown(p, tctx);
 }
-
 #define MAX_DEPTH 2            /* Only go this far down the tree */
 
-static bool test_key(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 
+static bool test_key(struct dcerpc_pipe *p, struct torture_context *tctx, 
                     struct policy_handle *handle, int depth)
 {
        if (depth == MAX_DEPTH)
                return true;
 
-       if (!test_QueryInfoKey(p, mem_ctx, handle, NULL)) {
+       if (!test_QueryInfoKey(p, tctx, handle, NULL)) {
        }
 
-       if (!test_NotifyChangeKeyValue(p, mem_ctx, handle)) {
+       if (!test_NotifyChangeKeyValue(p, tctx, handle)) {
        }
        
-       if (!test_GetKeySecurity(p, mem_ctx, handle)) {
+       if (!test_GetKeySecurity(p, tctx, handle)) {
        }
 
-       if (!test_EnumKey(p, mem_ctx, handle, depth)) {
+       if (!test_EnumKey(p, tctx, handle, depth)) {
        }
 
-       if (!test_EnumValue(p, mem_ctx, handle, 0xFF, 0xFFFF)) {
+       if (!test_EnumValue(p, tctx, handle, 0xFF, 0xFFFF)) {
        }
 
-       test_CloseKey(p, mem_ctx, handle);
+       test_CloseKey(p, tctx, handle);
 
        return true;
 }
 
 typedef NTSTATUS (*winreg_open_fn)(struct dcerpc_pipe *, TALLOC_CTX *, void *);
 
-static bool test_Open(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx
-                     const char *name, winreg_open_fn open_fn)
+static bool test_Open(struct torture_context *tctx, struct dcerpc_pipe *p
+                     void *userdata)
 {
        struct policy_handle handle, newhandle;
        bool ret = true, created = false, created2 = false, deleted = false;
        bool created3 = false, created_subkey = false;
        struct winreg_OpenHKLM r;
-       NTSTATUS status;
 
-       printf("Testing %s\n", name);
+       winreg_open_fn open_fn = userdata;
 
        r.in.system_name = 0;
        r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
        r.out.handle = &handle;
        
-       status = open_fn(p, mem_ctx, &r);
-       if (!NT_STATUS_IS_OK(status)) {
-               return false;
-       }
+       torture_assert_ntstatus_ok(tctx, open_fn(p, tctx, &r), 
+                                                          "open");
 
-       test_Cleanup(p, mem_ctx, &handle, TEST_KEY1);
-       test_Cleanup(p, mem_ctx, &handle, TEST_KEY2);
-       test_Cleanup(p, mem_ctx, &handle, TEST_SUBKEY);
-       test_Cleanup(p, mem_ctx, &handle, TEST_KEY3);
-       test_Cleanup(p, mem_ctx, &handle, TEST_KEY_BASE);
+       test_Cleanup(p, tctx, &handle, TEST_KEY1);
+       test_Cleanup(p, tctx, &handle, TEST_KEY2);
+       test_Cleanup(p, tctx, &handle, TEST_SUBKEY);
+       test_Cleanup(p, tctx, &handle, TEST_KEY3);
+       test_Cleanup(p, tctx, &handle, TEST_KEY_BASE);
 
-       if (!test_CreateKey(p, mem_ctx, &handle, TEST_KEY1, NULL)) {
-               printf("CreateKey failed - not considering a failure\n");
+       if (!test_CreateKey(p, tctx, &handle, TEST_KEY1, NULL)) {
+               torture_comment(tctx, "CreateKey failed - not considering a failure\n");
        } else {
                created = true;
        }
 
-       if (created && !test_FlushKey(p, mem_ctx, &handle)) {
-               printf("FlushKey failed\n");
+       if (created && !test_FlushKey(p, tctx, &handle)) {
+               torture_comment(tctx, "FlushKey failed\n");
                ret = false;
        }
 
-       if (created && !test_OpenKey(p, mem_ctx, &handle, TEST_KEY1, &newhandle)) {
-               printf("CreateKey failed (OpenKey after Create didn't work)\n");
-               ret = false;
-       }
+       if (created && !test_OpenKey(p, tctx, &handle, TEST_KEY1, &newhandle))
+               torture_fail(tctx, 
+                                        "CreateKey failed (OpenKey after Create didn't work)\n");
 
-       if (created && !test_DeleteKey(p, mem_ctx, &handle, TEST_KEY1)) {
-               printf("DeleteKey failed\n");
+       if (created && !test_DeleteKey(p, tctx, &handle, TEST_KEY1)) {
+               torture_comment(tctx, "DeleteKey failed\n");
                ret = false;
        } else {
                deleted = true;
        }
 
-       if (created && !test_FlushKey(p, mem_ctx, &handle)) {
-               printf("FlushKey failed\n");
+       if (created && !test_FlushKey(p, tctx, &handle)) {
+               torture_comment(tctx, "FlushKey failed\n");
                ret = false;
        }
 
        if (created && deleted && 
-           test_OpenKey(p, mem_ctx, &handle, TEST_KEY1, &newhandle)) {
-               printf("DeleteKey failed (OpenKey after Delete worked)\n");
+           test_OpenKey(p, tctx, &handle, TEST_KEY1, &newhandle)) {
+               torture_comment(tctx, 
+                                               "DeleteKey failed (OpenKey after Delete worked)\n");
                ret = false;
        }
 
-       if (!test_GetVersion(p, mem_ctx, &handle)) {
-               printf("GetVersion failed\n");
+       if (!test_GetVersion(p, tctx, &handle)) {
+               torture_comment(tctx, "GetVersion failed\n");
                ret = false;
        }
 
-       if (created && test_CreateKey_sd(p, mem_ctx, &handle, TEST_KEY2, 
+       if (created && test_CreateKey_sd(p, tctx, &handle, TEST_KEY2, 
                                          NULL, &newhandle)) {
                created2 = true;
        }
 
-       if (created2 && !test_GetKeySecurity(p, mem_ctx, &newhandle)) {
+       if (created2 && !test_GetKeySecurity(p, tctx, &newhandle)) {
                printf("GetKeySecurity failed\n");
                ret = false;
        }
 
-       if (created2 && !test_CloseKey(p, mem_ctx, &newhandle)) {
+       if (created2 && !test_CloseKey(p, tctx, &newhandle)) {
                printf("CloseKey failed\n");
                ret = false;
        }
 
-       if (created && !test_DeleteKey(p, mem_ctx, &handle, TEST_KEY2)) {
+       if (created && !test_DeleteKey(p, tctx, &handle, TEST_KEY2)) {
                printf("DeleteKey failed\n");
                ret = false;
        }
 
-       if (created && test_CreateKey(p, mem_ctx, &handle, TEST_KEY3, NULL)) {
+       if (created && test_CreateKey(p, tctx, &handle, TEST_KEY3, NULL)) {
                created3 = true;
        }
 
        if (created3 && 
-           test_CreateKey(p, mem_ctx, &handle, TEST_SUBKEY, NULL)) 
+           test_CreateKey(p, tctx, &handle, TEST_SUBKEY, NULL)) 
        {
                created_subkey = true;
        }
 
        if (created_subkey && 
-           !test_DeleteKeyWithSubkey(p, mem_ctx, &handle, TEST_KEY3)) 
+           !test_DeleteKeyWithSubkey(p, tctx, &handle, TEST_KEY3)) 
        {
                printf("DeleteKeyWithSubkey failed "
                       "(DeleteKey didn't return ACCESS_DENIED)\n");
@@ -839,42 +709,37 @@ static bool test_Open(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
        }
 
        if (created_subkey && 
-           !test_DeleteKey(p, mem_ctx, &handle, TEST_SUBKEY))
+           !test_DeleteKey(p, tctx, &handle, TEST_SUBKEY))
        {
                printf("DeleteKey failed\n");
                ret = false;
        }
 
        if (created3 &&
-           !test_DeleteKey(p, mem_ctx, &handle, TEST_KEY3))
+           !test_DeleteKey(p, tctx, &handle, TEST_KEY3))
        {
                printf("DeleteKey failed\n");
                ret = false;
        }
 
        /* The HKCR hive has a very large fanout */
-
        if (open_fn == (void *)dcerpc_winreg_OpenHKCR) {
-               if(!test_key(p, mem_ctx, &handle, MAX_DEPTH - 1)) {
+               if(!test_key(p, tctx, &handle, MAX_DEPTH - 1)) {
                        ret = false;
                }
        }
 
-       if(!test_key(p, mem_ctx, &handle, 0)) {
+       if(!test_key(p, tctx, &handle, 0)) {
                ret = false;
        }
 
-       test_Cleanup(p, mem_ctx, &handle, TEST_KEY_BASE);
+       test_Cleanup(p, tctx, &handle, TEST_KEY_BASE);
 
        return ret;
 }
 
-bool torture_rpc_winreg(struct torture_context *torture)
+struct torture_suite *torture_rpc_winreg(TALLOC_CTX *mem_ctx)
 {
-        NTSTATUS status;
-       struct dcerpc_pipe *p;
-       TALLOC_CTX *mem_ctx;
-       bool ret = true;
        struct {
                const char *name;
                winreg_open_fn fn;
@@ -883,29 +748,22 @@ bool torture_rpc_winreg(struct torture_context *torture)
                        {"OpenHKCR", (winreg_open_fn)dcerpc_winreg_OpenHKCR },
                        {"OpenHKCU", (winreg_open_fn)dcerpc_winreg_OpenHKCU }};
        int i;
-       mem_ctx = talloc_init("torture_rpc_winreg");
+       struct torture_tcase *tcase;
+       struct torture_suite *suite = torture_suite_create(mem_ctx, "WINREG");
 
-       status = torture_rpc_connection(mem_ctx, &p, &ndr_table_winreg);
+       tcase = torture_suite_add_rpc_iface_tcase(suite, "winreg", 
+                                                                                         &ndr_table_winreg);
 
-       if (!NT_STATUS_IS_OK(status)) {
-               talloc_free(mem_ctx);
-               return false;
-       }
+       torture_rpc_tcase_add_test(tcase, "InitiateSystemShutdown", 
+                                                          test_InitiateSystemShutdown);
 
-       if (!torture_setting_bool(torture, "dangerous", false)) {
-               printf("winreg_InitiateShutdown disabled - enable dangerous tests to use\n");
-       } else {
-               ret &= test_InitiateSystemShutdown(p, mem_ctx, "spottyfood", 30);
-               ret &= test_AbortSystemShutdown(p, mem_ctx);
-               ret &= test_InitiateSystemShutdownEx(p, mem_ctx, "spottyfood", 30);
-               ret &= test_AbortSystemShutdown(p, mem_ctx);
-       }
+       torture_rpc_tcase_add_test(tcase, "InitiateSystemShutdownEx", 
+                                                          test_InitiateSystemShutdownEx);
 
        for (i = 0; i < ARRAY_SIZE(open_fns); i++) {
-               ret &= test_Open(p, mem_ctx, open_fns[i].name, open_fns[i].fn);
+               torture_rpc_tcase_add_test_ex(tcase, open_fns[i].name, test_Open, 
+                                                                         open_fns[i].fn);
        }
 
-       talloc_free(mem_ctx);
-
-       return ret;
+       return suite;
 }
index 003582179e068957b461d16d84c268f6a6b85ea1..683b0f114b6f5dabd6b96d865e5804cbc7913e20 100644 (file)
@@ -433,3 +433,37 @@ struct torture_suite *torture_find_suite(struct torture_suite *parent,
 
        return NULL;
 }
+
+static bool wrap_test_with_simple_test(struct torture_context *torture_ctx,
+                                                                       struct torture_tcase *tcase,
+                                                                       struct torture_test *test)
+{
+       bool (*fn) (struct torture_context *, const void *tcase_data);
+
+       fn = test->fn;
+
+       return fn(torture_ctx, tcase->data);
+}
+
+struct torture_test *torture_tcase_add_simple_test(
+               struct torture_tcase *tcase,
+               const char *name,
+               bool (*run) (struct torture_context *test, const void *tcase_data))
+{
+       struct torture_test *test; 
+       
+       test = talloc(tcase, struct torture_test);
+
+       test->name = talloc_strdup(test, name);
+       test->description = NULL;
+       test->run = wrap_test_with_simple_test;
+       test->fn = run;
+       test->data = NULL;
+       test->dangerous = False;
+
+       DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+
+       return test;
+}
+
+
index 4dd5e4530038fbe7b141a8b15252c5e6c40d5b99..c3b0092d48909e1119d1e726fa7bebaed946f1cf 100644 (file)
@@ -165,6 +165,13 @@ struct torture_tcase *torture_suite_add_simple_tcase(
                bool (*run) (struct torture_context *test, const void *test_data),
                const void *data);
 
+/* Convenience function that adds a test which only 
+ * gets the test case data */
+struct torture_test *torture_tcase_add_simple_test(
+               struct torture_tcase *tcase,
+               const char *name,
+               bool (*run) (struct torture_context *test, const void *tcase_data));
+
 /* Convenience wrapper that adds a test that doesn't need any 
  * testcase data */
 struct torture_tcase *torture_suite_add_simple_test(
@@ -258,6 +265,20 @@ void torture_result(struct torture_context *test,
        talloc_free(__got); \
        } while(0)
 
+#define torture_assert_file_contains(torture_ctx,filename,expected,cmt)\
+       do { const char *__got, *__expected = (expected); \
+       size_t __size; \
+       __got = file_load(filename, *size, torture_ctx); \
+       if (strcmp_safe(__got, __expected) != 0) { \
+               torture_result(torture_ctx, TORTURE_FAIL, \
+                                          __location__": %s contained:\n%sExpected: %s%s\n", \
+                                          __got, __expected, cmt); \
+               talloc_free(__got); \
+               return false; \
+       } \
+       talloc_free(__got); \
+       } while(0)
+
 #define torture_assert_int_equal(torture_ctx,got,expected,cmt)\
        do { int __got = (got), __expected = (expected); \
        if (__got != __expected) { \
index aba386780e08fbc5f50c3b143b1ba26696050e59..83b5c4f4f92f92a89606cd9a2b25c7243c9a6a99 100644 (file)
@@ -4,7 +4,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: qooxdoo framework\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-02-12 03:06+0100\n"
+"POT-Creation-Date: 2007-02-10 16:11+0100\n"
 "PO-Revision-Date: 2006-12-19 15:52+0100\n"
 "Last-Translator: Automatically generated\n"
 "Language-Team: none\n"