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
(This used to be commit 7a1eec6358bc863dfc671c542b7185d3e39d7b5a)

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