From f0c650a38286c07b9f3e83139c15bfbadc70ad5f Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Mon, 23 May 2005 16:25:31 +0000 Subject: r6942: * merging the registry changes back to the 3.0 tree * removing the testprns tool (This used to be commit 81ffb0dbbbd244623507880c323a3c37e2b8dc4d) --- source3/Makefile.in | 19 +- source3/include/reg_objects.h | 63 ++ source3/include/regfio.h | 222 +++++ source3/include/rpc_reg.h | 88 +- source3/include/rpc_secdes.h | 44 +- source3/lib/util.c | 38 - source3/param/loadparm.c | 6 + source3/registry/reg_cachehook.c | 2 +- source3/registry/reg_db.c | 253 ++--- source3/registry/reg_eventlog.c | 18 +- source3/registry/reg_frontend.c | 42 +- source3/registry/reg_objects.c | 82 +- source3/registry/reg_printing.c | 382 ++++--- source3/registry/reg_shares.c | 164 +++ source3/registry/reg_util.c | 88 ++ source3/registry/regfio.c | 1871 +++++++++++++++++++++++++++++++++++ source3/rpc_client/cli_reg.c | 999 +++++++++---------- source3/rpc_parse/parse_misc.c | 20 +- source3/rpc_parse/parse_reg.c | 94 +- source3/rpc_server/srv_reg_nt.c | 237 ++++- source3/rpc_server/srv_spoolss_nt.c | 103 +- source3/rpc_server/srv_srvsvc_nt.c | 22 +- source3/utils/net_rpc_registry.c | 495 +++++++++ source3/utils/testprns.c | 66 -- 24 files changed, 4145 insertions(+), 1273 deletions(-) create mode 100644 source3/include/reg_objects.h create mode 100644 source3/include/regfio.h create mode 100644 source3/registry/reg_shares.c create mode 100644 source3/registry/reg_util.c create mode 100644 source3/registry/regfio.c create mode 100644 source3/utils/net_rpc_registry.c delete mode 100644 source3/utils/testprns.c diff --git a/source3/Makefile.in b/source3/Makefile.in index 778ceaaa0b..d00b56872f 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -120,7 +120,7 @@ PATH_FLAGS = $(PATH_FLAGS6) $(PASSWD_FLAGS) SBIN_PROGS = bin/smbd@EXEEXT@ bin/nmbd@EXEEXT@ bin/swat@EXEEXT@ @EXTRA_SBIN_PROGS@ BIN_PROGS1 = bin/smbclient@EXEEXT@ bin/net@EXEEXT@ bin/smbspool@EXEEXT@ \ - bin/testparm@EXEEXT@ bin/testprns@EXEEXT@ bin/smbstatus@EXEEXT@ + bin/testparm@EXEEXT@ bin/smbstatus@EXEEXT@ BIN_PROGS2 = bin/smbcontrol@EXEEXT@ bin/smbtree@EXEEXT@ bin/tdbbackup@EXEEXT@ \ bin/nmblookup@EXEEXT@ bin/pdbedit@EXEEXT@ bin/tdbdump@EXEEXT@ \ bin/tdbtool@EXEEXT@ @@ -260,7 +260,8 @@ LIBMSRPC_OBJ = rpc_client/cli_lsarpc.o rpc_client/cli_samr.o \ REGOBJS_OBJ = registry/reg_objects.o REGISTRY_OBJ = registry/reg_frontend.o registry/reg_cachehook.o registry/reg_printing.o \ - registry/reg_db.o registry/reg_eventlog.o + registry/reg_db.o registry/reg_eventlog.o registry/reg_shares.o \ + registry/reg_util.o RPC_LSA_OBJ = rpc_server/srv_lsa.o rpc_server/srv_lsa_nt.o @@ -270,6 +271,7 @@ RPC_SAMR_OBJ = rpc_server/srv_samr.o rpc_server/srv_samr_nt.o \ rpc_server/srv_samr_util.o RPC_REG_OBJ = rpc_server/srv_reg.o rpc_server/srv_reg_nt.o +RPC_REG_OBJ = rpc_server/srv_reg.o rpc_server/srv_reg_nt.o $(REGFIO_OBJ) RPC_LSA_DS_OBJ = rpc_server/srv_lsa_ds.o rpc_server/srv_lsa_ds_nt.o @@ -369,6 +371,8 @@ AUTH_OBJ = auth/auth.o @AUTH_STATIC@ auth/auth_util.o auth/auth_compat.o \ MANGLE_OBJ = smbd/mangle.o smbd/mangle_hash.o smbd/mangle_map.o smbd/mangle_hash2.o +REGFIO_OBJ = registry/regfio.o + SMBD_OBJ_MAIN = smbd/server.o BUILDOPT_OBJ = smbd/build_options.o @@ -463,9 +467,6 @@ TESTPARM_OBJ = utils/testparm.o \ $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \ $(SECRETS_OBJ) $(LIBSAMBA_OBJ) -TESTPRNS_OBJ = utils/testprns.o $(PARAM_OBJ) $(PRINTING_OBJ) \ - $(LIB_NONSMBD_OBJ) libsmb/nterr.o - SMBPASSWD_OBJ = utils/smbpasswd.o $(PASSCHANGE_OBJ) $(PARAM_OBJ) $(SECRETS_OBJ) \ $(LIBSMB_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ)\ $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) \ @@ -537,7 +538,7 @@ NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_ads_cldap.o utils/net_help.o \ utils/net_rpc_join.o utils/net_time.o utils/net_lookup.o \ utils/net_cache.o utils/net_groupmap.o utils/net_idmap.o \ utils/net_status.o utils/net_rpc_printer.o utils/net_rpc_rights.o \ - utils/net_rpc_service.o + utils/net_rpc_service.o utils/net_rpc_registry.o NET_OBJ = $(NET_OBJ1) $(PARAM_OBJ) $(SECRETS_OBJ) $(LIBSMB_OBJ) \ $(RPC_PARSE_OBJ) $(PASSDB_OBJ) $(GROUPDB_OBJ) \ @@ -545,7 +546,7 @@ NET_OBJ = $(NET_OBJ1) $(PARAM_OBJ) $(SECRETS_OBJ) $(LIBSMB_OBJ) \ $(LIBMSRPC_OBJ) $(IDMAP_OBJ) \ $(LIBADS_OBJ) $(LIBADS_SERVER_OBJ) $(POPT_LIB_OBJ) \ $(SMBLDAP_OBJ) $(DCUTIL_OBJ) $(SERVER_MUTEX_OBJ) \ - $(AFS_OBJ) $(AFS_SETTOKEN_OBJ) $(PRINTERDB_OBJ) + $(AFS_OBJ) $(AFS_SETTOKEN_OBJ) $(PRINTERDB_OBJ) $(REGFIO_OBJ) CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) \ $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) $(SECRETS_OBJ) @@ -881,10 +882,6 @@ bin/testparm@EXEEXT@: $(TESTPARM_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ @$(CC) $(FLAGS) -o $@ $(TESTPARM_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) @POPTLIBS@ -bin/testprns@EXEEXT@: $(TESTPRNS_OBJ) bin/.dummy - @echo Linking $@ - @$(CC) $(FLAGS) -o $@ $(TESTPRNS_OBJ) $(LDFLAGS) $(DYNEXP) $(PRINT_LIBS) $(LIBS) - bin/smbstatus@EXEEXT@: $(STATUS_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ @$(CC) $(FLAGS) -o $@ $(STATUS_OBJ) $(LDFLAGS) $(DYNEXP) $(LIBS) \ diff --git a/source3/include/reg_objects.h b/source3/include/reg_objects.h new file mode 100644 index 0000000000..a31f7097d3 --- /dev/null +++ b/source3/include/reg_objects.h @@ -0,0 +1,63 @@ +/* + Unix SMB/CIFS implementation. + SMB parameters and setup + Copyright (C) Gerald Carter 2002-2005. + + 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 _REG_OBJECTS_H /* _REG_OBJECTS_H */ +#define _REG_OBJECTS_H + +/* structure to contain registry values */ + +typedef struct { + fstring valuename; + uint16 type; + uint32 size; /* in bytes */ + uint8 *data_p; +} REGISTRY_VALUE; + +/* container for registry values */ + +typedef struct { + TALLOC_CTX *ctx; + uint32 num_values; + REGISTRY_VALUE **values; +} REGVAL_CTR; + +/* container for registry subkey names */ + +typedef struct { + TALLOC_CTX *ctx; + uint32 num_subkeys; + char **subkeys; +} REGSUBKEY_CTR; + +/* represent a registry key with all its subkeys and values */ + +struct _regobj_key; + +typedef struct _regobj_key { + TALLOC_CTX *ctx; + + char *name; + + REGVAL_CTR values; + REGSUBKEY_CTR subkeys; +} REGOBJ_KEY; + +#endif /* _REG_OBJECTS_H */ + diff --git a/source3/include/regfio.h b/source3/include/regfio.h new file mode 100644 index 0000000000..e088a4a344 --- /dev/null +++ b/source3/include/regfio.h @@ -0,0 +1,222 @@ +/* + * Unix SMB/CIFS implementation. + * Windows NT registry I/O library + * Copyright (c) Gerald (Jerry) Carter 2005 + * + * 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. + */ + +/************************************************************ + * Most of this information was obtained from + * http://www.wednesday.demon.co.uk/dosreg.html + * Thanks Nigel! + ***********************************************************/ + + +#ifndef _REGFIO_H +#define _REGFIO_H + +/* Macros */ + +#define REGF_BLOCKSIZE 0x1000 +#define REGF_ALLOC_BLOCK 0x1000 + +/* header sizes for various records */ + +#define REGF_HDR_SIZE 4 +#define HBIN_HDR_SIZE 4 +#define HBIN_HEADER_REC_SIZE 0x24 +#define REC_HDR_SIZE 2 + +#define REGF_OFFSET_NONE 0xffffffff + +/* Flags for the vk records */ + +#define VK_FLAG_NAME_PRESENT 0x0001 +#define VK_DATA_IN_OFFSET 0x80000000 + +/* NK record macros */ + +#define NK_TYPE_LINKKEY 0x0010 +#define NK_TYPE_NORMALKEY 0x0020 +#define NK_TYPE_ROOTKEY 0x002c + +#define HBIN_STORE_REF(x, y) { x->hbin = y; y->ref_count++ }; +#define HBIN_REMOVE_REF(x, y) { x->hbin = NULL; y->ref_count-- /* if the count == 0; we can clean up */ }; + + +/* HBIN block */ +struct regf_hbin; +typedef struct regf_hbin { + struct regf_hbin *prev, *next; + uint32 file_off; /* my offset in the registry file */ + uint32 free_off; /* offset to free space within the hbin record */ + uint32 free_size; /* amount of data left in the block */ + int ref_count; /* how many active records are pointing to this block (not used currently) */ + + char header[HBIN_HDR_SIZE]; /* "hbin" */ + uint32 first_hbin_off; /* offset from first hbin block */ + uint32 block_size; /* block size of this blockually a multiple of 4096Kb) */ + + prs_struct ps; /* data */ + + BOOL dirty; /* has this hbin block been modified? */ +} REGF_HBIN; + +/* ??? List -- list of key offsets and hashed names for consistency */ + +typedef struct { + uint32 nk_off; + uint8 keycheck[sizeof(uint32)]; +} REGF_HASH_REC; + +typedef struct { + REGF_HBIN *hbin; /* pointer to HBIN record (in memory) containing this nk record */ + uint32 hbin_off; /* offset from beginning of this hbin block */ + uint32 rec_size; /* ((start_offset - end_offset) & 0xfffffff8) */ + + char header[REC_HDR_SIZE]; + uint16 num_keys; + REGF_HASH_REC *hashes; +} REGF_LF_REC; + +/* Key Value */ + +typedef struct { + REGF_HBIN *hbin; /* pointer to HBIN record (in memory) containing this nk record */ + uint32 hbin_off; /* offset from beginning of this hbin block */ + uint32 rec_size; /* ((start_offset - end_offset) & 0xfffffff8) */ + uint32 rec_off; /* offset stored in the value list */ + + char header[REC_HDR_SIZE]; + char *valuename; + uint32 data_size; + uint32 data_off; + uint8 *data; + uint32 type; + uint16 flag; +} REGF_VK_REC; + + +/* Key Security */ +struct _regf_sk_rec; + +typedef struct _regf_sk_rec { + struct _regf_sk_rec *next, *prev; + REGF_HBIN *hbin; /* pointer to HBIN record (in memory) containing this nk record */ + uint32 hbin_off; /* offset from beginning of this hbin block */ + uint32 rec_size; /* ((start_offset - end_offset) & 0xfffffff8) */ + + uint32 sk_off; /* offset parsed from NK record used as a key + to lookup reference to this SK record */ + + char header[REC_HDR_SIZE]; + uint32 prev_sk_off; + uint32 next_sk_off; + uint32 ref_count; + uint32 size; + SEC_DESC *sec_desc; +} REGF_SK_REC; + +/* Key Name */ + +typedef struct { + REGF_HBIN *hbin; /* pointer to HBIN record (in memory) containing this nk record */ + uint32 hbin_off; /* offset from beginning of this hbin block */ + uint32 subkey_index; /* index to next subkey record to return */ + uint32 rec_size; /* ((start_offset - end_offset) & 0xfffffff8) */ + + /* header information */ + + char header[REC_HDR_SIZE]; + uint16 key_type; + NTTIME mtime; + uint32 parent_off; /* back pointer in registry hive */ + uint32 classname_off; + char *classname; + char *keyname; + + /* max lengths */ + + uint32 max_bytes_subkeyname; /* max subkey name * 2 */ + uint32 max_bytes_subkeyclassname; /* max subkey classname length (as if) */ + uint32 max_bytes_valuename; /* max valuename * 2 */ + uint32 max_bytes_value; /* max value data size */ + + /* unknowns */ + + uint32 unk_index; /* nigel says run time index ? */ + + /* children */ + + uint32 num_subkeys; + uint32 subkeys_off; /* hash records that point to NK records */ + uint32 num_values; + uint32 values_off; /* value lists which point to VK records */ + uint32 sk_off; /* offset to SK record */ + + /* link in the other records here */ + + REGF_LF_REC subkeys; + REGF_VK_REC *values; + REGF_SK_REC *sec_desc; + +} REGF_NK_REC; + +/* REGF block */ + +typedef struct { + /* run time information */ + + int fd; /* file descriptor */ + int open_flags; /* flags passed to the open() call */ + TALLOC_CTX *mem_ctx; /* memory context for run-time file access information */ + REGF_HBIN *block_list; /* list of open hbin blocks */ + + /* file format information */ + + char header[REGF_HDR_SIZE]; /* "regf" */ + uint32 data_offset; /* offset to record in the first (or any?) hbin block */ + uint32 last_block; /* offset to last hbin block in file */ + uint32 checksum; /* XOR of bytes 0x0000 - 0x01FB */ + NTTIME mtime; + + REGF_SK_REC *sec_desc_list; /* list of security descriptors referenced by NK records */ + + /* unknowns used to simply writing */ + + uint32 unknown1; + uint32 unknown2; + uint32 unknown3; + uint32 unknown4; + uint32 unknown5; + uint32 unknown6; + +} REGF_FILE; + +/* Function Declarations */ + +REGF_FILE* regfio_open( const char *filename, int flags, int mode ); +int regfio_close( REGF_FILE *r ); + +REGF_NK_REC* regfio_rootkey( REGF_FILE *file ); +REGF_NK_REC* regfio_fetch_subkey( REGF_FILE *file, REGF_NK_REC *nk ); +REGF_NK_REC* regfio_write_key ( REGF_FILE *file, const char *name, + REGVAL_CTR *values, REGSUBKEY_CTR *subkeys, + SEC_DESC *sec_desc, REGF_NK_REC *parent ); + + +#endif /* _REGFIO_H */ + diff --git a/source3/include/rpc_reg.h b/source3/include/rpc_reg.h index f70fb5f03c..2849122667 100644 --- a/source3/include/rpc_reg.h +++ b/source3/include/rpc_reg.h @@ -25,6 +25,8 @@ #ifndef _RPC_REG_H /* _RPC_REG_H */ #define _RPC_REG_H +#include "reg_objects.h" + /* RPC opnum */ #define REG_OPEN_HKCR 0x00 @@ -58,12 +60,15 @@ #define HKEY_USERS 0x80000003 #define HKEY_PERFORMANCE_DATA 0x80000004 -#define KEY_HKLM "HKLM" -#define KEY_HKU "HKU" -#define KEY_HKCR "HKCR" -#define KEY_PRINTING "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Print" -#define KEY_EVENTLOG "HKLM\\SYSTEM\\CurrentControlSet\\Services\\Eventlog" -#define KEY_TREE_ROOT "" +#define KEY_HKLM "HKLM" +#define KEY_HKU "HKU" +#define KEY_HKCR "HKCR" +#define KEY_PRINTING "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Print" +#define KEY_PRINTING_2K "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print" +#define KEY_PRINTING_PORTS "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Ports" +#define KEY_EVENTLOG "HKLM\\SYSTEM\\CurrentControlSet\\Services\\Eventlog" +#define KEY_SHARES "HKLM\\SYSTEM\\CurrentControlSet\\Services\\LanmanServer\\Shares" +#define KEY_TREE_ROOT "" /* Registry data types */ @@ -80,36 +85,6 @@ #define REG_FULL_RESOURCE_DESCRIPTOR 9 #define REG_RESOURCE_REQUIREMENTS_LIST 10 -/* - * INTERNAL REGISTRY STRUCTURES - */ - -/* structure to contain registry values */ - -typedef struct { - fstring valuename; - uint16 type; - uint32 size; /* in bytes */ - uint8 *data_p; -} REGISTRY_VALUE; - -/* container for registry values */ - -typedef struct { - TALLOC_CTX *ctx; - uint32 num_values; - REGISTRY_VALUE **values; -} REGVAL_CTR; - -/* container for registry subkey names */ - -typedef struct { - TALLOC_CTX *ctx; - uint32 num_subkeys; - char **subkeys; -} REGSUBKEY_CTR; - - /* * container for function pointers to enumeration routines * for vitural registry view @@ -129,7 +104,6 @@ typedef struct { } REGISTRY_HOOK; - /* structure to store the registry handles */ typedef struct _RegistryKey { @@ -225,16 +199,16 @@ typedef struct { UNISTR4 name; uint32 *type; REGVAL_BUFFER *value; /* value, in byte buffer */ - uint32 *len_value1; - uint32 *len_value2; + uint32 *buffer_len; + uint32 *name_len; } REG_Q_ENUM_VALUE; typedef struct { UNISTR4 name; uint32 *type; REGVAL_BUFFER *value; - uint32 *len_value1; - uint32 *len_value2; + uint32 *buffer_len1; + uint32 *buffer_len2; WERROR status; } REG_R_ENUM_VALUE; @@ -377,33 +351,21 @@ typedef struct { typedef struct { POLICY_HND pol; uint32 key_index; - uint16 key_name_len; /* 0x0000 */ + uint16 key_name_len; uint16 unknown_1; /* 0x0414 */ - uint32 ptr1; /* pointer */ + uint32 ptr1; uint32 unknown_2; /* 0x0000 020A */ - uint8 pad1[8]; /* padding - zeros */ - uint32 ptr2; /* pointer */ - uint8 pad2[8]; /* padding - zeros */ - uint32 ptr3; /* pointer */ - NTTIME time; /* current time? */ + uint8 pad1[8]; + uint32 ptr2; + uint8 pad2[8]; + uint32 ptr3; + NTTIME time; } REG_Q_ENUM_KEY; typedef struct { - uint16 key_name_len; /* number of bytes in key name */ - uint16 unknown_1; /* 0x0414 - matches with query unknown_1 */ - - uint32 ptr1; /* pointer */ - uint32 unknown_2; /* 0x0000 020A */ - uint32 unknown_3; /* 0x0000 0000 */ - - UNISTR3 key_name; - - uint32 ptr2; /* pointer */ - uint8 pad2[8]; /* padding - zeros */ - - uint32 ptr3; /* pointer */ - NTTIME time; /* current time? */ - + UNISTR4 keyname; + UNISTR4 *classname; + NTTIME *time; WERROR status; /* return status */ } REG_R_ENUM_KEY; diff --git a/source3/include/rpc_secdes.h b/source3/include/rpc_secdes.h index ea987f9e4e..9eb4c9a41e 100644 --- a/source3/include/rpc_secdes.h +++ b/source3/include/rpc_secdes.h @@ -22,16 +22,6 @@ #ifndef _RPC_SECDES_H /* _RPC_SECDES_H */ #define _RPC_SECDES_H -#define SEC_RIGHTS_QUERY_VALUE 0x00000001 -#define SEC_RIGHTS_SET_VALUE 0x00000002 -#define SEC_RIGHTS_CREATE_SUBKEY 0x00000004 -#define SEC_RIGHTS_ENUM_SUBKEYS 0x00000008 -#define SEC_RIGHTS_NOTIFY 0x00000010 -#define SEC_RIGHTS_CREATE_LINK 0x00000020 -#define SEC_RIGHTS_READ 0x00020019 -#define SEC_RIGHTS_FULL_CONTROL 0x000f003f -#define SEC_RIGHTS_MAXIMUM_ALLOWED 0x02000000 - /* for ADS */ #define SEC_RIGHTS_LIST_CONTENTS 0x4 #define SEC_RIGHTS_LIST_OBJECT 0x80 @@ -518,5 +508,39 @@ typedef struct standard_mapping { SC_RIGHT_SVC_INTERROGATE | \ SC_RIGHT_SVC_USER_DEFINED_CONTROL ) +/* + * Access Bits for registry ACLS + */ + +/* used by registry ACLs */ + +#define SEC_RIGHTS_QUERY_VALUE 0x00000001 +#define SEC_RIGHTS_SET_VALUE 0x00000002 +#define SEC_RIGHTS_CREATE_SUBKEY 0x00000004 +#define SEC_RIGHTS_ENUM_SUBKEYS 0x00000008 +#define SEC_RIGHTS_NOTIFY 0x00000010 +#define SEC_RIGHTS_CREATE_LINK 0x00000020 +#define SEC_RIGHTS_MAXIMUM_ALLOWED 0x02000000 + + +#define REG_KEY_READ \ + ( STANDARD_RIGHTS_READ_ACCESS |\ + SEC_RIGHTS_QUERY_VALUE |\ + SEC_RIGHTS_ENUM_SUBKEYS |\ + SEC_RIGHTS_NOTIFY ) + +#define REG_KEY_EXECUTE REG_KEY_READ + +#define REG_KEY_WRITE \ + ( STANDARD_RIGHTS_READ_ACCESS |\ + SEC_RIGHTS_SET_VALUE |\ + SEC_RIGHTS_CREATE_SUBKEY ) + +#define REG_KEY_ALL \ + ( STANDARD_RIGHTS_REQUIRED_ACCESS |\ + REG_KEY_READ |\ + REG_KEY_WRITE |\ + SEC_RIGHTS_CREATE_LINK ) + #endif /* _RPC_SECDES_H */ diff --git a/source3/lib/util.c b/source3/lib/util.c index f92ffaedc0..00b08af7c3 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -2213,44 +2213,6 @@ int set_maxfiles(int requested_max) #endif } -/***************************************************************** - Splits out the start of the key (HKLM or HKU) and the rest of the key. -*****************************************************************/ - -BOOL reg_split_key(const char *full_keyname, uint32 *reg_type, char *key_name) -{ - pstring tmp; - - if (!next_token(&full_keyname, tmp, "\\", sizeof(tmp))) - return False; - - (*reg_type) = 0; - - DEBUG(10, ("reg_split_key: hive %s\n", tmp)); - - if (strequal(tmp, "HKLM") || strequal(tmp, "HKEY_LOCAL_MACHINE")) - (*reg_type) = HKEY_LOCAL_MACHINE; - else if (strequal(tmp, "HKCR") || strequal(tmp, "HKEY_CLASSES_ROOT")) - (*reg_type) = HKEY_CLASSES_ROOT; - else if (strequal(tmp, "HKU") || strequal(tmp, "HKEY_USERS")) - (*reg_type) = HKEY_USERS; - else if (strequal(tmp, "HKPD")||strequal(tmp, "HKEY_PERFORMANCE_DATA")) - (*reg_type) = HKEY_PERFORMANCE_DATA; - else { - DEBUG(10,("reg_split_key: unrecognised hive key %s\n", tmp)); - return False; - } - - if (next_token(&full_keyname, tmp, "\n\r", sizeof(tmp))) - fstrcpy(key_name, tmp); - else - key_name[0] = 0; - - DEBUG(10, ("reg_split_key: name %s\n", key_name)); - - return True; -} - /***************************************************************** Possibly replace mkstemp if it is broken. *****************************************************************/ diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 0ddd6bb0c7..ac6dbb4d4a 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -304,6 +304,7 @@ typedef struct BOOL bUseKerberosKeytab; BOOL bDeferSharingViolations; BOOL bEnablePrivileges; + BOOL bASUSupport; int restrict_anonymous; int name_cache_timeout; int client_signing; @@ -950,6 +951,7 @@ static struct parm_struct parm_table[] = { {"server signing", P_ENUM, P_GLOBAL, &Globals.server_signing, NULL, enum_smb_signing_vals, FLAG_ADVANCED}, {"client use spnego", P_BOOL, P_GLOBAL, &Globals.bClientUseSpnego, NULL, NULL, FLAG_ADVANCED}, + {"enable asu support", P_BOOL, P_GLOBAL, &Globals.bASUSupport, NULL, NULL, FLAG_ADVANCED}, {"enable svcctl", P_LIST, P_GLOBAL, &Globals.szServicesList, NULL, NULL, FLAG_ADVANCED}, {N_("Tuning Options"), P_SEP, P_SEPARATOR}, @@ -1593,6 +1595,8 @@ static void init_globals(void) Globals.bEnablePrivileges = False; + Globals.bASUSupport = True; + Globals.szServicesList = str_list_make( "Spooler NETLOGON", NULL ); } @@ -1844,6 +1848,7 @@ FN_GLOBAL_BOOL(lp_kernel_change_notify, &Globals.bKernelChangeNotify) FN_GLOBAL_BOOL(lp_use_kerberos_keytab, &Globals.bUseKerberosKeytab) FN_GLOBAL_BOOL(lp_defer_sharing_violations, &Globals.bDeferSharingViolations) FN_GLOBAL_BOOL(lp_enable_privileges, &Globals.bEnablePrivileges) +FN_GLOBAL_BOOL(lp_enable_asu_support, &Globals.bASUSupport) FN_GLOBAL_INTEGER(lp_os_level, &Globals.os_level) FN_GLOBAL_INTEGER(lp_max_ttl, &Globals.max_ttl) FN_GLOBAL_INTEGER(lp_max_wins_ttl, &Globals.max_wins_ttl) @@ -4007,6 +4012,7 @@ BOOL lp_load(const char *pszFname, BOOL global_only, BOOL save_defaults, /* When 'restrict anonymous = 2' guest connections to ipc$ are denied */ lp_add_ipc("IPC$", (lp_restrict_anonymous() < 2)); + if ( lp_enable_asu_support() ) lp_add_ipc("ADMIN$", False); } diff --git a/source3/registry/reg_cachehook.c b/source3/registry/reg_cachehook.c index dc7136a1d5..4b03a69acf 100644 --- a/source3/registry/reg_cachehook.c +++ b/source3/registry/reg_cachehook.c @@ -1,6 +1,6 @@ /* * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines + * Virtual Windows Registry Layer * Copyright (C) Gerald Carter 2002. * * This program is free software; you can redistribute it and/or modify diff --git a/source3/registry/reg_db.c b/source3/registry/reg_db.c index 46e93cd2b9..19f7e64479 100644 --- a/source3/registry/reg_db.c +++ b/source3/registry/reg_db.c @@ -1,7 +1,7 @@ /* * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines - * Copyright (C) Gerald Carter 2002. + * Virtual Windows Registry Layer + * Copyright (C) Gerald Carter 2002-2005 * * 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 @@ -28,161 +28,96 @@ static TDB_CONTEXT *tdb_reg; +static BOOL regdb_store_reg_keys( char *keyname, REGSUBKEY_CTR *ctr ); +static int regdb_fetch_reg_keys( char* key, REGSUBKEY_CTR *ctr ); + + + +/* List the deepest path into the registry. All part components will be created.*/ + +/* If you want to have a part of the path controlled by the tdb abd part by + a virtual registry db (e.g. printing), then you have to list the deepest path. + For example,"HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Print" + allows the reg_db backend to handle everything up to + "HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion" and then we'll hook + the reg_printing backend onto the last component of the path (see + KEY_PRINTING_2K in include/rpc_reg.h) --jerry */ + +static const char *builtin_registry_paths[] = { + "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print", + "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Ports", + "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Print", + "HKLM\\SYSTEM\\CurrentControlSet\\Control\\ProductOptions", + "HKLM\\SYSTEM\\CurrentControlSet\\Services\\LanmanServer\\Shares", + "HKLM\\SYSTEM\\CurrentControlSet\\Services\\EventLog", + "HKLM\\SYSTEM\\CurrentControlSet\\Services\\TcpIp\\Parameters", + "HKLM\\SYSTEM\\CurrentControlSet\\Services\\Netlogon\\Parameters", + "HKU", + "HKCR", + NULL }; + /*********************************************************************** Open the registry data in the tdb ***********************************************************************/ static BOOL init_registry_data( void ) { - pstring keyname; + pstring path, base, remaining; + fstring keyname, subkeyname; REGSUBKEY_CTR subkeys; - + int i; + const char *p, *p2; + ZERO_STRUCTP( &subkeys ); - - /* HKEY_LOCAL_MACHINE */ - regsubkey_ctr_init( &subkeys ); - pstrcpy( keyname, KEY_HKLM ); - regsubkey_ctr_addkey( &subkeys, "SYSTEM" ); - regsubkey_ctr_addkey( &subkeys, "SOFTWARE" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; - regsubkey_ctr_destroy( &subkeys ); - - - regsubkey_ctr_init( &subkeys ); - pstrcpy( keyname, KEY_HKLM ); - pstrcat( keyname, "/SOFTWARE" ); - regsubkey_ctr_addkey( &subkeys, "Microsoft" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; - regsubkey_ctr_destroy( &subkeys ); - - regsubkey_ctr_init( &subkeys ); - pstrcpy( keyname, KEY_HKLM ); - pstrcat( keyname, "/SOFTWARE/Microsoft" ); - regsubkey_ctr_addkey( &subkeys, "Windows NT" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; - regsubkey_ctr_destroy( &subkeys ); - - regsubkey_ctr_init( &subkeys ); - pstrcpy( keyname, KEY_HKLM ); - pstrcat( keyname, "/SOFTWARE/Microsoft/Windows NT" ); - regsubkey_ctr_addkey( &subkeys, "CurrentVersion" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; - regsubkey_ctr_destroy( &subkeys ); - - pstrcpy( keyname, KEY_HKLM ); - pstrcat( keyname, "/SOFTWARE/Microsoft/Windows NT/CurrentVersion" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; - - - regsubkey_ctr_init( &subkeys ); - pstrcpy( keyname, KEY_HKLM ); - pstrcat( keyname, "/SOFTWARE/Microsoft/Windows NT/CurrentVersion" ); - regsubkey_ctr_addkey( &subkeys, "SystemRoot" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; - regsubkey_ctr_destroy( &subkeys ); - - pstrcpy( keyname, KEY_HKLM ); - pstrcat( keyname, "/SOFTWARE/Microsoft/Windows NT/CurrentVersion/SystemRoot" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; + /* loop over all of the predefined paths and add each component */ + + for ( i=0; builtin_registry_paths[i] != NULL; i++ ) { + DEBUG(6,("init_registry_data: Adding [%s]\n", builtin_registry_paths[i])); - regsubkey_ctr_init( &subkeys ); - pstrcpy( keyname, KEY_HKLM ); - pstrcat( keyname, "/SYSTEM" ); - regsubkey_ctr_addkey( &subkeys, "CurrentControlSet" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; - regsubkey_ctr_destroy( &subkeys ); + pstrcpy( path, builtin_registry_paths[i] ); + pstrcpy( base, "" ); + p = path; - regsubkey_ctr_init( &subkeys ); - pstrcpy( keyname, KEY_HKLM ); - pstrcat( keyname, "/SYSTEM/CurrentControlSet" ); - regsubkey_ctr_addkey( &subkeys, "Control" ); - regsubkey_ctr_addkey( &subkeys, "Services" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; - regsubkey_ctr_destroy( &subkeys ); - - regsubkey_ctr_init( &subkeys ); - pstrcpy( keyname, KEY_HKLM ); - pstrcat( keyname, "/SYSTEM/CurrentControlSet/Control" ); - regsubkey_ctr_addkey( &subkeys, "Print" ); - regsubkey_ctr_addkey( &subkeys, "ProductOptions" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; - regsubkey_ctr_destroy( &subkeys ); - - regsubkey_ctr_init( &subkeys ); - pstrcpy( keyname, KEY_HKLM ); - pstrcat( keyname, "/SYSTEM/CurrentControlSet/Control/ProductOptions" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; - regsubkey_ctr_destroy( &subkeys ); /* added */ - - /* ProductType is a VALUE under ProductOptions */ - - regsubkey_ctr_init( &subkeys ); - pstrcpy( keyname, KEY_HKLM ); - pstrcat( keyname, "/SYSTEM/CurrentControlSet/Services" ); - regsubkey_ctr_addkey( &subkeys, "Netlogon" ); - regsubkey_ctr_addkey( &subkeys, "Tcpip" ); - regsubkey_ctr_addkey( &subkeys, "Eventlog" ); - - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; - regsubkey_ctr_destroy( &subkeys ); + while ( next_token(&p, keyname, "\\", sizeof(keyname)) ) { - regsubkey_ctr_init( &subkeys ); - pstrcpy( keyname, KEY_HKLM ); - pstrcat( keyname, "/SYSTEM/CurrentControlSet/Services/Netlogon" ); - regsubkey_ctr_addkey( &subkeys, "Parameters" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; - regsubkey_ctr_destroy( &subkeys ); - - pstrcpy( keyname, KEY_HKLM ); - pstrcat( keyname, "/SYSTEM/CurrentControlSet/Services/Netlogon/Parameters" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; + /* build up the registry path from the components */ + + if ( *base ) + pstrcat( base, "\\" ); + pstrcat( base, keyname ); + + /* get the immediate subkeyname (if we have one ) */ + + *subkeyname = '\0'; + if ( *p ) { + pstrcpy( remaining, p ); + p2 = remaining; + + if ( !next_token(&p2, subkeyname, "\\", sizeof(subkeyname)) ) + fstrcpy( subkeyname, p2 ); + } - regsubkey_ctr_init( &subkeys ); /*added */ - pstrcpy( keyname, KEY_HKLM ); /*added */ - pstrcat( keyname, "/SYSTEM/CurrentControlSet/Services/Tcpip" ); - regsubkey_ctr_addkey( &subkeys, "Parameters" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; - regsubkey_ctr_destroy( &subkeys ); - - pstrcpy( keyname, KEY_HKLM ); - pstrcat( keyname, "/SYSTEM/CurrentControlSet/Services/Tcpip/Parameters" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; + DEBUG(10,("init_registry_data: Storing key [%s] with subkey [%s]\n", + base, *subkeyname ? subkeyname : "NULL")); + + /* we don't really care if the lookup succeeds or not since + we are about to update the record. We just want any + subkeys already present */ + + regsubkey_ctr_init( &subkeys ); + + regdb_fetch_reg_keys( base, &subkeys ); + if ( *subkeyname ) + regsubkey_ctr_addkey( &subkeys, subkeyname ); + if ( !regdb_store_reg_keys( base, &subkeys )) + return False; + + regsubkey_ctr_destroy( &subkeys ); + } + } - pstrcpy( keyname, KEY_HKLM ); - pstrcat( keyname, "/SYSTEM/CurrentControlSet/Services/Eventlog" ); - if ( !regdb_store_reg_keys( keyname, &subkeys )) - return False; - - /* HKEY_USER */ - - pstrcpy( keyname, KEY_HKU ); - if ( !regdb_store_reg_keys( keyname, &subkeys ) ) - return False; - - /* HKEY_CLASSES_ROOT*/ - - pstrcpy( keyname, KEY_HKCR ); - if ( !regdb_store_reg_keys( keyname, &subkeys ) ) - return False; - return True; } @@ -197,12 +132,9 @@ BOOL init_registry_db( void ) if (tdb_reg && local_pid == sys_getpid()) return True; - /* - * try to open first without creating so we can determine - * if we need to init the data in the registry - */ + /* placeholder tdb; reinit upon startup */ - tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT, O_RDWR, 0600); + tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST, O_RDWR, 0600); if ( !tdb_reg ) { tdb_reg = tdb_open_log(lock_path("registry.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); @@ -213,12 +145,13 @@ BOOL init_registry_db( void ) } DEBUG(10,("init_registry: Successfully created registry tdb\n")); + } - /* create the registry here */ - if ( !init_registry_data() ) { - DEBUG(0,("init_registry: Failed to initiailize data in registry!\n")); - return False; - } + /* create the registry here */ + + if ( !init_registry_data() ) { + DEBUG(0,("init_registry: Failed to initiailize data in registry!\n")); + return False; } local_pid = sys_getpid(); @@ -238,7 +171,7 @@ BOOL init_registry_db( void ) case. ***********************************************************************/ -BOOL regdb_store_reg_keys( char *keyname, REGSUBKEY_CTR *ctr ) +static BOOL regdb_store_reg_keys( char *key, REGSUBKEY_CTR *ctr ) { TDB_DATA kbuf, dbuf; char *buffer, *tmpbuf; @@ -246,10 +179,16 @@ BOOL regdb_store_reg_keys( char *keyname, REGSUBKEY_CTR *ctr ) uint32 len, buflen; BOOL ret = True; uint32 num_subkeys = regsubkey_ctr_numkeys( ctr ); + pstring keyname; - if ( !keyname ) + if ( !key ) return False; + + pstrcpy( keyname, key ); + + /* convert to key format */ + pstring_sub( keyname, "\\", "/" ); strupper_m( keyname ); /* allocate some initial memory */ @@ -303,7 +242,7 @@ done: of null terminated character strings ***********************************************************************/ -int regdb_fetch_reg_keys( char* key, REGSUBKEY_CTR *ctr ) +static int regdb_fetch_reg_keys( char* key, REGSUBKEY_CTR *ctr ) { pstring path; uint32 num_items; @@ -352,7 +291,7 @@ int regdb_fetch_reg_keys( char* key, REGSUBKEY_CTR *ctr ) of null terminated character strings ***********************************************************************/ -int regdb_fetch_reg_values( char* key, REGVAL_CTR *val ) +static int regdb_fetch_reg_values( char* key, REGVAL_CTR *val ) { UNISTR2 data; int num_vals; @@ -394,7 +333,7 @@ int regdb_fetch_reg_values( char* key, REGVAL_CTR *val ) values in the registry.tdb ***********************************************************************/ -BOOL regdb_store_reg_values( char *key, REGVAL_CTR *val ) +static BOOL regdb_store_reg_values( char *key, REGVAL_CTR *val ) { return False; } diff --git a/source3/registry/reg_eventlog.c b/source3/registry/reg_eventlog.c index ccac7a190e..50e4995b9e 100644 --- a/source3/registry/reg_eventlog.c +++ b/source3/registry/reg_eventlog.c @@ -1,6 +1,6 @@ /* * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines + * Virtual Windows Registry Layer * Copyright (C) Marcin Krzysztof Porwit 2005. * * This program is free software; you can redistribute it and/or modify @@ -186,7 +186,7 @@ static char* trim_eventlog_reg_path( char *path ) Enumerate registry subkey names given a registry path. Caller is responsible for freeing memory to **subkeys *********************************************************************/ -int eventlog_subkey_info( char *key, REGSUBKEY_CTR *subkey_ctr ) +static int eventlog_subkey_info( char *key, REGSUBKEY_CTR *subkey_ctr ) { char *path; BOOL top_level = False; @@ -202,10 +202,14 @@ int eventlog_subkey_info( char *key, REGSUBKEY_CTR *subkey_ctr ) if ( !path ) top_level = True; - evtlog_list = lp_eventlog_list(); num_subkeys = 0; + if ( !(evtlog_list = lp_eventlog_list()) ) { + SAFE_FREE(path); + return num_subkeys; + } + - if ( top_level ) + if ( top_level ) { /* todo - get the eventlog subkey values from the smb.conf file for ( num_subkeys=0; num_subkeysnum_subkeys; - /* allocate a space for the char* in the array */ - - if ( ctr->subkeys == 0 ) - ctr->subkeys = TALLOC_P( ctr->ctx, char *); - else { - pp = TALLOC_REALLOC_ARRAY( ctr->ctx, ctr->subkeys, char *, ctr->num_subkeys+1); - if ( pp ) - ctr->subkeys = pp; - } + len = strlen( keyname ); + + /* make sure the keyname is not already there */ + + for ( i=0; inum_subkeys; i++ ) { + if ( strequal( ctr->subkeys[i], keyname ) ) + return ctr->num_subkeys; + } - /* allocate the string and save it in the array */ + /* allocate a space for the char* in the array */ - ctr->subkeys[ctr->num_subkeys] = TALLOC( ctr->ctx, len+1 ); - strncpy( ctr->subkeys[ctr->num_subkeys], keyname, len+1 ); - ctr->num_subkeys++; + if ( ctr->subkeys == 0 ) + ctr->subkeys = TALLOC_P( ctr->ctx, char *); + else { + pp = TALLOC_REALLOC_ARRAY( ctr->ctx, ctr->subkeys, char *, ctr->num_subkeys+1); + if ( pp ) + ctr->subkeys = pp; } + + /* allocate the string and save it in the array */ + + ctr->subkeys[ctr->num_subkeys] = TALLOC( ctr->ctx, len+1 ); + strncpy( ctr->subkeys[ctr->num_subkeys], keyname, len+1 ); + ctr->num_subkeys++; return ctr->num_subkeys; } @@ -239,30 +247,30 @@ int regval_ctr_addvalue( REGVAL_CTR *ctr, const char *name, uint16 type, { REGISTRY_VALUE **ppreg; - if ( name ) - { - /* allocate a slot in the array of pointers */ + if ( !name ) + return ctr->num_values; + + /* allocate a slot in the array of pointers */ - if ( ctr->num_values == 0 ) - ctr->values = TALLOC_P( ctr->ctx, REGISTRY_VALUE *); - else { - ppreg = TALLOC_REALLOC_ARRAY( ctr->ctx, ctr->values, REGISTRY_VALUE *, ctr->num_values+1 ); - if ( ppreg ) - ctr->values = ppreg; - } + if ( ctr->num_values == 0 ) + ctr->values = TALLOC_P( ctr->ctx, REGISTRY_VALUE *); + else { + ppreg = TALLOC_REALLOC_ARRAY( ctr->ctx, ctr->values, REGISTRY_VALUE *, ctr->num_values+1 ); + if ( ppreg ) + ctr->values = ppreg; + } - /* allocate a new value and store the pointer in the arrya */ + /* allocate a new value and store the pointer in the arrya */ - ctr->values[ctr->num_values] = TALLOC_P( ctr->ctx, REGISTRY_VALUE); + ctr->values[ctr->num_values] = TALLOC_P( ctr->ctx, REGISTRY_VALUE); - /* init the value */ + /* init the value */ - fstrcpy( ctr->values[ctr->num_values]->valuename, name ); - ctr->values[ctr->num_values]->type = type; - ctr->values[ctr->num_values]->data_p = TALLOC_MEMDUP( ctr->ctx, data_p, size ); - ctr->values[ctr->num_values]->size = size; - ctr->num_values++; - } + fstrcpy( ctr->values[ctr->num_values]->valuename, name ); + ctr->values[ctr->num_values]->type = type; + ctr->values[ctr->num_values]->data_p = TALLOC_MEMDUP( ctr->ctx, data_p, size ); + ctr->values[ctr->num_values]->size = size; + ctr->num_values++; return ctr->num_values; } diff --git a/source3/registry/reg_printing.c b/source3/registry/reg_printing.c index ee4d1dcb64..a7a89fdc34 100644 --- a/source3/registry/reg_printing.c +++ b/source3/registry/reg_printing.c @@ -1,7 +1,7 @@ /* * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines - * Copyright (C) Gerald Carter 2002. + * Virtual Windows Registry Layer + * Copyright (C) Gerald Carter 2002-2005 * * 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 @@ -38,7 +38,7 @@ static const char *top_level_keys[MAX_TOP_LEVEL_KEYS] = { "Forms", "Printers" }; - + /********************************************************************** It is safe to assume that every registry path passed into on of @@ -52,7 +52,14 @@ static const char *top_level_keys[MAX_TOP_LEVEL_KEYS] = { static char* trim_reg_path( char *path ) { char *p; - uint16 key_len = strlen(KEY_PRINTING); + uint16 key_len = strlen(path); + uint16 base_key_len; + + static int key_printing_len = strlen( KEY_PRINTING ); + static int key_printing2k_len = strlen( KEY_PRINTING_2K ); + static int key_printing_ports_len = strlen( KEY_PRINTING_PORTS ); + + /* * sanity check...this really should never be True. @@ -60,14 +67,30 @@ static char* trim_reg_path( char *path ) * the path buffer in the extreme case. */ - if ( strlen(path) < key_len ) { + if ( (key_len < key_printing_len) + && (key_len < key_printing2k_len) + && (key_len < key_printing_ports_len) ) + { DEBUG(0,("trim_reg_path: Registry path too short! [%s]\n", path)); - DEBUG(0,("trim_reg_path: KEY_PRINTING => [%s]!\n", KEY_PRINTING)); + return NULL; + } + + base_key_len = 0; + if ( StrnCaseCmp( KEY_PRINTING, path, key_printing_len ) == 0 ) { + base_key_len = key_printing_len; + } + else if ( StrnCaseCmp( KEY_PRINTING_2K, path, key_printing2k_len ) == 0 ) { + base_key_len = key_printing2k_len; + } + else if ( StrnCaseCmp( KEY_PRINTING_PORTS, path, key_printing2k_len ) == 0 ) { + base_key_len = key_printing_ports_len; + } + else { + DEBUG(0,("trim_reg_path: invalid path [%s]\n", path )); return NULL; } - - p = path + strlen( KEY_PRINTING ); + p = path + base_key_len; if ( *p == '\\' ) p++; @@ -78,10 +101,38 @@ static char* trim_reg_path( char *path ) return NULL; } +/********************************************************************** + *********************************************************************/ + +static int fill_ports_values( REGVAL_CTR *values ) +{ + int numlines, i; + char **lines; + UNISTR2 data; + WERROR result; + + result = enumports_hook( &numlines, &lines ); + + if ( !W_ERROR_IS_OK(result) ) + return -1; + + init_unistr2( &data, "", UNI_STR_TERMINATE); + for ( i=0; i[%s]\n", key ? key : "NULL" )); - /* listed architectures of installed drivers */ + /* list all possible architectures */ - if ( !key ) - { - /* Windows 9x drivers */ - - if ( get_ntdrivers( &drivers, environments[0], 0 ) ) - regsubkey_ctr_addkey( subkeys, environments[0] ); - SAFE_FREE( drivers ); - - /* Windows NT/2k intel drivers */ - - if ( get_ntdrivers( &drivers, environments[1], 2 ) - || get_ntdrivers( &drivers, environments[1], 3 ) ) - { - regsubkey_ctr_addkey( subkeys, environments[1] ); - } - SAFE_FREE( drivers ); - - /* Windows NT 4.0; non-intel drivers */ - for ( i=2; environments[i]; i++ ) { - if ( get_ntdrivers( &drivers, environments[i], 2 ) ) - regsubkey_ctr_addkey( subkeys, environments[i] ); - - } - SAFE_FREE( drivers ); + if ( !key ) { + for ( num_subkeys=0; environments[num_subkeys]; num_subkeys++ ) + regsubkey_ctr_addkey( subkeys, environments[num_subkeys] ); - num_subkeys = regsubkey_ctr_numkeys( subkeys ); - goto done; + return num_subkeys; } /* we are dealing with a subkey of "Environments */ - key2 = SMB_STRDUP( key ); + pstrcpy( key2, key ); keystr = key2; - reg_split_path( keystr, &base, &new_path ); + reg_split_path( keystr, &base, &subkeypath ); /* sanity check */ for ( env_index=0; environments[env_index]; env_index++ ) { - if ( StrCaseCmp( environments[env_index], base ) == 0 ) { - valid_env = True; + if ( strequal( environments[env_index], base ) ) break; - } } + if ( !environments[env_index] ) + return -1; + + /* ...\Print\Environements\...\ */ + + if ( !subkeypath ) { + regsubkey_ctr_addkey( subkeys, "Drivers" ); + regsubkey_ctr_addkey( subkeys, "Print Processors" ); + + return 2; + } + + /* more of the key path to process */ + + keystr = subkeypath; + reg_split_path( keystr, &base, &subkeypath ); - if ( !valid_env ) + /* ...\Print\Environements\...\Drivers\ */ + + if ( strequal(base, "Drivers") ) + env_subkey_type = ENVIRONMENT_DRIVERS; + else if ( strequal(base, "Print Processors") ) + env_subkey_type = ENVIRONMENT_PRINTPROC; + else + /* invalid path */ return -1; - - /* enumerate driver versions; environment is environments[env_index] */ - if ( !new_path ) { - switch ( env_index ) { - case 0: /* Win9x */ - if ( get_ntdrivers( &drivers, environments[0], 0 ) ) { - regsubkey_ctr_addkey( subkeys, "0" ); - SAFE_FREE( drivers ); - } - break; - case 1: /* Windows NT/2k - intel */ - if ( get_ntdrivers( &drivers, environments[1], 2 ) ) { - regsubkey_ctr_addkey( subkeys, "2" ); - SAFE_FREE( drivers ); - } - if ( get_ntdrivers( &drivers, environments[1], 3 ) ) { - regsubkey_ctr_addkey( subkeys, "3" ); - SAFE_FREE( drivers ); - } - break; - default: /* Windows NT - nonintel */ - if ( get_ntdrivers( &drivers, environments[env_index], 2 ) ) { - regsubkey_ctr_addkey( subkeys, "2" ); - SAFE_FREE( drivers ); - } - - } + if ( !subkeypath ) { + switch ( env_subkey_type ) { + case ENVIRONMENT_DRIVERS: + switch ( env_index ) { + case 0: /* Win9x */ + regsubkey_ctr_addkey( subkeys, "Version-0" ); + break; + default: /* Windows NT based systems */ + regsubkey_ctr_addkey( subkeys, "Version-2" ); + regsubkey_ctr_addkey( subkeys, "Version-3" ); + break; + } - num_subkeys = regsubkey_ctr_numkeys( subkeys ); - goto done; + return regsubkey_ctr_numkeys( subkeys ); + + case ENVIRONMENT_PRINTPROC: + if ( env_index == 1 || env_index == 5 || env_index == 6 ) + regsubkey_ctr_addkey( subkeys, "winprint" ); + + return regsubkey_ctr_numkeys( subkeys ); + } } /* we finally get to enumerate the drivers */ - keystr = new_path; - reg_split_path( keystr, &base, &new_path ); + keystr = subkeypath; + reg_split_path( keystr, &base, &subkeypath ); + + /* get thr print processors key out of the way */ + if ( env_subkey_type == ENVIRONMENT_PRINTPROC ) { + if ( !strequal( base, "winprint" ) ) + return -1; + return !subkeypath ? 0 : -1; + } - if ( !new_path ) { - num_drivers = get_ntdrivers( &drivers, environments[env_index], atoi(base) ); + /* only dealing with drivers from here on out */ + + version = atoi(&base[strlen(base)-1]); + + switch (env_index) { + case 0: + if ( version != 0 ) + return -1; + break; + default: + if ( version != 2 && version != 3 ) + return -1; + break; + } + + + if ( !subkeypath ) { + num_drivers = get_ntdrivers( &drivers, environments[env_index], version ); for ( i=0; i [%s]\n", key ? key : "NULL")); if ( !key ) return 0; - /* - * The only key below KEY_PRINTING\Environments that - * posseses values is each specific printer driver - * First get the arch, version, & driver name - */ + /* The only keys below KEY_PRINTING\Environments is the + specific printer driver info */ - /* env */ + /* environment */ - key2 = SMB_STRDUP( key ); + pstrcpy( key2, key ); keystr = key2; - reg_split_path( keystr, &base, &new_path ); - if ( !base || !new_path ) + reg_split_path( keystr, &base, &subkeypath ); + if ( !subkeypath ) return 0; - fstrcpy( env, base ); + fstrcpy( arch_environment, base ); - /* version */ + /* Driver */ - keystr = new_path; - reg_split_path( keystr, &base, &new_path ); - if ( !base || !new_path ) + keystr = subkeypath; + reg_split_path( keystr, &base, &subkeypath ); + + if ( strequal(base, "Drivers") ) + env_subkey_type = ENVIRONMENT_DRIVERS; + else if ( strequal(base, "Print Processors") ) + env_subkey_type = ENVIRONMENT_PRINTPROC; + else + /* invalid path */ + return -1; + + if ( !subkeypath ) return 0; - version = atoi( base ); + + /* for now bail out if we are seeing anything other than the drivers key */ + + if ( env_subkey_type == ENVIRONMENT_PRINTPROC ) + return 0; + + keystr = subkeypath; + reg_split_path( keystr, &base, &subkeypath ); + + version = atoi(&base[strlen(base)-1]); /* printer driver name */ - keystr = new_path; - reg_split_path( keystr, &base, &new_path ); - /* new_path should be NULL here since this must be the last key */ - if ( !base || new_path ) + keystr = subkeypath; + reg_split_path( keystr, &base, &subkeypath ); + /* don't go any deeper for now */ + if ( subkeypath ) return 0; fstrcpy( driver, base ); - w_result = get_a_printer_driver( &driver_ctr, 3, driver, env, version ); + w_result = get_a_printer_driver( &driver_ctr, 3, driver, arch_environment, version ); if ( !W_ERROR_IS_OK(w_result) ) return -1; @@ -350,7 +431,6 @@ static int print_subpath_values_environments( char *key, REGVAL_CTR *val ) free_a_printer_driver( driver_ctr, 3 ); - SAFE_FREE( key2 ); SAFE_FREE( buffer ); DEBUG(8,("print_subpath_values_environments: Exit\n")); @@ -480,6 +560,11 @@ static int print_subpath_printers( char *key, REGSUBKEY_CTR *subkeys ) for (snum=0; snumstatus, sizeof(info2->status) ); regval_ctr_addvalue( val, "StartTime", REG_DWORD, (char*)&info2->starttime, sizeof(info2->starttime) ); regval_ctr_addvalue( val, "UntilTime", REG_DWORD, (char*)&info2->untiltime, sizeof(info2->untiltime) ); - regval_ctr_addvalue( val, "cjobs", REG_DWORD, (char*)&info2->cjobs, sizeof(info2->cjobs) ); - regval_ctr_addvalue( val, "AveragePPM", REG_DWORD, (char*)&info2->averageppm, sizeof(info2->averageppm) ); - init_unistr2( &data, info2->printername, UNI_STR_TERMINATE); - regval_ctr_addvalue( val, "Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + /* strip the \\server\ from this string */ + if ( !(p = strrchr( info2->printername, '\\' ) ) ) + p = info2->printername; + else + p++; + init_unistr2( &data, p, UNI_STR_TERMINATE); + regval_ctr_addvalue( val, "Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + init_unistr2( &data, info2->location, UNI_STR_TERMINATE); - regval_ctr_addvalue( val, "Location", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + regval_ctr_addvalue( val, "Location", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + init_unistr2( &data, info2->comment, UNI_STR_TERMINATE); - regval_ctr_addvalue( val, "Comment", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + regval_ctr_addvalue( val, "Description", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + init_unistr2( &data, info2->parameters, UNI_STR_TERMINATE); - regval_ctr_addvalue( val, "Parameters", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + regval_ctr_addvalue( val, "Parameters", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + init_unistr2( &data, info2->portname, UNI_STR_TERMINATE); - regval_ctr_addvalue( val, "Port", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); - init_unistr2( &data, info2->servername, UNI_STR_TERMINATE); - regval_ctr_addvalue( val, "Server", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + regval_ctr_addvalue( val, "Port", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + init_unistr2( &data, info2->sharename, UNI_STR_TERMINATE); - regval_ctr_addvalue( val, "Share", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + regval_ctr_addvalue( val, "Share Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + init_unistr2( &data, info2->drivername, UNI_STR_TERMINATE); - regval_ctr_addvalue( val, "Driver", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + regval_ctr_addvalue( val, "Printer Driver", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + init_unistr2( &data, info2->sepfile, UNI_STR_TERMINATE); - regval_ctr_addvalue( val, "Separator File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); - init_unistr2( &data, "winprint", UNI_STR_TERMINATE); + regval_ctr_addvalue( val, "Separator File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + + init_unistr2( &data, "WinPrint", UNI_STR_TERMINATE); regval_ctr_addvalue( val, "Print Processor", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); - + + init_unistr2( &data, "RAW", UNI_STR_TERMINATE); + regval_ctr_addvalue( val, "Datatype", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); + /* use a prs_struct for converting the devmode and security - descriptor to REG_BIARY */ + descriptor to REG_BINARY */ prs_init( &prs, MAX_PDU_FRAG_LEN, regval_ctr_getctx(val), MARSHALL); @@ -735,7 +833,7 @@ static int handle_printing_subpath( char *key, REGSUBKEY_CTR *subkeys, REGVAL_CT Caller is responsible for freeing memory to **subkeys *********************************************************************/ -int printing_subkey_info( char *key, REGSUBKEY_CTR *subkey_ctr ) +static int printing_subkey_info( char *key, REGSUBKEY_CTR *subkey_ctr ) { char *path; BOOL top_level = False; @@ -751,8 +849,15 @@ int printing_subkey_info( char *key, REGSUBKEY_CTR *subkey_ctr ) top_level = True; if ( top_level ) { - for ( num_subkeys=0; num_subkeys[%s]\n", key)); + + path = trim_reg_path( key ); + + /* check to see if we are dealing with the top level key */ + + if ( !path ) + top_level = True; + + if ( top_level ) { + num_subkeys = 1; + regsubkey_ctr_addkey( subkey_ctr, "Security" ); + } +#if 0 + else + num_subkeys = handle_share_subpath( path, subkey_ctr, NULL ); +#endif + + SAFE_FREE( path ); + + return num_subkeys; +} + +/********************************************************************** + Enumerate registry values given a registry path. + Caller is responsible for freeing memory + *********************************************************************/ + +static int shares_value_info( char *key, REGVAL_CTR *val ) +{ + char *path; + BOOL top_level = False; + int num_values = 0; + + DEBUG(10,("printing_value_info: key=>[%s]\n", key)); + + path = trim_reg_path( key ); + + /* check to see if we are dealing with the top level key */ + + if ( !path ) + top_level = True; + + /* fill in values from the getprinterdata_printer_server() */ + if ( top_level ) + num_values = 0; +#if 0 + else + num_values = handle_printing_subpath( path, NULL, val ); +#endif + + + return num_values; +} + +/********************************************************************** + Stub function which always returns failure since we don't want + people storing printing information directly via regostry calls + (for now at least) + *********************************************************************/ + +static BOOL shares_store_subkey( char *key, REGSUBKEY_CTR *subkeys ) +{ + return False; +} + +/********************************************************************** + Stub function which always returns failure since we don't want + people storing printing information directly via regostry calls + (for now at least) + *********************************************************************/ + +static BOOL shares_store_value( char *key, REGVAL_CTR *val ) +{ + return False; +} + +/* + * Table of function pointers for accessing printing data + */ + +REGISTRY_OPS shares_reg_ops = { + shares_subkey_info, + shares_value_info, + shares_store_subkey, + shares_store_value +}; + + diff --git a/source3/registry/reg_util.c b/source3/registry/reg_util.c new file mode 100644 index 0000000000..9120ce0e0a --- /dev/null +++ b/source3/registry/reg_util.c @@ -0,0 +1,88 @@ +/* + * Unix SMB/CIFS implementation. + * Virtual Windows Registry Layer (utility functions) + * Copyright (C) Gerald Carter 2002-2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Implementation of registry frontend view functions. */ + +#include "includes.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +/*********************************************************************** + Utility function for splitting the base path of a registry path off + by setting base and new_path to the apprapriate offsets withing the + path. + + WARNING!! Does modify the original string! + ***********************************************************************/ + +BOOL reg_split_path( char *path, char **base, char **new_path ) +{ + char *p; + + *new_path = *base = NULL; + + if ( !path) + return False; + + *base = path; + + p = strchr( path, '\\' ); + + if ( p ) { + *p = '\0'; + *new_path = p+1; + } + + return True; +} + + +/*********************************************************************** + Utility function for splitting the base path of a registry path off + by setting base and new_path to the appropriate offsets withing the + path. + + WARNING!! Does modify the original string! + ***********************************************************************/ + +BOOL reg_split_key( char *path, char **base, char **key ) +{ + char *p; + + *key = *base = NULL; + + if ( !path) + return False; + + *base = path; + + p = strrchr( path, '\\' ); + + if ( p ) { + *p = '\0'; + *key = p+1; + } + + return True; +} + + + diff --git a/source3/registry/regfio.c b/source3/registry/regfio.c new file mode 100644 index 0000000000..ab6be77f18 --- /dev/null +++ b/source3/registry/regfio.c @@ -0,0 +1,1871 @@ +/* + * Unix SMB/CIFS implementation. + * Windows NT registry I/O library + * Copyright (c) Gerald (Jerry) Carter 2005 + * + * 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 "regfio.h" + +/******************************************************************* + * + * TODO : Right now this code basically ignores classnames. + * + ******************************************************************/ + + +/******************************************************************* +*******************************************************************/ + +static int write_block( REGF_FILE *file, prs_struct *ps, uint32 offset ) +{ + int bytes_written, returned; + char *buffer = prs_data_p( ps ); + uint32 buffer_size = prs_data_size( ps ); + SMB_STRUCT_STAT sbuf; + + if ( file->fd == -1 ) + return -1; + + /* check for end of file */ + + if ( sys_fstat( file->fd, &sbuf ) ) { + DEBUG(0,("write_block: stat() failed! (%s)\n", strerror(errno))); + return -1; + } + + if ( lseek( file->fd, offset, SEEK_SET ) == -1 ) { + DEBUG(0,("write_block: lseek() failed! (%s)\n", strerror(errno) )); + return -1; + } + + bytes_written = returned = 0; + while ( bytes_written < buffer_size ) { + if ( (returned = write( file->fd, buffer+bytes_written, buffer_size-bytes_written )) == -1 ) { + DEBUG(0,("write_block: write() failed! (%s)\n", strerror(errno) )); + return False; + } + + bytes_written += returned; + } + + return bytes_written; +} + +/******************************************************************* +*******************************************************************/ + +static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset, uint32 block_size ) +{ + int bytes_read, returned; + char *buffer; + SMB_STRUCT_STAT sbuf; + + /* check for end of file */ + + if ( sys_fstat( file->fd, &sbuf ) ) { + DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno))); + return -1; + } + + if ( (size_t)file_offset >= sbuf.st_size ) + return -1; + + /* if block_size == 0, we are parsnig HBIN records and need + to read some of the header to get the block_size from there */ + + if ( block_size == 0 ) { + uint8 hdr[0x20]; + + if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) { + DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) )); + return -1; + } + + returned = read( file->fd, hdr, 0x20 ); + if ( (returned == -1) || (returned < 0x20) ) { + DEBUG(0,("read_block: failed to read in HBIN header. Is the file corrupt?\n")); + return -1; + } + + /* make sure this is an hbin header */ + + if ( strncmp( hdr, "hbin", HBIN_HDR_SIZE ) != 0 ) { + DEBUG(0,("read_block: invalid block header!\n")); + return -1; + } + + block_size = IVAL( hdr, 0x08 ); + } + + DEBUG(10,("read_block: block_size == 0x%x\n", block_size )); + + /* set the offset, initialize the buffer, and read the block from disk */ + + if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) { + DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) )); + return -1; + } + + prs_init( ps, block_size, file->mem_ctx, UNMARSHALL ); + buffer = prs_data_p( ps ); + bytes_read = returned = 0; + + while ( bytes_read < block_size ) { + if ( (returned = read( file->fd, buffer+bytes_read, block_size-bytes_read )) == -1 ) { + DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) )); + return False; + } + if ( (returned == 0) && (bytes_read < block_size) ) { + DEBUG(0,("read_block: not a vald registry file ?\n" )); + return False; + } + + bytes_read += returned; + } + + return bytes_read; +} + +/******************************************************************* +*******************************************************************/ + +static BOOL write_hbin_block( REGF_FILE *file, REGF_HBIN *hbin ) +{ + if ( !hbin->dirty ) + return True; + + /* write free space record if any is available */ + + if ( hbin->free_off != REGF_OFFSET_NONE ) { + uint32 header = 0xffffffff; + + if ( !prs_set_offset( &hbin->ps, hbin->free_off-sizeof(uint32) ) ) + return False; + if ( !prs_uint32( "free_size", &hbin->ps, 0, &hbin->free_size ) ) + return False; + if ( !prs_uint32( "free_header", &hbin->ps, 0, &header ) ) + return False; + } + + hbin->dirty = (write_block( file, &hbin->ps, hbin->file_off ) != -1); + + return hbin->dirty; +} + +/******************************************************************* +*******************************************************************/ + +static BOOL hbin_block_close( REGF_FILE *file, REGF_HBIN *hbin ) +{ + REGF_HBIN *p; + + /* remove the block from the open list and flush it to disk */ + + for ( p=file->block_list; p && p!=hbin; p=p->next ) + ;; + + if ( p == hbin ) { + DLIST_REMOVE( file->block_list, hbin ); + } + else + DEBUG(0,("hbin_block_close: block not in open list!\n")); + + if ( !write_hbin_block( file, hbin ) ) + return False; + + return True; +} + +/******************************************************************* +*******************************************************************/ + +static BOOL prs_regf_block( const char *desc, prs_struct *ps, int depth, REGF_FILE *file ) +{ + prs_debug(ps, depth, desc, "prs_regf_block"); + depth++; + + if ( !prs_uint8s( True, "header", ps, depth, file->header, sizeof( file->header )) ) + return False; + + /* yes, these values are always identical so store them only once */ + + if ( !prs_uint32( "unknown1", ps, depth, &file->unknown1 )) + return False; + if ( !prs_uint32( "unknown1 (again)", ps, depth, &file->unknown1 )) + return False; + + /* get the modtime */ + + if ( !prs_set_offset( ps, 0x0c ) ) + return False; + if ( !smb_io_time( "modtime", &file->mtime, ps, depth ) ) + return False; + + /* constants */ + + if ( !prs_uint32( "unknown2", ps, depth, &file->unknown2 )) + return False; + if ( !prs_uint32( "unknown3", ps, depth, &file->unknown3 )) + return False; + if ( !prs_uint32( "unknown4", ps, depth, &file->unknown4 )) + return False; + if ( !prs_uint32( "unknown5", ps, depth, &file->unknown5 )) + return False; + + /* get file offsets */ + + if ( !prs_set_offset( ps, 0x24 ) ) + return False; + if ( !prs_uint32( "data_offset", ps, depth, &file->data_offset )) + return False; + if ( !prs_uint32( "last_block", ps, depth, &file->last_block )) + return False; + + /* one more constant */ + + if ( !prs_uint32( "unknown6", ps, depth, &file->unknown6 )) + return False; + + /* get the checksum */ + + if ( !prs_set_offset( ps, 0x01fc ) ) + return False; + if ( !prs_uint32( "checksum", ps, depth, &file->checksum )) + return False; + + return True; +} + +/******************************************************************* +*******************************************************************/ + +static BOOL prs_hbin_block( const char *desc, prs_struct *ps, int depth, REGF_HBIN *hbin ) +{ + uint32 block_size2; + + prs_debug(ps, depth, desc, "prs_regf_block"); + depth++; + + if ( !prs_uint8s( True, "header", ps, depth, hbin->header, sizeof( hbin->header )) ) + return False; + + if ( !prs_uint32( "first_hbin_off", ps, depth, &hbin->first_hbin_off )) + return False; + + /* The dosreg.cpp comments say that the block size is at 0x1c. + According to a WINXP NTUSER.dat file, this is wrong. The block_size + is at 0x08 */ + + if ( !prs_uint32( "block_size", ps, depth, &hbin->block_size )) + return False; + + block_size2 = hbin->block_size; + prs_set_offset( ps, 0x1c ); + if ( !prs_uint32( "block_size2", ps, depth, &block_size2 )) + return False; + + if ( MARSHALLING(ps) ) + hbin->dirty = True; + + + return True; +} + +/******************************************************************* +*******************************************************************/ + +static BOOL prs_nk_rec( const char *desc, prs_struct *ps, int depth, REGF_NK_REC *nk ) +{ + uint16 class_length, name_length; + uint32 start; + uint32 data_size, start_off, end_off; + uint32 unknown_off = REGF_OFFSET_NONE; + + nk->hbin_off = prs_offset( ps ); + start = nk->hbin_off; + + prs_debug(ps, depth, desc, "prs_nk_rec"); + depth++; + + /* back up and get the data_size */ + + if ( !prs_set_offset( ps, prs_offset(ps)-sizeof(uint32)) ) + return False; + start_off = prs_offset( ps ); + if ( !prs_uint32( "rec_size", ps, depth, &nk->rec_size )) + return False; + + if ( !prs_uint8s( True, "header", ps, depth, nk->header, sizeof( nk->header )) ) + return False; + + if ( !prs_uint16( "key_type", ps, depth, &nk->key_type )) + return False; + if ( !smb_io_time( "mtime", &nk->mtime, ps, depth )) + return False; + + if ( !prs_set_offset( ps, start+0x0010 ) ) + return False; + if ( !prs_uint32( "parent_off", ps, depth, &nk->parent_off )) + return False; + if ( !prs_uint32( "num_subkeys", ps, depth, &nk->num_subkeys )) + return False; + + if ( !prs_set_offset( ps, start+0x001c ) ) + return False; + if ( !prs_uint32( "subkeys_off", ps, depth, &nk->subkeys_off )) + return False; + if ( !prs_uint32( "unknown_off", ps, depth, &unknown_off) ) + return False; + + if ( !prs_set_offset( ps, start+0x0024 ) ) + return False; + if ( !prs_uint32( "num_values", ps, depth, &nk->num_values )) + return False; + if ( !prs_uint32( "values_off", ps, depth, &nk->values_off )) + return False; + if ( !prs_uint32( "sk_off", ps, depth, &nk->sk_off )) + return False; + if ( !prs_uint32( "classname_off", ps, depth, &nk->classname_off )) + return False; + + if ( !prs_uint32( "max_bytes_subkeyname", ps, depth, &nk->max_bytes_subkeyname)) + return False; + if ( !prs_uint32( "max_bytes_subkeyclassname", ps, depth, &nk->max_bytes_subkeyclassname)) + return False; + if ( !prs_uint32( "max_bytes_valuename", ps, depth, &nk->max_bytes_valuename)) + return False; + if ( !prs_uint32( "max_bytes_value", ps, depth, &nk->max_bytes_value)) + return False; + if ( !prs_uint32( "unknown index", ps, depth, &nk->unk_index)) + return False; + + name_length = nk->keyname ? strlen(nk->keyname) : 0 ; + class_length = nk->classname ? strlen(nk->classname) : 0 ; + if ( !prs_uint16( "name_length", ps, depth, &name_length )) + return False; + if ( !prs_uint16( "class_length", ps, depth, &class_length )) + return False; + + if ( class_length ) { + ;; + } + + if ( name_length ) { + if ( UNMARSHALLING(ps) ) { + if ( !(nk->keyname = PRS_ALLOC_MEM( ps, char, name_length+1 )) ) + return False; + } + + if ( !prs_uint8s( True, "name", ps, depth, nk->keyname, name_length) ) + return False; + + if ( UNMARSHALLING(ps) ) + nk->keyname[name_length] = '\0'; + } + + end_off = prs_offset( ps ); + + /* data_size must be divisible by 8 and large enough to hold the original record */ + + data_size = ((start_off - end_off) & 0xfffffff8 ); + if ( data_size > nk->rec_size ) + DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, nk->rec_size)); + + if ( MARSHALLING(ps) ) + nk->hbin->dirty = True; + + return True; +} + +/******************************************************************* +*******************************************************************/ + +static uint32 regf_block_checksum( prs_struct *ps ) +{ + char *buffer = prs_data_p( ps ); + uint32 checksum, x; + int i; + + /* XOR of all bytes 0x0000 - 0x01FB */ + + checksum = x = 0; + + for ( i=0; i<0x01FB; i+=4 ) { + x = IVAL(buffer, i ); + checksum ^= x; + } + + return checksum; +} + +/******************************************************************* +*******************************************************************/ + +static BOOL read_regf_block( REGF_FILE *file ) +{ + prs_struct ps; + uint32 checksum; + + /* grab the first block from the file */ + + if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 ) + return False; + + /* parse the block and verify the checksum */ + + if ( !prs_regf_block( "regf_header", &ps, 0, file ) ) + return False; + + checksum = regf_block_checksum( &ps ); + + prs_mem_free( &ps ); + + if ( file->checksum != checksum ) { + DEBUG(0,("read_regf_block: invalid checksum\n" )); + return False; + } + + return True; +} + +/******************************************************************* +*******************************************************************/ + +static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset ) +{ + REGF_HBIN *hbin; + uint32 record_size, curr_off, block_size, header; + + if ( !(hbin = TALLOC_ZERO_P(file->mem_ctx, REGF_HBIN)) ) + return NULL; + hbin->file_off = offset; + hbin->free_off = -1; + + if ( read_block( file, &hbin->ps, offset, 0 ) == -1 ) + return NULL; + + if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) ) + return NULL; + + /* this should be the same thing as hbin->block_size but just in case */ + + block_size = prs_data_size( &hbin->ps ); + + /* Find the available free space offset. Always at the end, + so walk the record list and stop when you get to the end. + The end is defined by a record header of 0xffffffff. The + previous 4 bytes contains the amount of free space remaining + in the hbin block. */ + + /* remember that the record_size is in the 4 bytes preceeding the record itself */ + + if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE-sizeof(uint32) ) ) + return False; + + record_size = 0; + curr_off = prs_offset( &hbin->ps ); + while ( header != 0xffffffff ) { + /* not done yet so reset the current offset to the + next record_size field */ + + curr_off = curr_off+record_size; + + /* for some reason the record_size of the last record in + an hbin block can extend past the end of the block + even though the record fits within the remaining + space....aaarrrgggghhhhhh */ + + if ( curr_off >= block_size ) { + record_size = -1; + curr_off = -1; + break; + } + + if ( !prs_set_offset( &hbin->ps, curr_off) ) + return False; + + if ( !prs_uint32( "rec_size", &hbin->ps, 0, &record_size ) ) + return False; + if ( !prs_uint32( "header", &hbin->ps, 0, &header ) ) + return False; + + SMB_ASSERT( record_size != 0 ); + + if ( record_size & 0x80000000 ) { + /* absolute_value(record_size) */ + record_size = (record_size ^ 0xffffffff) + 1; + } + } + + /* save the free space offset */ + + if ( header == 0xffffffff ) { + + /* account for the fact that the curr_off is 4 bytes behind the actual + record header */ + + hbin->free_off = curr_off + sizeof(uint32); + hbin->free_size = record_size; + } + + DEBUG(10,("read_hbin_block: free space offset == 0x%x\n", hbin->free_off)); + + if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE ) ) + return False; + + return hbin; +} + +/******************************************************************* + Input a randon offset and receive the correpsonding HBIN + block for it +*******************************************************************/ + +static BOOL hbin_contains_offset( REGF_HBIN *hbin, uint32 offset ) +{ + if ( !hbin ) + return False; + + if ( (offset > hbin->first_hbin_off) && (offset < (hbin->first_hbin_off+hbin->block_size)) ) + return True; + + return False; +} + +/******************************************************************* + Input a randon offset and receive the correpsonding HBIN + block for it +*******************************************************************/ + +static REGF_HBIN* lookup_hbin_block( REGF_FILE *file, uint32 offset ) +{ + REGF_HBIN *hbin = NULL; + uint32 block_off; + + /* start with the open list */ + + for ( hbin=file->block_list; hbin; hbin=hbin->next ) { + DEBUG(10,("lookup_hbin_block: address = 0x%x [0x%x]\n", hbin->file_off, (uint32)hbin )); + if ( hbin_contains_offset( hbin, offset ) ) + return hbin; + } + + if ( !hbin ) { + /* start at the beginning */ + + block_off = REGF_BLOCKSIZE; + do { + /* cleanup before the next round */ + if ( hbin ) + prs_mem_free( &hbin->ps ); + + hbin = read_hbin_block( file, block_off ); + + if ( hbin ) + block_off = hbin->file_off + hbin->block_size; + + } while ( hbin && !hbin_contains_offset( hbin, offset ) ); + } + + if ( hbin ) + DLIST_ADD( file->block_list, hbin ); + + return hbin; +} + +/******************************************************************* +*******************************************************************/ + +static BOOL prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash ) +{ + prs_debug(ps, depth, desc, "prs_hash_rec"); + depth++; + + if ( !prs_uint32( "nk_off", ps, depth, &hash->nk_off )) + return False; + if ( !prs_uint8s( True, "keycheck", ps, depth, hash->keycheck, sizeof( hash->keycheck )) ) + return False; + + return True; +} + +/******************************************************************* +*******************************************************************/ + +static BOOL hbin_prs_lf_records( const char *desc, REGF_HBIN *hbin, int depth, REGF_NK_REC *nk ) +{ + int i; + REGF_LF_REC *lf = &nk->subkeys; + uint32 data_size, start_off, end_off; + + prs_debug(&hbin->ps, depth, desc, "prs_lf_records"); + depth++; + + /* check if we have anything to do first */ + + if ( nk->num_subkeys == 0 ) + return True; + + /* move to the LF record */ + + if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) ) + return False; + + /* backup and get the data_size */ + + if ( !prs_set_offset( &hbin->ps, prs_offset(&hbin->ps)-sizeof(uint32)) ) + return False; + start_off = prs_offset( &hbin->ps ); + if ( !prs_uint32( "rec_size", &hbin->ps, depth, &lf->rec_size )) + return False; + + if ( !prs_uint8s( True, "header", &hbin->ps, depth, lf->header, sizeof( lf->header )) ) + return False; + + if ( !prs_uint16( "num_keys", &hbin->ps, depth, &lf->num_keys)) + return False; + + if ( UNMARSHALLING(&hbin->ps) ) { + if ( !(lf->hashes = PRS_ALLOC_MEM( &hbin->ps, REGF_HASH_REC, lf->num_keys )) ) + return False; + } + + for ( i=0; inum_keys; i++ ) { + if ( !prs_hash_rec( "hash_rec", &hbin->ps, depth, &lf->hashes[i] ) ) + return False; + } + + end_off = prs_offset( &hbin->ps ); + + /* data_size must be divisible by 8 and large enough to hold the original record */ + + data_size = ((start_off - end_off) & 0xfffffff8 ); + if ( data_size > lf->rec_size ) + DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size)); + + if ( MARSHALLING(&hbin->ps) ) + hbin->dirty = True; + + return True; +} + +/******************************************************************* +*******************************************************************/ + +static BOOL hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk ) +{ + prs_struct *ps = &hbin->ps; + uint16 tag = 0xFFFF; + uint32 data_size, start_off, end_off; + + + prs_debug(ps, depth, desc, "hbin_prs_sk_rec"); + depth++; + + if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) ) + return False; + + /* backup and get the data_size */ + + if ( !prs_set_offset( &hbin->ps, prs_offset(&hbin->ps)-sizeof(uint32)) ) + return False; + start_off = prs_offset( &hbin->ps ); + if ( !prs_uint32( "rec_size", &hbin->ps, depth, &sk->rec_size )) + return False; + + if ( !prs_uint8s( True, "header", ps, depth, sk->header, sizeof( sk->header )) ) + return False; + if ( !prs_uint16( "tag", ps, depth, &tag)) + return False; + + if ( !prs_uint32( "prev_sk_off", ps, depth, &sk->prev_sk_off)) + return False; + if ( !prs_uint32( "next_sk_off", ps, depth, &sk->next_sk_off)) + return False; + if ( !prs_uint32( "ref_count", ps, depth, &sk->ref_count)) + return False; + if ( !prs_uint32( "size", ps, depth, &sk->size)) + return False; + + if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth )) + return False; + + end_off = prs_offset( &hbin->ps ); + + /* data_size must be divisible by 8 and large enough to hold the original record */ + + data_size = ((start_off - end_off) & 0xfffffff8 ); + if ( data_size > sk->rec_size ) + DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size)); + + if ( MARSHALLING(&hbin->ps) ) + hbin->dirty = True; + + return True; +} + +/******************************************************************* +*******************************************************************/ + +static BOOL hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_VK_REC *vk, REGF_FILE *file ) +{ + uint32 offset; + uint16 name_length; + prs_struct *ps = &hbin->ps; + uint32 data_size, start_off, end_off; + + prs_debug(ps, depth, desc, "prs_vk_rec"); + depth++; + + /* backup and get the data_size */ + + if ( !prs_set_offset( &hbin->ps, prs_offset(&hbin->ps)-sizeof(uint32)) ) + return False; + start_off = prs_offset( &hbin->ps ); + if ( !prs_uint32( "rec_size", &hbin->ps, depth, &vk->rec_size )) + return False; + + if ( !prs_uint8s( True, "header", ps, depth, vk->header, sizeof( vk->header )) ) + return False; + + if ( MARSHALLING(&hbin->ps) ) + name_length = strlen(vk->valuename); + + if ( !prs_uint16( "name_length", ps, depth, &name_length )) + return False; + if ( !prs_uint32( "data_size", ps, depth, &vk->data_size )) + return False; + if ( !prs_uint32( "data_off", ps, depth, &vk->data_off )) + return False; + if ( !prs_uint32( "type", ps, depth, &vk->type)) + return False; + if ( !prs_uint16( "flag", ps, depth, &vk->flag)) + return False; + + offset = prs_offset( ps ); + offset += 2; /* skip 2 bytes */ + prs_set_offset( ps, offset ); + + /* get the name */ + + if ( vk->flag&VK_FLAG_NAME_PRESENT ) { + + if ( UNMARSHALLING(&hbin->ps) ) { + if ( !(vk->valuename = PRS_ALLOC_MEM( ps, char, name_length+1 ))) + return False; + } + if ( !prs_uint8s( True, "name", ps, depth, vk->valuename, name_length ) ) + return False; + } + + end_off = prs_offset( &hbin->ps ); + + /* get the data if necessary */ + + if ( vk->data_size != 0 ) { + BOOL charmode = False; + + if ( (vk->type == REG_SZ) || (vk->type == REG_MULTI_SZ) ) + charmode = True; + + /* the data is stored in the offset if the size <= 4 */ + + if ( !(vk->data_size & VK_DATA_IN_OFFSET) ) { + REGF_HBIN *hblock = hbin; + uint32 data_rec_size; + + if ( UNMARSHALLING(&hbin->ps) ) { + if ( !(vk->data = PRS_ALLOC_MEM( ps, uint8, vk->data_size) ) ) + return False; + } + + /* this data can be in another hbin */ + if ( !hbin_contains_offset( hbin, vk->data_off ) ) { + if ( !(hblock = lookup_hbin_block( file, vk->data_off )) ) + return False; + } + if ( !(prs_set_offset( &hblock->ps, (vk->data_off+HBIN_HDR_SIZE-hblock->first_hbin_off)-sizeof(uint32) )) ) + return False; + + if ( MARSHALLING(&hblock->ps) ) { + data_rec_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8; + data_rec_size = ( data_rec_size - 1 ) ^ 0xFFFFFFFF; + } + if ( !prs_uint32( "data_rec_size", &hblock->ps, depth, &data_rec_size )) + return False; + if ( !prs_uint8s( charmode, "data", &hblock->ps, depth, vk->data, vk->data_size) ) + return False; + + if ( MARSHALLING(&hblock->ps) ) + hblock->dirty = True; + } + else { + if ( !(vk->data = PRS_ALLOC_MEM( ps, uint8, 4 ) ) ) + return False; + SIVAL( vk->data, 0, vk->data_off ); + } + + } + + /* data_size must be divisible by 8 and large enough to hold the original record */ + + data_size = ((start_off - end_off ) & 0xfffffff8 ); + if ( data_size != vk->rec_size ) + DEBUG(10,("prs_vk_rec: data_size check failed (0x%x < 0x%x)\n", data_size, vk->rec_size)); + + if ( MARSHALLING(&hbin->ps) ) + hbin->dirty = True; + + return True; +} + +/******************************************************************* + read a VK record which is contained in the HBIN block stored + in the prs_struct *ps. +*******************************************************************/ + +static BOOL hbin_prs_vk_records( const char *desc, REGF_HBIN *hbin, int depth, REGF_NK_REC *nk, REGF_FILE *file ) +{ + int i; + uint32 record_size; + + prs_debug(&hbin->ps, depth, desc, "prs_vk_records"); + depth++; + + /* check if we have anything to do first */ + + if ( nk->num_values == 0 ) + return True; + + if ( UNMARSHALLING(&hbin->ps) ) { + if ( !(nk->values = PRS_ALLOC_MEM( &hbin->ps, REGF_VK_REC, nk->num_values ) ) ) + return False; + } + + /* convert the offset to something relative to this HBIN block */ + + if ( !prs_set_offset( &hbin->ps, nk->values_off+HBIN_HDR_SIZE-hbin->first_hbin_off-sizeof(uint32)) ) + return False; + + if ( MARSHALLING( &hbin->ps) ) { + record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8; + record_size = (record_size - 1) ^ 0xFFFFFFFF; + } + + if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) ) + return False; + + for ( i=0; inum_values; i++ ) { + if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) ) + return False; + } + + for ( i=0; inum_values; i++ ) { + REGF_HBIN *sub_hbin = hbin; + uint32 new_offset; + + if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) ) { + sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off ); + if ( !sub_hbin ) { + DEBUG(0,("hbin_prs_vk_records: Failed to find HBIN block containing offset [0x%x]\n", + nk->values[i].hbin_off)); + return False; + } + } + + new_offset = nk->values[i].rec_off + HBIN_HDR_SIZE - sub_hbin->first_hbin_off; + if ( !prs_set_offset( &sub_hbin->ps, new_offset ) ) + return False; + if ( !hbin_prs_vk_rec( "vk_rec", sub_hbin, depth, &nk->values[i], file ) ) + return False; + } + + if ( MARSHALLING(&hbin->ps) ) + hbin->dirty = True; + + + return True; +} + + +/******************************************************************* +*******************************************************************/ + +static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset ) +{ + REGF_SK_REC *p_sk; + + for ( p_sk=file->sec_desc_list; p_sk; p_sk=p_sk->next ) { + if ( p_sk->sk_off == offset ) + return p_sk; + } + + return NULL; +} + +/******************************************************************* +*******************************************************************/ + +static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd ) +{ + REGF_SK_REC *p; + + for ( p=file->sec_desc_list; p; p=p->next ) { + if ( sec_desc_equal( p->sec_desc, sd ) ) + return p; + } + + /* failure */ + + return NULL; +} + +/******************************************************************* +*******************************************************************/ + +static BOOL hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk ) +{ + int depth = 0; + REGF_HBIN *sub_hbin; + + prs_debug(&hbin->ps, depth, "", "fetch_key"); + depth++; + + /* get the initial nk record */ + + if ( !prs_nk_rec( "nk_rec", &hbin->ps, depth, nk )) + return False; + + /* fill in values */ + + if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) ) { + sub_hbin = hbin; + if ( !hbin_contains_offset( hbin, nk->values_off ) ) { + sub_hbin = lookup_hbin_block( file, nk->values_off ); + if ( !sub_hbin ) { + DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing value_list_offset [0x%x]\n", + nk->values_off)); + return False; + } + } + + if ( !hbin_prs_vk_records( "vk_rec", sub_hbin, depth, nk, file )) + return False; + } + + /* now get subkeys */ + + if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) ) { + sub_hbin = hbin; + if ( !hbin_contains_offset( hbin, nk->subkeys_off ) ) { + sub_hbin = lookup_hbin_block( file, nk->subkeys_off ); + if ( !sub_hbin ) { + DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing subkey_offset [0x%x]\n", + nk->subkeys_off)); + return False; + } + } + + if ( !hbin_prs_lf_records( "lf_rec", sub_hbin, depth, nk )) + return False; + } + + /* get the to the security descriptor. First look if we have already parsed it */ + + if ( (nk->sk_off!=REGF_OFFSET_NONE) && !( nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )) ) { + + sub_hbin = hbin; + if ( !hbin_contains_offset( hbin, nk->sk_off ) ) { + sub_hbin = lookup_hbin_block( file, nk->sk_off ); + if ( !sub_hbin ) { + DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing sk_offset [0x%x]\n", + nk->subkeys_off)); + return False; + } + } + + if ( !(nk->sec_desc = TALLOC_ZERO_P( file->mem_ctx, REGF_SK_REC )) ) + return False; + nk->sec_desc->sk_off = nk->sk_off; + if ( !hbin_prs_sk_rec( "sk_rec", sub_hbin, depth, nk->sec_desc )) + return False; + + /* add to the list of security descriptors (ref_count has been read from the files) */ + + nk->sec_desc->sk_off = nk->sk_off; + DLIST_ADD( file->sec_desc_list, nk->sec_desc ); + } + + return True; +} + +/******************************************************************* +*******************************************************************/ + +static BOOL next_record( REGF_HBIN *hbin, const char *hdr, BOOL *eob ) +{ + char header[REC_HDR_SIZE] = ""; + uint32 record_size; + uint32 curr_off, block_size; + BOOL found = False; + prs_struct *ps = &hbin->ps; + + curr_off = prs_offset( ps ); + if ( curr_off == 0 ) + prs_set_offset( ps, HBIN_HEADER_REC_SIZE ); + + /* assume that the current offset is at the reacord header + and we need to backup to read the record size */ + + curr_off -= sizeof(uint32); + + block_size = prs_data_size( ps ); + record_size = 0; + while ( !found ) { + + curr_off = curr_off+record_size; + if ( curr_off >= block_size ) + break; + + if ( !prs_set_offset( &hbin->ps, curr_off) ) + return False; + + if ( !prs_uint32( "record_size", ps, 0, &record_size ) ) + return False; + if ( !prs_uint8s( True, "header", ps, 0, header, REC_HDR_SIZE ) ) + return False; + + if ( record_size & 0x80000000 ) { + /* absolute_value(record_size) */ + record_size = (record_size ^ 0xffffffff) + 1; + } + + if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) { + found = True; + curr_off += sizeof(uint32); + } + } + + /* mark prs_struct as done ( at end ) if no more SK records */ + /* mark end-of-block as True */ + + if ( !found ) { + prs_set_offset( &hbin->ps, prs_data_size(&hbin->ps) ); + *eob = True; + return False; + } + + if ( !prs_set_offset( ps, curr_off ) ) + return False; + + return True; +} + +/******************************************************************* +*******************************************************************/ + +static BOOL next_nk_record( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk, BOOL *eob ) +{ + if ( next_record( hbin, "nk", eob ) && hbin_prs_key( file, hbin, nk ) ) + return True; + + return False; +} + +/******************************************************************* + Intialize the newly created REGF_BLOCK in *file and write the + block header to disk +*******************************************************************/ + +static BOOL init_regf_block( REGF_FILE *file ) +{ + prs_struct ps; + BOOL result = True; + + if ( !prs_init( &ps, REGF_BLOCKSIZE, file->mem_ctx, MARSHALL ) ) + return False; + + memcpy( file->header, "regf", REGF_HDR_SIZE ); + file->data_offset = 0x20; + file->last_block = 0x1000; + + /* set mod time */ + + unix_to_nt_time( &file->mtime, time(NULL) ); + + /* hard coded values...no diea what these are ... maybe in time */ + + file->unknown1 = 0x2; + file->unknown2 = 0x1; + file->unknown3 = 0x3; + file->unknown4 = 0x0; + file->unknown5 = 0x1; + file->unknown6 = 0x1; + + /* write header to the buffer */ + + if ( !prs_regf_block( "regf_header", &ps, 0, file ) ) { + result = False; + goto out; + } + + /* calculate the checksum, re-marshall data (to include the checksum) + and write to disk */ + + file->checksum = regf_block_checksum( &ps ); + prs_set_offset( &ps, 0 ); + if ( !prs_regf_block( "regf_header", &ps, 0, file ) ) { + result = False; + goto out; + } + + if ( write_block( file, &ps, 0 ) == -1 ) { + DEBUG(0,("init_regf_block: Failed to initialize registry header block!\n")); + result = False; + goto out; + } + +out: + prs_mem_free( &ps ); + + return result; +} +/******************************************************************* + Open the registry file and then read in the REGF block to get the + first hbin offset. +*******************************************************************/ + + REGF_FILE* regfio_open( const char *filename, int flags, int mode ) +{ + REGF_FILE *rb; + + if ( !(rb = SMB_MALLOC_P(REGF_FILE)) ) { + DEBUG(0,("ERROR allocating memory\n")); + return NULL; + } + ZERO_STRUCTP( rb ); + rb->fd = -1; + + if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) ) { + regfio_close( rb ); + return NULL; + } + + rb->open_flags = flags; + + /* open and existing file */ + + if ( (rb->fd = open(filename, flags, mode)) == -1 ) { + DEBUG(0,("regfio_open: failure to open %s (%s)\n", filename, strerror(errno))); + regfio_close( rb ); + return NULL; + } + + /* check if we are creating a new file or overwriting an existing one */ + + if ( flags & (O_CREAT|O_TRUNC) ) { + if ( !init_regf_block( rb ) ) { + DEBUG(0,("regfio_open: Failed to read initial REGF block\n")); + regfio_close( rb ); + return NULL; + } + + /* success */ + return rb; + } + + /* read in an existing file */ + + if ( !read_regf_block( rb ) ) { + DEBUG(0,("regfio_open: Failed to read initial REGF block\n")); + regfio_close( rb ); + return NULL; + } + + /* success */ + + return rb; +} + +/******************************************************************* +*******************************************************************/ + +static void regfio_mem_free( REGF_FILE *file ) +{ + /* free any talloc()'d memory */ + + if ( file && file->mem_ctx ) + talloc_destroy( file->mem_ctx ); +} + +/******************************************************************* +*******************************************************************/ + + int regfio_close( REGF_FILE *file ) +{ + int fd; + + /* cleanup for a file opened for write */ + + if ( file->open_flags & (O_WRONLY|O_RDWR) ) { + prs_struct ps; + REGF_SK_REC *sk; + + /* write of sd list */ + + for ( sk=file->sec_desc_list; sk; sk=sk->next ) { + hbin_prs_sk_rec( "sk_rec", sk->hbin, 0, sk ); + } + + /* flush any dirty blocks */ + + while ( file->block_list ) { + hbin_block_close( file, file->block_list ); + } + + ZERO_STRUCT( ps ); + + unix_to_nt_time( &file->mtime, time(NULL) ); + + if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) != -1 ) { + /* now use for writing */ + prs_switch_type( &ps, MARSHALL ); + + /* stream the block once, generate the checksum, + and stream it again */ + prs_set_offset( &ps, 0 ); + prs_regf_block( "regf_blocK", &ps, 0, file ); + file->checksum = regf_block_checksum( &ps ); + prs_set_offset( &ps, 0 ); + prs_regf_block( "regf_blocK", &ps, 0, file ); + + /* now we are ready to write it to disk */ + if ( write_block( file, &ps, 0 ) == -1 ) + DEBUG(0,("regfio_close: failed to update the regf header block!\n")); + } + + prs_mem_free( &ps ); + } + + regfio_mem_free( file ); + + /* nothing tdo do if there is no open file */ + + if ( !file || (file->fd == -1) ) + return 0; + + fd = file->fd; + file->fd = -1; + SAFE_FREE( file ); + + return close( fd ); +} + +/******************************************************************* +*******************************************************************/ + +static void regfio_flush( REGF_FILE *file ) +{ + REGF_HBIN *hbin; + + for ( hbin=file->block_list; hbin; hbin=hbin->next ) { + write_hbin_block( file, hbin ); + } +} + +/******************************************************************* + There should be only *one* root key in the registry file based + on my experience. --jerry +*******************************************************************/ + +REGF_NK_REC* regfio_rootkey( REGF_FILE *file ) +{ + REGF_NK_REC *nk; + REGF_HBIN *hbin; + uint32 offset = REGF_BLOCKSIZE; + BOOL found = False; + BOOL eob; + + if ( !file ) + return NULL; + + if ( !(nk = TALLOC_ZERO_P( file->mem_ctx, REGF_NK_REC )) ) { + DEBUG(0,("regfio_rootkey: talloc() failed!\n")); + return NULL; + } + + /* scan through the file on HBIN block at a time looking + for an NK record with a type == 0x002c. + Normally this is the first nk record in the first hbin + block (but I'm not assuming that for now) */ + + while ( (hbin = read_hbin_block( file, offset )) ) { + eob = False; + + while ( !eob) { + if ( next_nk_record( file, hbin, nk, &eob ) ) { + if ( nk->key_type == NK_TYPE_ROOTKEY ) { + found = True; + break; + } + } + prs_mem_free( &hbin->ps ); + } + + if ( found ) + break; + + offset += hbin->block_size; + } + + if ( !found ) { + DEBUG(0,("regfio_rootkey: corrupt registry file ? No root key record located\n")); + return NULL; + } + + DLIST_ADD( file->block_list, hbin ); + + return nk; +} + +/******************************************************************* + This acts as an interator over the subkeys defined for a given + NK record. Remember that offsets are from the *first* HBIN block. +*******************************************************************/ + + REGF_NK_REC* regfio_fetch_subkey( REGF_FILE *file, REGF_NK_REC *nk ) +{ + REGF_NK_REC *subkey; + REGF_HBIN *hbin; + uint32 nk_offset; + + /* see if there is anything left to report */ + + if ( !nk || (nk->subkeys_off==REGF_OFFSET_NONE) || (nk->subkey_index >= nk->num_subkeys) ) + return NULL; + + /* find the HBIN block which should contain the nk record */ + + if ( !(hbin = lookup_hbin_block( file, nk->subkeys.hashes[nk->subkey_index].nk_off )) ) { + DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n", + nk->subkeys.hashes[nk->subkey_index].nk_off)); + return NULL; + } + + nk_offset = nk->subkeys.hashes[nk->subkey_index].nk_off; + if ( !prs_set_offset( &hbin->ps, (HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off) ) ) + return NULL; + + nk->subkey_index++; + if ( !(subkey = TALLOC_ZERO_P( file->mem_ctx, REGF_NK_REC )) ) + return NULL; + + if ( !hbin_prs_key( file, hbin, subkey ) ) + return NULL; + + return subkey; +} + + +/******************************************************************* +*******************************************************************/ + +static REGF_HBIN* regf_hbin_allocate( REGF_FILE *file, uint32 block_size ) +{ + REGF_HBIN *hbin; + SMB_STRUCT_STAT sbuf; + + if ( !(hbin = TALLOC_ZERO_P( file->mem_ctx, REGF_HBIN )) ) + return NULL; + + memcpy( hbin->header, "hbin", sizeof(HBIN_HDR_SIZE) ); + + + if ( sys_fstat( file->fd, &sbuf ) ) { + DEBUG(0,("regf_hbin_allocate: stat() failed! (%s)\n", strerror(errno))); + return NULL; + } + + hbin->file_off = sbuf.st_size; + + hbin->free_off = HBIN_HEADER_REC_SIZE; + hbin->free_size = block_size - hbin->free_off + sizeof(uint32);; + + hbin->block_size = block_size; + hbin->first_hbin_off = hbin->file_off - REGF_BLOCKSIZE; + + if ( !prs_init( &hbin->ps, block_size, file->mem_ctx, MARSHALL ) ) + return NULL; + + if ( !prs_hbin_block( "new_hbin", &hbin->ps, 0, hbin ) ) + return NULL; + + if ( !write_hbin_block( file, hbin ) ) + return NULL; + + file->last_block = hbin->file_off; + + return hbin; +} + +/******************************************************************* +*******************************************************************/ + +static void update_free_space( REGF_HBIN *hbin, uint32 size_used ) +{ + hbin->free_off += size_used; + hbin->free_size -= size_used; + + if ( hbin->free_off >= hbin->block_size ) { + hbin->free_off = REGF_OFFSET_NONE; + } + + return; +} + +/******************************************************************* +*******************************************************************/ + +static REGF_HBIN* find_free_space( REGF_FILE *file, uint32 size ) +{ + REGF_HBIN *hbin, *p_hbin; + uint32 block_off; + BOOL cached; + + /* check open block list */ + + for ( hbin=file->block_list; hbin!=NULL; hbin=hbin->next ) { + /* only check blocks that actually have available space */ + + if ( hbin->free_off == REGF_OFFSET_NONE ) + continue; + + /* check for a large enough available chunk */ + + if ( (hbin->block_size - hbin->free_off) >= size ) { + DLIST_PROMOTE( file->block_list, hbin ); + goto done; + } + } + + /* parse the file until we find a block with + enough free space; save the last non-filled hbin */ + + block_off = REGF_BLOCKSIZE; + do { + /* cleanup before the next round */ + cached = False; + if ( hbin ) + prs_mem_free( &hbin->ps ); + + hbin = read_hbin_block( file, block_off ); + + if ( hbin ) { + + /* make sure that we don't already have this block in memory */ + + for ( p_hbin=file->block_list; p_hbin!=NULL; p_hbin=p_hbin->next ) { + if ( p_hbin->file_off == hbin->file_off ) { + cached = True; + break; + } + } + + block_off = hbin->file_off + hbin->block_size; + + if ( cached ) { + prs_mem_free( &hbin->ps ); + hbin = NULL; + continue; + } + } + /* if (cached block or (new block and not enough free space)) then continue looping */ + } while ( cached || (hbin && (hbin->free_size < size)) ); + + /* no free space; allocate a new one */ + + if ( !hbin ) { + uint32 alloc_size; + + /* allocate in multiples of REGF_ALLOC_BLOCK; make sure (size + hbin_header) fits */ + + alloc_size = ((size+HBIN_HEADER_REC_SIZE) / REGF_ALLOC_BLOCK ) + REGF_ALLOC_BLOCK; + + if ( !(hbin = regf_hbin_allocate( file, alloc_size )) ) { + DEBUG(0,("find_free_space: regf_hbin_allocate() failed!\n")); + return NULL; + } + DLIST_ADD( file->block_list, hbin ); + } + +done: + /* set the offset to be ready to write */ + + if ( !prs_set_offset( &hbin->ps, hbin->free_off-sizeof(uint32) ) ) + return NULL; + + /* write the record size as a placeholder for now, it should be + probably updated by the caller once it all of the data necessary + for the record */ + + if ( !prs_uint32("allocated_size", &hbin->ps, 0, &size) ) + return False; + + update_free_space( hbin, size ); + + return hbin; +} + +/******************************************************************* +*******************************************************************/ + +static uint32 sk_record_data_size( SEC_DESC * sd ) +{ + uint32 size, size_mod8; + + size_mod8 = 0; + + /* the record size is sizeof(hdr) + name + static members + data_size_field */ + + size = sizeof(uint32)*5 + sec_desc_size( sd ) + sizeof(uint32); + + /* multiple of 8 */ + size_mod8 = size & 0xfffffff8; + if ( size_mod8 < size ) + size_mod8 += 8; + + return size_mod8; +} + +/******************************************************************* +*******************************************************************/ + +static uint32 vk_record_data_size( REGF_VK_REC *vk ) +{ + uint32 size, size_mod8; + + size_mod8 = 0; + + /* the record size is sizeof(hdr) + name + static members + data_size_field */ + + size = REC_HDR_SIZE + (sizeof(uint16)*3) + (sizeof(uint32)*3) + sizeof(uint32); + + if ( vk->valuename ) + size += strlen(vk->valuename); + + /* multiple of 8 */ + size_mod8 = size & 0xfffffff8; + if ( size_mod8 < size ) + size_mod8 += 8; + + return size_mod8; +} + +/******************************************************************* +*******************************************************************/ + +static uint32 lf_record_data_size( uint32 num_keys ) +{ + uint32 size, size_mod8; + + size_mod8 = 0; + + /* the record size is sizeof(hdr) + num_keys + sizeof of hash_array + data_size_uint32 */ + + size = REC_HDR_SIZE + sizeof(uint16) + (sizeof(REGF_HASH_REC) * num_keys) + sizeof(uint32); + + /* multiple of 8 */ + size_mod8 = size & 0xfffffff8; + if ( size_mod8 < size ) + size_mod8 += 8; + + return size_mod8; +} + +/******************************************************************* +*******************************************************************/ + +static uint32 nk_record_data_size( REGF_NK_REC *nk ) +{ + uint32 size, size_mod8; + + size_mod8 = 0; + + /* the record size is static + length_of_keyname + length_of_classname + data_size_uint32 */ + + size = 0x4c + strlen(nk->keyname) + sizeof(uint32); + + if ( nk->classname ) + size += strlen( nk->classname ); + + /* multiple of 8 */ + size_mod8 = size & 0xfffffff8; + if ( size_mod8 < size ) + size_mod8 += 8; + + return size_mod8; +} + +/******************************************************************* +*******************************************************************/ + +static BOOL create_vk_record( REGF_FILE *file, REGF_VK_REC *vk, REGISTRY_VALUE *value ) +{ + char *name = regval_name(value); + REGF_HBIN *data_hbin; + + ZERO_STRUCTP( vk ); + + memcpy( vk->header, "vk", REC_HDR_SIZE ); + + if ( name ) { + vk->valuename = talloc_strdup( file->mem_ctx, regval_name(value) ); + vk->flag = VK_FLAG_NAME_PRESENT; + } + + vk->data_size = regval_size( value ); + vk->type = regval_type( value ); + + if ( vk->data_size > sizeof(uint32) ) { + uint32 data_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8; + + vk->data = TALLOC_MEMDUP( file->mem_ctx, regval_data_p(value), vk->data_size ); + + /* go ahead and store the offset....we'll pick this hbin block back up when + we stream the data */ + + data_hbin = find_free_space(file, data_size ); + vk->data_off = prs_offset( &data_hbin->ps ) + data_hbin->first_hbin_off - HBIN_HDR_SIZE; + } + else { + vk->data_size |= VK_DATA_IN_OFFSET; + memcpy( &vk->data_off, regval_data_p(value), sizeof(uint32) ); + } + + return True; +} + +/******************************************************************* +*******************************************************************/ + +static int hashrec_cmp( REGF_HASH_REC *h1, REGF_HASH_REC *h2 ) +{ + return StrnCaseCmp( h1->keycheck, h2->keycheck, sizeof(uint32) ); +} + +/******************************************************************* +*******************************************************************/ + + REGF_NK_REC* regfio_write_key( REGF_FILE *file, const char *name, + REGVAL_CTR *values, REGSUBKEY_CTR *subkeys, + SEC_DESC *sec_desc, REGF_NK_REC *parent ) +{ + REGF_NK_REC *nk; + REGF_HBIN *vlist_hbin; + uint32 size; + + if ( !(nk = TALLOC_ZERO_P( file->mem_ctx, REGF_NK_REC )) ) + return NULL; + + memcpy( nk->header, "nk", REC_HDR_SIZE ); + + if ( !parent ) + nk->key_type = NK_TYPE_ROOTKEY; + else + nk->key_type = NK_TYPE_NORMALKEY; + + /* store the parent offset (or -1 if a the root key */ + + nk->parent_off = parent ? (parent->hbin_off + parent->hbin->file_off - REGF_BLOCKSIZE - HBIN_HDR_SIZE ) : REGF_OFFSET_NONE; + + /* no classname currently */ + + nk->classname_off = REGF_OFFSET_NONE; + nk->classname = NULL; + nk->keyname = talloc_strdup( file->mem_ctx, name ); + + /* current modification time */ + + unix_to_nt_time( &nk->mtime, time(NULL) ); + + /* allocate the record on disk */ + + size = nk_record_data_size( nk ); + nk->rec_size = ( size - 1 ) ^ 0XFFFFFFFF; + nk->hbin = find_free_space( file, size ); + nk->hbin_off = prs_offset( &nk->hbin->ps ); + + /* Update the hash record in the parent */ + + if ( parent ) { + REGF_HASH_REC *hash = &parent->subkeys.hashes[parent->subkey_index]; + + hash->nk_off = prs_offset( &nk->hbin->ps ) + nk->hbin->first_hbin_off - HBIN_HDR_SIZE; + memcpy( hash->keycheck, name, sizeof(uint32) ); + parent->subkey_index++; + + /* sort the list by keyname */ + + qsort( parent->subkeys.hashes, parent->subkey_index, sizeof(REGF_HASH_REC), QSORT_CAST hashrec_cmp ); + + if ( !hbin_prs_lf_records( "lf_rec", parent->subkeys.hbin, 0, parent ) ) + return False; + } + + /* write the security descriptor */ + + nk->sk_off = REGF_OFFSET_NONE; + if ( sec_desc ) { + uint32 sk_size = sk_record_data_size( sec_desc ); + REGF_HBIN *sk_hbin; + REGF_SK_REC *tmp = NULL; + + /* search for it in the existing list of sd's */ + + if ( (nk->sec_desc = find_sk_record_by_sec_desc( file, sec_desc )) == NULL ) { + /* not found so add it to the list */ + + sk_hbin = find_free_space( file, sk_size ); + + if ( !(nk->sec_desc = TALLOC_ZERO_P( file->mem_ctx, REGF_SK_REC )) ) + return NULL; + + /* now we have to store the security descriptor in the list and + update the offsets */ + + memcpy( nk->sec_desc->header, "sk", REC_HDR_SIZE ); + nk->sec_desc->hbin = sk_hbin; + nk->sec_desc->hbin_off = prs_offset( &sk_hbin->ps ); + nk->sec_desc->sk_off = prs_offset( &sk_hbin->ps ) + sk_hbin->first_hbin_off - HBIN_HDR_SIZE; + nk->sec_desc->rec_size = (sk_size-1) ^ 0xFFFFFFFF; + + nk->sec_desc->sec_desc = sec_desc; + nk->sec_desc->ref_count = 0; + + /* size value must be self-inclusive */ + nk->sec_desc->size = sec_desc_size(sec_desc) + sizeof(uint32); + + DLIST_ADD_END( file->sec_desc_list, nk->sec_desc, tmp ); + + /* initialize offsets */ + + nk->sec_desc->prev_sk_off = nk->sec_desc->sk_off; + nk->sec_desc->next_sk_off = nk->sec_desc->sk_off; + + /* now update the offsets for us and the previous sd in the list */ + + if ( nk->sec_desc->prev ) { + REGF_SK_REC *prev = nk->sec_desc->prev; + + nk->sec_desc->prev_sk_off = prev->hbin_off + prev->hbin->first_hbin_off - HBIN_HDR_SIZE; + prev->next_sk_off = nk->sk_off; + } + } + + /* dump the reference count */ + + nk->sk_off = nk->sec_desc->sk_off; + nk->sec_desc->ref_count++; + } + + /* write the subkeys */ + + nk->subkeys_off = REGF_OFFSET_NONE; + if ( (nk->num_subkeys = regsubkey_ctr_numkeys( subkeys )) != 0 ) { + uint32 lf_size = lf_record_data_size( nk->num_subkeys ); + uint32 namelen; + int i; + + nk->subkeys.hbin = find_free_space( file, lf_size ); + nk->subkeys.hbin_off = prs_offset( &nk->subkeys.hbin->ps ); + nk->subkeys.rec_size = (lf_size-1) ^ 0xFFFFFFFF; + nk->subkeys_off = prs_offset( &nk->subkeys.hbin->ps ) + nk->subkeys.hbin->first_hbin_off - HBIN_HDR_SIZE; + + memcpy( nk->subkeys.header, "lf", REC_HDR_SIZE ); + + nk->subkeys.num_keys = nk->num_subkeys; + if ( !(nk->subkeys.hashes = TALLOC_ZERO_ARRAY( file->mem_ctx, REGF_HASH_REC, nk->subkeys.num_keys )) ) + return NULL; + nk->subkey_index = 0; + + /* update the max_bytes_subkey{name,classname} fields */ + for ( i=0; inum_subkeys; i++ ) { + namelen = strlen( regsubkey_ctr_specific_key(subkeys, i) ); + if ( namelen*2 > nk->max_bytes_subkeyname ) + nk->max_bytes_subkeyname = namelen * 2; + } + } + + /* write the values */ + + nk->values_off = REGF_OFFSET_NONE; + if ( (nk->num_values = regval_ctr_numvals( values )) != 0 ) { + uint32 vlist_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8; + int i; + + vlist_hbin = find_free_space( file, vlist_size ); + nk->values_off = prs_offset( &vlist_hbin->ps ) + vlist_hbin->first_hbin_off - HBIN_HDR_SIZE; + + if ( !(nk->values = TALLOC_ARRAY( file->mem_ctx, REGF_VK_REC, nk->num_values )) ) + return NULL; + + /* create the vk records */ + + for ( i=0; inum_values; i++ ) { + uint32 vk_size, namelen, datalen; + REGISTRY_VALUE *r; + + r = regval_ctr_specific_value( values, i ); + create_vk_record( file, &nk->values[i], r ); + vk_size = vk_record_data_size( &nk->values[i] ); + nk->values[i].hbin = find_free_space( file, vk_size ); + nk->values[i].hbin_off = prs_offset( &nk->values[i].hbin->ps ); + nk->values[i].rec_size = ( vk_size - 1 ) ^ 0xFFFFFFFF; + nk->values[i].rec_off = prs_offset( &nk->values[i].hbin->ps ) + + nk->values[i].hbin->first_hbin_off + - HBIN_HDR_SIZE; + + /* update the max bytes fields if necessary */ + + namelen = strlen( regval_name(r) ); + if ( namelen*2 > nk->max_bytes_valuename ) + nk->max_bytes_valuename = namelen * 2; + + datalen = regval_size( r ); + if ( datalen*2 > nk->max_bytes_value ) + nk->max_bytes_value = datalen * 2; + } + } + + /* stream the records */ + + prs_set_offset( &nk->hbin->ps, nk->hbin_off ); + if ( !prs_nk_rec( "nk_rec", &nk->hbin->ps, 0, nk ) ) + return False; + + if ( nk->num_values ) { + if ( !hbin_prs_vk_records( "vk_records", vlist_hbin, 0, nk, file ) ) + return False; + } + + + regfio_flush( file ); + + return nk; +} + diff --git a/source3/rpc_client/cli_reg.c b/source3/rpc_client/cli_reg.c index 87b41d248e..164bdd3129 100644 --- a/source3/rpc_client/cli_reg.c +++ b/source3/rpc_client/cli_reg.c @@ -8,6 +8,7 @@ Copyright (C) Jeremy Allison 1999. Copyright (C) Simo Sorce 2001 Copyright (C) Jeremy Cooper 2004 + Copyright (C) Gerald (Jerry) Carter 2005 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,130 +26,46 @@ */ #include "includes.h" +#include "rpc_client.h" /* Shutdown a server */ -/* internal connect to a registry hive root (open a registry policy) */ +/******************************************************************* + internal connect to a registry hive root (open a registry policy) +*******************************************************************/ static WERROR cli_reg_open_hive_int(struct cli_state *cli, TALLOC_CTX *mem_ctx, uint16 op_code, const char *op_name, uint32 access_mask, POLICY_HND *hnd) { - prs_struct rbuf; - prs_struct qbuf; - REG_Q_OPEN_HIVE q_o; - REG_R_OPEN_HIVE r_o; - WERROR result = WERR_GENERAL_FAILURE; + REG_Q_OPEN_HIVE in; + REG_R_OPEN_HIVE out; + prs_struct qbuf, rbuf; - ZERO_STRUCT(q_o); - ZERO_STRUCT(r_o); + ZERO_STRUCT(in); + ZERO_STRUCT(out); - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); + init_reg_q_open_hive(&in, access_mask); - init_reg_q_open_hive(&q_o, access_mask); + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, op_code, + in, out, + qbuf, rbuf, + reg_io_q_open_hive, + reg_io_r_open_hive, + WERR_GENERAL_FAILURE ); - /* Marshall the query parameters */ - if (!reg_io_q_open_hive("", &q_o, &qbuf, 0)) - goto done; + if ( !W_ERROR_IS_OK( out.status ) ) + return out.status; - /* Send the request, receive the response */ - if (!rpc_api_pipe_req(cli, PI_WINREG, op_code, &qbuf, &rbuf)) - goto done; + memcpy( hnd, &out.pol, sizeof(POLICY_HND) ); - /* Unmarshall the response */ - if (!reg_io_r_open_hive("", &r_o, &rbuf, 0)) - goto done; - - result = r_o.status; - if (NT_STATUS_IS_OK(result)) - *hnd = r_o.pol; - -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); - - return result; -} - - -WERROR cli_reg_shutdown(struct cli_state * cli, TALLOC_CTX *mem_ctx, - const char *msg, uint32 timeout, BOOL do_reboot, - BOOL force) -{ - prs_struct qbuf; - prs_struct rbuf; - REG_Q_SHUTDOWN q_s; - REG_R_SHUTDOWN r_s; - WERROR result = WERR_GENERAL_FAILURE; - - if (msg == NULL) return WERR_INVALID_PARAM; - - ZERO_STRUCT (q_s); - ZERO_STRUCT (r_s); - - prs_init(&qbuf , MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); - - /* Marshall data and send request */ - - init_reg_q_shutdown(&q_s, msg, timeout, do_reboot, force); - - if (!reg_io_q_shutdown("", &q_s, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_SHUTDOWN, &qbuf, &rbuf)) - goto done; - - /* Unmarshall response */ - - if(reg_io_r_shutdown("", &r_s, &rbuf, 0)) - result = r_s.status; - -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); - - return result; -} - - -/* Abort a server shutdown */ - -WERROR cli_reg_abort_shutdown(struct cli_state * cli, TALLOC_CTX *mem_ctx) -{ - prs_struct rbuf; - prs_struct qbuf; - REG_Q_ABORT_SHUTDOWN q_s; - REG_R_ABORT_SHUTDOWN r_s; - WERROR result = WERR_GENERAL_FAILURE; - - ZERO_STRUCT (q_s); - ZERO_STRUCT (r_s); - - prs_init(&qbuf , MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); - - /* Marshall data and send request */ - - init_reg_q_abort_shutdown(&q_s); - - if (!reg_io_q_abort_shutdown("", &q_s, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_ABORT_SHUTDOWN, &qbuf, &rbuf)) - goto done; - - /* Unmarshall response */ - - if (reg_io_r_abort_shutdown("", &r_s, &rbuf, 0)) - result = r_s.status; - -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf ); - - return result; + return out.status; } -/* connect to a registry hive root (open a registry policy) */ +/******************************************************************* + connect to a registry hive root (open a registry policy) +*******************************************************************/ WERROR cli_reg_connect(struct cli_state *cli, TALLOC_CTX *mem_ctx, uint32 reg_type, uint32 access_mask, @@ -184,43 +101,86 @@ WERROR cli_reg_connect(struct cli_state *cli, TALLOC_CTX *mem_ctx, access_mask, reg_hnd); } -/**************************************************************************** -do a REG Unknown 0xB command. sent after a create key or create value. -this might be some sort of "sync" or "refresh" command, sent after -modification of the registry... -****************************************************************************/ -WERROR cli_reg_flush_key(struct cli_state *cli, TALLOC_CTX *mem_ctx, - POLICY_HND *hnd) + +/******************************************************************* +*******************************************************************/ + +WERROR cli_reg_shutdown(struct cli_state * cli, TALLOC_CTX *mem_ctx, + const char *msg, uint32 timeout, BOOL do_reboot, + BOOL force) { - prs_struct rbuf; - prs_struct qbuf; - REG_Q_FLUSH_KEY q_o; - REG_R_FLUSH_KEY r_o; - WERROR result = WERR_GENERAL_FAILURE; + REG_Q_SHUTDOWN in; + REG_R_SHUTDOWN out; + prs_struct qbuf, rbuf; - prs_init(&qbuf , MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); + if (msg == NULL) + return WERR_INVALID_PARAM; + + ZERO_STRUCT (in); + ZERO_STRUCT (out); /* Marshall data and send request */ - init_reg_q_flush_key(&q_o, hnd); + init_reg_q_shutdown(&in, msg, timeout, do_reboot, force); - if (!reg_io_q_flush_key("", &q_o, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_FLUSH_KEY, &qbuf, &rbuf)) - goto done; + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_SHUTDOWN, + in, out, + qbuf, rbuf, + reg_io_q_shutdown, + reg_io_r_shutdown, + WERR_GENERAL_FAILURE ); - ZERO_STRUCT(r_o); + return out.status; +} - /* Unmarshall response */ +/******************************************************************* +*******************************************************************/ + +WERROR cli_reg_abort_shutdown(struct cli_state * cli, TALLOC_CTX *mem_ctx) +{ + REG_Q_ABORT_SHUTDOWN in; + REG_R_ABORT_SHUTDOWN out; + prs_struct qbuf, rbuf; + + ZERO_STRUCT (in); + ZERO_STRUCT (out); + + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_ABORT_SHUTDOWN, + in, out, + qbuf, rbuf, + reg_io_q_abort_shutdown, + reg_io_r_abort_shutdown, + WERR_GENERAL_FAILURE ); + + return out.status; +} - if (reg_io_r_flush_key("", &r_o, &rbuf, 0)) - result = r_o.status; -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); +/**************************************************************************** +do a REG Unknown 0xB command. sent after a create key or create value. +this might be some sort of "sync" or "refresh" command, sent after +modification of the registry... +****************************************************************************/ +WERROR cli_reg_flush_key(struct cli_state *cli, TALLOC_CTX *mem_ctx, + POLICY_HND *hnd) +{ + REG_Q_FLUSH_KEY in; + REG_R_FLUSH_KEY out; + prs_struct qbuf, rbuf; - return result; + ZERO_STRUCT (in); + ZERO_STRUCT (out); + + init_reg_q_flush_key(&in, hnd); + + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_FLUSH_KEY, + in, out, + qbuf, rbuf, + reg_io_q_flush_key, + reg_io_r_flush_key, + WERR_GENERAL_FAILURE ); + + return out.status; } /**************************************************************************** @@ -234,96 +194,93 @@ WERROR cli_reg_query_key(struct cli_state *cli, TALLOC_CTX *mem_ctx, uint32 *max_valnamelen, uint32 *max_valbufsize, uint32 *sec_desc, NTTIME *mod_time) { - prs_struct rbuf; - prs_struct qbuf; - REG_Q_QUERY_KEY q_o; - REG_R_QUERY_KEY r_o; + REG_Q_QUERY_KEY in; + REG_R_QUERY_KEY out; + prs_struct qbuf, rbuf; uint32 saved_class_len = *class_len; - WERROR result = WERR_GENERAL_FAILURE; - - prs_init(&qbuf , MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); - - /* Marshall data and send request */ - - init_reg_q_query_key( &q_o, hnd, key_class ); - if (!reg_io_q_query_key("", &q_o, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_QUERY_KEY, &qbuf, &rbuf)) - goto done; + ZERO_STRUCT (in); + ZERO_STRUCT (out); - ZERO_STRUCT(r_o); + init_reg_q_query_key( &in, hnd, key_class ); - /* Unmarshall response */ + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_QUERY_KEY, + in, out, + qbuf, rbuf, + reg_io_q_query_key, + reg_io_r_query_key, + WERR_GENERAL_FAILURE ); - if (!reg_io_r_query_key("", &r_o, &rbuf, 0)) - goto done; + if ( W_ERROR_EQUAL( out.status, WERR_MORE_DATA ) ) { + ZERO_STRUCT (in); - result = r_o.status; - if (NT_STATUS_EQUAL(result, ERROR_INSUFFICIENT_BUFFER)) { - *class_len = r_o.class.string->uni_max_len; - goto done; - } else if (!NT_STATUS_IS_OK(result)) - goto done; + *class_len = out.class.string->uni_max_len; + if ( *class_len > saved_class_len ) + return out.status; + + /* set a string of spaces and NULL terminate */ - *class_len = r_o.class.string->uni_max_len; - unistr2_to_ascii(key_class, r_o.class.string, saved_class_len-1); - *num_subkeys = r_o.num_subkeys ; - *max_subkeylen = r_o.max_subkeylen ; - *num_values = r_o.num_values ; - *max_valnamelen = r_o.max_valnamelen; - *max_valbufsize = r_o.max_valbufsize; - *sec_desc = r_o.sec_desc ; - *mod_time = r_o.mod_time ; - /* Maybe: *max_classlen = r_o.reserved; */ + memset( key_class, (int)' ', *class_len ); + key_class[*class_len] = '\0'; + + init_reg_q_query_key( &in, hnd, key_class ); -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); + ZERO_STRUCT (out); - return result; + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_QUERY_KEY, + in, out, + qbuf, rbuf, + reg_io_q_query_key, + reg_io_r_query_key, + WERR_GENERAL_FAILURE ); + } + + if ( !W_ERROR_IS_OK( out.status ) ) + return out.status; + + *class_len = out.class.string->uni_max_len; + unistr2_to_ascii(key_class, out.class.string, saved_class_len-1); + *num_subkeys = out.num_subkeys ; + *max_subkeylen = out.max_subkeylen ; + *num_values = out.num_values ; + *max_valnamelen = out.max_valnamelen; + *max_valbufsize = out.max_valbufsize; + *sec_desc = out.sec_desc ; + *mod_time = out.mod_time ; + /* Maybe: *max_classlen = out.reserved; */ + + return out.status; } /**************************************************************************** -do a REG Unknown 1A ****************************************************************************/ + WERROR cli_reg_getversion(struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *hnd, uint32 *unk) { - prs_struct rbuf; - prs_struct qbuf; - REG_Q_GETVERSION q_o; - REG_R_GETVERSION r_o; - WERROR result = WERR_GENERAL_FAILURE; - - prs_init(&qbuf , MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); - - /* Marshall data and send request */ + REG_Q_GETVERSION in; + REG_R_GETVERSION out; + prs_struct qbuf, rbuf; - init_reg_q_getversion(&q_o, hnd); - - if (!reg_io_q_getversion("", &q_o, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_GETVERSION, &qbuf, &rbuf)) - goto done; - - ZERO_STRUCT(r_o); - - /* Unmarshall response */ - - if (!reg_io_r_getversion("", &r_o, &rbuf, 0)) - goto done; - - result = r_o.status; - if (NT_STATUS_IS_OK(result)) - if (unk != NULL) - *unk = r_o.unknown; - -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); - - return result; + ZERO_STRUCT (in); + ZERO_STRUCT (out); + + init_reg_q_getversion(&in, hnd); + + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_GETVERSION, + in, out, + qbuf, rbuf, + reg_io_q_getversion, + reg_io_r_getversion, + WERR_GENERAL_FAILURE ); + + + if ( !W_ERROR_IS_OK( out.status ) ) + return out.status; + + *unk = out.unknown; + + return out.status; } /**************************************************************************** @@ -333,41 +290,30 @@ WERROR cli_reg_query_info(struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *hnd, const char *val_name, uint32 *type, REGVAL_BUFFER *buffer) { - prs_struct rbuf; - prs_struct qbuf; - REG_Q_INFO q_o; - REG_R_INFO r_o; - WERROR result = WERR_GENERAL_FAILURE; - - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); - - /* Marshall data and send request */ - - init_reg_q_info(&q_o, hnd, val_name, buffer); - - if (!reg_io_q_info("", &q_o, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_INFO, &qbuf, &rbuf)) - goto done; + REG_Q_INFO in; + REG_R_INFO out; + prs_struct qbuf, rbuf; - ZERO_STRUCT(r_o); - - /* Unmarshall response */ - - if (!reg_io_r_info("", &r_o, &rbuf, 0)) - goto done; - - result = r_o.status; - if (NT_STATUS_IS_OK(result)) { - *type = *r_o.type; - *buffer = *r_o.value; - } - -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); - - return result; + ZERO_STRUCT (in); + ZERO_STRUCT (out); + + init_reg_q_info(&in, hnd, val_name, buffer); + + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_QUERY_KEY, + in, out, + qbuf, rbuf, + reg_io_q_info, + reg_io_r_info, + WERR_GENERAL_FAILURE ); + + + if ( !W_ERROR_IS_OK( out.status ) ) + return out.status; + + *type = *out.type; + *buffer = *out.value; + + return out.status; } /**************************************************************************** @@ -377,43 +323,30 @@ WERROR cli_reg_set_key_sec(struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *hnd, uint32 sec_info, size_t secdesc_size, SEC_DESC *sec_desc) { - prs_struct rbuf; - prs_struct qbuf; - REG_Q_SET_KEY_SEC q_o; - REG_R_SET_KEY_SEC r_o; + REG_Q_SET_KEY_SEC in; + REG_R_SET_KEY_SEC out; + prs_struct qbuf, rbuf; SEC_DESC_BUF *sec_desc_buf; - WERROR result = WERR_GENERAL_FAILURE; - - /* - * Flatten the security descriptor. - */ - sec_desc_buf = make_sec_desc_buf(mem_ctx, secdesc_size, sec_desc); - if (sec_desc_buf == NULL) - goto done; - - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); - - /* Marshall data and send request */ - - init_reg_q_set_key_sec(&q_o, hnd, sec_info, sec_desc_buf); - if (!reg_io_q_set_key_sec("", &q_o, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_SET_KEY_SEC, &qbuf, &rbuf)) - goto done; - - ZERO_STRUCT(r_o); - - /* Unmarshall response */ - - if (reg_io_r_set_key_sec("", &r_o, &rbuf, 0)) - result = r_o.status; - -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); - - return result; + ZERO_STRUCT (in); + ZERO_STRUCT (out); + + /* Flatten the security descriptor */ + + if ( !(sec_desc_buf = make_sec_desc_buf(mem_ctx, secdesc_size, sec_desc)) ) + return WERR_GENERAL_FAILURE; + + init_reg_q_set_key_sec(&in, hnd, sec_info, sec_desc_buf); + + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_SET_KEY_SEC, + in, out, + qbuf, rbuf, + reg_io_q_set_key_sec, + reg_io_r_set_key_sec, + WERR_GENERAL_FAILURE ); + + + return out.status; } @@ -424,53 +357,32 @@ WERROR cli_reg_get_key_sec(struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *hnd, uint32 sec_info, uint32 *sec_buf_size, SEC_DESC_BUF *sec_buf) { - prs_struct rbuf; - prs_struct qbuf; - REG_Q_GET_KEY_SEC q_o; - REG_R_GET_KEY_SEC r_o; - WERROR result = WERR_GENERAL_FAILURE; - - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); - - /* Marshall data and send request */ - - init_reg_q_get_key_sec(&q_o, hnd, sec_info, *sec_buf_size, sec_buf); - - if (!reg_io_q_get_key_sec("", &q_o, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_GET_KEY_SEC, &qbuf, &rbuf)) - goto done; - - ZERO_STRUCT(r_o); + REG_Q_GET_KEY_SEC in; + REG_R_GET_KEY_SEC out; + prs_struct qbuf, rbuf; - /* Unmarshall response */ - - r_o.data = sec_buf; - - if (*sec_buf_size != 0) - { - sec_buf->sec = TALLOC(mem_ctx, *sec_buf_size); - } - - if (!reg_io_r_get_key_sec("", &r_o, &rbuf, 0)) - goto done; - - result = r_o.status; - if (NT_STATUS_IS_OK(result)) - (*sec_buf_size) = r_o.data->len; - else if (NT_STATUS_EQUAL(result, ERROR_INSUFFICIENT_BUFFER)) - { - /* - * get the maximum buffer size: it was too small - */ - (*sec_buf_size) = r_o.hdr_sec.buf_max_len; - } + ZERO_STRUCT (in); + ZERO_STRUCT (out); + + init_reg_q_get_key_sec(&in, hnd, sec_info, *sec_buf_size, sec_buf); -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_GET_KEY_SEC, + in, out, + qbuf, rbuf, + reg_io_q_get_key_sec, + reg_io_r_get_key_sec, + WERR_GENERAL_FAILURE ); + - return result; + /* this might be able to return WERR_MORE_DATA, I'm not sure */ + + if ( !W_ERROR_IS_OK( out.status ) ) + return out.status; + + sec_buf = out.data; + *sec_buf_size = out.data->len; + + return out.status; } /**************************************************************************** @@ -479,35 +391,23 @@ do a REG Delete Value WERROR cli_reg_delete_val(struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *hnd, char *val_name) { - prs_struct rbuf; - prs_struct qbuf; - REG_Q_DELETE_VALUE q_o; - REG_R_DELETE_VALUE r_o; - WERROR result = WERR_GENERAL_FAILURE; - - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); - - /* Marshall data and send request */ - - init_reg_q_delete_val(&q_o, hnd, val_name); - - if (!reg_io_q_delete_val("", &q_o, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_DELETE_VALUE, &qbuf, &rbuf)) - goto done; - - ZERO_STRUCT(r_o); - - /* Unmarshall response */ - - if (reg_io_r_delete_val("", &r_o, &rbuf, 0)) - result = r_o.status; - -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); + REG_Q_DELETE_VALUE in; + REG_R_DELETE_VALUE out; + prs_struct qbuf, rbuf; - return result; + ZERO_STRUCT (in); + ZERO_STRUCT (out); + + init_reg_q_delete_val(&in, hnd, val_name); + + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_DELETE_VALUE, + in, out, + qbuf, rbuf, + reg_io_q_delete_val, + reg_io_r_delete_val, + WERR_GENERAL_FAILURE ); + + return out.status; } /**************************************************************************** @@ -516,35 +416,23 @@ do a REG Delete Key WERROR cli_reg_delete_key(struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *hnd, char *key_name) { - prs_struct rbuf; - prs_struct qbuf; - REG_Q_DELETE_KEY q_o; - REG_R_DELETE_KEY r_o; - WERROR result = WERR_GENERAL_FAILURE; - - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); - - /* Marshall data and send request */ - - init_reg_q_delete_key(&q_o, hnd, key_name); + REG_Q_DELETE_KEY in; + REG_R_DELETE_KEY out; + prs_struct qbuf, rbuf; - if (!reg_io_q_delete_key("", &q_o, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_DELETE_KEY, &qbuf, &rbuf)) - goto done; - - ZERO_STRUCT(r_o); - - /* Unmarshall response */ - - if (reg_io_r_delete_key("", &r_o, &rbuf, 0)) - result = r_o.status; - -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); - - return result; + ZERO_STRUCT (in); + ZERO_STRUCT (out); + + init_reg_q_delete_key(&in, hnd, key_name); + + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_DELETE_KEY, + in, out, + qbuf, rbuf, + reg_io_q_delete_key, + reg_io_r_delete_key, + WERR_GENERAL_FAILURE ); + + return out.status; } /**************************************************************************** @@ -554,51 +442,41 @@ WERROR cli_reg_create_key(struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *hnd, char *key_name, char *key_class, uint32 access_desired, POLICY_HND *key) { - prs_struct rbuf; - prs_struct qbuf; - REG_Q_CREATE_KEY q_o; - REG_R_CREATE_KEY r_o; + REG_Q_CREATE_KEY in; + REG_R_CREATE_KEY out; + prs_struct qbuf, rbuf; SEC_DESC *sec; SEC_DESC_BUF *sec_buf; size_t sec_len; - WERROR result = WERR_GENERAL_FAILURE; - - ZERO_STRUCT(q_o); - - if ((sec = make_sec_desc(mem_ctx, 1, SEC_DESC_SELF_RELATIVE, - NULL, NULL, NULL, NULL, &sec_len)) == NULL) - goto done; - - if ((sec_buf = make_sec_desc_buf(mem_ctx, sec_len, sec)) == NULL) - goto done; - - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); - - /* Marshall data and send request */ - init_reg_q_create_key(&q_o, hnd, key_name, key_class, access_desired, sec_buf); - - if (!reg_io_q_create_key("", &q_o, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_CREATE_KEY, &qbuf, &rbuf)) - goto done; - - ZERO_STRUCT(r_o); - - /* Unmarshall response */ - - if (!reg_io_r_create_key("", &r_o, &rbuf, 0)) - goto done; - - result = r_o.status; - if (NT_STATUS_IS_OK(result)) - *key = r_o.key_pol; - -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); - - return result; + ZERO_STRUCT (in); + ZERO_STRUCT (out); + + if ( !(sec = make_sec_desc(mem_ctx, 1, SEC_DESC_SELF_RELATIVE, + NULL, NULL, NULL, NULL, &sec_len)) ) + { + return WERR_GENERAL_FAILURE; + } + + if ( !(sec_buf = make_sec_desc_buf(mem_ctx, sec_len, sec)) ) + return WERR_GENERAL_FAILURE; + + init_reg_q_create_key(&in, hnd, key_name, key_class, access_desired, sec_buf); + + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_CREATE_KEY, + in, out, + qbuf, rbuf, + reg_io_q_create_key, + reg_io_r_create_key, + WERR_GENERAL_FAILURE ); + + + if ( !W_ERROR_IS_OK( out.status ) ) + return out.status; + + memcpy( key, &out.key_pol, sizeof(POLICY_HND) ); + + return out.status; } /**************************************************************************** @@ -606,46 +484,40 @@ do a REG Enum Key ****************************************************************************/ WERROR cli_reg_enum_key(struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *hnd, int key_index, fstring key_name, - uint32 *unk_1, uint32 *unk_2, time_t *mod_time) + fstring class_name, time_t *mod_time) { - prs_struct rbuf; - prs_struct qbuf; - REG_Q_ENUM_KEY q_o; - REG_R_ENUM_KEY r_o; - WERROR result = WERR_GENERAL_FAILURE; - - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); + REG_Q_ENUM_KEY in; + REG_R_ENUM_KEY out; + prs_struct qbuf, rbuf; - /* Marshall data and send request */ - - init_reg_q_enum_key(&q_o, hnd, key_index); + ZERO_STRUCT (in); + ZERO_STRUCT (out); + + init_reg_q_enum_key(&in, hnd, key_index); - if (!reg_io_q_enum_key("", &q_o, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_ENUM_KEY, &qbuf, &rbuf)) - goto done; + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_ENUM_KEY, + in, out, + qbuf, rbuf, + reg_io_q_enum_key, + reg_io_r_enum_key, + WERR_GENERAL_FAILURE ); - ZERO_STRUCT(r_o); + if ( !W_ERROR_IS_OK(out.status) ) + return out.status; - /* Unmarshall response */ + if ( out.keyname.string ) + rpcstr_pull( key_name, out.keyname.string->buffer, sizeof(fstring), -1, STR_TERMINATE ); + else + fstrcpy( key_name, "(Default)" ); - if (!reg_io_r_enum_key("", &r_o, &rbuf, 0)) - goto done; + if ( out.classname && out.classname->string ) + rpcstr_pull( class_name, out.classname->string->buffer, sizeof(fstring), -1, STR_TERMINATE ); + else + fstrcpy( class_name, "" ); - result = r_o.status; - if (NT_STATUS_IS_OK(result)) { - (*unk_1) = r_o.unknown_1; - (*unk_2) = r_o.unknown_2; - unistr3_to_ascii(key_name, &r_o.key_name, - sizeof(fstring)-1); - (*mod_time) = nt_time_to_unix(&r_o.time); - } + *mod_time = nt_time_to_unix(out.time); -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); - - return result; + return out.status; } /**************************************************************************** @@ -655,162 +527,173 @@ WERROR cli_reg_set_val(struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *hnd, char *val_name, uint32 type, RPC_DATA_BLOB *data) { - prs_struct rbuf; - prs_struct qbuf; - REG_Q_SET_VALUE q_o; - REG_R_SET_VALUE r_o; - WERROR result = WERR_GENERAL_FAILURE; - - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); + REG_Q_SET_VALUE in; + REG_R_SET_VALUE out; + prs_struct qbuf, rbuf; - /* Marshall data and send request */ - - init_reg_q_set_val(&q_o, hnd, val_name, type, data); - - if (!reg_io_q_set_val("", &q_o, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_SET_VALUE, &qbuf, &rbuf)) - goto done; - - ZERO_STRUCT(r_o); - - /* Unmarshal response */ - - if (reg_io_r_set_val("", &r_o, &rbuf, 0)) - result = r_o.status; + ZERO_STRUCT (in); + ZERO_STRUCT (out); + + init_reg_q_set_val(&in, hnd, val_name, type, data); -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_SET_VALUE, + in, out, + qbuf, rbuf, + reg_io_q_set_val, + reg_io_r_set_val, + WERR_GENERAL_FAILURE ); - return result; + return out.status; } /**************************************************************************** do a REG Enum Value ****************************************************************************/ WERROR cli_reg_enum_val(struct cli_state *cli, TALLOC_CTX *mem_ctx, - POLICY_HND *hnd, int val_index, int max_valnamelen, - int max_valbufsize, fstring val_name, - uint32 *val_type, REGVAL_BUFFER *value) + POLICY_HND *hnd, int idx, + fstring val_name, uint32 *type, REGVAL_BUFFER *value) { - prs_struct rbuf; - prs_struct qbuf; - REG_Q_ENUM_VALUE q_o; - REG_R_ENUM_VALUE r_o; - WERROR result = WERR_GENERAL_FAILURE; + REG_Q_ENUM_VALUE in; + REG_R_ENUM_VALUE out; + prs_struct qbuf, rbuf; - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); - - /* Marshall data and send request */ + ZERO_STRUCT (in); + ZERO_STRUCT (out); + + init_reg_q_enum_val(&in, hnd, idx, 0x0100, 0x1000); - init_reg_q_enum_val(&q_o, hnd, val_index, val_name, max_valbufsize); + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_ENUM_VALUE, + in, out, + qbuf, rbuf, + reg_io_q_enum_val, + reg_io_r_enum_val, + WERR_GENERAL_FAILURE ); - if (!reg_io_q_enum_val("", &q_o, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_ENUM_VALUE, &qbuf, &rbuf)) - goto done; + if ( W_ERROR_EQUAL(out.status, WERR_MORE_DATA) ) { - ZERO_STRUCT(r_o); + ZERO_STRUCT (in); - /* Unmarshall response */ + init_reg_q_enum_val(&in, hnd, idx, 0x0100, *out.buffer_len1); - if (!reg_io_r_enum_val("", &r_o, &rbuf, 0)) - goto done; + ZERO_STRUCT (out); - result = r_o.status; - if (NT_STATUS_IS_OK(result) || - NT_STATUS_EQUAL(result, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - (*val_type) = *r_o.type; - unistr2_to_ascii(val_name, r_o.name.string, sizeof(fstring)-1); - *value = *r_o.value; + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_ENUM_VALUE, + in, out, + qbuf, rbuf, + reg_io_q_enum_val, + reg_io_r_enum_val, + WERR_GENERAL_FAILURE ); } -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); + if ( !W_ERROR_IS_OK(out.status) ) + return out.status; - return result; + unistr2_to_ascii(val_name, out.name.string, sizeof(fstring)-1); + *type = *out.type; + *value = *out.value; + + return out.status; } /**************************************************************************** -do a REG Open Key ****************************************************************************/ + WERROR cli_reg_open_entry(struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *hnd, char *key_name, uint32 access_desired, POLICY_HND *key_hnd) { - prs_struct rbuf; - prs_struct qbuf; - REG_Q_OPEN_ENTRY q_o; - REG_R_OPEN_ENTRY r_o; - WERROR result = WERR_GENERAL_FAILURE; - - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); + REG_Q_OPEN_ENTRY in; + REG_R_OPEN_ENTRY out; + prs_struct qbuf, rbuf; - /* Marshall data and send request */ - - init_reg_q_open_entry(&q_o, hnd, key_name, access_desired); - - /* turn parameters into data stream */ - if (!reg_io_q_open_entry("", &q_o, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_OPEN_ENTRY, &qbuf, &rbuf)) - goto done; - - ZERO_STRUCT(r_o); - - /* Unmarsall response */ - - if (!reg_io_r_open_entry("", &r_o, &rbuf, 0)) - goto done; + ZERO_STRUCT (in); + ZERO_STRUCT (out); + + init_reg_q_open_entry(&in, hnd, key_name, access_desired); - result = r_o.status; - if (NT_STATUS_IS_OK(result)) - *key_hnd = r_o.pol; + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_OPEN_ENTRY, + in, out, + qbuf, rbuf, + reg_io_q_open_entry, + reg_io_r_open_entry, + WERR_GENERAL_FAILURE ); -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); + if ( !W_ERROR_IS_OK( out.status ) ) + return out.status; - return result; + memcpy( key_hnd, &out.pol, sizeof(POLICY_HND) ); + + return out.status; } /**************************************************************************** -do a REG Close ****************************************************************************/ + WERROR cli_reg_close(struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *hnd) { - prs_struct rbuf; - prs_struct qbuf; - REG_Q_CLOSE q_c; - REG_R_CLOSE r_c; - WERROR result = WERR_GENERAL_FAILURE; - - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - prs_init(&rbuf, 0, mem_ctx, UNMARSHALL); + REG_Q_CLOSE in; + REG_R_CLOSE out; + prs_struct qbuf, rbuf; - /* Marshall data and send request */ - - init_reg_q_close(&q_c, hnd); + ZERO_STRUCT (in); + ZERO_STRUCT (out); + + init_reg_q_close(&in, hnd); + + CLI_DO_RPC( cli, mem_ctx, PI_WINREG, REG_CLOSE, + in, out, + qbuf, rbuf, + reg_io_q_close, + reg_io_r_close, + WERR_GENERAL_FAILURE ); + + return out.status; +} - if (!reg_io_q_close("", &q_c, &qbuf, 0) || - !rpc_api_pipe_req(cli, PI_WINREG, REG_CLOSE, &qbuf, &rbuf)) - goto done; - ZERO_STRUCT(r_c); +/* + ################################################################# + Utility functions + ################################################################# + */ - /* Unmarshall response */ +/***************************************************************** + Splits out the start of the key (HKLM or HKU) and the rest of the key. +*****************************************************************/ - if (reg_io_r_close("", &r_c, &rbuf, 0)) - result = r_c.status; +BOOL reg_split_hive(const char *full_keyname, uint32 *reg_type, pstring key_name) +{ + pstring tmp; + + if (!next_token(&full_keyname, tmp, "\\", sizeof(tmp))) + return False; + + (*reg_type) = 0; + + DEBUG(10, ("reg_split_key: hive %s\n", tmp)); + + if (strequal(tmp, "HKLM") || strequal(tmp, "HKEY_LOCAL_MACHINE")) + (*reg_type) = HKEY_LOCAL_MACHINE; + else if (strequal(tmp, "HKCR") || strequal(tmp, "HKEY_CLASSES_ROOT")) + (*reg_type) = HKEY_CLASSES_ROOT; + else if (strequal(tmp, "HKU") || strequal(tmp, "HKEY_USERS")) + (*reg_type) = HKEY_USERS; + else if (strequal(tmp, "HKPD")||strequal(tmp, "HKEY_PERFORMANCE_DATA")) + (*reg_type) = HKEY_PERFORMANCE_DATA; + else { + DEBUG(10,("reg_split_key: unrecognised hive key %s\n", tmp)); + return False; + } + + if (next_token(&full_keyname, tmp, "\n\r", sizeof(tmp))) + pstrcpy(key_name, tmp); + else + key_name[0] = 0; -done: - prs_mem_free(&rbuf); - prs_mem_free(&qbuf); + DEBUG(10, ("reg_split_key: name %s\n", key_name)); - return result; + return True; } diff --git a/source3/rpc_parse/parse_misc.c b/source3/rpc_parse/parse_misc.c index faa00d1862..ccb3e75ac8 100644 --- a/source3/rpc_parse/parse_misc.c +++ b/source3/rpc_parse/parse_misc.c @@ -132,6 +132,15 @@ BOOL smb_io_time(const char *desc, NTTIME *nttime, prs_struct *ps, int depth) return True; } +/******************************************************************* + Reads or writes an NTTIME structure. +********************************************************************/ + +BOOL smb_io_nttime(const char *desc, prs_struct *ps, int depth, NTTIME *nttime) +{ + return smb_io_time( desc, nttime, ps, depth ); +} + /******************************************************************* Gets an enumeration handle from an ENUM_HND structure. ********************************************************************/ @@ -680,7 +689,7 @@ BOOL smb_io_regval_buffer(const char *desc, prs_struct *ps, int depth, REGVAL_BU if(!prs_align(ps)) return False; - if(!prs_uint32("uni_max_len", ps, depth, &buf2->buf_max_len)) + if(!prs_uint32("buf_max_len", ps, depth, &buf2->buf_max_len)) return False; if(!prs_uint32("offset ", ps, depth, &buf2->offset)) return False; @@ -1081,6 +1090,9 @@ BOOL smb_io_unistr2(const char *desc, UNISTR2 *uni2, uint32 buffer, prs_struct * BOOL prs_unistr4(const char *desc, prs_struct *ps, int depth, UNISTR4 *uni4) { + prs_debug(ps, depth, desc, "prs_unistr4"); + depth++; + if ( !prs_uint16("length", ps, depth, &uni4->length )) return False; if ( !prs_uint16("size", ps, depth, &uni4->size )) @@ -1728,6 +1740,11 @@ BOOL smb_io_unistr3(const char *desc, UNISTR3 *name, prs_struct *ps, int depth) if(!prs_uint32("uni_str_len", ps, depth, &name->uni_str_len)) return False; + + /* we're done if there is no string */ + + if ( name->uni_str_len == 0 ) + return True; /* don't know if len is specified by uni_str_len member... */ /* assume unicode string is unicode-null-terminated, instead */ @@ -1738,7 +1755,6 @@ BOOL smb_io_unistr3(const char *desc, UNISTR3 *name, prs_struct *ps, int depth) return True; } - /******************************************************************* Stream a uint64_struct ********************************************************************/ diff --git a/source3/rpc_parse/parse_reg.c b/source3/rpc_parse/parse_reg.c index a51b4269e3..ce23d15a11 100644 --- a/source3/rpc_parse/parse_reg.c +++ b/source3/rpc_parse/parse_reg.c @@ -75,6 +75,8 @@ BOOL reg_io_q_open_hive(const char *desc, REG_Q_OPEN_HIVE *q_u, if(!prs_pointer("server", ps, depth, (void**)&q_u->server, sizeof(uint16), (PRS_POINTER_CAST)prs_uint16)) return False; + if(!prs_align(ps)) + return False; if(!prs_uint32("access", ps, depth, &q_u->access)) return False; @@ -1056,8 +1058,8 @@ makes a structure. ********************************************************************/ void init_reg_q_enum_val(REG_Q_ENUM_VALUE *q_u, POLICY_HND *pol, - uint32 val_idx, char *name, - uint32 max_buf_len) + uint32 val_idx, + uint32 max_name_len, uint32 max_buf_len) { ZERO_STRUCTP(q_u); @@ -1065,19 +1067,21 @@ void init_reg_q_enum_val(REG_Q_ENUM_VALUE *q_u, POLICY_HND *pol, q_u->val_index = val_idx; - init_unistr4( &q_u->name, name, UNI_STR_TERMINATE ); + q_u->name.size = max_name_len*2; + q_u->name.string = TALLOC_ZERO_P( get_talloc_ctx(), UNISTR2 ); + q_u->name.string->uni_max_len = max_name_len; q_u->type = TALLOC_P( get_talloc_ctx(), uint32 ); *q_u->type = 0x0; - q_u->value = TALLOC_P( get_talloc_ctx(), REGVAL_BUFFER ); + q_u->value = TALLOC_ZERO_P( get_talloc_ctx(), REGVAL_BUFFER ); q_u->value->buf_max_len = max_buf_len; - q_u->len_value1 = TALLOC_P( get_talloc_ctx(), uint32 ); - *q_u->len_value1 = max_buf_len; + q_u->buffer_len = TALLOC_P( get_talloc_ctx(), uint32 ); + *q_u->buffer_len = max_buf_len; - q_u->len_value2 = TALLOC_P( get_talloc_ctx(), uint32 ); - *q_u->len_value2 = max_buf_len; + q_u->name_len = TALLOC_P( get_talloc_ctx(), uint32 ); + *q_u->name_len = 0x0; } /******************************************************************* @@ -1088,8 +1092,6 @@ void init_reg_r_enum_val(REG_R_ENUM_VALUE *r_u, REGISTRY_VALUE *val ) { uint32 real_size; - DEBUG(8,("init_reg_r_enum_val: Enter\n")); - ZERO_STRUCTP(r_u); /* value name */ @@ -1110,13 +1112,10 @@ void init_reg_r_enum_val(REG_R_ENUM_VALUE *r_u, REGISTRY_VALUE *val ) /* lengths */ - r_u->len_value1 = TALLOC_P( get_talloc_ctx(), uint32 ); - *r_u->len_value1 = real_size; - - r_u->len_value2 = TALLOC_P( get_talloc_ctx(), uint32 ); - *r_u->len_value2 = real_size; - - DEBUG(8,("init_reg_r_enum_val: Exit\n")); + r_u->buffer_len1 = TALLOC_P( get_talloc_ctx(), uint32 ); + *r_u->buffer_len1 = real_size; + r_u->buffer_len2 = TALLOC_P( get_talloc_ctx(), uint32 ); + *r_u->buffer_len2 = real_size; } /******************************************************************* @@ -1153,9 +1152,9 @@ BOOL reg_io_q_enum_val(const char *desc, REG_Q_ENUM_VALUE *q_u, prs_struct *ps, if(!prs_align(ps)) return False; - if(!prs_pointer("len_value1", ps, depth, (void**)&q_u->len_value1, sizeof(uint32), (PRS_POINTER_CAST)prs_uint32)) + if(!prs_pointer("buffer_len", ps, depth, (void**)&q_u->buffer_len, sizeof(uint32), (PRS_POINTER_CAST)prs_uint32)) return False; - if(!prs_pointer("len_value2", ps, depth, (void**)&q_u->len_value2, sizeof(uint32), (PRS_POINTER_CAST)prs_uint32)) + if(!prs_pointer("name_len", ps, depth, (void**)&q_u->name_len, sizeof(uint32), (PRS_POINTER_CAST)prs_uint32)) return False; return True; @@ -1189,12 +1188,11 @@ BOOL reg_io_r_enum_val(const char *desc, REG_R_ENUM_VALUE *r_u, prs_struct *ps, if(!prs_align(ps)) return False; - if(!prs_pointer("len_value1", ps, depth, (void**)&r_u->len_value1, sizeof(uint32), (PRS_POINTER_CAST)prs_uint32)) + if(!prs_pointer("buffer_len1", ps, depth, (void**)&r_u->buffer_len1, sizeof(uint32), (PRS_POINTER_CAST)prs_uint32)) return False; - if(!prs_pointer("len_value2", ps, depth, (void**)&r_u->len_value2, sizeof(uint32), (PRS_POINTER_CAST)prs_uint32)) + if(!prs_pointer("buffer_len2", ps, depth, (void**)&r_u->buffer_len2, sizeof(uint32), (PRS_POINTER_CAST)prs_uint32)) return False; - if(!prs_werror("status", ps, depth, &r_u->status)) return False; @@ -1305,23 +1303,14 @@ void init_reg_q_enum_key(REG_Q_ENUM_KEY *q_u, POLICY_HND *pol, uint32 key_idx) makes a reply structure. ********************************************************************/ -void init_reg_r_enum_key(REG_R_ENUM_KEY *r_u, char *subkey, uint32 unknown_1, - uint32 unknown_2) +void init_reg_r_enum_key(REG_R_ENUM_KEY *r_u, char *subkey ) { if ( !r_u ) return; - r_u->unknown_1 = unknown_1; - r_u->unknown_2 = unknown_2; - r_u->unknown_3 = 0x0; - - r_u->key_name_len = (strlen(subkey)+1) * 2; - if (r_u->key_name_len) - r_u->ptr1 = 0x1; - init_unistr3( &r_u->key_name, subkey ); - - r_u->ptr2 = 0x1; - r_u->ptr3 = 0x1; + init_unistr4( &r_u->keyname, subkey, STR_TERMINATE ); + r_u->classname = TALLOC_ZERO_P( get_talloc_ctx(), UNISTR4 ); + r_u->time = TALLOC_ZERO_P( get_talloc_ctx(), NTTIME ); } /******************************************************************* @@ -1392,42 +1381,21 @@ BOOL reg_io_r_enum_key(const char *desc, REG_R_ENUM_KEY *q_u, prs_struct *ps, i if(!prs_align(ps)) return False; + if ( !prs_unistr4( "keyname", ps, depth, &q_u->keyname ) ) + return False; - if(!prs_uint16("key_name_len", ps, depth, &q_u->key_name_len)) + if(!prs_align(ps)) return False; - if(!prs_uint16("unknown_1", ps, depth, &q_u->unknown_1)) + if (!prs_pointer("class", ps, depth, (void**)&q_u->classname, sizeof(UNISTR4), (PRS_POINTER_CAST)prs_unistr4)) return False; - if(!prs_uint32("ptr1", ps, depth, &q_u->ptr1)) + if(!prs_align(ps)) return False; - - if (q_u->ptr1 != 0) { - if(!prs_uint32("unknown_2", ps, depth, &q_u->unknown_2)) - return False; - if(!prs_uint32("unknown_3", ps, depth, &q_u->unknown_3)) - return False; - if(!smb_io_unistr3("key_name", &q_u->key_name, ps, depth)) - return False; - if(!prs_align(ps)) - return False; - } - - if(!prs_uint32("ptr2", ps, depth, &q_u->ptr2)) + if (!prs_pointer("time", ps, depth, (void**)&q_u->time, sizeof(NTTIME), (PRS_POINTER_CAST)smb_io_nttime)) return False; - if (q_u->ptr2 != 0) { - if(!prs_uint8s(False, "pad2", ps, depth, q_u->pad2, sizeof(q_u->pad2))) - return False; - } - - if(!prs_uint32("ptr3", ps, depth, &q_u->ptr3)) + if(!prs_align(ps)) return False; - - if (q_u->ptr3 != 0) { - if(!smb_io_time("", &q_u->time, ps, depth)) - return False; - } - if(!prs_werror("status", ps, depth, &q_u->status)) return False; diff --git a/source3/rpc_server/srv_reg_nt.c b/source3/rpc_server/srv_reg_nt.c index f031a3213f..4211e9b9f4 100644 --- a/source3/rpc_server/srv_reg_nt.c +++ b/source3/rpc_server/srv_reg_nt.c @@ -25,6 +25,7 @@ /* Implementation of registry functions. */ #include "includes.h" +#include "regfio.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_SRV @@ -38,6 +39,10 @@ ((unsigned int)IVAL((hnd)->data5,4)),((unsigned int)sys_getpid()) +/* no idea if this is correct, just use the file access bits for now */ + +struct generic_mapping reg_map = { REG_KEY_READ, REG_KEY_WRITE, REG_KEY_EXECUTE, REG_KEY_ALL }; + static REGISTRY_KEY *regkeys_list; @@ -534,7 +539,7 @@ WERROR _reg_enum_key(pipes_struct *p, REG_Q_ENUM_KEY *q_u, REG_R_ENUM_KEY *r_u) /* subkey has the string name now */ - init_reg_r_enum_key( r_u, subkey, q_u->unknown_1, q_u->unknown_2 ); + init_reg_r_enum_key( r_u, subkey ); DEBUG(5,("_reg_enum_key: Exit\n")); @@ -625,6 +630,7 @@ WERROR _reg_shutdown_ex(pipes_struct *p, REG_Q_SHUTDOWN_EX *q_u, REG_R_SHUTDOWN_ int ret; BOOL can_shutdown; + pstrcpy(shutdown_script, lp_shutdown_script()); if ( !*shutdown_script ) @@ -635,7 +641,7 @@ WERROR _reg_shutdown_ex(pipes_struct *p, REG_Q_SHUTDOWN_EX *q_u, REG_R_SHUTDOWN_ pstrcpy( message, "" ); if ( q_u->message ) { UNISTR2 *msg_string = q_u->message->string; - + rpcstr_pull( message, msg_string->buffer, sizeof(message), msg_string->uni_str_len*2, 0 ); } alpha_strcpy (chkmsg, message, NULL, sizeof(message)); @@ -650,7 +656,7 @@ WERROR _reg_shutdown_ex(pipes_struct *p, REG_Q_SHUTDOWN_EX *q_u, REG_R_SHUTDOWN_ all_string_sub( shutdown_script, "%r", r, sizeof(shutdown_script) ); all_string_sub( shutdown_script, "%f", f, sizeof(shutdown_script) ); all_string_sub( shutdown_script, "%x", reason, sizeof(shutdown_script) ); - + can_shutdown = user_has_privileges( p->pipe_user.nt_user_token, &se_remote_shutdown ); /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root @@ -667,7 +673,7 @@ WERROR _reg_shutdown_ex(pipes_struct *p, REG_Q_SHUTDOWN_EX *q_u, REG_R_SHUTDOWN_ unbecome_root(); /********** END SeRemoteShutdownPrivilege BLOCK **********/ - + DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n", shutdown_script, ret)); @@ -714,6 +720,48 @@ WERROR _reg_abort_shutdown(pipes_struct *p, REG_Q_ABORT_SHUTDOWN *q_u, REG_R_ABO return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED; } +/******************************************************************* + ********************************************************************/ + +static int validate_reg_filename( pstring fname ) +{ + char *p; + int num_services = lp_numservices(); + int snum; + pstring share_path; + pstring unix_fname; + + /* convert to a unix path, stripping the C:\ along the way */ + + if ( !(p = valid_share_pathname( fname ) )) + return -1; + + /* has to exist within a valid file share */ + + for ( snum=0; snumpol ); pstring filename; + int snum; DEBUG(5,("_reg_restore_key: Enter\n")); - /* - * basically this is a no op function which just verifies - * that the client gave us a valid registry key handle - */ - if ( !regkey ) return WERR_BADFID; @@ -736,14 +780,169 @@ WERROR _reg_restore_key(pipes_struct *p, REG_Q_RESTORE_KEY *q_u, REG_R_RESTORE_ DEBUG(8,("_reg_restore_key: verifying restore of key [%s] from \"%s\"\n", regkey->name, filename)); + if ( (snum = validate_reg_filename( filename )) == -1 ) + return WERR_OBJECT_PATH_INVALID; + + DEBUG(2,("_reg_restore_key: Restoring [%s] from %s in share %s\n", regkey->name, filename, lp_servicename(snum) )); + #if 0 - validate_reg_filemame( filename ); return restore_registry_key( regkey, filename ); #endif return WERR_OK; } +/******************************************************************** +********************************************************************/ + +static WERROR reg_write_tree( REGF_FILE *regfile, const char *keypath, + REGF_NK_REC *parent, SEC_DESC *sec_desc ) +{ + REGF_NK_REC *key; + REGVAL_CTR values; + REGSUBKEY_CTR subkeys; + int i, num_subkeys; + pstring key_tmp; + char *keyname, *parentpath; + pstring subkeypath; + char *subkeyname; + REGISTRY_KEY registry_key; + WERROR result = WERR_OK; + + if ( !regfile ) + return WERR_GENERAL_FAILURE; + + if ( !keypath ) + return WERR_OBJECT_PATH_INVALID; + + /* split up the registry key path */ + + pstrcpy( key_tmp, keypath ); + if ( !reg_split_key( key_tmp, &parentpath, &keyname ) ) + return WERR_OBJECT_PATH_INVALID; + + if ( !keyname ) + keyname = parentpath; + + /* we need a REGISTRY_KEY object here to enumerate subkeys and values */ + + ZERO_STRUCT( registry_key ); + pstrcpy( registry_key.name, keypath ); + if ( !(registry_key.hook = reghook_cache_find( registry_key.name )) ) + return WERR_BADFILE; + + + /* lookup the values and subkeys */ + + ZERO_STRUCT( values ); + ZERO_STRUCT( subkeys ); + + regsubkey_ctr_init( &subkeys ); + regval_ctr_init( &values ); + + fetch_reg_keys( ®istry_key, &subkeys ); + fetch_reg_values( ®istry_key, &values ); + + /* write out this key */ + + if ( !(key = regfio_write_key( regfile, keyname, &values, &subkeys, sec_desc, parent )) ) { + result = WERR_CAN_NOT_COMPLETE; + goto done; + } + + /* write each one of the subkeys out */ + + num_subkeys = regsubkey_ctr_numkeys( &subkeys ); + for ( i=0; imem_ctx, &sd )) ) { + regfio_close( regfile ); + return result; + } + + /* write the registry tree to the file */ + + result = reg_write_tree( regfile, krecord->name, NULL, sd ); + + /* cleanup */ + + regfio_close( regfile ); + + return result; +} + /******************************************************************* ********************************************************************/ @@ -751,25 +950,23 @@ WERROR _reg_save_key(pipes_struct *p, REG_Q_SAVE_KEY *q_u, REG_R_SAVE_KEY *r_u) { REGISTRY_KEY *regkey = find_regkey_index_by_hnd( p, &q_u->pol ); pstring filename; + int snum; DEBUG(5,("_reg_save_key: Enter\n")); - - /* - * basically this is a no op function which just verifies - * that the client gave us a valid registry key handle - */ - + if ( !regkey ) return WERR_BADFID; rpcstr_pull(filename, q_u->filename.string->buffer, sizeof(filename), q_u->filename.string->uni_str_len*2, STR_TERMINATE); DEBUG(8,("_reg_save_key: verifying backup of key [%s] to \"%s\"\n", regkey->name, filename)); - -#if 0 - validate_reg_filemame( filename ); + + if ( (snum = validate_reg_filename( filename )) == -1 ) + return WERR_OBJECT_PATH_INVALID; + + DEBUG(2,("_reg_save_key: Saving [%s] to %s in share %s\n", regkey->name, filename, lp_servicename(snum) )); + return backup_registry_key( regkey, filename ); -#endif return WERR_OK; } diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c index b7091b2ade..2fee1972ab 100644 --- a/source3/rpc_server/srv_spoolss_nt.c +++ b/source3/rpc_server/srv_spoolss_nt.c @@ -2353,9 +2353,8 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint *type = REG_BINARY; *needed = 0x114; - if((*data = (uint8 *)TALLOC(ctx, *needed)) == NULL) + if ( !(*data = TALLOC_ZERO_ARRAY(ctx, uint8, *needed)) ) return WERR_NOMEM; - ZERO_STRUCTP( *data ); SIVAL(*data, 0, *needed); /* size */ SIVAL(*data, 4, 5); /* Windows 2000 == 5.0 */ @@ -7249,16 +7248,11 @@ static void fill_port_2(PORT_INFO_2 *port, const char *name) } /**************************************************************************** - enumports level 1. + wrapper around the enumer ports command ****************************************************************************/ -static WERROR enumports_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned) +WERROR enumports_hook( int *count, char ***lines ) { - PORT_INFO_1 *ports=NULL; - int i=0; - WERROR result = WERR_OK; - - if (*lp_enumports_cmd()) { char *cmd = lp_enumports_cmd(); char **qlines; pstring command; @@ -7266,6 +7260,18 @@ static WERROR enumports_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *need int ret; int fd; + + /* if no hook then just fill in the default port */ + + if ( !*cmd ) { + qlines = SMB_MALLOC_ARRAY( char*, 2 ); + qlines[0] = SMB_STRDUP( SAMBA_PRINTER_PORT_NAME ); + qlines[1] = NULL; + numlines = 1; + } + else { + /* we have a valid enumport command */ + slprintf(command, sizeof(command)-1, "%s \"%d\"", cmd, 1); DEBUG(10,("Running [%s]\n", command)); @@ -7274,7 +7280,7 @@ static WERROR enumports_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *need if (ret != 0) { if (fd != -1) close(fd); - /* Is this the best error to return here? */ + return WERR_ACCESS_DENIED; } @@ -7282,6 +7288,28 @@ static WERROR enumports_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *need qlines = fd_lines_load(fd, &numlines); DEBUGADD(10,("Lines returned = [%d]\n", numlines)); close(fd); + } + + *count = numlines; + *lines = qlines; + + return WERR_OK; +} + +/**************************************************************************** + enumports level 1. +****************************************************************************/ + +static WERROR enumports_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned) +{ + PORT_INFO_1 *ports=NULL; + int i=0; + WERROR result = WERR_OK; + char **qlines; + int numlines; + + if ( !W_ERROR_IS_OK(result = enumports_hook( &numlines, &qlines )) ) + return result; if(numlines) { if((ports=SMB_MALLOC_ARRAY( PORT_INFO_1, numlines )) == NULL) { @@ -7301,17 +7329,6 @@ static WERROR enumports_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *need *returned = numlines; - } else { - *returned = 1; /* Sole Samba port returned. */ - - if((ports=SMB_MALLOC_P(PORT_INFO_1)) == NULL) - return WERR_NOMEM; - - DEBUG(10,("enumports_level_1: port name %s\n", SAMBA_PRINTER_PORT_NAME)); - - fill_port_1(&ports[0], SAMBA_PRINTER_PORT_NAME); - } - /* check the required size. */ for (i=0; i<*returned; i++) { DEBUGADD(6,("adding port [%d]'s size\n", i)); @@ -7352,40 +7369,12 @@ static WERROR enumports_level_2(RPC_BUFFER *buffer, uint32 offered, uint32 *need PORT_INFO_2 *ports=NULL; int i=0; WERROR result = WERR_OK; - - if (*lp_enumports_cmd()) { - char *cmd = lp_enumports_cmd(); - char *path; char **qlines; - pstring tmp_file; - pstring command; int numlines; - int ret; - int fd; - - if (*lp_pathname(lp_servicenumber(PRINTERS_NAME))) - path = lp_pathname(lp_servicenumber(PRINTERS_NAME)); - else - path = lp_lockdir(); - - slprintf(tmp_file, sizeof(tmp_file)-1, "%s/smbcmd.%u.", path, (unsigned int)sys_getpid()); - slprintf(command, sizeof(command)-1, "%s \"%d\"", cmd, 2); - unlink(tmp_file); - DEBUG(10,("Running [%s > %s]\n", command,tmp_file)); - ret = smbrun(command, &fd); - DEBUGADD(10,("returned [%d]\n", ret)); - if (ret != 0) { - if (fd != -1) - close(fd); - /* Is this the best error to return here? */ - return WERR_ACCESS_DENIED; - } + if ( !W_ERROR_IS_OK(result = enumports_hook( &numlines, &qlines )) ) + return result; - numlines = 0; - qlines = fd_lines_load(fd, &numlines); - DEBUGADD(10,("Lines returned = [%d]\n", numlines)); - close(fd); if(numlines) { if((ports=SMB_MALLOC_ARRAY( PORT_INFO_2, numlines)) == NULL) { @@ -7403,18 +7392,6 @@ static WERROR enumports_level_2(RPC_BUFFER *buffer, uint32 offered, uint32 *need *returned = numlines; - } else { - - *returned = 1; - - if((ports=SMB_MALLOC_P(PORT_INFO_2)) == NULL) - return WERR_NOMEM; - - DEBUG(10,("enumports_level_2: port name %s\n", SAMBA_PRINTER_PORT_NAME)); - - fill_port_2(&ports[0], SAMBA_PRINTER_PORT_NAME); - } - /* check the required size. */ for (i=0; i<*returned; i++) { DEBUGADD(6,("adding port [%d]'s size\n", i)); diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c index b5768a09af..0e699d922b 100644 --- a/source3/rpc_server/srv_srvsvc_nt.c +++ b/source3/rpc_server/srv_srvsvc_nt.c @@ -1480,7 +1480,7 @@ WERROR _srv_net_share_get_info(pipes_struct *p, SRV_Q_NET_SHARE_GET_INFO *q_u, S Check a given DOS pathname is valid for a share. ********************************************************************/ -static char *valid_share_pathname(char *dos_pathname) +char *valid_share_pathname(char *dos_pathname) { char *ptr; @@ -1493,7 +1493,7 @@ static char *valid_share_pathname(char *dos_pathname) if (strlen(dos_pathname) > 2 && ptr[1] == ':' && ptr[0] != '/') ptr += 2; - /* Only abolute paths allowed. */ + /* Only absolute paths allowed. */ if (*ptr != '/') return NULL; @@ -1525,8 +1525,12 @@ WERROR _srv_net_share_set_info(pipes_struct *p, SRV_Q_NET_SHARE_SET_INFO *q_u, S r_u->parm_error = 0; - if (strequal(share_name,"IPC$") || strequal(share_name,"ADMIN$") || strequal(share_name,"global")) + if ( strequal(share_name,"IPC$") + || ( lp_enable_asu_support() && strequal(share_name,"ADMIN$") ) + || strequal(share_name,"global") ) + { return WERR_ACCESS_DENIED; + } snum = find_service(share_name); @@ -1756,8 +1760,12 @@ WERROR _srv_net_share_add(pipes_struct *p, SRV_Q_NET_SHARE_ADD *q_u, SRV_R_NET_S return WERR_UNKNOWN_LEVEL; } - if (strequal(share_name,"IPC$") || strequal(share_name,"ADMIN$") || strequal(share_name,"global")) + if ( strequal(share_name,"IPC$") + || ( lp_enable_asu_support() && strequal(share_name,"ADMIN$") ) + || strequal(share_name,"global") ) + { return WERR_ACCESS_DENIED; + } snum = find_service(share_name); @@ -1839,8 +1847,12 @@ WERROR _srv_net_share_del(pipes_struct *p, SRV_Q_NET_SHARE_DEL *q_u, SRV_R_NET_S unistr2_to_ascii(share_name, &q_u->uni_share_name, sizeof(share_name)); - if (strequal(share_name,"IPC$") || strequal(share_name,"ADMIN$") || strequal(share_name,"global")) + if ( strequal(share_name,"IPC$") + || ( lp_enable_asu_support() && strequal(share_name,"ADMIN$") ) + || strequal(share_name,"global") ) + { return WERR_ACCESS_DENIED; + } snum = find_service(share_name); diff --git a/source3/utils/net_rpc_registry.c b/source3/utils/net_rpc_registry.c new file mode 100644 index 0000000000..53378fadef --- /dev/null +++ b/source3/utils/net_rpc_registry.c @@ -0,0 +1,495 @@ +/* + Samba Unix/Linux SMB client library + Distributed SMB/CIFS Server Management Utility + Copyright (C) Gerald (Jerry) Carter 2005 + + 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 "utils/net.h" +#include "regfio.h" +#include "reg_objects.h" + + +/******************************************************************** +********************************************************************/ + +char* dump_regval_type( uint32 type ) +{ + static fstring string; + + switch (type) { + case REG_SZ: + fstrcpy( string, "REG_SZ" ); + break; + case REG_MULTI_SZ: + fstrcpy( string, "REG_MULTI_SZ" ); + break; + case REG_EXPAND_SZ: + fstrcpy( string, "REG_EXPAND_SZ" ); + break; + case REG_DWORD: + fstrcpy( string, "REG_DWORD" ); + break; + case REG_BINARY: + fstrcpy( string, "REG_BINARY" ); + break; + default: + fstr_sprintf( string, "UNKNOWN [%d]", type ); + } + + return string; +} +/******************************************************************** +********************************************************************/ + +void dump_regval_buffer( uint32 type, REGVAL_BUFFER *buffer ) +{ + pstring string; + uint32 value; + + switch (type) { + case REG_SZ: + rpcstr_pull( string, buffer->buffer, sizeof(string), -1, STR_TERMINATE ); + d_printf("%s\n", string); + break; + case REG_MULTI_SZ: + d_printf("\n"); + break; + case REG_DWORD: + value = IVAL( buffer->buffer, 0 ); + d_printf( "0x%x\n", value ); + break; + case REG_BINARY: + d_printf("\n"); + break; + + + default: + d_printf( "\tUnknown type [%d]\n", type ); + } +} + +/******************************************************************** +********************************************************************/ + +static NTSTATUS rpc_registry_enumerate_internal( const DOM_SID *domain_sid, const char *domain_name, + struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv ) +{ + WERROR result = WERR_GENERAL_FAILURE; + uint32 hive; + pstring subpath; + POLICY_HND pol_hive, pol_key; + uint32 idx; + + if (argc != 1 ) { + d_printf("Usage: net rpc enumerate [recurse]\n"); + d_printf("Example:: net rpc enumerate 'HKLM\\Software\\Samba'\n"); + return NT_STATUS_OK; + } + + if ( !reg_split_hive( argv[0], &hive, subpath ) ) { + d_printf("invalid registry path\n"); + return NT_STATUS_OK; + } + + /* open the top level hive and then the registry key */ + + result = cli_reg_connect( cli, mem_ctx, hive, MAXIMUM_ALLOWED_ACCESS, &pol_hive ); + if ( !W_ERROR_IS_OK(result) ) { + d_printf("Unable to connect to remote registry\n"); + return werror_to_ntstatus(result); + } + + result = cli_reg_open_entry( cli, mem_ctx, &pol_hive, subpath, MAXIMUM_ALLOWED_ACCESS, &pol_key ); + if ( !W_ERROR_IS_OK(result) ) { + d_printf("Unable to open [%s]\n", argv[0]); + return werror_to_ntstatus(result); + } + + /* get the subkeys */ + + result = WERR_OK; + idx = 0; + while ( W_ERROR_IS_OK(result) ) { + time_t modtime; + fstring keyname, classname; + + result = cli_reg_enum_key( cli, mem_ctx, &pol_key, idx, + keyname, classname, &modtime ); + + if ( W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS) ) { + result = WERR_OK; + break; + } + + d_printf("Keyname = %s\n", keyname ); + d_printf("Classname = %s\n", classname ); + d_printf("Modtime = %s\n", http_timestring(modtime) ); + d_printf("\n" ); + + idx++; + } + + if ( !W_ERROR_IS_OK(result) ) + goto out; + + /* get the values */ + + result = WERR_OK; + idx = 0; + while ( W_ERROR_IS_OK(result) ) { + uint32 type; + fstring name; + REGVAL_BUFFER value; + + fstrcpy( name, "" ); + ZERO_STRUCT( value ); + + result = cli_reg_enum_val( cli, mem_ctx, &pol_key, idx, + name, &type, &value ); + + if ( W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS) ) { + result = WERR_OK; + break; + } + + d_printf("Valuename = %s\n", name ); + d_printf("Type = %s\n", dump_regval_type(type) ); + d_printf("Data = " ); + dump_regval_buffer( type, &value ); + d_printf("\n" ); + + idx++; + } + + +out: + /* cleanup */ + + cli_reg_close( cli, mem_ctx, &pol_key ); + cli_reg_close( cli, mem_ctx, &pol_hive ); + + return werror_to_ntstatus(result); +} + +/******************************************************************** +********************************************************************/ + +static int rpc_registry_enumerate( int argc, const char **argv ) +{ + return run_rpc_command( NULL, PI_WINREG, 0, + rpc_registry_enumerate_internal, argc, argv ); +} + +/******************************************************************** +********************************************************************/ + +static NTSTATUS rpc_registry_backup_internal( const DOM_SID *domain_sid, const char *domain_name, + struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv ) +{ + WERROR result = WERR_GENERAL_FAILURE; + uint32 hive; + pstring subpath; + POLICY_HND pol_hive, pol_key; + REGF_FILE *regfile; + + if (argc != 2 ) { + d_printf("Usage: net rpc backup \n"); + return NT_STATUS_OK; + } + + if ( !reg_split_hive( argv[0], &hive, subpath ) ) { + d_printf("invalid registry path\n"); + return NT_STATUS_OK; + } + + /* open the top level hive and then the registry key */ + + result = cli_reg_connect( cli, mem_ctx, hive, MAXIMUM_ALLOWED_ACCESS, &pol_hive ); + if ( !W_ERROR_IS_OK(result) ) { + d_printf("Unable to connect to remote registry\n"); + return werror_to_ntstatus(result); + } + + result = cli_reg_open_entry( cli, mem_ctx, &pol_hive, subpath, MAXIMUM_ALLOWED_ACCESS, &pol_key ); + if ( !W_ERROR_IS_OK(result) ) { + d_printf("Unable to open [%s]\n", argv[0]); + return werror_to_ntstatus(result); + } + + /* open the file */ + + if ( !(regfile = regfio_open( argv[1], (O_RDWR|O_CREAT|O_TRUNC), 0600 )) ) { + d_printf("Unable to open registry file [%s]\n", argv[1]); + return werror_to_ntstatus(WERR_GENERAL_FAILURE); + } + + + /* cleanup */ + + regfio_close( regfile ); + cli_reg_close( cli, mem_ctx, &pol_key ); + cli_reg_close( cli, mem_ctx, &pol_hive ); + + return werror_to_ntstatus(result); +} + +/******************************************************************** +********************************************************************/ + +static int rpc_registry_backup( int argc, const char **argv ) +{ + return run_rpc_command( NULL, PI_WINREG, 0, + rpc_registry_backup_internal, argc, argv ); +} + + +/******************************************************************** +********************************************************************/ + +static void dump_values( REGF_NK_REC *nk ) +{ + int i, j; + pstring data_str; + uint32 data_size, data; + + if ( !nk->values ) + return; + + for ( i=0; inum_values; i++ ) { + d_printf( "\"%s\" = ", nk->values[i].valuename ? nk->values[i].valuename : "(default)" ); + d_printf( "(%s) ", dump_regval_type( nk->values[i].type ) ); + + data_size = nk->values[i].data_size & ~VK_DATA_IN_OFFSET; + switch ( nk->values[i].type ) { + case REG_SZ: + rpcstr_pull( data_str, nk->values[i].data, sizeof(data_str), -1, STR_TERMINATE ); + d_printf( "%s", data_str ); + break; + case REG_MULTI_SZ: + case REG_EXPAND_SZ: + for ( j=0; jvalues[i].data[j] ); + } + break; + case REG_DWORD: + data = IVAL( nk->values[i].data, 0 ); + d_printf("0x%x", data ); + break; + case REG_BINARY: + for ( j=0; jvalues[i].data[j] ); + } + break; + default: + d_printf("unknown"); + break; + } + + d_printf( "\n" ); + } + +} + +/******************************************************************** +********************************************************************/ + +static BOOL dump_registry_tree( REGF_FILE *file, REGF_NK_REC *nk, const char *parent ) +{ + REGF_NK_REC *key; + pstring regpath; + + /* depth first dump of the registry tree */ + + while ( (key = regfio_fetch_subkey( file, nk )) ) { + pstr_sprintf( regpath, "%s\\%s", parent, key->keyname ); + d_printf("[%s]\n", regpath ); + dump_values( key ); + d_printf("\n"); + dump_registry_tree( file, key, regpath ); + } + + return True; +} + +/******************************************************************** +********************************************************************/ + +static BOOL write_registry_tree( REGF_FILE *infile, REGF_NK_REC *nk, + REGF_NK_REC *parent, REGF_FILE *outfile, + const char *parentpath ) +{ + REGF_NK_REC *key, *subkey; + REGVAL_CTR values; + REGSUBKEY_CTR subkeys; + int i; + pstring path; + + ZERO_STRUCT( values ); + ZERO_STRUCT( subkeys ); + + regsubkey_ctr_init( &subkeys ); + regval_ctr_init( &values ); + + /* copy values into the REGVAL_CTR */ + + for ( i=0; inum_values; i++ ) { + regval_ctr_addvalue( &values, nk->values[i].valuename, nk->values[i].type, + nk->values[i].data, (nk->values[i].data_size & ~VK_DATA_IN_OFFSET) ); + } + + /* copy subkeys into the REGSUBKEY_CTR */ + + while ( (subkey = regfio_fetch_subkey( infile, nk )) ) { + regsubkey_ctr_addkey( &subkeys, subkey->keyname ); + } + + key = regfio_write_key( outfile, nk->keyname, &values, &subkeys, nk->sec_desc->sec_desc, parent ); + + /* write each one of the subkeys out */ + + pstr_sprintf( path, "%s%s%s", parentpath, parent ? "\\" : "", nk->keyname ); + nk->subkey_index = 0; + while ( (subkey = regfio_fetch_subkey( infile, nk )) ) { + write_registry_tree( infile, subkey, key, outfile, path ); + } + + regval_ctr_destroy( &values ); + regsubkey_ctr_destroy( &subkeys ); + + d_printf("[%s]\n", path ); + + return True; +} + +/******************************************************************** +********************************************************************/ + +static int rpc_registry_dump( int argc, const char **argv ) +{ + REGF_FILE *registry; + REGF_NK_REC *nk; + + if (argc != 1 ) { + d_printf("Usage: net rpc dump \n"); + return 0; + } + + d_printf("Opening %s....", argv[0]); + if ( !(registry = regfio_open( argv[0], O_RDONLY, 0)) ) { + d_printf("Failed to open %s for reading\n", argv[0]); + return 1; + } + d_printf("ok\n"); + + /* get the root of the registry file */ + + nk = regfio_rootkey( registry ); + d_printf("[%s]\n", nk->keyname); + dump_values( nk ); + d_printf("\n"); + + dump_registry_tree( registry, nk, nk->keyname ); + +#if 0 + talloc_report_full( registry->mem_ctx, stderr ); +#endif + d_printf("Closing registry..."); + regfio_close( registry ); + d_printf("ok\n"); + + return 0; +} + +/******************************************************************** +********************************************************************/ + +static int rpc_registry_copy( int argc, const char **argv ) +{ + REGF_FILE *infile, *outfile; + REGF_NK_REC *nk; + + if (argc != 2 ) { + d_printf("Usage: net rpc copy \n"); + return 0; + } + + d_printf("Opening %s....", argv[0]); + if ( !(infile = regfio_open( argv[0], O_RDONLY, 0 )) ) { + d_printf("Failed to open %s for reading\n", argv[0]); + return 1; + } + d_printf("ok\n"); + + d_printf("Opening %s....", argv[1]); + if ( !(outfile = regfio_open( argv[1], (O_RDWR|O_CREAT|O_TRUNC), (S_IREAD|S_IWRITE) )) ) { + d_printf("Failed to open %s for writing\n", argv[1]); + return 1; + } + d_printf("ok\n"); + + /* get the root of the registry file */ + + nk = regfio_rootkey( infile ); + d_printf("RootKey: [%s]\n", nk->keyname); + + write_registry_tree( infile, nk, NULL, outfile, "" ); + + d_printf("Closing %s...", argv[1]); + regfio_close( outfile ); + d_printf("ok\n"); + + d_printf("Closing %s...", argv[0]); + regfio_close( infile ); + d_printf("ok\n"); + + return 0; +} + +/******************************************************************** +********************************************************************/ + +static int net_help_registry( int argc, const char **argv ) +{ + d_printf("net rpc registry enumerate [recurse] Enumerate the subkeya and values for a given registry path\n"); + d_printf("net rpc registry backup Backup a registry tree to a local file\n"); + d_printf("net rpc registry dump Dump the contents of a registry file to stdout\n"); + + return -1; +} + +/******************************************************************** +********************************************************************/ + +int net_rpc_registry(int argc, const char **argv) +{ + struct functable func[] = { + {"enumerate", rpc_registry_enumerate}, + {"backup", rpc_registry_backup}, + {"dump", rpc_registry_dump}, + {"copy", rpc_registry_copy}, + {NULL, NULL} + }; + + if ( argc ) + return net_run_function( argc, argv, func, net_help_registry ); + + return net_help_registry( argc, argv ); +} + + diff --git a/source3/utils/testprns.c b/source3/utils/testprns.c deleted file mode 100644 index 5af40b06d1..0000000000 --- a/source3/utils/testprns.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - Unix SMB/CIFS implementation. - test printer setup - Copyright (C) Karl Auer 1993, 1994-1998 - - 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. -*/ - -/* - * Testbed for pcap.c - * - * This module simply checks a given printer name against the compiled-in - * printcap file. - * - * The operation is performed with DEBUGLEVEL at 3. - * - * Useful for a quick check of a printcap file. - * - */ - -#include "includes.h" - -/* - * NOTE: this code is likely to be removed, and no longer supports - * checking against non-configured printcap files. -Rob - */ - -int main(int argc, char *argv[]) -{ - setup_logging(argv[0],True); - - printf("NOTICE: This program is now deprecated and will be removed \n"); - printf("in a future Samba release.\n\n"); - - if (argc != 2) - printf("Usage: testprns printername\n"); - else - { - dbf = x_fopen("test.log", O_WRONLY|O_CREAT|O_TRUNC, 0644); - if (dbf == NULL) { - printf("Unable to open logfile.\n"); - } else { - DEBUGLEVEL = 3; - printf("Looking for printer %s\n", argv[1]); - load_printers(); - if (!pcap_printername_ok(argv[1])) - printf("Printer name %s is not valid.\n", argv[1]); - else - printf("Printer name %s is valid.\n", argv[1]); - x_fclose(dbf); - } - } - return (0); -} -- cgit