1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

r24667: Finally merge the registry improvements that Wilco Baan Hofman and I have

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 7a1eec6358)
This commit is contained in:
Jelmer Vernooij 2007-08-26 15:16:40 +00:00 committed by Gerald (Jerry) Carter
parent 8e789517b7
commit b409d4120f
63 changed files with 7291 additions and 4058 deletions

View 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

5
BRANCH.TODO Normal file
View File

@ -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

View 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

48
source4/lib/policy/adm.h Normal file
View File

@ -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__ */

View File

@ -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

View File

@ -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;
}

142
source4/lib/policy/lex.l Normal file
View File

@ -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 */
}

View File

@ -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);
}

View 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

View 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.

View 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:

View File

@ -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;
}

View 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
################################################

333
source4/lib/registry/dir.c Normal file
View File

@ -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,
};

145
source4/lib/registry/hive.c Normal file
View File

@ -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);
}

197
source4/lib/registry/hive.h Normal file
View File

@ -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__ */

View File

@ -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);
}

501
source4/lib/registry/ldb.c Normal file
View File

@ -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,
};

View File

@ -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;
}

View 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

View 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>

View 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>

View 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>

View 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
@ -19,153 +20,191 @@
*/
#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"
_PUBLIC_ WERROR reg_preg_diff_load(int fd, const struct reg_diff_callbacks *callbacks, void *callback_data);
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;
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;
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;
}
/* 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 (W_ERROR_IS_OK(error2))
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++;
tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
callbacks->add_key(callback_data, tmppath);
reg_generate_diff_key(diff, t1, t2);
}
W_ERROR_NOT_OK_RETURN(
reg_open_key(mem_ctx, newkey, keyname1, &t2));
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;
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)));
}
if (r1 == NULL && r2 == NULL)
continue;
}
reg_generate_diff_key(diff, r1, r2);
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;
}
}
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);
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;
}
}
fdprintf(xf, "\n");
if (callbacks->done != NULL) {
callbacks->done(callback_data);
}
close(xf);
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);
if (fd == -1) {
DEBUG(0, ("Error opening registry patch file `%s'\n", fn));
return NULL;
}
diff = talloc_zero(ctx, struct reg_diff);
if (diff == NULL) {
close(fd);
return NULL;
}
char hdr[4];
diff->format = afdgets(fd, diff, 0);
if (!diff->format) {
talloc_free(diff);
close(fd);
return NULL;
fd = open(filename, O_RDONLY, 0);
if (fd == -1) {
DEBUG(0, ("Error opening registry patch file `%s'\n", filename));
return WERR_GENERAL_FAILURE;
}
while ((line = afdgets(fd, diff, 0))) {
/* Ignore comments and empty lines */
if (strlen(line) == 0 || line[0] == ';') {
curkey = NULL;
talloc_free(line);
continue;
}
/* 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;
}
/* 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;
}
/* 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;
}
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);
/* Delete value */
if (strcmp(p, "-")) {
curval->changetype = REG_DIFF_DEL_VAL;
talloc_free(line);
continue;
}
q = strchr_m(p, ':');
if (q) {
*q = '\0';
q++;
}
curval->changetype = REG_DIFF_SET_VAL;
reg_string_to_val(curkey->values, q?p:"REG_SZ", q?q:p, &curval->type, &curval->data);
talloc_free(line);
if (read(fd, &hdr, 4) != 4) {
DEBUG(0, ("Error reading registry patch file `%s'\n", filename));
return WERR_GENERAL_FAILURE;
}
close(fd);
return diff;
/* 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);
}
}
/**
* Apply diff to a registry context
* The reg_diff_apply functions
*/
_PUBLIC_ BOOL reg_diff_apply (const struct reg_diff *diff, struct registry_context *ctx)
static WERROR reg_diff_apply_add_key(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 *tmp;
WERROR error;
int i, j;
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_key_add_abs(ctx, ctx, key_name, 0, NULL, &tmp);
if(!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Unable to delete key '%s'\n", diff->keys[i].name));
return False;
}
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;
}
continue;
}
static WERROR reg_diff_apply_del_key(void *_ctx, const char *key_name)
{
struct registry_context *ctx = _ctx;
WERROR error;
/* Add / change key */
error = reg_open_key_abs(mem_ctx, ctx, diff->keys[i].name, &tmp);
error = reg_key_del_abs(ctx, key_name);
/* 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;
}
}
if(!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Unable to delete key '%s'\n", key_name));
return error;
}
return WERR_OK;
}
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;
}
}
}
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);
if (W_ERROR_EQUAL(error, WERR_DEST_NOT_FOUND)) {
DEBUG(0, ("Error opening key '%s'\n", path));
return error;
}
return True;
/* Set value */
error = reg_val_set(tmp, value_name,
value_type, value);
if (!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Error setting value '%s'\n", value_name));
return error;
}
return WERR_OK;
}
static WERROR reg_diff_apply_del_value (void *_ctx, const char *key_name, const char *value_name)
{
struct registry_context *ctx = _ctx;
struct registry_key *tmp;
WERROR error;
/* Open key */
error = reg_open_key_abs(ctx, ctx, key_name, &tmp);
if (!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Error opening key '%s'\n", key_name));
return error;
}
error = reg_del_value(tmp, value_name);
if (!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Error deleting value '%s'\n", value_name));
return error;
}
return WERR_OK;
}
static WERROR reg_diff_apply_del_all_values(void *_ctx, const char *key_name)
{
struct registry_context *ctx = _ctx;
struct registry_key *key;
WERROR error;
int i;
uint32_t num_values;
error = reg_open_key_abs(ctx, ctx, key_name, &key);
if (!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Error opening key '%s'\n", key_name));
return error;
}
W_ERROR_NOT_OK_RETURN(reg_key_get_info(ctx, key,
NULL,
NULL,
&num_values,
NULL));
for (i = 0; i < num_values; i++) {
const char *name;
W_ERROR_NOT_OK_RETURN(reg_key_get_value_by_index(ctx, key, i, &name,
NULL, NULL));
W_ERROR_NOT_OK_RETURN(reg_del_value(key, name));
}
return WERR_OK;
}
/**
* Apply diff to a registry context
*/
_PUBLIC_ WERROR reg_diff_apply (const char *filename, struct registry_context *ctx)
{
struct reg_diff_callbacks callbacks;
callbacks.add_key = reg_diff_apply_add_key;
callbacks.del_key = reg_diff_apply_del_key;
callbacks.set_value = reg_diff_apply_set_value;
callbacks.del_value = reg_diff_apply_del_value;
callbacks.del_all_values = reg_diff_apply_del_all_values;
callbacks.done = NULL;
return reg_diff_load(filename, &callbacks, ctx);
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

1923
source4/lib/registry/regf.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -45,8 +45,8 @@ interface regf
uint32 data_offset;
uint32 last_block;
[value(1)] uint32 uk7; /* 1 */
[charset(UTF16)] uint16 description[0x40];
uint32 padding[83]; /* Padding */
[charset(UTF16)] uint16 description[0x20];
uint32 padding[99]; /* Padding */
/* Checksum of first 0x200 bytes XOR-ed */
uint32 chksum;
};
@ -66,7 +66,7 @@ interface regf
uint8 data[offset_to_next-0x20];
/* data is filled with:
uint32 length;
Negative if in used, positive otherwise
Negative if in use, positive otherwise
Always a multiple of 8
uint8_t data[length];
Free space marker if 0xffffffff

View File

@ -2,7 +2,7 @@
Unix SMB/CIFS implementation.
Registry interface
Copyright (C) Gerald Carter 2002.
Copyright (C) Jelmer Vernooij 2003-2004.
Copyright (C) Jelmer Vernooij 2003-2007.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -21,9 +21,12 @@
#ifndef _REGISTRY_H /* _REGISTRY_H */
#define _REGISTRY_H
struct registry_context;
#include "core.h"
#include "talloc/talloc.h"
#include "librpc/gen_ndr/security.h"
#include "lib/registry/hive.h"
/* Handles for the predefined keys */
#define HKEY_CLASSES_ROOT 0x80000000
@ -36,6 +39,9 @@
#define HKEY_PERFORMANCE_TEXT 0x80000050
#define HKEY_PERFORMANCE_NLSTEXT 0x80000060
#define HKEY_FIRST HKEY_CLASSES_ROOT
#define HKEY_LAST HKEY_PERFORMANCE_NLSTEXT
struct reg_predefined_key {
uint32_t handle;
const char *name;
@ -52,17 +58,16 @@ extern const struct reg_predefined_key reg_predefined_keys[];
#define REGISTRY_INTERFACE_VERSION 1
struct reg_key_operations;
/* structure to store the registry handles */
struct registry_key
{
const char *name;
const char *path;
const char *class_name;
NTTIME last_mod;
struct registry_hive *hive;
void *backend_data;
struct registry_context *context;
};
#include "lib/registry/patchfile.h"
struct registry_value
{
const char *name;
@ -74,109 +79,87 @@ struct registry_value
typedef void (*reg_key_notification_function) (void);
typedef void (*reg_value_notification_function) (void);
/*
* Container for function pointers to enumeration routines
* for virtual registry view
*
* Backends can provide :
* - just one hive (example: nt4, w95)
* - several hives (example: rpc).
*
* Backends should always do case-insensitive compares
* (everything is case-insensitive but case-preserving,
* just like the FS)
*
* There is no save function as all operations are expected to
* be atomic.
*/
struct hive_operations {
const char *name;
/* Implement this one */
WERROR (*open_hive) (struct registry_hive *, struct registry_key **);
/* Or this one */
WERROR (*open_key) (TALLOC_CTX *, const struct registry_key *, const char *name, struct registry_key **);
WERROR (*num_subkeys) (const struct registry_key *, uint32_t *count);
WERROR (*num_values) (const struct registry_key *, uint32_t *count);
WERROR (*get_subkey_by_index) (TALLOC_CTX *, const struct registry_key *, int idx, struct registry_key **);
/* Can not contain more than one level */
WERROR (*get_subkey_by_name) (TALLOC_CTX *, const struct registry_key *, const char *name, struct registry_key **);
WERROR (*get_value_by_index) (TALLOC_CTX *, const struct registry_key *, int idx, struct registry_value **);
/* Can not contain more than one level */
WERROR (*get_value_by_name) (TALLOC_CTX *, const struct registry_key *, const char *name, struct registry_value **);
/* Security control */
WERROR (*key_get_sec_desc) (TALLOC_CTX *, const struct registry_key *, struct security_descriptor **);
WERROR (*key_set_sec_desc) (const struct registry_key *, const struct security_descriptor *);
/* Notification */
WERROR (*request_key_change_notify) (const struct registry_key *, reg_key_notification_function);
WERROR (*request_value_change_notify) (const struct registry_value *, reg_value_notification_function);
/* Key management */
WERROR (*add_key)(TALLOC_CTX *, const struct registry_key *, const char *name, uint32_t access_mask, struct security_descriptor *, struct registry_key **);
WERROR (*del_key)(const struct registry_key *, const char *name);
WERROR (*flush_key) (const struct registry_key *);
/* Value management */
WERROR (*set_value)(const struct registry_key *, const char *name, uint32_t type, const DATA_BLOB data);
WERROR (*del_value)(const struct registry_key *, const char *valname);
};
struct cli_credentials;
struct registry_context;
struct registry_hive
{
const struct hive_operations *functions;
struct registry_key *root;
struct auth_session_info *session_info;
struct cli_credentials *credentials;
void *backend_data;
const char *location;
};
struct registry_operations {
const char *name;
/* Handle to a full registry
* contains zero or more hives */
WERROR (*get_key_info) (TALLOC_CTX *mem_ctx,
const struct registry_key *key,
const char **classname,
uint32_t *numsubkeys,
uint32_t *numvalues,
NTTIME *last_change_time);
WERROR (*flush_key) (struct registry_key *key);
WERROR (*get_predefined_key) (const struct registry_context *ctx,
uint32_t key_id,
struct registry_key **key);
WERROR (*open_key) (TALLOC_CTX *mem_ctx,
struct registry_key *parent,
const char *path,
struct registry_key **key);
WERROR (*create_key) (TALLOC_CTX *mem_ctx,
struct registry_key *parent,
const char *name,
const char *key_class,
struct security_descriptor *security,
struct registry_key **key);
WERROR (*delete_key) (struct registry_key *key, const char *name);
WERROR (*delete_value) (struct registry_key *key, const char *name);
WERROR (*enum_key) (TALLOC_CTX *mem_ctx,
const struct registry_key *key, uint32_t idx,
const char **name,
const char **keyclass,
NTTIME *last_changed_time);
WERROR (*enum_value) (TALLOC_CTX *mem_ctx,
const struct registry_key *key, uint32_t idx,
const char **name,
uint32_t *type,
DATA_BLOB *data);
WERROR (*get_security) (TALLOC_CTX *mem_ctx,
const struct registry_key *key,
struct security_descriptor **security);
WERROR (*set_security) (struct registry_key *key,
const struct security_descriptor *security);
WERROR (*load_key) (struct registry_key *key,
const char *key_name,
const char *path);
WERROR (*unload_key) (struct registry_key *key, const char *name);
WERROR (*notify_value_change) (struct registry_key *key,
reg_value_notification_function fn);
WERROR (*get_value) (TALLOC_CTX *mem_ctx,
const struct registry_key *key,
const char *name,
uint32_t *type,
DATA_BLOB *data);
WERROR (*set_value) (struct registry_key *key,
const char *name,
uint32_t type,
const DATA_BLOB data);
};
/**
* Handle to a full registry
* contains zero or more hives
*/
struct registry_context {
void *backend_data;
struct cli_credentials *credentials;
struct auth_session_info *session_info;
WERROR (*get_predefined_key) (struct registry_context *, uint32_t hkey, struct registry_key **);
};
struct reg_init_function_entry {
const struct hive_operations *hive_functions;
struct reg_init_function_entry *prev, *next;
};
/* Representing differences between registry files */
struct reg_diff_value
{
const char *name;
enum { REG_DIFF_DEL_VAL, REG_DIFF_SET_VAL } changetype;
uint32_t type;
DATA_BLOB data;
};
struct reg_diff_key
{
const char *name;
enum { REG_DIFF_CHANGE_KEY, REG_DIFF_DEL_KEY } changetype;
uint32_t numvalues;
struct reg_diff_value *values;
};
struct reg_diff
{
const char *format;
uint32_t numkeys;
struct reg_diff_key *keys;
const struct registry_operations *ops;
};
struct auth_session_info;
@ -186,60 +169,110 @@ struct event_context;
#define _PUBLIC_
#endif
/**
* Open the locally defined registry.
*/
_PUBLIC_ WERROR reg_open_local (TALLOC_CTX *mem_ctx,
struct registry_context **ctx,
struct auth_session_info *session_info,
struct cli_credentials *credentials);
_PUBLIC_ WERROR reg_open_samba (TALLOC_CTX *mem_ctx,
struct registry_context **ctx,
struct auth_session_info *session_info,
struct cli_credentials *credentials);
/**
* Open the registry on a remote machine.
*/
_PUBLIC_ WERROR reg_open_remote(struct registry_context **ctx,
struct auth_session_info *session_info,
struct cli_credentials *credentials,
const char *location, struct event_context *ev);
_PUBLIC_ NTSTATUS registry_register(const void *_hive_ops);
_PUBLIC_ NTSTATUS registry_init(void);
_PUBLIC_ BOOL reg_has_backend(const char *backend);
_PUBLIC_ int reg_list_predefs(TALLOC_CTX *mem_ctx, char ***predefs, uint32_t **hkeys);
_PUBLIC_ WERROR reg_open_wine(struct registry_context **ctx, const char *path);
_PUBLIC_ const char *reg_get_predef_name(uint32_t hkey);
_PUBLIC_ WERROR reg_get_predefined_key_by_name(struct registry_context *ctx, const char *name, struct registry_key **key);
_PUBLIC_ WERROR reg_get_predefined_key(struct registry_context *ctx, uint32_t hkey, struct registry_key **key);
_PUBLIC_ WERROR reg_open_hive(TALLOC_CTX *parent_ctx, const char *backend, const char *location, struct auth_session_info *session_info, struct cli_credentials *credentials, struct registry_key **root);
_PUBLIC_ WERROR reg_open_key(TALLOC_CTX *mem_ctx, struct registry_key *parent, const char *name, struct registry_key **result);
_PUBLIC_ WERROR reg_key_get_value_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *key, int idx, struct registry_value **val);
_PUBLIC_ WERROR reg_key_num_subkeys(const struct registry_key *key, uint32_t *count);
_PUBLIC_ WERROR reg_key_num_values(const struct registry_key *key, uint32_t *count);
_PUBLIC_ WERROR reg_key_get_subkey_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *key, int idx, struct registry_key **subkey);
WERROR reg_key_get_subkey_by_name(TALLOC_CTX *mem_ctx, const struct registry_key *key, const char *name, struct registry_key **subkey);
_PUBLIC_ WERROR reg_key_get_value_by_name(TALLOC_CTX *mem_ctx, const struct registry_key *key, const char *name, struct registry_value **val);
_PUBLIC_ WERROR reg_get_predefined_key_by_name(struct registry_context *ctx,
const char *name,
struct registry_key **key);
_PUBLIC_ WERROR reg_get_predefined_key(const struct registry_context *ctx,
uint32_t hkey,
struct registry_key **key);
_PUBLIC_ WERROR reg_open_key(TALLOC_CTX *mem_ctx, struct registry_key *parent,
const char *name, struct registry_key **result);
_PUBLIC_ WERROR reg_key_get_value_by_index(TALLOC_CTX *mem_ctx,
const struct registry_key *key, uint32_t idx,
const char **name,
uint32_t *type,
DATA_BLOB *data);
_PUBLIC_ WERROR reg_key_get_info(TALLOC_CTX *mem_ctx,
const struct registry_key *key,
const char **class_name,
uint32_t *num_subkeys,
uint32_t *num_values,
NTTIME *last_change_time);
_PUBLIC_ WERROR reg_key_get_subkey_by_index(TALLOC_CTX *mem_ctx,
const struct registry_key *key,
int idx,
const char **name,
const char **classname,
NTTIME *last_mod_time);
WERROR reg_key_get_subkey_by_name(TALLOC_CTX *mem_ctx,
const struct registry_key *key,
const char *name,
struct registry_key **subkey);
_PUBLIC_ WERROR reg_key_get_value_by_name(TALLOC_CTX *mem_ctx,
const struct registry_key *key,
const char *name,
uint32_t *type,
DATA_BLOB *data);
_PUBLIC_ WERROR reg_key_del(struct registry_key *parent, const char *name);
_PUBLIC_ WERROR reg_key_add_name(TALLOC_CTX *mem_ctx, const struct registry_key *parent, const char *name, uint32_t access_mask, struct security_descriptor *desc, struct registry_key **newkey);
_PUBLIC_ WERROR reg_val_set(struct registry_key *key, const char *value, uint32_t type, DATA_BLOB data);
_PUBLIC_ WERROR reg_key_add_name(TALLOC_CTX *mem_ctx,
struct registry_key *parent, const char *name,
const char *classname,
struct security_descriptor *desc,
struct registry_key **newkey);
_PUBLIC_ WERROR reg_val_set(struct registry_key *key, const char *value,
uint32_t type, DATA_BLOB data);
_PUBLIC_ WERROR reg_get_sec_desc(TALLOC_CTX *ctx, const struct registry_key *key, struct security_descriptor **secdesc);
_PUBLIC_ WERROR reg_del_value(const struct registry_key *key, const char *valname);
_PUBLIC_ WERROR reg_key_flush(const struct registry_key *key);
_PUBLIC_ WERROR reg_key_subkeysizes(const struct registry_key *key, uint32_t *max_subkeylen, uint32_t *max_subkeysize);
_PUBLIC_ WERROR reg_key_valuesizes(const struct registry_key *key, uint32_t *max_valnamelen, uint32_t *max_valbufsize);
_PUBLIC_ WERROR reg_del_value(struct registry_key *key, const char *valname);
_PUBLIC_ WERROR reg_key_flush(struct registry_key *key);
WERROR reg_create_key (TALLOC_CTX *mem_ctx,
struct registry_key *parent,
const char *name,
const char *key_class,
struct security_descriptor *security,
struct registry_key **key);
/* Utility functions */
_PUBLIC_ const char *str_regtype(int type);
_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type, DATA_BLOB *data);
_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, struct registry_value *val) ;
_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type,
const DATA_BLOB data);
_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, const char *name,
uint32_t type, const DATA_BLOB data);
_PUBLIC_ BOOL reg_string_to_val(TALLOC_CTX *mem_ctx, const char *type_str, const char *data_str, uint32_t *type, DATA_BLOB *data);
char *reg_path_win2unix(char *path) ;
char *reg_path_unix2win(char *path) ;
WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, const char *name, struct registry_key **result);
WERROR reg_key_del_abs(struct registry_context *ctx, const char *path);
WERROR reg_key_add_abs(TALLOC_CTX *mem_ctx, struct registry_context *ctx, const char *path, uint32_t access_mask, struct security_descriptor *sec_desc, struct registry_key **result);
WERROR reg_load_key(struct registry_context *ctx, struct registry_key *key,
const char *name, const char *filename);
WERROR reg_mount_hive(struct registry_context *rctx,
struct hive_key *hive_key,
uint32_t key_id,
const char **elements);
/* Patch files */
struct registry_key *reg_import_hive_key(struct registry_context *ctx,
struct hive_key *hive,
uint32_t predef_key,
const char **elements);
_PUBLIC_ struct reg_diff *reg_generate_diff(TALLOC_CTX *mem_ctx, struct registry_context *ctx1, struct registry_context *ctx2);
_PUBLIC_ WERROR reg_diff_save(const struct reg_diff *diff, const char *filename);
_PUBLIC_ struct reg_diff *reg_diff_load(TALLOC_CTX *ctx, const char *fn);
_PUBLIC_ BOOL reg_diff_apply (const struct reg_diff *diff, struct registry_context *ctx);
NTSTATUS registry_rpc_init(void);
#endif /* _REGISTRY_H */

View File

@ -1,7 +1,7 @@
/*
Samba Unix/Linux SMB implementation
RPC backend for the registry library
Copyright (C) 2003-2004 Jelmer Vernooij, jelmer@samba.org
Copyright (C) 2003-2007 Jelmer Vernooij, jelmer@samba.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -20,7 +20,23 @@
#include "registry.h"
#include "librpc/gen_ndr/ndr_winreg_c.h"
static struct hive_operations reg_backend_rpc;
struct rpc_key {
struct registry_key key;
struct policy_handle pol;
struct dcerpc_pipe *pipe;
uint32_t num_values;
uint32_t num_subkeys;
uint32_t max_valnamelen;
uint32_t max_valdatalen;
};
struct rpc_registry_context {
struct registry_context context;
struct dcerpc_pipe *pipe;
};
static struct registry_operations reg_backend_rpc;
/**
* This is the RPC backend for the registry library.
@ -58,57 +74,46 @@ openhive(HKCR)
openhive(HKDD)
openhive(HKCC)
struct rpc_key_data {
struct policy_handle pol;
int num_subkeys;
int num_values;
int max_valnamelen;
int max_valdatalen;
};
static struct {
uint32_t hkey;
WERROR (*open) (struct dcerpc_pipe *p, TALLOC_CTX *, struct policy_handle *h);
} known_hives[] = {
{ HKEY_LOCAL_MACHINE, open_HKLM },
{ HKEY_CURRENT_USER, open_HKCU },
{ HKEY_CLASSES_ROOT, open_HKCR },
{ HKEY_PERFORMANCE_DATA, open_HKPD },
{ HKEY_USERS, open_HKU },
{ HKEY_DYN_DATA, open_HKDD },
{ HKEY_CURRENT_CONFIG, open_HKCC },
{ 0, NULL }
{ HKEY_LOCAL_MACHINE, open_HKLM },
{ HKEY_CURRENT_USER, open_HKCU },
{ HKEY_CLASSES_ROOT, open_HKCR },
{ HKEY_PERFORMANCE_DATA, open_HKPD },
{ HKEY_USERS, open_HKU },
{ HKEY_DYN_DATA, open_HKDD },
{ HKEY_CURRENT_CONFIG, open_HKCC },
{ 0, NULL }
};
static WERROR rpc_query_key(const struct registry_key *k);
static WERROR rpc_get_predefined_key (struct registry_context *ctx, uint32_t hkey_type, struct registry_key **k)
static WERROR rpc_get_predefined_key(struct registry_context *ctx,
uint32_t hkey_type,
struct registry_key **k)
{
int n;
struct registry_hive *h;
struct rpc_key_data *mykeydata;
struct rpc_registry_context *rctx = talloc_get_type(ctx,
struct rpc_registry_context);
struct rpc_key *mykeydata;
for(n = 0; known_hives[n].hkey; n++)
{
if(known_hives[n].hkey == hkey_type) break;
for(n = 0; known_hives[n].hkey; n++) {
if(known_hives[n].hkey == hkey_type)
break;
}
if(!known_hives[n].open) {
if (known_hives[n].open == NULL) {
DEBUG(1, ("No such hive %d\n", hkey_type));
return WERR_NO_MORE_ITEMS;
}
h = talloc(ctx, struct registry_hive);
h->functions = &reg_backend_rpc;
h->location = NULL;
h->backend_data = ctx->backend_data;
(*k) = h->root = talloc(h, struct registry_key);
(*k)->hive = h;
(*k)->backend_data = mykeydata = talloc(*k, struct rpc_key_data);
mykeydata = talloc(ctx, struct rpc_key);
mykeydata->pipe = rctx->pipe;
mykeydata->num_values = -1;
mykeydata->num_subkeys = -1;
return known_hives[n].open((struct dcerpc_pipe *)ctx->backend_data, *k, &(mykeydata->pol));
return known_hives[n].open(mykeydata->pipe, *k, &(mykeydata->pol));
}
#if 0
@ -136,44 +141,44 @@ static WERROR rpc_key_put_rpc_data(TALLOC_CTX *mem_ctx, struct registry_key *k)
}
#endif
static WERROR rpc_open_key(TALLOC_CTX *mem_ctx, const struct registry_key *h, const char *name, struct registry_key **key)
static WERROR rpc_open_key(TALLOC_CTX *mem_ctx, struct registry_key *h,
const char *name, struct registry_key **key)
{
struct rpc_key_data *mykeydata;
struct rpc_key *mykeydata = talloc_get_type(h, struct rpc_key),
*newkeydata;
struct winreg_OpenKey r;
*key = talloc(mem_ctx, struct registry_key);
(*key)->name = talloc_strdup(mem_ctx, name);
(*key)->backend_data = mykeydata = talloc(mem_ctx, struct rpc_key_data);
mykeydata->num_values = -1;
mykeydata->num_subkeys = -1;
mykeydata = talloc(mem_ctx, struct rpc_key);
/* Then, open the handle using the hive */
memset(&r, 0, sizeof(struct winreg_OpenKey));
r.in.parent_handle = &(((struct rpc_key_data *)h->backend_data)->pol);
r.in.parent_handle = &mykeydata->pol;
init_winreg_String(&r.in.keyname, name);
r.in.unknown = 0x00000000;
r.in.access_mask = 0x02000000;
r.out.handle = &mykeydata->pol;
r.out.handle = &newkeydata->pol;
dcerpc_winreg_OpenKey((struct dcerpc_pipe *)(h->hive->backend_data), mem_ctx, &r);
dcerpc_winreg_OpenKey(mykeydata->pipe, mem_ctx, &r);
return r.out.result;
}
static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *parent, int n, struct registry_value **value)
static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx,
const struct registry_key *parent,
uint32_t n,
const char **value_name,
uint32_t *type,
DATA_BLOB *data)
{
struct rpc_key_data *mykeydata = parent->backend_data;
struct rpc_key *mykeydata = talloc_get_type(parent, struct rpc_key);
WERROR error;
struct winreg_EnumValue r;
uint32_t len1, zero = 0;
enum winreg_Type type;
NTSTATUS status;
struct winreg_StringBuf name;
uint8_t u8;
if(mykeydata->num_values == -1) {
if (mykeydata->num_values == -1) {
error = rpc_query_key(parent);
if(!W_ERROR_IS_OK(error)) return error;
}
@ -187,13 +192,13 @@ static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, const struct registry_
r.in.handle = &mykeydata->pol;
r.in.enum_index = n;
r.in.name = &name;
r.in.type = &type;
r.in.type = type;
r.in.value = &u8;
r.in.length = &zero;
r.in.size = &len1;
r.out.name = &name;
status = dcerpc_winreg_EnumValue((struct dcerpc_pipe *)parent->hive->backend_data, mem_ctx, &r);
status = dcerpc_winreg_EnumValue(mykeydata->pipe, mem_ctx, &r);
if(NT_STATUS_IS_ERR(status)) {
DEBUG(0, ("Error in EnumValue: %s\n", nt_errstr(status)));
return WERR_GENERAL_FAILURE;
@ -201,20 +206,23 @@ static WERROR rpc_get_value_by_index(TALLOC_CTX *mem_ctx, const struct registry_
if(NT_STATUS_IS_OK(status) &&
W_ERROR_IS_OK(r.out.result) && r.out.length) {
*value = talloc(mem_ctx, struct registry_value);
(*value)->name = talloc_strdup(mem_ctx, r.out.name->name);
(*value)->data_type = type;
(*value)->data = data_blob_talloc(mem_ctx, r.out.value, *r.out.length);
*value_name = talloc_strdup(mem_ctx, r.out.name->name);
*data = data_blob_talloc(mem_ctx, r.out.value, *r.out.length);
return WERR_OK;
}
return r.out.result;
}
static WERROR rpc_get_subkey_by_index(TALLOC_CTX *mem_ctx, const struct registry_key *parent, int n, struct registry_key **subkey)
static WERROR rpc_get_subkey_by_index(TALLOC_CTX *mem_ctx,
const struct registry_key *parent,
uint32_t n,
const char **name,
const char **keyclass,
NTTIME *last_changed_time)
{
struct winreg_EnumKey r;
struct rpc_key_data *mykeydata = parent->backend_data;
struct rpc_key *mykeydata = talloc_get_type(parent, struct rpc_key);
NTSTATUS status;
struct winreg_StringBuf namebuf, classbuf;
NTTIME change_time = 0;
@ -233,40 +241,47 @@ static WERROR rpc_get_subkey_by_index(TALLOC_CTX *mem_ctx, const struct registry
r.in.last_changed_time = &change_time;
r.out.name = &namebuf;
status = dcerpc_winreg_EnumKey((struct dcerpc_pipe *)parent->hive->backend_data, mem_ctx, &r);
status = dcerpc_winreg_EnumKey(mykeydata->pipe, mem_ctx, &r);
if(NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(r.out.result)) {
char *name = talloc_strdup(mem_ctx, r.out.name->name);
return rpc_open_key(mem_ctx, parent, name, subkey);
*name = talloc_strdup(mem_ctx, r.out.name->name);
*keyclass = talloc_strdup(mem_ctx, r.out.keyclass->name);
*last_changed_time = *r.out.last_changed_time;
}
return r.out.result;
}
static WERROR rpc_add_key(TALLOC_CTX *mem_ctx, const struct registry_key *parent, const char *name, uint32_t access_mask, struct security_descriptor *sec, struct registry_key **key)
static WERROR rpc_add_key(TALLOC_CTX *mem_ctx,
struct registry_key *parent, const char *name,
const char *key_class,
struct security_descriptor *sec,
struct registry_key **key)
{
NTSTATUS status;
struct winreg_CreateKey r;
struct rpc_key *parentkd = talloc_get_type(parent, struct rpc_key);
struct rpc_key *rpck = talloc(mem_ctx, struct rpc_key);
init_winreg_String(&r.in.name, name);
init_winreg_String(&r.in.keyclass, NULL);
r.in.handle = parent->backend_data;
r.out.new_handle = talloc(mem_ctx, struct policy_handle);
r.in.handle = &parentkd->pol;
r.out.new_handle = &rpck->pol;
r.in.options = 0;
r.in.access_mask = access_mask;
r.in.access_mask = SEC_STD_ALL;
r.in.secdesc = NULL;
status = dcerpc_winreg_CreateKey((struct dcerpc_pipe *)(parent->hive->backend_data), mem_ctx, &r);
status = dcerpc_winreg_CreateKey(parentkd->pipe, mem_ctx, &r);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(rpck);
DEBUG(1, ("CreateKey failed - %s\n", nt_errstr(status)));
return ntstatus_to_werror(status);
}
if (W_ERROR_IS_OK(r.out.result)) {
*key = talloc(mem_ctx, struct registry_key);
(*key)->name = talloc_strdup(*key, name);
(*key)->backend_data = r.out.new_handle;
rpck->pipe = talloc_reference(rpck, parentkd->pipe);
*key = (struct registry_key *)rpck;
}
return r.out.result;
@ -276,14 +291,14 @@ static WERROR rpc_query_key(const struct registry_key *k)
{
NTSTATUS status;
struct winreg_QueryInfoKey r;
struct rpc_key_data *mykeydata = k->backend_data;
struct rpc_key *mykeydata = talloc_get_type(k, struct rpc_key);
TALLOC_CTX *mem_ctx = talloc_init("query_key");
r.in.classname = talloc(mem_ctx, struct winreg_String);
init_winreg_String(r.in.classname, NULL);
r.in.handle = &mykeydata->pol;
status = dcerpc_winreg_QueryInfoKey((struct dcerpc_pipe *)(k->hive->backend_data), mem_ctx, &r);
status = dcerpc_winreg_QueryInfoKey(mykeydata->pipe, mem_ctx, &r);
talloc_free(mem_ctx);
if (!NT_STATUS_IS_OK(status)) {
@ -301,26 +316,29 @@ static WERROR rpc_query_key(const struct registry_key *k)
return r.out.result;
}
static WERROR rpc_del_key(const struct registry_key *parent, const char *name)
static WERROR rpc_del_key(struct registry_key *parent, const char *name)
{
NTSTATUS status;
struct rpc_key_data *mykeydata = parent->backend_data;
struct rpc_key *mykeydata = talloc_get_type(parent, struct rpc_key);
struct winreg_DeleteKey r;
TALLOC_CTX *mem_ctx = talloc_init("del_key");
r.in.handle = &mykeydata->pol;
init_winreg_String(&r.in.key, name);
status = dcerpc_winreg_DeleteKey((struct dcerpc_pipe *)parent->hive->backend_data, mem_ctx, &r);
status = dcerpc_winreg_DeleteKey(mykeydata->pipe, mem_ctx, &r);
talloc_free(mem_ctx);
return r.out.result;
}
static WERROR rpc_num_values(const struct registry_key *key, uint32_t *count)
static WERROR rpc_get_info(TALLOC_CTX *mem_ctx, const struct registry_key *key,
const char **classname,
uint32_t *numsubkeys,
uint32_t *numvalue)
{
struct rpc_key_data *mykeydata = key->backend_data;
struct rpc_key *mykeydata = talloc_get_type(key, struct rpc_key);
WERROR error;
if(mykeydata->num_values == -1) {
@ -328,42 +346,34 @@ static WERROR rpc_num_values(const struct registry_key *key, uint32_t *count)
if(!W_ERROR_IS_OK(error)) return error;
}
*count = mykeydata->num_values;
/* FIXME: *classname = talloc_strdup(mem_ctx, mykeydata->classname); */
*numvalue = mykeydata->num_values;
*numsubkeys = mykeydata->num_subkeys;
return WERR_OK;
}
static WERROR rpc_num_subkeys(const struct registry_key *key, uint32_t *count)
{
struct rpc_key_data *mykeydata = key->backend_data;
WERROR error;
if(mykeydata->num_subkeys == -1) {
error = rpc_query_key(key);
if(!W_ERROR_IS_OK(error)) return error;
}
*count = mykeydata->num_subkeys;
return WERR_OK;
}
static struct hive_operations reg_backend_rpc = {
static struct registry_operations reg_backend_rpc = {
.name = "rpc",
.open_key = rpc_open_key,
.get_subkey_by_index = rpc_get_subkey_by_index,
.get_value_by_index = rpc_get_value_by_index,
.add_key = rpc_add_key,
.del_key = rpc_del_key,
.num_subkeys = rpc_num_subkeys,
.num_values = rpc_num_values,
.enum_key = rpc_get_subkey_by_index,
.enum_value = rpc_get_value_by_index,
.create_key = rpc_add_key,
.delete_key = rpc_del_key,
.get_key_info = rpc_get_info,
};
_PUBLIC_ WERROR reg_open_remote(struct registry_context **ctx, struct auth_session_info *session_info, struct cli_credentials *credentials,
const char *location, struct event_context *ev)
_PUBLIC_ WERROR reg_open_remote(struct registry_context **ctx,
struct auth_session_info *session_info,
struct cli_credentials *credentials,
const char *location, struct event_context *ev)
{
NTSTATUS status;
struct dcerpc_pipe *p;
struct rpc_registry_context *rctx;
*ctx = talloc(NULL, struct registry_context);
dcerpc_init();
rctx = talloc(NULL, struct rpc_registry_context);
/* Default to local smbd if no connection is specified */
if (!location) {
@ -374,7 +384,7 @@ _PUBLIC_ WERROR reg_open_remote(struct registry_context **ctx, struct auth_sessi
&p, location,
&ndr_table_winreg,
credentials, ev);
(*ctx)->backend_data = p;
rctx->pipe = p;
if(NT_STATUS_IS_ERR(status)) {
DEBUG(1, ("Unable to open '%s': %s\n", location, nt_errstr(status)));
@ -383,13 +393,7 @@ _PUBLIC_ WERROR reg_open_remote(struct registry_context **ctx, struct auth_sessi
return ntstatus_to_werror(status);
}
(*ctx)->get_predefined_key = rpc_get_predefined_key;
*ctx = (struct registry_context *)rctx;
return WERR_OK;
}
NTSTATUS registry_rpc_init(void)
{
dcerpc_init();
return registry_register(&reg_backend_rpc);
}

View File

@ -1,6 +1,6 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Jelmer Vernooij 2004.
Copyright (C) Jelmer Vernooij 2004-2007.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -24,30 +24,51 @@
* @brief Samba-specific registry functions
*/
static WERROR reg_samba_get_predef (struct registry_context *ctx, uint32_t hkey, struct registry_key **k)
WERROR mount_samba_hive(struct registry_context *ctx,
struct auth_session_info *auth_info,
struct cli_credentials *creds,
const char *name,
uint32_t hive_id)
{
WERROR error;
const char *conf;
char *backend;
struct hive_key *hive;
const char *location;
const char *hivename = reg_get_predef_name(hkey);
*k = NULL;
location = talloc_asprintf(ctx, "%s/%s.ldb", lp_private_dir(), name);
conf = lp_parm_string(-1, "registry", hivename);
if (!conf) {
return WERR_NOT_SUPPORTED;
error = reg_open_hive(ctx, location, auth_info, creds, &hive);
if (!W_ERROR_IS_OK(error))
return error;
return reg_mount_hive(ctx, hive, hive_id, NULL);
}
_PUBLIC_ WERROR reg_open_samba (TALLOC_CTX *mem_ctx,
struct registry_context **ctx,
struct auth_session_info *session_info,
struct cli_credentials *credentials)
{
WERROR result;
result = reg_open_local(mem_ctx, ctx, session_info, credentials);
if (!W_ERROR_IS_OK(result)) {
return result;
}
location = strchr(conf, ':');
if (location) {
backend = talloc_strndup(ctx, conf, (int)(location - conf));
location++;
} else {
backend = talloc_strdup(ctx, "ldb");
location = conf;
}
mount_samba_hive(*ctx, session_info, credentials,
"hklm", HKEY_LOCAL_MACHINE);
mount_samba_hive(*ctx, session_info, credentials,
"hkcr", HKEY_CLASSES_ROOT);
/* FIXME: Should be mounted from NTUSER.DAT in the home directory of the
* current user */
mount_samba_hive(*ctx, session_info, credentials,
"hkcu", HKEY_CURRENT_USER);
mount_samba_hive(*ctx, session_info, credentials,
"hku", HKEY_USERS);
/* FIXME: Different hive backend for HKEY_CLASSES_ROOT: merged view of HKEY_LOCAL_MACHINE\Software\Classes
* and HKEY_CURRENT_USER\Software\Classes */
@ -59,23 +80,6 @@ static WERROR reg_samba_get_predef (struct registry_context *ctx, uint32_t hkey,
/* FIXME: HKEY_LOCAL_MACHINE\Hardware is autogenerated */
/* FIXME: HKEY_LOCAL_MACHINE\Security\SAM is an alias for HKEY_LOCAL_MACHINE\SAM */
error = reg_open_hive(ctx, backend, location, ctx->session_info, ctx->credentials, k);
talloc_free(backend);
return error;
}
_PUBLIC_ WERROR reg_open_local (TALLOC_CTX *mem_ctx,
struct registry_context **ctx,
struct auth_session_info *session_info,
struct cli_credentials *credentials)
{
*ctx = talloc(mem_ctx, struct registry_context);
(*ctx)->credentials = talloc_reference(*ctx, credentials);
(*ctx)->session_info = talloc_reference(*ctx, session_info);
(*ctx)->get_predefined_key = reg_samba_get_predef;
return WERR_OK;
}

View File

@ -0,0 +1,105 @@
/*
Unix SMB/CIFS implementation.
local testing of registry diff functionality
Copyright (C) Jelmer Vernooij 2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "lib/registry/registry.h"
#include "lib/cmdline/popt_common.h"
#include "torture/torture.h"
#include "librpc/gen_ndr/winreg.h"
static bool test_generate_diff(struct torture_context *test)
{
/* WERROR reg_generate_diff(struct registry_context *ctx1,
struct registry_context *ctx2,
const struct reg_diff_callbacks *callbacks,
void *callback_data)
*/
return true;
}
static bool test_diff_load(struct torture_context *test)
{
/* WERROR reg_diff_load(const char *filename, const struct reg_diff_callbacks *callbacks, void *callback_data) */
return true;
}
static bool test_diff_apply(struct torture_context *test)
{
/*
_PUBLIC_ WERROR reg_diff_apply (const char *filename, struct registry_context *ctx)
*/
return true;
}
static const char *added_key = NULL;
static WERROR test_add_key (void *callback_data, const char *key_name)
{
added_key = talloc_strdup(callback_data, key_name);
return WERR_OK;
}
static bool test_generate_diff_key_add(struct torture_context *test)
{
struct reg_diff_callbacks cb;
struct registry_key rk;
return true;
ZERO_STRUCT(cb);
cb.add_key = test_add_key;
if (W_ERROR_IS_OK(reg_generate_diff_key(&rk, NULL, "bla", &cb, test)))
return false;
torture_assert_str_equal(test, added_key, "bla", "key added");
return true;
}
static bool test_generate_diff_key_null(struct torture_context *test)
{
struct reg_diff_callbacks cb;
ZERO_STRUCT(cb);
if (!W_ERROR_IS_OK(reg_generate_diff_key(NULL, NULL, "", &cb, NULL)))
return false;
return true;
}
struct torture_suite *torture_registry_diff(TALLOC_CTX *mem_ctx)
{
struct torture_suite *suite = torture_suite_create(mem_ctx,
"DIFF");
torture_suite_add_simple_test(suite, "test_generate_diff_key_add", test_generate_diff_key_add);
torture_suite_add_simple_test(suite, "test_generate_diff_key_null", test_generate_diff_key_null);
torture_suite_add_simple_test(suite, "test_diff_apply", test_diff_apply);
torture_suite_add_simple_test(suite, "test_generate_diff", test_generate_diff);
torture_suite_add_simple_test(suite, "test_diff_load", test_diff_load);
return suite;
}

View File

@ -3,7 +3,7 @@
local testing of registry library
Copyright (C) Jelmer Vernooij 2005
Copyright (C) Jelmer Vernooij 2005-2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -25,6 +25,10 @@
#include "torture/torture.h"
#include "librpc/gen_ndr/winreg.h"
struct torture_suite *torture_registry_hive(TALLOC_CTX *mem_ctx);
struct torture_suite *torture_registry_registry(TALLOC_CTX *mem_ctx);
struct torture_suite *torture_registry_diff(TALLOC_CTX *mem_ctx);
static bool test_str_regtype(struct torture_context *ctx)
{
torture_assert_str_equal(ctx, str_regtype(1), "REG_SZ", "REG_SZ failed");
@ -38,7 +42,8 @@ static bool test_reg_val_data_string_dword(struct torture_context *ctx)
{
uint32_t d = 0x20;
DATA_BLOB db = { (uint8_t *)&d, sizeof(d) };
torture_assert_str_equal(ctx, "0x20", reg_val_data_string(ctx, REG_DWORD, &db), "dword failed");
torture_assert_str_equal(ctx, "0x20",
reg_val_data_string(ctx, REG_DWORD, db), "dword failed");
return true;
}
@ -46,9 +51,9 @@ static bool test_reg_val_data_string_sz(struct torture_context *ctx)
{
DATA_BLOB db;
db.length = convert_string_talloc(ctx, CH_UNIX, CH_UTF16, "bla", 3, (void **)&db.data);
torture_assert_str_equal(ctx, "bla", reg_val_data_string(ctx, REG_SZ, &db), "sz failed");
torture_assert_str_equal(ctx, "bla", reg_val_data_string(ctx, REG_SZ, db), "sz failed");
db.length = 4;
torture_assert_str_equal(ctx, "bl", reg_val_data_string(ctx, REG_SZ, &db), "sz failed");
torture_assert_str_equal(ctx, "bl", reg_val_data_string(ctx, REG_SZ, db), "sz failed");
return true;
}
@ -56,7 +61,9 @@ static bool test_reg_val_data_string_binary(struct torture_context *ctx)
{
uint8_t x[] = { 0x1, 0x2, 0x3, 0x4 };
DATA_BLOB db = { x, 4 };
torture_assert_str_equal(ctx, "01020304", reg_val_data_string(ctx, REG_BINARY, &db), "binary failed");
torture_assert_str_equal(ctx, "01020304",
reg_val_data_string(ctx, REG_BINARY, db),
"binary failed");
return true;
}
@ -64,18 +71,20 @@ static bool test_reg_val_data_string_binary(struct torture_context *ctx)
static bool test_reg_val_data_string_empty(struct torture_context *ctx)
{
DATA_BLOB db = { NULL, 0 };
torture_assert_str_equal(ctx, "", reg_val_data_string(ctx, REG_BINARY, &db), "empty failed");
torture_assert_str_equal(ctx, "",
reg_val_data_string(ctx, REG_BINARY, db), "empty failed");
return true;
}
static bool test_reg_val_description(struct torture_context *ctx)
{
struct registry_value val;
val.name = "camel";
val.data_type = REG_SZ;
val.data.length = convert_string_talloc(ctx, CH_UNIX, CH_UTF16, "stationary traveller",
strlen("stationary traveller"), (void **)&val.data.data);
torture_assert_str_equal(ctx, "camel = REG_SZ : stationary traveller", reg_val_description(ctx, &val),
DATA_BLOB data;
data.length = convert_string_talloc(ctx, CH_UNIX, CH_UTF16,
"stationary traveller",
strlen("stationary traveller"),
(void **)&data.data);
torture_assert_str_equal(ctx, "camel = REG_SZ : stationary traveller",
reg_val_description(ctx, "camel", REG_SZ, data),
"reg_val_description failed");
return true;
}
@ -83,12 +92,11 @@ static bool test_reg_val_description(struct torture_context *ctx)
static bool test_reg_val_description_nullname(struct torture_context *ctx)
{
struct registry_value val;
val.name = NULL;
val.data_type = REG_SZ;
val.data.length = convert_string_talloc(ctx, CH_UNIX, CH_UTF16, "west berlin",
strlen("west berlin"), (void **)&val.data.data);
torture_assert_str_equal(ctx, "<No Name> = REG_SZ : west berlin", reg_val_description(ctx, &val),
DATA_BLOB data;
data.length = convert_string_talloc(ctx, CH_UNIX, CH_UTF16, "west berlin",
strlen("west berlin"), (void **)&data.data);
torture_assert_str_equal(ctx, "<No Name> = REG_SZ : west berlin",
reg_val_description(ctx, NULL, REG_SZ, data),
"description with null name failed");
return true;
}
@ -98,12 +106,22 @@ struct torture_suite *torture_registry(TALLOC_CTX *mem_ctx)
struct torture_suite *suite = torture_suite_create(mem_ctx,
"REGISTRY");
torture_suite_add_simple_test(suite, "str_regtype", test_str_regtype);
torture_suite_add_simple_test(suite, "reg_val_data_string dword", test_reg_val_data_string_dword);
torture_suite_add_simple_test(suite, "reg_val_data_string sz", test_reg_val_data_string_sz);
torture_suite_add_simple_test(suite, "reg_val_data_string binary", test_reg_val_data_string_binary);
torture_suite_add_simple_test(suite, "reg_val_data_string empty", test_reg_val_data_string_empty);
torture_suite_add_simple_test(suite, "reg_val_description", test_reg_val_description);
torture_suite_add_simple_test(suite, "reg_val_description null", test_reg_val_description_nullname);
torture_suite_add_simple_test(suite, "reg_val_data_string dword",
test_reg_val_data_string_dword);
torture_suite_add_simple_test(suite, "reg_val_data_string sz",
test_reg_val_data_string_sz);
torture_suite_add_simple_test(suite, "reg_val_data_string binary",
test_reg_val_data_string_binary);
torture_suite_add_simple_test(suite, "reg_val_data_string empty",
test_reg_val_data_string_empty);
torture_suite_add_simple_test(suite, "reg_val_description",
test_reg_val_description);
torture_suite_add_simple_test(suite, "reg_val_description null",
test_reg_val_description_nullname);
torture_suite_add_suite(suite, torture_registry_hive(mem_ctx));
torture_suite_add_suite(suite, torture_registry_registry(mem_ctx));
torture_suite_add_suite(suite, torture_registry_diff(mem_ctx));
return suite;
}

View File

@ -0,0 +1,383 @@
/*
Unix SMB/CIFS implementation.
local testing of registry library - hives
Copyright (C) Jelmer Vernooij 2005-2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "lib/registry/registry.h"
#include "lib/cmdline/popt_common.h"
#include "torture/torture.h"
#include "librpc/gen_ndr/winreg.h"
#include "system/filesys.h"
NTSTATUS torture_temp_dir(struct torture_context *tctx, const char *prefix,
const char **tempdir);
static bool test_del_nonexistant_key(struct torture_context *tctx,
const void *test_data)
{
const struct hive_key *root = test_data;
WERROR error = hive_key_del(root, "bla");
torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
"invalid return code");
return true;
}
static bool test_keyinfo_root(struct torture_context *tctx,
const void *test_data)
{
uint32_t num_subkeys, num_values;
const struct hive_key *root = test_data;
WERROR error;
/* This is a new backend. There should be no subkeys and no
* values */
error = hive_key_get_info(tctx, root, NULL, &num_subkeys, &num_values,
NULL);
torture_assert_werr_ok(tctx, error, "reg_key_num_subkeys()");
torture_assert_int_equal(tctx, num_subkeys, 0, "New key has non-zero subkey count");
torture_assert_werr_ok(tctx, error, "reg_key_num_values");
torture_assert_int_equal(tctx, num_values, 0, "New key has non-zero value count");
return true;
}
static bool test_keyinfo_nums(struct torture_context *tctx,
const void *test_data)
{
uint32_t num_subkeys, num_values;
const struct hive_key *root = test_data;
WERROR error;
struct hive_key *subkey;
uint32_t data = 42;
error = hive_key_add_name(tctx, root, "Nested Keyll", NULL,
NULL, &subkey);
torture_assert_werr_ok(tctx, error, "hive_key_add_name");
error = hive_set_value(root, "Answer", REG_DWORD,
data_blob_talloc(tctx, &data, sizeof(data)));
torture_assert_werr_ok(tctx, error, "hive_set_value");
/* This is a new backend. There should be no subkeys and no
* values */
error = hive_key_get_info(tctx, root, NULL, &num_subkeys, &num_values,
NULL);
torture_assert_werr_ok(tctx, error, "reg_key_num_subkeys()");
torture_assert_int_equal(tctx, num_subkeys, 1, "subkey count");
torture_assert_werr_ok(tctx, error, "reg_key_num_values");
torture_assert_int_equal(tctx, num_values, 1, "value count");
return true;
}
static bool test_add_subkey(struct torture_context *tctx,
const void *test_data)
{
WERROR error;
struct hive_key *subkey;
const struct hive_key *root = test_data;
TALLOC_CTX *mem_ctx = tctx;
error = hive_key_add_name(mem_ctx, root, "Nested Key", NULL,
NULL, &subkey);
torture_assert_werr_ok(tctx, error, "hive_key_add_name");
error = hive_key_del(root, "Nested Key");
torture_assert_werr_ok(tctx, error, "reg_key_del");
return true;
}
static bool test_flush_key(struct torture_context *tctx,
const void *test_data)
{
const struct hive_key *root = test_data;
torture_assert_werr_ok(tctx, hive_key_flush(root), "flush key");
return true;
}
static bool test_del_key(struct torture_context *tctx, const void *test_data)
{
WERROR error;
struct hive_key *subkey;
const struct hive_key *root = test_data;
TALLOC_CTX *mem_ctx = tctx;
error = hive_key_add_name(mem_ctx, root, "Nested Key", NULL,
NULL, &subkey);
torture_assert_werr_ok(tctx, error, "hive_key_add_name");
error = hive_key_del(root, "Nested Key");
torture_assert_werr_ok(tctx, error, "reg_key_del");
error = hive_key_del(root, "Nested Key");
torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, "reg_key_del");
return true;
}
static bool test_set_value(struct torture_context *tctx,
const void *test_data)
{
WERROR error;
struct hive_key *subkey;
const struct hive_key *root = test_data;
TALLOC_CTX *mem_ctx = tctx;
uint32_t data = 42;
error = hive_key_add_name(mem_ctx, root, "YA Nested Key", NULL,
NULL, &subkey);
torture_assert_werr_ok(tctx, error, "hive_key_add_name");
error = hive_set_value(subkey, "Answer", REG_DWORD,
data_blob_talloc(mem_ctx, &data, sizeof(data)));
torture_assert_werr_ok(tctx, error, "hive_set_value");
return true;
}
static bool test_get_value(struct torture_context *tctx, const void *test_data)
{
WERROR error;
struct hive_key *subkey;
const struct hive_key *root = test_data;
TALLOC_CTX *mem_ctx = tctx;
uint32_t data = 42;
uint32_t type;
DATA_BLOB value;
error = hive_key_add_name(mem_ctx, root, "EYA Nested Key", NULL,
NULL, &subkey);
torture_assert_werr_ok(tctx, error, "hive_key_add_name");
error = hive_get_value(mem_ctx, subkey, "Answer", &type, &value);
torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
"getting missing value");
error = hive_set_value(subkey, "Answer", REG_DWORD,
data_blob_talloc(mem_ctx, &data, sizeof(data)));
torture_assert_werr_ok(tctx, error, "hive_set_value");
error = hive_get_value(mem_ctx, subkey, "Answer", &type, &value);
torture_assert_werr_ok(tctx, error, "getting value");
torture_assert(tctx, memcmp(value.data, &data, 4) == 0, "value data");
torture_assert_int_equal(tctx, value.length, 4, "value length");
torture_assert_int_equal(tctx, type, REG_DWORD, "value type");
return true;
}
static bool test_del_value(struct torture_context *tctx, const void *test_data)
{
WERROR error;
struct hive_key *subkey;
const struct hive_key *root = test_data;
TALLOC_CTX *mem_ctx = tctx;
uint32_t data = 42;
uint32_t type;
DATA_BLOB value;
error = hive_key_add_name(mem_ctx, root, "EEYA Nested Key", NULL,
NULL, &subkey);
torture_assert_werr_ok(tctx, error, "hive_key_add_name");
error = hive_set_value(subkey, "Answer", REG_DWORD,
data_blob_talloc(mem_ctx, &data, sizeof(data)));
torture_assert_werr_ok(tctx, error, "hive_set_value");
error = hive_del_value(subkey, "Answer");
torture_assert_werr_ok(tctx, error, "deleting value");
error = hive_get_value(mem_ctx, subkey, "Answer", &type, &value);
torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, "getting value");
error = hive_del_value(subkey, "Answer");
torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND, "deleting value");
return true;
}
static bool test_list_values(struct torture_context *tctx,
const void *test_data)
{
WERROR error;
struct hive_key *subkey;
const struct hive_key *root = test_data;
TALLOC_CTX *mem_ctx = tctx;
uint32_t data = 42;
uint32_t type;
DATA_BLOB value;
const char *name;
error = hive_key_add_name(mem_ctx, root, "AYAYA Nested Key", NULL,
NULL, &subkey);
torture_assert_werr_ok(tctx, error, "hive_key_add_name");
error = hive_set_value(subkey, "Answer", REG_DWORD,
data_blob_talloc(mem_ctx, &data, sizeof(data)));
torture_assert_werr_ok(tctx, error, "hive_set_value");
error = hive_get_value_by_index(mem_ctx, subkey, 0, &name, &type, &value);
torture_assert_werr_ok(tctx, error, "getting value");
torture_assert_str_equal(tctx, name, "Answer", "value name");
torture_assert(tctx, memcmp(value.data, &data, 4) == 0, "value data");
torture_assert_int_equal(tctx, value.length, 4, "value length");
torture_assert_int_equal(tctx, type, REG_DWORD, "value type");
error = hive_get_value_by_index(mem_ctx, subkey, 1, &name, &type, &value);
torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS,
"getting missing value");
return true;
}
static void tcase_add_tests(struct torture_tcase *tcase)
{
torture_tcase_add_simple_test(tcase, "del_nonexistant_key",
test_del_nonexistant_key);
torture_tcase_add_simple_test(tcase, "add_subkey", test_add_subkey);
torture_tcase_add_simple_test(tcase, "flush_key", test_flush_key);
torture_tcase_add_simple_test(tcase, "get_info", test_keyinfo_root);
torture_tcase_add_simple_test(tcase, "get_info_nums", test_keyinfo_nums);
torture_tcase_add_simple_test(tcase, "set_value", test_set_value);
torture_tcase_add_simple_test(tcase, "get_value", test_get_value);
torture_tcase_add_simple_test(tcase, "list_values", test_list_values);
torture_tcase_add_simple_test(tcase, "del_key", test_del_key);
torture_tcase_add_simple_test(tcase, "del_value", test_del_value);
}
static bool hive_setup_dir(struct torture_context *tctx, void **data)
{
struct hive_key *key;
WERROR error;
const char *dirname;
NTSTATUS status;
status = torture_temp_dir(tctx, "hive-dir", &dirname);
if (!NT_STATUS_IS_OK(status))
return false;
rmdir(dirname);
error = reg_create_directory(tctx, dirname, &key);
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Unable to initialize dir hive\n");
return false;
}
*data = key;
return true;
}
static bool hive_setup_ldb(struct torture_context *tctx, void **data)
{
struct hive_key *key;
WERROR error;
const char *dirname;
NTSTATUS status;
status = torture_temp_dir(tctx, "hive-ldb", &dirname);
if (!NT_STATUS_IS_OK(status))
return false;
rmdir(dirname);
error = reg_open_ldb_file(tctx, dirname, NULL, NULL, &key);
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Unable to initialize ldb hive\n");
return false;
}
*data = key;
return true;
}
static bool hive_setup_regf(struct torture_context *tctx, void **data)
{
struct hive_key *key;
WERROR error;
const char *dirname;
NTSTATUS status;
status = torture_temp_dir(tctx, "hive-dir", &dirname);
if (!NT_STATUS_IS_OK(status))
return false;
rmdir(dirname);
error = reg_create_regf_file(tctx, dirname, 5, &key);
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Unable to create new regf file\n");
return false;
}
*data = key;
return true;
}
static bool test_dir_refuses_null_location(struct torture_context *tctx)
{
torture_assert_werr_equal(tctx, WERR_INVALID_PARAM,
reg_open_directory(NULL, NULL, NULL),
"reg_open_directory accepts NULL location");
return true;
}
struct torture_suite *torture_registry_hive(TALLOC_CTX *mem_ctx)
{
struct torture_tcase *tcase;
struct torture_suite *suite = torture_suite_create(mem_ctx,
"HIVE");
torture_suite_add_simple_test(suite, "dir-refuses-null-location",
test_dir_refuses_null_location);
tcase = torture_suite_add_tcase(suite, "dir");
torture_tcase_set_fixture(tcase, hive_setup_dir, NULL);
tcase_add_tests(tcase);
tcase = torture_suite_add_tcase(suite, "ldb");
torture_tcase_set_fixture(tcase, hive_setup_ldb, NULL);
tcase_add_tests(tcase);
tcase = torture_suite_add_tcase(suite, "regf");
torture_tcase_set_fixture(tcase, hive_setup_regf, NULL);
tcase_add_tests(tcase);
return suite;
}

View File

@ -0,0 +1,486 @@
/*
Unix SMB/CIFS implementation.
local testing of registry library - registry backend
Copyright (C) Jelmer Vernooij 2005-2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "lib/registry/registry.h"
#include "lib/cmdline/popt_common.h"
#include "torture/torture.h"
#include "librpc/gen_ndr/winreg.h"
#include "system/filesys.h"
NTSTATUS torture_temp_dir(struct torture_context *tctx, const char *prefix,
const char **tempdir);
/**
* Test obtaining a predefined key.
*/
static bool test_get_predefined(struct torture_context *tctx,
const void *_data)
{
const struct registry_context *rctx = _data;
struct registry_key *root;
WERROR error;
error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root);
torture_assert_werr_ok(tctx, error,
"getting predefined key failed");
return true;
}
/**
* Test creating a new subkey
*/
static bool test_create_subkey(struct torture_context *tctx,
const void *_data)
{
const struct registry_context *rctx = _data;
struct registry_key *root, *newkey;
WERROR error;
error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root);
torture_assert_werr_ok(tctx, error,
"getting predefined key failed");
error = reg_key_add_name(rctx, root, "Bad Bentheim", NULL, NULL, &newkey);
torture_assert_werr_ok(tctx, error, "Creating key return code");
torture_assert(tctx, newkey != NULL, "Creating new key");
return true;
}
/**
* Test creating a new nested subkey
*/
static bool test_create_nested_subkey(struct torture_context *tctx,
const void *_data)
{
const struct registry_context *rctx = _data;
struct registry_key *root, *newkey1, *newkey2;
WERROR error;
error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root);
torture_assert_werr_ok(tctx, error,
"getting predefined key failed");
error = reg_key_add_name(rctx, root, "Hamburg", NULL, NULL,
&newkey1);
torture_assert_werr_ok(tctx, error, "Creating key return code");
torture_assert(tctx, newkey2 != NULL, "Creating new key");
error = reg_key_add_name(rctx, root, "Hamburg\\Hamburg", NULL, NULL,
&newkey2);
torture_assert_werr_ok(tctx, error, "Creating key return code");
torture_assert(tctx, newkey2 != NULL, "Creating new key");
return true;
}
/**
* Test creating a new subkey
*/
static bool test_key_add_abs_top(struct torture_context *tctx,
const void *_data)
{
const struct registry_context *rctx = _data;
struct registry_key *root;
WERROR error;
error = reg_key_add_abs(tctx, rctx, "HKEY_CLASSES_ROOT", 0, NULL, &root);
torture_assert_werr_equal(tctx, error, WERR_ALREADY_EXISTS, "create top level");
return true;
}
/**
* Test creating a new subkey
*/
static bool test_key_add_abs(struct torture_context *tctx,
const void *_data)
{
WERROR error;
const struct registry_context *rctx = _data;
struct registry_key *root, *result1, *result2;
error = reg_key_add_abs(tctx, rctx, "HKEY_CLASSES_ROOT\\bloe", 0, NULL, &result1);
torture_assert_werr_ok(tctx, error, "create lowest");
error = reg_key_add_abs(tctx, rctx, "HKEY_CLASSES_ROOT\\bloe\\bla", 0, NULL, &result1);
torture_assert_werr_ok(tctx, error, "create nested");
error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root);
torture_assert_werr_ok(tctx, error,
"getting predefined key failed");
error = reg_open_key(tctx, root, "bloe", &result2);
torture_assert_werr_ok(tctx, error, "opening key");
error = reg_open_key(tctx, root, "bloe\\bla", &result2);
torture_assert_werr_ok(tctx, error, "opening key");
return true;
}
static bool test_del_key(struct torture_context *tctx, const void *_data)
{
const struct registry_context *rctx = _data;
struct registry_key *root, *newkey;
WERROR error;
error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, &root);
torture_assert_werr_ok(tctx, error,
"getting predefined key failed");
error = reg_key_add_name(rctx, root, "Hamburg", NULL, NULL, &newkey);
torture_assert_werr_ok(tctx, error, "Creating key return code");
torture_assert(tctx, newkey != NULL, "Creating new key");
error = reg_key_del(root, "Hamburg");
torture_assert_werr_ok(tctx, error, "Delete key");
error = reg_key_del(root, "Hamburg");
torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
"Delete missing key");
return true;
}
/**
* Convenience function for opening the HKEY_CLASSES_ROOT hive and
* creating a single key for testing purposes.
*/
static bool create_test_key(struct torture_context *tctx,
const struct registry_context *rctx,
const char *name,
struct registry_key **root,
struct registry_key **subkey)
{
WERROR error;
error = reg_get_predefined_key(rctx, HKEY_CLASSES_ROOT, root);
torture_assert_werr_ok(tctx, error,
"getting predefined key failed");
error = reg_key_add_name(rctx, *root, name, NULL, NULL, subkey);
torture_assert_werr_ok(tctx, error, "Creating key return code");
return true;
}
static bool test_flush_key(struct torture_context *tctx, const void *_data)
{
const struct registry_context *rctx = _data;
struct registry_key *root, *subkey;
WERROR error;
if (!create_test_key(tctx, rctx, "Munchen", &root, &subkey))
return false;
error = reg_key_flush(subkey);
torture_assert_werr_ok(tctx, error, "flush key");
return true;
}
static bool test_query_key(struct torture_context *tctx, const void *_data)
{
const struct registry_context *rctx = _data;
struct registry_key *root, *subkey;
WERROR error;
NTTIME last_changed_time;
uint32_t num_subkeys, num_values;
const char *classname;
if (!create_test_key(tctx, rctx, "Munchen", &root, &subkey))
return false;
error = reg_key_get_info(tctx, subkey, &classname,
&num_subkeys, &num_values,
&last_changed_time);
torture_assert_werr_ok(tctx, error, "get info key");
torture_assert(tctx, classname == NULL, "classname");
torture_assert_int_equal(tctx, num_subkeys, 0, "num subkeys");
torture_assert_int_equal(tctx, num_values, 0, "num values");
return true;
}
static bool test_query_key_nums(struct torture_context *tctx, const void *_data)
{
const struct registry_context *rctx = _data;
struct registry_key *root, *subkey1, *subkey2;
WERROR error;
uint32_t num_subkeys, num_values;
uint32_t data = 42;
if (!create_test_key(tctx, rctx, "Berlin", &root, &subkey1))
return false;
error = reg_key_add_name(rctx, subkey1, "Bentheim", NULL, NULL, &subkey2);
torture_assert_werr_ok(tctx, error, "Creating key return code");
error = reg_val_set(subkey1, "Answer", REG_DWORD,
data_blob_talloc(tctx, &data, sizeof(data)));
torture_assert_werr_ok(tctx, error, "set value");
error = reg_key_get_info(tctx, subkey1, NULL, &num_subkeys,
&num_values, NULL);
torture_assert_werr_ok(tctx, error, "get info key");
torture_assert_int_equal(tctx, num_subkeys, 1, "num subkeys");
torture_assert_int_equal(tctx, num_values, 1, "num values");
return true;
}
/**
* Test that the subkeys of a key can be enumerated, that
* the returned parameters for get_subkey_by_index are optional and
* that enumerating the parents of a non-top-level node works.
*/
static bool test_list_subkeys(struct torture_context *tctx, const void *_data)
{
const struct registry_context *rctx = _data;
struct registry_key *subkey = NULL, *root;
WERROR error;
NTTIME last_mod_time;
const char *classname, *name;
if (!create_test_key(tctx, rctx, "Goettingen", &root, &subkey))
return false;
error = reg_key_get_subkey_by_index(tctx, root, 0, &name, &classname,
&last_mod_time);
torture_assert_werr_ok(tctx, error, "Enum keys return code");
torture_assert_str_equal(tctx, name, "Goettingen", "Enum keys data");
error = reg_key_get_subkey_by_index(tctx, root, 0, NULL, NULL, NULL);
torture_assert_werr_ok(tctx, error, "Enum keys with NULL arguments return code");
error = reg_key_get_subkey_by_index(tctx, root, 1, NULL, NULL, NULL);
torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS,
"Invalid error for no more items");
error = reg_key_get_subkey_by_index(tctx, subkey, 0, NULL, NULL, NULL);
torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS,
"Invalid error for no more items");
return true;
}
/**
* Test setting a value
*/
static bool test_set_value(struct torture_context *tctx, const void *_data)
{
const struct registry_context *rctx = _data;
struct registry_key *subkey = NULL, *root;
WERROR error;
uint32_t data = 42;
if (!create_test_key(tctx, rctx, "Dusseldorf", &root, &subkey))
return false;
error = reg_val_set(subkey, "Answer", REG_DWORD,
data_blob_talloc(tctx, &data, sizeof(data)));
torture_assert_werr_ok (tctx, error, "setting value");
return true;
}
/**
* Test getting a value
*/
static bool test_get_value(struct torture_context *tctx, const void *_data)
{
const struct registry_context *rctx = _data;
struct registry_key *subkey = NULL, *root;
WERROR error;
DATA_BLOB data;
uint32_t value = 42;
uint32_t type;
if (!create_test_key(tctx, rctx, "Duisburg", &root, &subkey))
return false;
error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type,
&data);
torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
"getting missing value");
error = reg_val_set(subkey, __FUNCTION__, REG_DWORD,
data_blob_talloc(tctx, &value, 4));
torture_assert_werr_ok (tctx, error, "setting value");
error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type,
&data);
torture_assert_werr_ok(tctx, error, "getting value");
torture_assert_int_equal(tctx, 4, data.length, "value length ok");
torture_assert(tctx, memcmp(data.data, &value, 4) == 0, "value content ok");
torture_assert_int_equal(tctx, REG_DWORD, type, "value type");
return true;
}
/**
* Test unsetting a value
*/
static bool test_del_value(struct torture_context *tctx, const void *_data)
{
const struct registry_context *rctx = _data;
struct registry_key *subkey = NULL, *root;
WERROR error;
DATA_BLOB data;
uint32_t value = 42;
uint32_t type;
if (!create_test_key(tctx, rctx, "Duisburg", &root, &subkey))
return false;
error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type,
&data);
torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
"getting missing value");
error = reg_val_set(subkey, __FUNCTION__, REG_DWORD,
data_blob_talloc(tctx, &value, 4));
torture_assert_werr_ok (tctx, error, "setting value");
error = reg_del_value(subkey, __FUNCTION__);
torture_assert_werr_ok (tctx, error, "unsetting value");
error = reg_key_get_value_by_name(tctx, subkey, __FUNCTION__, &type, &data);
torture_assert_werr_equal(tctx, error, WERR_NOT_FOUND,
"getting missing value");
return true;
}
/**
* Test listing values
*/
static bool test_list_values(struct torture_context *tctx, const void *_data)
{
const struct registry_context *rctx = _data;
struct registry_key *subkey = NULL, *root;
WERROR error;
DATA_BLOB data;
uint32_t value = 42;
uint32_t type;
const char *name;
if (!create_test_key(tctx, rctx, "Bonn", &root, &subkey))
return false;
error = reg_val_set(subkey, "bar", REG_DWORD,
data_blob_talloc(tctx, &value, 4));
torture_assert_werr_ok (tctx, error, "setting value");
error = reg_key_get_value_by_index(tctx, subkey, 0, &name, &type, &data);
torture_assert_werr_ok(tctx, error, "getting value");
torture_assert_str_equal(tctx, name, "bar", "value name");
torture_assert_int_equal(tctx, 4, data.length, "value length");
torture_assert(tctx, memcmp(data.data, &value, 4) == 0, "value content");
torture_assert_int_equal(tctx, REG_DWORD, type, "value type");
error = reg_key_get_value_by_index(tctx, subkey, 1, &name, &type, &data);
torture_assert_werr_equal(tctx, error, WERR_NO_MORE_ITEMS,
"getting missing value");
return true;
}
static bool setup_local_registry(struct torture_context *tctx, void **data)
{
struct registry_context *rctx;
WERROR error;
const char *tempdir;
NTSTATUS status;
struct hive_key *hive_key;
error = reg_open_local(tctx, &rctx, NULL, NULL);
if (!W_ERROR_IS_OK(error))
return false;
status = torture_temp_dir(tctx, "registry-local", &tempdir);
if (!NT_STATUS_IS_OK(status))
return false;
error = reg_open_ldb_file(tctx,
talloc_asprintf(tctx, "%s/classes_root.ldb", tempdir),
NULL,
NULL,
&hive_key);
if (!W_ERROR_IS_OK(error))
return false;
error = reg_mount_hive(rctx, hive_key, HKEY_CLASSES_ROOT, NULL);
if (!W_ERROR_IS_OK(error))
return false;
*data = rctx;
return true;
}
static void tcase_add_tests(struct torture_tcase *tcase)
{
torture_tcase_add_simple_test(tcase, "list_subkeys", test_list_subkeys);
torture_tcase_add_simple_test(tcase, "get_predefined_key",
test_get_predefined);
torture_tcase_add_simple_test(tcase, "create_key", test_create_subkey);
torture_tcase_add_simple_test(tcase, "create_key",
test_create_nested_subkey);
torture_tcase_add_simple_test(tcase, "key_add_abs", test_key_add_abs);
torture_tcase_add_simple_test(tcase, "key_add_abs_top", test_key_add_abs_top);
torture_tcase_add_simple_test(tcase, "set_value", test_set_value);
torture_tcase_add_simple_test(tcase, "get_value", test_get_value);
torture_tcase_add_simple_test(tcase, "list_values", test_list_values);
torture_tcase_add_simple_test(tcase, "del_key", test_del_key);
torture_tcase_add_simple_test(tcase, "del_value", test_del_value);
torture_tcase_add_simple_test(tcase, "flush_key", test_flush_key);
torture_tcase_add_simple_test(tcase, "query_key", test_query_key);
torture_tcase_add_simple_test(tcase, "query_key_nums", test_query_key_nums);
}
struct torture_suite *torture_registry_registry(TALLOC_CTX *mem_ctx)
{
struct torture_tcase *tcase;
struct torture_suite *suite = torture_suite_create(mem_ctx,
"REGISTRY");
tcase = torture_suite_add_tcase(suite, "local");
torture_tcase_set_fixture(tcase, setup_local_registry, NULL);
tcase_add_tests(tcase);
return suite;
}

View File

@ -0,0 +1,75 @@
/*
Unix SMB/CIFS implementation.
Popt routines specifically for registry
Copyright (C) Jelmer Vernooij 2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "auth/credentials/credentials.h"
#include "lib/registry/registry.h"
struct registry_context *reg_common_open_remote(const char *remote, struct cli_credentials *creds)
{
struct registry_context *h;
WERROR error;
error = reg_open_remote(&h, NULL, creds, remote, NULL);
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Unable to open remote registry at %s:%s \n", remote, win_errstr(error));
return NULL;
}
return h;
}
struct registry_key *reg_common_open_file(const char *path, struct cli_credentials *creds)
{
struct hive_key *hive_root;
struct registry_context *h;
WERROR error;
error = reg_open_hive(NULL, path, NULL, creds, &hive_root);
if(!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Unable to open '%s': %s \n", path, win_errstr(error));
return NULL;
}
error = reg_open_local(NULL, &h, NULL, creds);
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Unable to initialize local registry: %s\n", win_errstr(error));
return NULL;
}
return reg_import_hive_key(h, hive_root, -1, NULL);
}
struct registry_context *reg_common_open_local(struct cli_credentials *creds)
{
WERROR error;
struct registry_context *h;
error = reg_open_samba(NULL, &h, NULL, creds);
if(!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Unable to open local registry:%s \n", win_errstr(error));
return NULL;
}
return h;
}

View File

@ -2,7 +2,8 @@
Unix SMB/CIFS implementation.
simple registry frontend
Copyright (C) Jelmer Vernooij 2004-2005
Copyright (C) Jelmer Vernooij 2004-2007
Copyright (C) Wilco Baan Hofman 2006
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -22,63 +23,115 @@
#include "lib/registry/registry.h"
#include "lib/events/events.h"
#include "lib/cmdline/popt_common.h"
#include "lib/registry/tools/common.h"
int main(int argc, char **argv)
enum reg_backend { REG_UNKNOWN, REG_LOCAL, REG_REMOTE, REG_NULL };
static struct registry_context *open_backend(poptContext pc, enum reg_backend backend, const char *remote_host)
{
WERROR error;
struct registry_context *ctx;
switch (backend) {
case REG_UNKNOWN:
poptPrintUsage(pc, stderr, 0);
return NULL;
case REG_LOCAL:
error = reg_open_samba(NULL, &ctx, NULL, cmdline_credentials);
break;
case REG_REMOTE:
error = reg_open_remote(&ctx, NULL, cmdline_credentials, remote_host, NULL);
break;
case REG_NULL:
error = reg_open_local(NULL, &ctx, NULL, cmdline_credentials);
break;
}
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Error: %s\n", win_errstr(error));
return NULL;
}
return ctx;
}
int main(int argc, const char **argv)
{
int opt;
poptContext pc;
char *outputfile = NULL;
enum reg_backend backend1 = REG_UNKNOWN, backend2 = REG_UNKNOWN;
const char *remote1 = NULL, *remote2 = NULL;
struct registry_context *h1 = NULL, *h2 = NULL;
int from_null = 0;
WERROR error;
struct reg_diff *diff;
struct poptOption long_options[] = {
POPT_AUTOHELP
{"output", 'o', POPT_ARG_STRING, &outputfile, 'o', "output file to use", NULL },
{"null", 'n', POPT_ARG_NONE, &from_null, 'n', "Diff from NULL", NULL },
{"remote", 'R', POPT_ARG_STRING, NULL, 0, "Connect to remote server" , NULL },
{"local", 'L', POPT_ARG_NONE, NULL, 0, "Open local registry", NULL },
{"output", 'o', POPT_ARG_STRING, &outputfile, 0, "output file to use", NULL },
{"null", 'n', POPT_ARG_NONE, NULL, 'n', "Diff from NULL", NULL },
{"remote", 'R', POPT_ARG_STRING, NULL, 'R', "Connect to remote server" , NULL },
{"local", 'L', POPT_ARG_NONE, NULL, 'L', "Open local registry", NULL },
POPT_COMMON_SAMBA
POPT_COMMON_CREDENTIALS
POPT_COMMON_VERSION
{ NULL }
};
TALLOC_CTX *ctx;
void *callback_data;
struct reg_diff_callbacks *callbacks;
registry_init();
ctx = talloc_init("regdiff");
pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0);
pc = poptGetContext(argv[0], argc, argv, long_options,0);
while((opt = poptGetNextOpt(pc)) != -1) {
error = WERR_OK;
switch(opt) {
case 'L':
if (!h1 && !from_null) error = reg_open_local(NULL, &h1, NULL, cmdline_credentials);
else if (!h2) error = reg_open_local(NULL, &h2, NULL, cmdline_credentials);
if (backend1 == REG_UNKNOWN)
backend1 = REG_LOCAL;
else if (backend2 == REG_UNKNOWN)
backend2 = REG_LOCAL;
break;
case 'n':
if (backend1 == REG_UNKNOWN)
backend1 = REG_NULL;
else if (backend2 == REG_UNKNOWN)
backend2 = REG_NULL;
break;
case 'R':
if (!h1 && !from_null)
error = reg_open_remote(&h1, NULL, cmdline_credentials,
poptGetOptArg(pc), NULL);
else if (!h2) error = reg_open_remote(&h2, NULL, cmdline_credentials,
poptGetOptArg(pc), NULL);
if (backend1 == REG_UNKNOWN) {
backend1 = REG_REMOTE;
remote1 = poptGetOptArg(pc);
} else if (backend2 == REG_UNKNOWN) {
backend2 = REG_REMOTE;
remote2 = poptGetOptArg(pc);
}
break;
}
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Error: %s\n", win_errstr(error));
return 1;
}
}
h1 = open_backend(pc, backend1, remote1);
if (h1 == NULL)
return 1;
h2 = open_backend(pc, backend2, remote2);
if (h2 == NULL)
return 1;
poptFreeContext(pc);
diff = reg_generate_diff(NULL, h1, h2);
if (!diff) {
fprintf(stderr, "Unable to generate diff between keys\n");
error = reg_dotreg_diff_save(ctx, outputfile, &callbacks, &callback_data);
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Problem saving registry diff to '%s': %s\n", outputfile, win_errstr(error));
return -1;
}
reg_diff_save(diff, outputfile);
error = reg_generate_diff(h1, h2, callbacks, callback_data);
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Unable to generate diff between keys: %s\n", win_errstr(error));
return -1;
}
return 0;
}

View File

@ -2,7 +2,7 @@
Unix SMB/CIFS implementation.
simple registry frontend
Copyright (C) 2004-2005 Jelmer Vernooij, jelmer@samba.org
Copyright (C) 2004-2007 Jelmer Vernooij, jelmer@samba.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -22,6 +22,8 @@
#include "lib/events/events.h"
#include "lib/registry/registry.h"
#include "lib/cmdline/popt_common.h"
#include "lib/registry/tools/common.h"
#include "lib/registry/patchfile.h"
int main(int argc, char **argv)
{
@ -29,12 +31,12 @@ int main(int argc, char **argv)
poptContext pc;
const char *patch;
struct registry_context *h;
const char *file = NULL;
const char *remote = NULL;
struct reg_diff *diff;
WERROR error;
struct poptOption long_options[] = {
POPT_AUTOHELP
{"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL},
{"file", 'F', POPT_ARG_STRING, &file, 0, "file path", NULL },
POPT_COMMON_SAMBA
POPT_COMMON_CREDENTIALS
{ NULL }
@ -45,29 +47,24 @@ int main(int argc, char **argv)
while((opt = poptGetNextOpt(pc)) != -1) {
}
registry_init();
if (remote) {
error = reg_open_remote (&h, NULL, cmdline_credentials, remote, NULL);
h = reg_common_open_remote (remote, cmdline_credentials);
} else {
error = reg_open_local (NULL, &h, NULL, cmdline_credentials);
h = reg_common_open_local (cmdline_credentials);
}
if (W_ERROR_IS_OK(error)) {
fprintf(stderr, "Error: %s\n", win_errstr(error));
if (h == NULL)
return 1;
}
patch = poptGetArg(pc);
poptFreeContext(pc);
diff = reg_diff_load(NULL, patch);
if (!diff) {
fprintf(stderr, "Unable to load registry patch from `%s'\n", patch);
if (patch == NULL) {
poptPrintUsage(pc, stderr, 0);
return 1;
}
reg_diff_apply(diff, h);
poptFreeContext(pc);
reg_diff_apply(patch, h);
return 0;
}

View File

@ -2,7 +2,7 @@
Unix SMB/CIFS implementation.
simple registry frontend
Copyright (C) Jelmer Vernooij 2004
Copyright (C) Jelmer Vernooij 2004-2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -25,8 +25,15 @@
#include "system/time.h"
#include "lib/smbreadline/smbreadline.h"
#include "librpc/gen_ndr/ndr_security.h"
#include "lib/registry/tools/common.h"
/*
struct regshell_context {
struct registry_context *registry;
const char *path;
struct registry_key *current;
};
/* *
* ck/cd - change key
* ls - list values/keys
* rmval/rm - remove value
@ -40,29 +47,40 @@
* exit
*/
static struct registry_key *cmd_info(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
static WERROR cmd_info(struct regshell_context *ctx, int argc, char **argv)
{
struct security_descriptor *sec_desc = NULL;
time_t last_mod;
WERROR error;
const char *classname;
NTTIME last_change;
error = reg_key_get_info(ctx, ctx->current, &classname, NULL, NULL, &last_change);
if (!W_ERROR_IS_OK(error)) {
printf("Error getting key info: %s\n", win_errstr(error));
return error;
}
printf("Name: %s\n", cur->name);
printf("Full path: %s\n", cur->path);
printf("Key Class: %s\n", cur->class_name);
last_mod = nt_time_to_unix(cur->last_mod);
printf("Name: %s\n", strchr(ctx->path, '\\')?strrchr(ctx->path, '\\')+1:
ctx->path);
printf("Full path: %s\n", ctx->path);
printf("Key Class: %s\n", classname);
last_mod = nt_time_to_unix(last_change);
printf("Time Last Modified: %s\n", ctime(&last_mod));
error = reg_get_sec_desc(mem_ctx, cur, &sec_desc);
error = reg_get_sec_desc(ctx, ctx->current, &sec_desc);
if (!W_ERROR_IS_OK(error)) {
printf("Error getting security descriptor\n");
} else {
ndr_print_debug((ndr_print_fn_t)ndr_print_security_descriptor, "Security", sec_desc);
}
return error;
}
ndr_print_debug((ndr_print_fn_t)ndr_print_security_descriptor, "Security", sec_desc);
talloc_free(sec_desc);
return cur;
return WERR_OK;
}
static struct registry_key *cmd_predef(TALLOC_CTX *mem_ctx, struct registry_context *ctx, struct registry_key *cur, int argc, char **argv)
static WERROR cmd_predef(struct regshell_context *ctx, int argc, char **argv)
{
struct registry_key *ret = NULL;
if (argc < 2) {
@ -70,165 +88,195 @@ static struct registry_key *cmd_predef(TALLOC_CTX *mem_ctx, struct registry_cont
} else if (!ctx) {
fprintf(stderr, "No full registry loaded, no predefined keys defined\n");
} else {
WERROR error = reg_get_predefined_key_by_name(ctx, argv[1], &ret);
WERROR error = reg_get_predefined_key_by_name(ctx->registry, argv[1], &ret);
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Error opening predefined key %s: %s\n", argv[1], win_errstr(error));
ret = NULL;
return error;
}
}
return ret;
return WERR_OK;
}
static struct registry_key *cmd_pwd(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
static WERROR cmd_pwd(struct regshell_context *ctx,
int argc, char **argv)
{
printf("%s\n", cur->path);
return cur;
printf("%s\n", ctx->path);
return WERR_OK;
}
static struct registry_key *cmd_set(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
static WERROR cmd_set(struct regshell_context *ctx, int argc, char **argv)
{
struct registry_value val;
WERROR error;
if (argc < 4) {
fprintf(stderr, "Usage: set value-name type value\n");
return cur;
return WERR_INVALID_PARAM;
}
if (!reg_string_to_val(mem_ctx, argv[2], argv[3], &val.data_type, &val.data)) {
if (!reg_string_to_val(ctx, argv[2], argv[3], &val.data_type,
&val.data)) {
fprintf(stderr, "Unable to interpret data\n");
return cur;
return WERR_INVALID_PARAM;
}
error = reg_val_set(cur, argv[1], val.data_type, val.data);
error = reg_val_set(ctx->current, argv[1], val.data_type, val.data);
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Error setting value: %s\n", win_errstr(error));
return NULL;
return error;
}
return cur;
return WERR_OK;
}
static struct registry_key *cmd_ck(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
static WERROR cmd_ck(struct regshell_context *ctx, int argc, char **argv)
{
struct registry_key *new = NULL;
WERROR error;
if(argc < 2) {
new = cur;
new = ctx->current;
} else {
error = reg_open_key(mem_ctx, cur, argv[1], &new);
error = reg_open_key(ctx->registry, ctx->current, argv[1], &new);
if(!W_ERROR_IS_OK(error)) {
DEBUG(0, ("Error opening specified key: %s\n", win_errstr(error)));
return NULL;
return error;
}
}
printf("Current path is: %s\n", new->path);
ctx->path = talloc_asprintf(ctx, "%s\\%s", ctx->path, argv[1]);
printf("Current path is: %s\n", ctx->path);
ctx->current = new;
return new;
return WERR_OK;
}
static struct registry_key *cmd_print(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
static WERROR cmd_print(struct regshell_context *ctx, int argc, char **argv)
{
struct registry_value *value;
uint32_t value_type;
DATA_BLOB value_data;
WERROR error;
if (argc != 2) {
fprintf(stderr, "Usage: print <valuename>");
return NULL;
return WERR_INVALID_PARAM;
}
error = reg_key_get_value_by_name(mem_ctx, cur, argv[1], &value);
error = reg_key_get_value_by_name(ctx, ctx->current, argv[1],
&value_type, &value_data);
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "No such value '%s'\n", argv[1]);
return NULL;
return error;
}
printf("%s\n%s\n", str_regtype(value->data_type), reg_val_data_string(mem_ctx, value->data_type, &value->data));
return NULL;
printf("%s\n%s\n", str_regtype(value_type),
reg_val_data_string(ctx, value_type, value_data));
return WERR_OK;
}
static struct registry_key *cmd_ls(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
static WERROR cmd_ls(struct regshell_context *ctx, int argc, char **argv)
{
int i;
WERROR error;
struct registry_value *value;
struct registry_key *sub;
for(i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(mem_ctx, cur, i, &sub)); i++) {
printf("K %s\n", sub->name);
uint32_t data_type;
DATA_BLOB data;
const char *name;
for (i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(ctx, ctx->current, i, &name, NULL, NULL)); i++) {
printf("K %s\n", name);
}
if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
if (!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
DEBUG(0, ("Error occured while browsing thru keys: %s\n", win_errstr(error)));
}
for(i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(mem_ctx, cur, i, &value)); i++) {
printf("V \"%s\" %s %s\n", value->name, str_regtype(value->data_type), reg_val_data_string(mem_ctx, value->data_type, &value->data));
for (i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(ctx, ctx->current, i, &name, &data_type, &data)); i++) {
printf("V \"%s\" %s %s\n", value->name, str_regtype(data_type),
reg_val_data_string(ctx, data_type, data));
}
return NULL;
return WERR_OK;
}
static struct registry_key *cmd_mkkey(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
static WERROR cmd_mkkey(struct regshell_context *ctx, int argc, char **argv)
{
struct registry_key *tmp;
WERROR error;
if(argc < 2) {
fprintf(stderr, "Usage: mkkey <keyname>\n");
return NULL;
}
if(!W_ERROR_IS_OK(reg_key_add_name(mem_ctx, cur, argv[1], 0, NULL, &tmp))) {
fprintf(stderr, "Error adding new subkey '%s'\n", argv[1]);
return NULL;
return WERR_INVALID_PARAM;
}
return NULL;
error = reg_key_add_name(ctx, ctx->current, argv[1], 0, NULL, &tmp);
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Error adding new subkey '%s'\n", argv[1]);
return error;
}
return WERR_OK;
}
static struct registry_key *cmd_rmkey(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
static WERROR cmd_rmkey(struct regshell_context *ctx,
int argc, char **argv)
{
WERROR error;
if(argc < 2) {
fprintf(stderr, "Usage: rmkey <name>\n");
return NULL;
return WERR_INVALID_PARAM;
}
if(!W_ERROR_IS_OK(reg_key_del(cur, argv[1]))) {
error = reg_key_del(ctx->current, argv[1]);
if(!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Error deleting '%s'\n", argv[1]);
return error;
} else {
fprintf(stderr, "Successfully deleted '%s'\n", argv[1]);
}
return NULL;
return WERR_OK;
}
static struct registry_key *cmd_rmval(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
static WERROR cmd_rmval(struct regshell_context *ctx, int argc, char **argv)
{
WERROR error;
if(argc < 2) {
fprintf(stderr, "Usage: rmval <valuename>\n");
return NULL;
return WERR_INVALID_PARAM;
}
if(!W_ERROR_IS_OK(reg_del_value(cur, argv[1]))) {
error = reg_del_value(ctx->current, argv[1]);
if(!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Error deleting value '%s'\n", argv[1]);
return error;
} else {
fprintf(stderr, "Successfully deleted value '%s'\n", argv[1]);
}
return NULL;
return WERR_OK;
}
static struct registry_key *cmd_exit(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *cur, int argc, char **argv)
static WERROR cmd_exit(struct regshell_context *ctx,
int argc, char **argv)
{
exit(0);
return NULL;
return WERR_OK;
}
static struct registry_key *cmd_help(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *, int, char **);
static WERROR cmd_help(struct regshell_context *ctx, int, char **);
static struct {
const char *name;
const char *alias;
const char *help;
struct registry_key *(*handle)(TALLOC_CTX *mem_ctx, struct registry_context *ctx,struct registry_key *, int argc, char **argv);
WERROR (*handle)(struct regshell_context *ctx,
int argc, char **argv);
} regshell_cmds[] = {
{"ck", "cd", "Change current key", cmd_ck },
{"info", "i", "Show detailed information of a key", cmd_info },
@ -245,17 +293,19 @@ static struct {
{NULL }
};
static struct registry_key *cmd_help(TALLOC_CTX *mem_ctx, struct registry_context *ctx, struct registry_key *cur, int argc, char **argv)
static WERROR cmd_help(struct regshell_context *ctx,
int argc, char **argv)
{
int i;
printf("Available commands:\n");
for(i = 0; regshell_cmds[i].name; i++) {
printf("%s - %s\n", regshell_cmds[i].name, regshell_cmds[i].help);
}
return NULL;
return WERR_OK;
}
static struct registry_key *process_cmd(TALLOC_CTX *mem_ctx, struct registry_context *ctx, struct registry_key *k, char *line)
static WERROR process_cmd(struct regshell_context *ctx,
char *line)
{
int argc;
char **argv = NULL;
@ -263,19 +313,19 @@ static struct registry_key *process_cmd(TALLOC_CTX *mem_ctx, struct registry_con
if ((ret = poptParseArgvString(line, &argc, (const char ***) &argv)) != 0) {
fprintf(stderr, "regshell: %s\n", poptStrerror(ret));
return k;
return WERR_INVALID_PARAM;
}
for(i = 0; regshell_cmds[i].name; i++) {
if(!strcmp(regshell_cmds[i].name, argv[0]) ||
(regshell_cmds[i].alias && !strcmp(regshell_cmds[i].alias, argv[0]))) {
return regshell_cmds[i].handle(mem_ctx, ctx, k, argc, argv);
return regshell_cmds[i].handle(ctx, argc, argv);
}
}
fprintf(stderr, "No such command '%s'\n", argv[0]);
return k;
return WERR_INVALID_PARAM;
}
#define MAX_COMPLETIONS 100
@ -333,7 +383,7 @@ cleanup:
static char **reg_complete_key(const char *text, int start, int end)
{
struct registry_key *base;
struct registry_key *subkey;
const char *subkeyname;
int i, j = 1;
int samelen = 0;
int len;
@ -351,10 +401,11 @@ static char **reg_complete_key(const char *text, int start, int end)
len = strlen(text);
for(i = 0; j < MAX_COMPLETIONS-1; i++) {
status = reg_key_get_subkey_by_index(mem_ctx, base, i, &subkey);
status = reg_key_get_subkey_by_index(mem_ctx, base, i, &subkeyname,
NULL, NULL);
if(W_ERROR_IS_OK(status)) {
if(!strncmp(text, subkey->name, len)) {
matches[j] = strdup(subkey->name);
if(!strncmp(text, subkeyname, len)) {
matches[j] = strdup(subkeyname);
j++;
if (j == 1)
@ -381,7 +432,8 @@ static char **reg_complete_key(const char *text, int start, int end)
if (j == 2) { /* Exact match */
asprintf(&matches[0], "%s%s", base_n, matches[1]);
} else {
asprintf(&matches[0], "%s%s", base_n, talloc_strndup(mem_ctx, matches[1], samelen));
asprintf(&matches[0], "%s%s", base_n,
talloc_strndup(mem_ctx, matches[1], samelen));
}
talloc_free(mem_ctx);
@ -400,19 +452,17 @@ static char **reg_completion(const char *text, int start, int end)
}
}
int main(int argc, char **argv)
int main(int argc, char **argv)
{
int opt;
const char *backend = NULL;
struct registry_key *curkey = NULL;
const char *file = NULL;
poptContext pc;
WERROR error;
TALLOC_CTX *mem_ctx = talloc_init("cmd");
const char *remote = NULL;
struct registry_context *h = NULL;
struct regshell_context *ctx;
bool ret = true;
struct poptOption long_options[] = {
POPT_AUTOHELP
{"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL},
{"file", 'F', POPT_ARG_STRING, &file, 0, "open hive file", NULL },
{"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL},
POPT_COMMON_SAMBA
POPT_COMMON_CREDENTIALS
@ -425,64 +475,62 @@ static char **reg_completion(const char *text, int start, int end)
while((opt = poptGetNextOpt(pc)) != -1) {
}
registry_init();
ctx = talloc_zero(NULL, struct regshell_context);
if (remote) {
error = reg_open_remote (&h, NULL, cmdline_credentials, remote, NULL);
} else if (backend) {
error = reg_open_hive(NULL, backend, poptGetArg(pc), NULL, cmdline_credentials, &curkey);
if (remote != NULL) {
ctx->registry = reg_common_open_remote(remote, cmdline_credentials);
} else if (file != NULL) {
ctx->current = reg_common_open_file(file, cmdline_credentials);
ctx->registry = ctx->current->context;
ctx->path = talloc_strdup(ctx, "");
} else {
error = reg_open_local(NULL, &h, NULL, cmdline_credentials);
ctx->registry = reg_common_open_local(cmdline_credentials);
}
if(!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Unable to open registry\n");
if (ctx->registry == NULL)
return 1;
}
if (h) {
if (ctx->current == NULL) {
int i;
for (i = 0; reg_predefined_keys[i].handle; i++) {
WERROR err;
err = reg_get_predefined_key(h, reg_predefined_keys[i].handle, &curkey);
err = reg_get_predefined_key(ctx->registry,
reg_predefined_keys[i].handle,
&ctx->current);
if (W_ERROR_IS_OK(err)) {
ctx->path = talloc_strdup(ctx, reg_predefined_keys[i].name);
break;
} else {
curkey = NULL;
ctx->current = NULL;
}
}
}
if (!curkey) {
if (ctx->current == NULL) {
fprintf(stderr, "Unable to access any of the predefined keys\n");
return -1;
}
poptFreeContext(pc);
while(True) {
while (true) {
char *line, *prompt;
if(curkey->hive->root->name) {
asprintf(&prompt, "%s:%s> ", curkey->hive->root->name, curkey->path);
} else {
asprintf(&prompt, "%s> ", curkey->path);
}
asprintf(&prompt, "%s> ", ctx->path);
current_key = curkey; /* No way to pass a void * pointer
via readline :-( */
current_key = ctx->current; /* No way to pass a void * pointer
via readline :-( */
line = smb_readline(prompt, NULL, reg_completion);
if(!line)
if (line == NULL)
break;
if(line[0] != '\n') {
struct registry_key *new = process_cmd(mem_ctx, h, curkey, line);
if(new)curkey = new;
if (line[0] != '\n') {
ret = W_ERROR_IS_OK(process_cmd(ctx, line));
}
}
talloc_free(mem_ctx);
talloc_free(ctx);
return 0;
return (ret?0:1);
}

View File

@ -2,7 +2,7 @@
Unix SMB/CIFS implementation.
simple registry frontend
Copyright (C) Jelmer Vernooij 2004
Copyright (C) Jelmer Vernooij 2004-2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -20,52 +20,66 @@
#include "includes.h"
#include "lib/registry/registry.h"
#include "lib/registry/tools/common.h"
#include "lib/events/events.h"
#include "lib/cmdline/popt_common.h"
static void print_tree(int l, struct registry_key *p, int fullpath, int novals)
/**
* Print a registry key recursively
*
* @param level Level at which to print
* @param p Key to print
* @param fullpath Whether the full pat hshould be printed or just the last bit
* @param novals Whether values should not be printed
*/
static void print_tree(int level, struct registry_key *p,
const char *name,
bool fullpath, bool novals)
{
struct registry_key *subkey;
struct registry_value *value;
const char *valuename;
const char *keyname;
uint32_t value_type;
DATA_BLOB value_data;
struct security_descriptor *sec_desc;
WERROR error;
int i;
TALLOC_CTX *mem_ctx;
for(i = 0; i < l; i++) putchar(' ');
/* Hive name */
if(p->hive->root == p) {
if(p->hive->root->name) printf("%s\n", p->hive->root->name); else printf("<No Name>\n");
} else {
if(!p->name) printf("<No Name>\n");
if(fullpath) printf("%s\n", p->path);
else printf("%s\n", p->name?p->name:"(NULL)");
}
for(i = 0; i < level; i++) putchar(' '); puts(name);
mem_ctx = talloc_init("print_tree");
for(i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(mem_ctx, p, i, &subkey)); i++) {
print_tree(l+1, subkey, fullpath, novals);
for (i = 0; W_ERROR_IS_OK(error = reg_key_get_subkey_by_index(mem_ctx, p, i, &keyname, NULL, NULL)); i++) {
SMB_ASSERT(strlen(keyname) > 0);
if (!W_ERROR_IS_OK(reg_open_key(mem_ctx, p, keyname, &subkey)))
continue;
print_tree(level+1, subkey, (fullpath && strlen(name))?
talloc_asprintf(mem_ctx, "%s\\%s", name, keyname):
keyname, fullpath, novals);
}
talloc_free(mem_ctx);
if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
DEBUG(0, ("Error occured while fetching subkeys for '%s': %s\n", p->path, win_errstr(error)));
DEBUG(0, ("Error occured while fetching subkeys for '%s': %s\n",
name, win_errstr(error)));
}
if(!novals) {
if (!novals) {
mem_ctx = talloc_init("print_tree");
for(i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(mem_ctx, p, i, &value)); i++) {
for(i = 0; W_ERROR_IS_OK(error = reg_key_get_value_by_index(mem_ctx,
p, i, &valuename, &value_type, &value_data)); i++) {
int j;
char *desc;
for(j = 0; j < l+1; j++) putchar(' ');
desc = reg_val_description(mem_ctx, value);
for(j = 0; j < level+1; j++) putchar(' ');
desc = reg_val_description(mem_ctx, valuename, value_type,
value_data);
printf("%s\n", desc);
}
talloc_free(mem_ctx);
if(!W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) {
DEBUG(0, ("Error occured while fetching values for '%s': %s\n", p->path, win_errstr(error)));
DEBUG(0, ("Error occured while fetching values for '%s': %s\n",
name, win_errstr(error)));
}
}
@ -79,21 +93,22 @@ static void print_tree(int l, struct registry_key *p, int fullpath, int novals)
int main(int argc, char **argv)
{
int opt, i;
const char *backend = NULL;
const char *file = NULL;
const char *remote = NULL;
poptContext pc;
struct registry_context *h = NULL;
struct registry_key *root = NULL;
struct registry_key *start_key = NULL;
WERROR error;
int fullpath = 0, no_values = 0;
bool fullpath = false, no_values = false;
struct poptOption long_options[] = {
POPT_AUTOHELP
{"backend", 'b', POPT_ARG_STRING, &backend, 0, "backend to use", NULL},
{"fullpath", 'f', POPT_ARG_NONE, &fullpath, 0, "show full paths", NULL},
{"file", 'F', POPT_ARG_STRING, &file, 0, "file path", NULL },
{"remote", 'R', POPT_ARG_STRING, &remote, 0, "connect to specified remote server", NULL },
{"fullpath", 'f', POPT_ARG_NONE, &fullpath, 0, "show full paths", NULL},
{"no-values", 'V', POPT_ARG_NONE, &no_values, 0, "don't show values", NULL},
POPT_COMMON_SAMBA
POPT_COMMON_CREDENTIALS
POPT_COMMON_VERSION
{ NULL }
};
@ -102,48 +117,35 @@ int main(int argc, char **argv)
while((opt = poptGetNextOpt(pc)) != -1) {
}
registry_init();
if (remote) {
error = reg_open_remote(&h, NULL, cmdline_credentials, remote, NULL);
if(!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Unable to open remote registry at %s:%s \n", remote, win_errstr(error));
return 1;
}
} else if (backend) {
error = reg_open_hive(NULL, backend, poptGetArg(pc), NULL, cmdline_credentials, &root);
if(!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Unable to open '%s' with backend '%s':%s \n", poptGetArg(pc), backend, win_errstr(error));
return 1;
}
if (remote != NULL) {
h = reg_common_open_remote(remote, cmdline_credentials);
} else if (file != NULL) {
start_key = reg_common_open_file(file, cmdline_credentials);
} else {
error = reg_open_local (NULL, &h, NULL, cmdline_credentials);
if(!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Unable to open local registry:%s \n", win_errstr(error));
return 1;
}
h = reg_common_open_local(cmdline_credentials);
}
if (h == NULL && start_key == NULL)
return 1;
poptFreeContext(pc);
error = WERR_OK;
if (root != NULL) {
print_tree(0, root, fullpath, no_values);
if (start_key != NULL) {
print_tree(0, start_key, "", fullpath, no_values);
} else {
for(i = 0; reg_predefined_keys[i].handle; i++) {
error = reg_get_predefined_key(h, reg_predefined_keys[i].handle, &root);
error = reg_get_predefined_key(h, reg_predefined_keys[i].handle,
&start_key);
if (!W_ERROR_IS_OK(error)) {
fprintf(stderr, "Skipping %s\n", reg_predefined_keys[i].name);
fprintf(stderr, "Skipping %s: %s\n", reg_predefined_keys[i].name,
win_errstr(error));
continue;
}
SMB_ASSERT(root);
print_tree(0, root, fullpath, no_values);
SMB_ASSERT(start_key != NULL);
print_tree(0, start_key, reg_predefined_keys[i].name, fullpath,
no_values);
}
}

View File

@ -1,7 +1,7 @@
/*
Unix SMB/CIFS implementation.
Transparent registry backend handling
Copyright (C) Jelmer Vernooij 2003-2004.
Copyright (C) Jelmer Vernooij 2003-2007.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -50,27 +50,30 @@ _PUBLIC_ const char *str_regtype(int type)
return "Unknown";
}
_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type, DATA_BLOB *data)
_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type,
const DATA_BLOB data)
{
char *ret = NULL;
if(data->length == 0) return talloc_strdup(mem_ctx, "");
if (data.length == 0)
return talloc_strdup(mem_ctx, "");
switch (type) {
case REG_EXPAND_SZ:
case REG_SZ:
convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, data->data, data->length, (void **)&ret);
convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, data.data, data.length,
(void **)&ret);
return ret;
case REG_BINARY:
ret = data_blob_hex_string(mem_ctx, data);
ret = data_blob_hex_string(mem_ctx, &data);
return ret;
case REG_DWORD:
if (*(int *)data->data == 0)
if (*(int *)data.data == 0)
return talloc_strdup(mem_ctx, "0");
return talloc_asprintf(mem_ctx, "0x%x", *(int *)data->data);
return talloc_asprintf(mem_ctx, "0x%x", *(int *)data.data);
case REG_MULTI_SZ:
/* FIXME */
@ -84,9 +87,13 @@ _PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type, DATA_BLOB
}
/** Generate a string that describes a registry value */
_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, struct registry_value *val)
_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, const char *name,
uint32_t data_type,
const DATA_BLOB data)
{
return talloc_asprintf(mem_ctx, "%s = %s : %s", val->name?val->name:"<No Name>", str_regtype(val->data_type), reg_val_data_string(mem_ctx, val->data_type, &val->data));
return talloc_asprintf(mem_ctx, "%s = %s : %s", name?name:"<No Name>",
str_regtype(data_type),
reg_val_data_string(mem_ctx, data_type, data));
}
_PUBLIC_ BOOL reg_string_to_val(TALLOC_CTX *mem_ctx, const char *type_str, const char *data_str, uint32_t *type, DATA_BLOB *data)
@ -136,29 +143,6 @@ _PUBLIC_ BOOL reg_string_to_val(TALLOC_CTX *mem_ctx, const char *type_str, const
return True;
}
/**
* Replace all \'s with /'s
*/
char *reg_path_win2unix(char *path)
{
int i;
for(i = 0; path[i]; i++) {
if(path[i] == '\\') path[i] = '/';
}
return path;
}
/**
* Replace all /'s with \'s
*/
char *reg_path_unix2win(char *path)
{
int i;
for(i = 0; path[i]; i++) {
if(path[i] == '/') path[i] = '\\';
}
return path;
}
/** Open a key by name (including the predefined key name!) */
WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, const char *name, struct registry_key **result)
{
@ -167,14 +151,16 @@ WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, co
int predeflength;
char *predefname;
if(strchr(name, '\\')) predeflength = strchr(name, '\\')-name;
else predeflength = strlen(name);
if (strchr(name, '\\') != NULL)
predeflength = strchr(name, '\\')-name;
else
predeflength = strlen(name);
predefname = talloc_strndup(mem_ctx, name, predeflength);
error = reg_get_predefined_key_by_name(handle, predefname, &predef);
talloc_free(predefname);
if(!W_ERROR_IS_OK(error)) {
if (!W_ERROR_IS_OK(error)) {
return error;
}
@ -186,7 +172,9 @@ WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, co
}
}
static WERROR get_abs_parent(TALLOC_CTX *mem_ctx, struct registry_context *ctx, const char *path, struct registry_key **parent, const char **name)
static WERROR get_abs_parent(TALLOC_CTX *mem_ctx, struct registry_context *ctx,
const char *path, struct registry_key **parent,
const char **name)
{
char *parent_name;
WERROR error;
@ -195,14 +183,14 @@ static WERROR get_abs_parent(TALLOC_CTX *mem_ctx, struct registry_context *ctx,
return WERR_FOOBAR;
}
parent_name = talloc_strndup(mem_ctx, path, strrchr(path, '\\')-1-path);
parent_name = talloc_strndup(mem_ctx, path, strrchr(path, '\\')-path);
error = reg_open_key_abs(mem_ctx, ctx, parent_name, parent);
if (!W_ERROR_IS_OK(error)) {
return error;
}
*name = talloc_strdup(mem_ctx, strchr(path, '\\')+1);
*name = talloc_strdup(mem_ctx, strrchr(path, '\\')+1);
return WERR_OK;
}
@ -228,20 +216,27 @@ WERROR reg_key_del_abs(struct registry_context *ctx, const char *path)
return error;
}
WERROR reg_key_add_abs(TALLOC_CTX *mem_ctx, struct registry_context *ctx, const char *path, uint32_t access_mask, struct security_descriptor *sec_desc, struct registry_key **result)
WERROR reg_key_add_abs(TALLOC_CTX *mem_ctx, struct registry_context *ctx,
const char *path, uint32_t access_mask,
struct security_descriptor *sec_desc,
struct registry_key **result)
{
struct registry_key *parent;
const char *n;
WERROR error;
if (!strchr(path, '\\')) {
return WERR_FOOBAR;
return WERR_ALREADY_EXISTS;
}
error = get_abs_parent(mem_ctx, ctx, path, &parent, &n);
if (W_ERROR_IS_OK(error)) {
error = reg_key_add_name(mem_ctx, parent, n, access_mask, sec_desc, result);
if (!W_ERROR_IS_OK(error)) {
DEBUG(2, ("Opening parent of %s failed with %s\n", path,
win_errstr(error)));
return error;
}
error = reg_key_add_name(mem_ctx, parent, n, NULL, sec_desc, result);
return error;
}

View File

@ -1,7 +1,7 @@
/*
Unix SMB/CIFS implementation.
Registry interface
Copyright (C) Jelmer Vernooij 2004.
Copyright (C) Jelmer Vernooij 2007.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -26,8 +26,6 @@ static WERROR wine_open_reg (struct registry_hive *h, struct registry_key **key)
/* FIXME: Open h->location and mmap it */
}
static REG_OPS reg_backend_wine = {
.name = "wine",
.open_hive = wine_open_reg,

View File

@ -28,7 +28,7 @@
/*******************************************************************
Close the low 3 fd's and open dev/null in their place.
********************************************************************/
static void close_low_fds(BOOL stderr_too)
static void close_low_fds(bool stderr_too)
{
#ifndef VALGRIND
int fd;
@ -65,7 +65,7 @@ static void close_low_fds(BOOL stderr_too)
Become a daemon, discarding the controlling terminal.
**/
_PUBLIC_ void become_daemon(BOOL Fork)
_PUBLIC_ void become_daemon(bool Fork)
{
if (Fork) {
if (fork()) {
@ -87,7 +87,7 @@ _PUBLIC_ void become_daemon(BOOL Fork)
#endif /* HAVE_SETSID */
/* Close fd's 0,1,2. Needed if started by rsh */
close_low_fds(False); /* Don't close stderr, let the debug system
close_low_fds(false); /* Don't close stderr, let the debug system
attach it to the logfile */
}

View File

@ -59,11 +59,12 @@ _PUBLIC_ struct dcesrv_handle *dcesrv_handle_new(struct dcesrv_connection_contex
return h;
}
/*
/**
find an internal handle given a wire handle. If the wire handle is NULL then
allocate a new handle
*/
_PUBLIC_ struct dcesrv_handle *dcesrv_handle_fetch(struct dcesrv_connection_context *context,
_PUBLIC_ struct dcesrv_handle *dcesrv_handle_fetch(
struct dcesrv_connection_context *context,
struct policy_handle *p,
uint8_t handle_type)
{

View File

@ -28,14 +28,20 @@
enum handle_types { HTYPE_REGVAL, HTYPE_REGKEY };
static NTSTATUS dcerpc_winreg_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
static NTSTATUS dcerpc_winreg_bind(struct dcesrv_call_state *dce_call,
const struct dcesrv_interface *iface)
{
struct registry_context *ctx;
WERROR err;
err = reg_open_local(dce_call->context,
err = reg_open_samba(dce_call->context,
&ctx, dce_call->conn->auth_state.session_info, NULL);
if (!W_ERROR_IS_OK(err)) {
DEBUG(0, ("Error opening registry: %s\n", win_errstr(err)));
return NT_STATUS_UNSUCCESSFUL;
}
dce_call->context->private = ctx;
return NT_STATUS_OK;
@ -43,7 +49,9 @@ static NTSTATUS dcerpc_winreg_bind(struct dcesrv_call_state *dce_call, const str
#define DCESRV_INTERFACE_WINREG_BIND dcerpc_winreg_bind
static WERROR dcesrv_winreg_openhive (struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, uint32_t hkey, struct policy_handle **outh)
static WERROR dcesrv_winreg_openhive(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx, uint32_t hkey,
struct policy_handle **outh)
{
struct registry_context *ctx = dce_call->context->private;
struct dcesrv_handle *h;
@ -79,8 +87,9 @@ func_winreg_OpenHive(HKPN,HKEY_PERFORMANCE_NLSTEXT)
/*
winreg_CloseKey
*/
static WERROR dcesrv_winreg_CloseKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_CloseKey *r)
static WERROR dcesrv_winreg_CloseKey(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_CloseKey *r)
{
struct dcesrv_handle *h;
@ -93,12 +102,12 @@ static WERROR dcesrv_winreg_CloseKey(struct dcesrv_call_state *dce_call, TALLOC_
return WERR_OK;
}
/*
winreg_CreateKey
*/
static WERROR dcesrv_winreg_CreateKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_CreateKey *r)
static WERROR dcesrv_winreg_CreateKey(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_CreateKey *r)
{
struct dcesrv_handle *h, *newh;
WERROR error;
@ -124,10 +133,9 @@ static WERROR dcesrv_winreg_CreateKey(struct dcesrv_call_state *dce_call, TALLOC
}
}
error = reg_key_add_name(newh, (struct registry_key *)h->data, r->in.name.name,
r->in.access_mask,
r->in.secdesc?&sd:NULL,
(struct registry_key **)&newh->data);
error = reg_key_add_name(newh, (struct registry_key *)h->data,
r->in.name.name, NULL, r->in.secdesc?&sd:NULL,
(struct registry_key **)&newh->data);
if (W_ERROR_IS_OK(error)) {
r->out.new_handle = &newh->wire_handle;
} else {
@ -141,8 +149,9 @@ static WERROR dcesrv_winreg_CreateKey(struct dcesrv_call_state *dce_call, TALLOC
/*
winreg_DeleteKey
*/
static WERROR dcesrv_winreg_DeleteKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_DeleteKey *r)
static WERROR dcesrv_winreg_DeleteKey(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_DeleteKey *r)
{
struct dcesrv_handle *h;
@ -155,8 +164,9 @@ static WERROR dcesrv_winreg_DeleteKey(struct dcesrv_call_state *dce_call, TALLOC
/*
winreg_DeleteValue
*/
static WERROR dcesrv_winreg_DeleteValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_DeleteValue *r)
static WERROR dcesrv_winreg_DeleteValue(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_DeleteValue *r)
{
struct dcesrv_handle *h;
struct registry_key *key;
@ -172,25 +182,29 @@ static WERROR dcesrv_winreg_DeleteValue(struct dcesrv_call_state *dce_call, TALL
/*
winreg_EnumKey
*/
static WERROR dcesrv_winreg_EnumKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_EnumKey *r)
static WERROR dcesrv_winreg_EnumKey(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_EnumKey *r)
{
struct dcesrv_handle *h;
struct registry_key *key;
const char *name;
NTTIME last_mod;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
r->out.result = reg_key_get_subkey_by_index(mem_ctx, (struct registry_key *)h->data, r->in.enum_index, &key);
r->out.result = reg_key_get_subkey_by_index(mem_ctx,
(struct registry_key *)h->data, r->in.enum_index,
&name, NULL, &last_mod);
if (W_ERROR_IS_OK(r->out.result)) {
if (2*strlen_m_term(key->name) > r->in.name->size) {
if (2*strlen_m_term(name) > r->in.name->size) {
return WERR_MORE_DATA;
}
r->out.name->length = 2*strlen_m_term(key->name);
r->out.name->name = key->name;
r->out.name->length = 2*strlen_m_term(name);
r->out.name->name = name;
r->out.keyclass = talloc_zero(mem_ctx, struct winreg_StringBuf);
if (r->in.last_changed_time) {
r->out.last_changed_time = &key->last_mod;
r->out.last_changed_time = &last_mod;
}
}
@ -201,19 +215,24 @@ static WERROR dcesrv_winreg_EnumKey(struct dcesrv_call_state *dce_call, TALLOC_C
/*
winreg_EnumValue
*/
static WERROR dcesrv_winreg_EnumValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_EnumValue *r)
static WERROR dcesrv_winreg_EnumValue(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_EnumValue *r)
{
struct dcesrv_handle *h;
struct registry_key *key;
struct registry_value *value;
WERROR result;
const char *data_name;
uint32_t data_type;
DATA_BLOB data;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
key = h->data;
result = reg_key_get_value_by_index(mem_ctx, key, r->in.enum_index, &value);
result = reg_key_get_value_by_index(mem_ctx, key, r->in.enum_index,
&data_name,
&data_type, &data);
if (!W_ERROR_IS_OK(result)) {
return result;
}
@ -222,32 +241,32 @@ static WERROR dcesrv_winreg_EnumValue(struct dcesrv_call_state *dce_call, TALLOC
want that back */
if (r->in.type != NULL) {
r->out.type = talloc(mem_ctx, enum winreg_Type);
*r->out.type = value->data_type;
*r->out.type = data_type;
}
/* check the client has enough room for the value */
if (r->in.value != NULL &&
r->in.size != NULL &&
value->data.length > *r->in.size) {
data.length > *r->in.size) {
return WERR_MORE_DATA;
}
/* and enough room for the name */
if (r->in.name->size < 2*strlen_m_term(value->name)) {
if (r->in.name->size < 2*strlen_m_term(data_name)) {
return WERR_MORE_DATA;
}
r->out.name->name = value->name;
r->out.name->length = 2*strlen_m_term(value->name);
r->out.name->size = 2*strlen_m_term(value->name);
r->out.name->name = data_name;
r->out.name->length = 2*strlen_m_term(data_name);
r->out.name->size = 2*strlen_m_term(data_name);
if (r->in.value) {
r->out.value = value->data.data;
r->out.value = data.data;
}
if (r->in.size) {
r->out.size = talloc(mem_ctx, uint32_t);
*r->out.size = value->data.length;
*r->out.size = data.length;
r->out.length = r->out.size;
}
@ -258,8 +277,9 @@ static WERROR dcesrv_winreg_EnumValue(struct dcesrv_call_state *dce_call, TALLOC
/*
winreg_FlushKey
*/
static WERROR dcesrv_winreg_FlushKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_FlushKey *r)
static WERROR dcesrv_winreg_FlushKey(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_FlushKey *r)
{
struct dcesrv_handle *h;
@ -272,8 +292,9 @@ static WERROR dcesrv_winreg_FlushKey(struct dcesrv_call_state *dce_call, TALLOC_
/*
winreg_GetKeySecurity
*/
static WERROR dcesrv_winreg_GetKeySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_GetKeySecurity *r)
static WERROR dcesrv_winreg_GetKeySecurity(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_GetKeySecurity *r)
{
struct dcesrv_handle *h;
@ -286,8 +307,9 @@ static WERROR dcesrv_winreg_GetKeySecurity(struct dcesrv_call_state *dce_call, T
/*
winreg_LoadKey
*/
static WERROR dcesrv_winreg_LoadKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_LoadKey *r)
static WERROR dcesrv_winreg_LoadKey(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_LoadKey *r)
{
return WERR_NOT_SUPPORTED;
}
@ -296,8 +318,9 @@ static WERROR dcesrv_winreg_LoadKey(struct dcesrv_call_state *dce_call, TALLOC_C
/*
winreg_NotifyChangeKeyValue
*/
static WERROR dcesrv_winreg_NotifyChangeKeyValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_NotifyChangeKeyValue *r)
static WERROR dcesrv_winreg_NotifyChangeKeyValue(
struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx, struct winreg_NotifyChangeKeyValue *r)
{
return WERR_NOT_SUPPORTED;
}
@ -306,8 +329,9 @@ static WERROR dcesrv_winreg_NotifyChangeKeyValue(struct dcesrv_call_state *dce_c
/*
winreg_OpenKey
*/
static WERROR dcesrv_winreg_OpenKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_OpenKey *r)
static WERROR dcesrv_winreg_OpenKey(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_OpenKey *r)
{
struct dcesrv_handle *h, *newh;
WERROR result;
@ -336,82 +360,66 @@ static WERROR dcesrv_winreg_OpenKey(struct dcesrv_call_state *dce_call, TALLOC_C
/*
winreg_QueryInfoKey
*/
static WERROR dcesrv_winreg_QueryInfoKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_QueryInfoKey *r)
static WERROR dcesrv_winreg_QueryInfoKey(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_QueryInfoKey *r)
{
struct dcesrv_handle *h;
struct registry_key *k;
WERROR ret;
const char *classname;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
k = h->data;
ret = reg_key_num_subkeys(k, r->out.num_subkeys);
if (!W_ERROR_IS_OK(ret)) {
return ret;
}
ret = reg_key_get_info(mem_ctx, k, &classname, r->out.num_subkeys,
r->out.num_values, r->out.last_changed_time);
ret = reg_key_num_values(k, r->out.num_values);
if (!W_ERROR_IS_OK(ret)) {
return ret;
}
if (r->out.classname != NULL)
r->out.classname->name = classname;
ret = reg_key_subkeysizes(k, r->out.max_subkeysize, r->out.max_subkeylen);
if (!W_ERROR_IS_OK(ret)) {
return ret;
}
ret = reg_key_valuesizes(k, r->out.max_valnamelen, r->out.max_valbufsize);
if (!W_ERROR_IS_OK(ret)) {
return ret;
}
r->out.secdescsize = 0; /* FIXME */
ZERO_STRUCT(r->out.last_changed_time); /* FIXME */
if (!W_ERROR_IS_OK(ret)) {
return ret;
}
return WERR_OK;
return ret;
}
/*
winreg_QueryValue
*/
static WERROR dcesrv_winreg_QueryValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_QueryValue *r)
static WERROR dcesrv_winreg_QueryValue(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_QueryValue *r)
{
struct dcesrv_handle *h;
struct registry_key *key;
struct registry_value *val;
uint32_t value_type;
DATA_BLOB value_data;
WERROR result;
DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY);
key = h->data;
result = reg_key_get_value_by_name(mem_ctx, key, r->in.value_name.name, &val);
result = reg_key_get_value_by_name(mem_ctx, key, r->in.value_name.name,
&value_type, &value_data);
if (!W_ERROR_IS_OK(result)) {
return result;
}
/* Just asking for the size of the buffer */
r->out.type = (enum winreg_Type *)&val->data_type;
r->out.type = &value_type;
r->out.length = talloc(mem_ctx, uint32_t);
if (!r->out.length) {
return WERR_NOMEM;
}
*r->out.length = val->data.length;
if (!r->in.data) {
*r->out.length = value_data.length;
if (r->in.data == NULL) {
r->out.size = talloc(mem_ctx, uint32_t);
*r->out.size = val->data.length;
*r->out.size = value_data.length;
} else {
r->out.size = r->in.size;
r->out.data = val->data.data;
r->out.data = value_data.data;
}
return WERR_OK;
@ -421,8 +429,9 @@ static WERROR dcesrv_winreg_QueryValue(struct dcesrv_call_state *dce_call, TALLO
/*
winreg_ReplaceKey
*/
static WERROR dcesrv_winreg_ReplaceKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_ReplaceKey *r)
static WERROR dcesrv_winreg_ReplaceKey(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_ReplaceKey *r)
{
return WERR_NOT_SUPPORTED;
}
@ -431,8 +440,9 @@ static WERROR dcesrv_winreg_ReplaceKey(struct dcesrv_call_state *dce_call, TALLO
/*
winreg_RestoreKey
*/
static WERROR dcesrv_winreg_RestoreKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_RestoreKey *r)
static WERROR dcesrv_winreg_RestoreKey(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_RestoreKey *r)
{
return WERR_NOT_SUPPORTED;
}
@ -441,8 +451,9 @@ static WERROR dcesrv_winreg_RestoreKey(struct dcesrv_call_state *dce_call, TALLO
/*
winreg_SaveKey
*/
static WERROR dcesrv_winreg_SaveKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_SaveKey *r)
static WERROR dcesrv_winreg_SaveKey(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_SaveKey *r)
{
return WERR_NOT_SUPPORTED;
}
@ -451,8 +462,9 @@ static WERROR dcesrv_winreg_SaveKey(struct dcesrv_call_state *dce_call, TALLOC_C
/*
winreg_SetKeySecurity
*/
static WERROR dcesrv_winreg_SetKeySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_SetKeySecurity *r)
static WERROR dcesrv_winreg_SetKeySecurity(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_SetKeySecurity *r)
{
return WERR_NOT_SUPPORTED;
}
@ -461,8 +473,9 @@ static WERROR dcesrv_winreg_SetKeySecurity(struct dcesrv_call_state *dce_call, T
/*
winreg_SetValue
*/
static WERROR dcesrv_winreg_SetValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_SetValue *r)
static WERROR dcesrv_winreg_SetValue(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_SetValue *r)
{
struct dcesrv_handle *h;
struct registry_key *key;
@ -488,8 +501,9 @@ static WERROR dcesrv_winreg_SetValue(struct dcesrv_call_state *dce_call, TALLOC_
/*
winreg_UnLoadKey
*/
static WERROR dcesrv_winreg_UnLoadKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_UnLoadKey *r)
static WERROR dcesrv_winreg_UnLoadKey(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_UnLoadKey *r)
{
return WERR_NOT_SUPPORTED;
}
@ -498,8 +512,9 @@ static WERROR dcesrv_winreg_UnLoadKey(struct dcesrv_call_state *dce_call, TALLOC
/*
winreg_InitiateSystemShutdown
*/
static WERROR dcesrv_winreg_InitiateSystemShutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_InitiateSystemShutdown *r)
static WERROR dcesrv_winreg_InitiateSystemShutdown(
struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_InitiateSystemShutdown *r)
{
return WERR_NOT_SUPPORTED;
}
@ -508,8 +523,9 @@ static WERROR dcesrv_winreg_InitiateSystemShutdown(struct dcesrv_call_state *dce
/*
winreg_AbortSystemShutdown
*/
static WERROR dcesrv_winreg_AbortSystemShutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_AbortSystemShutdown *r)
static WERROR dcesrv_winreg_AbortSystemShutdown(
struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_AbortSystemShutdown *r)
{
return WERR_NOT_SUPPORTED;
}
@ -518,8 +534,9 @@ static WERROR dcesrv_winreg_AbortSystemShutdown(struct dcesrv_call_state *dce_ca
/*
winreg_GetVersion
*/
static WERROR dcesrv_winreg_GetVersion(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_GetVersion *r)
static WERROR dcesrv_winreg_GetVersion(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_GetVersion *r)
{
struct dcesrv_handle *h;
@ -537,8 +554,9 @@ static WERROR dcesrv_winreg_GetVersion(struct dcesrv_call_state *dce_call, TALLO
/*
winreg_QueryMultipleValues
*/
static WERROR dcesrv_winreg_QueryMultipleValues(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_QueryMultipleValues *r)
static WERROR dcesrv_winreg_QueryMultipleValues(
struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_QueryMultipleValues *r)
{
return WERR_NOT_SUPPORTED;
}
@ -547,8 +565,9 @@ static WERROR dcesrv_winreg_QueryMultipleValues(struct dcesrv_call_state *dce_ca
/*
winreg_InitiateSystemShutdownEx
*/
static WERROR dcesrv_winreg_InitiateSystemShutdownEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_InitiateSystemShutdownEx *r)
static WERROR dcesrv_winreg_InitiateSystemShutdownEx(
struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_InitiateSystemShutdownEx *r)
{
return WERR_NOT_SUPPORTED;
}
@ -557,8 +576,9 @@ static WERROR dcesrv_winreg_InitiateSystemShutdownEx(struct dcesrv_call_state *d
/*
winreg_SaveKeyEx
*/
static WERROR dcesrv_winreg_SaveKeyEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_SaveKeyEx *r)
static WERROR dcesrv_winreg_SaveKeyEx(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct winreg_SaveKeyEx *r)
{
return WERR_NOT_SUPPORTED;
}
@ -567,8 +587,9 @@ static WERROR dcesrv_winreg_SaveKeyEx(struct dcesrv_call_state *dce_call, TALLOC
/*
winreg_QueryMultipleValues2
*/
static WERROR dcesrv_winreg_QueryMultipleValues2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_QueryMultipleValues2 *r)
static WERROR dcesrv_winreg_QueryMultipleValues2(
struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct winreg_QueryMultipleValues2 *r)
{
return WERR_NOT_SUPPORTED;
}

View File

@ -46,5 +46,4 @@ RPC-SVCCTL
RPC-DSSYNC
RPC-EPMAPPER
RPC-INITSHUTDOWN
RPC-WINREG
RPC-SAMSYNC

View File

@ -3,6 +3,8 @@
LEX="$1"
SRC="$2"
DEST="$3"
shift 3
ARGS="$*"
dir=`dirname $SRC`
file=`basename $SRC`
@ -29,12 +31,15 @@ if [ -r $DEST ]; then
fi
fi
TOP=`pwd`
if cd $dir && $LEX $file; then
if cd $dir && $LEX $ARGS $file; then
if [ -r $base.yy.c ];then
# we must guarantee that config.h comes first
echo "#include \"config.h\"" > $base.c
sed '/^#/ s|$base.yy\.c|$DEST|' $base.yy.c >> $base.c
rm -f $base.yy.c
elif [ ! -r base.c ]; then
echo "$base.c nor $base.yy.c generated."
exit 1
fi
fi
cd $TOP

View File

@ -575,8 +575,6 @@ static int ejs_ldb_attach_dsdb_schema_from_ldif(MprVarHandle eid, int argc, char
{
struct ldb_context *ldb;
WERROR status;
char *pf_name;
char *df_name;
const char *pf;
const char *df;

View File

@ -0,0 +1,17 @@
REGEDIT4
[HKEY_LOCAL_MACHINE]
[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\ProductOptions]
ProductType="LanmanNT"
[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Print]
[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Terminal Server]
[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters]
RefusePasswordChange=REG_DWORD:0
[HKEY_USERS]
[HKEY_CLASSES_ROOT]

View File

@ -262,7 +262,7 @@ static int binary_smbd_main(const char *binary_name, int argc, const char *argv[
if (opt_daemon) {
DEBUG(3,("Becoming a daemon.\n"));
become_daemon(True);
become_daemon(true);
}
cleanup_tmp_files();
@ -286,9 +286,6 @@ static int binary_smbd_main(const char *binary_name, int argc, const char *argv[
gensec_init(); /* FIXME: */
registry_init(); /* FIXME: maybe run this in the initialization function
of the winreg RPC server instead? */
ntptr_init(); /* FIXME: maybe run this in the initialization function
of the spoolss RPC server instead? */

View File

@ -23,6 +23,9 @@ OBJ_FILES = \
../../lib/socket_wrapper/testsuite.o \
irpc.o \
../../lib/registry/tests/generic.o \
../../lib/registry/tests/hive.o \
../../lib/registry/tests/diff.o \
../../lib/registry/tests/registry.o \
resolve.o \
../../lib/util/tests/strlist.o \
../../lib/util/tests/file.o \

View File

@ -457,7 +457,8 @@ static const uint8_t getkeysecurity_in_data[] = {
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static bool getkeysecurity_in_check(struct torture_context *tctx, struct winreg_GetKeySecurity *r)
static bool getkeysecurity_in_check(struct torture_context *tctx,
struct winreg_GetKeySecurity *r)
{
/* FIXME: Handle */
torture_assert_int_equal(tctx, r->in.sec_info, 2, "sec info");
@ -474,7 +475,8 @@ static const uint8_t getkeysecurity_out_data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static bool getkeysecurity_out_check(struct torture_context *tctx, struct winreg_GetKeySecurity *r)
static bool getkeysecurity_out_check(struct torture_context *tctx,
struct winreg_GetKeySecurity *r)
{
torture_assert_int_equal(tctx, r->in.sd->size, 20, "sd size");
torture_assert_int_equal(tctx, r->in.sd->len, 20, "sd len");

View File

@ -575,11 +575,11 @@ static bool test_handles_drsuapi(struct torture_context *torture)
}
struct torture_suite *torture_rpc_handles(void)
struct torture_suite *torture_rpc_handles(TALLOC_CTX *mem_ctx)
{
struct torture_suite *suite;
suite = torture_suite_create(talloc_autofree_context(), "HANDLES");
suite = torture_suite_create(mem_ctx, "HANDLES");
torture_suite_add_simple_test(suite, "lsarpc", test_handles_lsa);
torture_suite_add_simple_test(suite, "lsarpc-shared", test_handles_lsa_shared);
torture_suite_add_simple_test(suite, "samr", test_handles_samr);

View File

@ -134,6 +134,17 @@ static bool torture_rpc_wrap_test(struct torture_context *tctx,
return fn(tctx, (struct dcerpc_pipe *)tcase->data);
}
static bool torture_rpc_wrap_test_ex(struct torture_context *tctx,
struct torture_tcase *tcase,
struct torture_test *test)
{
bool (*fn) (struct torture_context *, struct dcerpc_pipe *, const void *);
fn = test->fn;
return fn(tctx, (struct dcerpc_pipe *)tcase->data, test->data);
}
_PUBLIC_ struct torture_test *torture_rpc_tcase_add_test(
struct torture_tcase *tcase,
const char *name,
@ -155,6 +166,29 @@ _PUBLIC_ struct torture_test *torture_rpc_tcase_add_test(
return test;
}
_PUBLIC_ struct torture_test *torture_rpc_tcase_add_test_ex(
struct torture_tcase *tcase,
const char *name,
bool (*fn) (struct torture_context *, struct dcerpc_pipe *,
void *),
void *userdata)
{
struct torture_test *test;
test = talloc(tcase, struct torture_test);
test->name = talloc_strdup(test, name);
test->description = NULL;
test->run = torture_rpc_wrap_test_ex;
test->dangerous = false;
test->data = userdata;
test->fn = fn;
DLIST_ADD(tcase->tests, test);
return test;
}
NTSTATUS torture_rpc_init(void)
{
struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "RPC");
@ -173,7 +207,8 @@ NTSTATUS torture_rpc_init(void)
torture_suite_add_suite(suite, torture_rpc_eventlog());
torture_suite_add_suite(suite, torture_rpc_atsvc());
torture_suite_add_suite(suite, torture_rpc_wkssvc());
torture_suite_add_suite(suite, torture_rpc_handles());
torture_suite_add_suite(suite, torture_rpc_handles(suite));
torture_suite_add_suite(suite, torture_rpc_winreg(suite));
torture_suite_add_simple_test(suite, "SPOOLSS", torture_rpc_spoolss);
torture_suite_add_simple_test(suite, "SAMR", torture_rpc_samr);
torture_suite_add_simple_test(suite, "SAMR-USERS", torture_rpc_samr_users);
@ -186,7 +221,6 @@ NTSTATUS torture_rpc_init(void)
torture_suite_add_simple_test(suite, "SRVSVC", torture_rpc_srvsvc);
torture_suite_add_simple_test(suite, "SVCCTL", torture_rpc_svcctl);
torture_suite_add_simple_test(suite, "EPMAPPER", torture_rpc_epmapper);
torture_suite_add_simple_test(suite, "WINREG", torture_rpc_winreg);
torture_suite_add_simple_test(suite, "INITSHUTDOWN", torture_rpc_initshutdown);
torture_suite_add_simple_test(suite, "OXIDRESOLVE", torture_rpc_oxidresolve);
torture_suite_add_simple_test(suite, "REMACT", torture_rpc_remact);

File diff suppressed because it is too large Load Diff

View File

@ -433,3 +433,37 @@ struct torture_suite *torture_find_suite(struct torture_suite *parent,
return NULL;
}
static bool wrap_test_with_simple_test(struct torture_context *torture_ctx,
struct torture_tcase *tcase,
struct torture_test *test)
{
bool (*fn) (struct torture_context *, const void *tcase_data);
fn = test->fn;
return fn(torture_ctx, tcase->data);
}
struct torture_test *torture_tcase_add_simple_test(
struct torture_tcase *tcase,
const char *name,
bool (*run) (struct torture_context *test, const void *tcase_data))
{
struct torture_test *test;
test = talloc(tcase, struct torture_test);
test->name = talloc_strdup(test, name);
test->description = NULL;
test->run = wrap_test_with_simple_test;
test->fn = run;
test->data = NULL;
test->dangerous = False;
DLIST_ADD_END(tcase->tests, test, struct torture_test *);
return test;
}

View File

@ -165,6 +165,13 @@ struct torture_tcase *torture_suite_add_simple_tcase(
bool (*run) (struct torture_context *test, const void *test_data),
const void *data);
/* Convenience function that adds a test which only
* gets the test case data */
struct torture_test *torture_tcase_add_simple_test(
struct torture_tcase *tcase,
const char *name,
bool (*run) (struct torture_context *test, const void *tcase_data));
/* Convenience wrapper that adds a test that doesn't need any
* testcase data */
struct torture_tcase *torture_suite_add_simple_test(
@ -258,6 +265,20 @@ void torture_result(struct torture_context *test,
talloc_free(__got); \
} while(0)
#define torture_assert_file_contains(torture_ctx,filename,expected,cmt)\
do { const char *__got, *__expected = (expected); \
size_t __size; \
__got = file_load(filename, *size, torture_ctx); \
if (strcmp_safe(__got, __expected) != 0) { \
torture_result(torture_ctx, TORTURE_FAIL, \
__location__": %s contained:\n%sExpected: %s%s\n", \
__got, __expected, cmt); \
talloc_free(__got); \
return false; \
} \
talloc_free(__got); \
} while(0)
#define torture_assert_int_equal(torture_ctx,got,expected,cmt)\
do { int __got = (got), __expected = (expected); \
if (__got != __expected) { \

View File

@ -4,7 +4,7 @@ msgid ""
msgstr ""
"Project-Id-Version: qooxdoo framework\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-02-12 03:06+0100\n"
"POT-Creation-Date: 2007-02-10 16:11+0100\n"
"PO-Revision-Date: 2006-12-19 15:52+0100\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"