mirror of
https://github.com/samba-team/samba.git
synced 2025-01-14 19:24:43 +03:00
18d4176633
items in cac_winreg.c * Get 'net rpc registry enumerate' to list values again * Fix winreg.idl QueryInfoKey(). The max_subkeysize is the max_classlen (we previously had this correct in Samba3") * fix valgrind error about uninitialized memory and use-before-set on size value inmemset() call * Fix key enumeration in 'net rpc registry enumerate' * regenerate gen_dir files based on local pidl patches Please note that the generated ndr files are from my local copy of pidl. If you need to regenerate, please apply the patch that I posted to the samba-technical list earlier today. (This used to be commit 5d843612a1b9d92022f76626f1c7473faebec4ba)
596 lines
16 KiB
C
596 lines
16 KiB
C
/*
|
|
Samba Unix/Linux SMB client library
|
|
Distributed SMB/CIFS Server Management Utility
|
|
|
|
Copyright (C) Gerald (Jerry) Carter 2005-2006
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
|
#include "includes.h"
|
|
#include "utils/net.h"
|
|
#include "regfio.h"
|
|
#include "reg_objects.h"
|
|
|
|
/********************************************************************
|
|
********************************************************************/
|
|
|
|
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: {
|
|
int i, num_values;
|
|
char **values;
|
|
|
|
d_printf("\n");
|
|
|
|
if (!NT_STATUS_IS_OK(reg_pull_multi_sz(NULL, buffer->buffer,
|
|
buffer->buf_len,
|
|
&num_values,
|
|
&values))) {
|
|
d_printf("reg_pull_multi_sz failed\n");
|
|
break;
|
|
}
|
|
|
|
for (i=0; i<num_values; i++) {
|
|
d_printf("%s\n", values[i]);
|
|
}
|
|
TALLOC_FREE(values);
|
|
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,
|
|
struct rpc_pipe_client *pipe_hnd,
|
|
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;
|
|
NTSTATUS status;
|
|
struct winreg_String subkeyname;
|
|
struct winreg_String classname;
|
|
uint32 num_subkeys, max_subkeylen, max_classlen;
|
|
uint32 num_values, max_valnamelen, max_valbufsize;
|
|
uint32 secdescsize;
|
|
NTTIME last_changed_time;
|
|
struct winreg_StringBuf subkey_namebuf;
|
|
char *name_buffer;
|
|
uint8 *value_buffer;
|
|
|
|
if (argc != 1 ) {
|
|
d_printf("Usage: net rpc enumerate <path> [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_fprintf(stderr, "invalid registry path\n");
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
/* open the top level hive and then the registry key */
|
|
|
|
status = rpccli_winreg_Connect(pipe_hnd, mem_ctx, hive, MAXIMUM_ALLOWED_ACCESS, &pol_hive );
|
|
if ( !NT_STATUS_IS_OK(status) ) {
|
|
d_fprintf(stderr, "Unable to connect to remote registry: "
|
|
"%s\n", nt_errstr(status));
|
|
return status;
|
|
}
|
|
|
|
subkeyname.name = subpath;
|
|
status = rpccli_winreg_OpenKey(pipe_hnd, mem_ctx, &pol_hive, subkeyname,
|
|
0, MAXIMUM_ALLOWED_ACCESS, &pol_key );
|
|
if ( !NT_STATUS_IS_OK(status) ) {
|
|
d_fprintf(stderr, "Unable to open [%s]: %s\n", argv[0],
|
|
nt_errstr(status));
|
|
return werror_to_ntstatus(result);
|
|
}
|
|
|
|
classname.name = NULL;
|
|
status = rpccli_winreg_QueryInfoKey( pipe_hnd, mem_ctx, &pol_key,
|
|
&classname, &num_subkeys, &max_subkeylen,
|
|
&max_classlen, &num_values, &max_valnamelen,
|
|
&max_valbufsize, &secdescsize, &last_changed_time );
|
|
|
|
if ( !NT_STATUS_IS_OK(status) ) {
|
|
d_fprintf(stderr, "Unable to determine subkeys (%s)\n",
|
|
nt_errstr(status));
|
|
return status;
|
|
}
|
|
|
|
/* values do not include the terminating NULL */
|
|
|
|
max_subkeylen += 2;
|
|
max_valnamelen += 2;
|
|
|
|
if ( (name_buffer = TALLOC_ARRAY( mem_ctx, char, max_subkeylen )) == NULL ) {
|
|
d_fprintf(stderr, "Memory allocation error.\n");
|
|
return NT_STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* get the subkeys */
|
|
|
|
status = NT_STATUS_OK;
|
|
idx = 0;
|
|
while ( NT_STATUS_IS_OK(status) ) {
|
|
struct winreg_StringBuf class_namebuf;
|
|
fstring kname;
|
|
NTTIME modtime;
|
|
|
|
class_namebuf.name = NULL;
|
|
class_namebuf.size = 0;
|
|
class_namebuf.length = 0;
|
|
|
|
/* zero out each time */
|
|
|
|
subkey_namebuf.length = 0;
|
|
subkey_namebuf.size = max_subkeylen;
|
|
memset( name_buffer, 0x0, max_subkeylen );
|
|
subkey_namebuf.name = name_buffer;
|
|
|
|
status = rpccli_winreg_EnumKey(pipe_hnd, mem_ctx, &pol_key, idx,
|
|
&subkey_namebuf, &class_namebuf, &modtime);
|
|
|
|
if ( W_ERROR_EQUAL(ntstatus_to_werror(status), WERR_NO_MORE_ITEMS) ) {
|
|
status = NT_STATUS_OK;
|
|
break;
|
|
}
|
|
|
|
if ( !NT_STATUS_IS_OK(status) )
|
|
goto out;
|
|
|
|
StrnCpy( kname, subkey_namebuf.name, MIN(subkey_namebuf.length,sizeof(kname))-1 );
|
|
kname[MIN(subkey_namebuf.length,sizeof(kname))-1] = '\0';
|
|
d_printf("Keyname = %s\n", kname);
|
|
d_printf("Modtime = %s\n",
|
|
http_timestring(nt_time_to_unix(modtime)) );
|
|
d_printf("\n" );
|
|
|
|
idx++;
|
|
}
|
|
|
|
if ( !NT_STATUS_IS_OK(status) )
|
|
goto out;
|
|
|
|
/* TALLOC_FREE( name_buffer ); */
|
|
|
|
if ( (name_buffer = TALLOC_ARRAY( mem_ctx, char, max_valnamelen )) == NULL ) {
|
|
d_fprintf(stderr, "Memory allocation error.\n");
|
|
return NT_STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if ( (value_buffer = TALLOC_ARRAY( mem_ctx, uint8, max_valbufsize )) == NULL ) {
|
|
d_fprintf(stderr, "Memory allocation error.\n");
|
|
return NT_STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* get the values */
|
|
|
|
status = NT_STATUS_OK;
|
|
idx = 0;
|
|
while ( NT_STATUS_IS_OK(status) ) {
|
|
enum winreg_Type type;
|
|
fstring name;
|
|
uint8 *data;
|
|
uint32 data_size, value_length;
|
|
struct winreg_StringBuf value_namebuf;
|
|
REGVAL_BUFFER value;
|
|
|
|
fstrcpy( name, "" );
|
|
ZERO_STRUCT( value );
|
|
|
|
memset( name_buffer, 0x0, max_valnamelen );
|
|
value_namebuf.name = name_buffer;
|
|
value_namebuf.length = 0;
|
|
value_namebuf.size = max_valnamelen;
|
|
|
|
memset( value_buffer, 0x0, max_valbufsize );
|
|
data = value_buffer;
|
|
data_size = max_valbufsize;
|
|
value_length = 0;
|
|
|
|
status = rpccli_winreg_EnumValue(pipe_hnd, mem_ctx, &pol_key, idx,
|
|
&value_namebuf, &type, data, &data_size, &value_length );
|
|
|
|
if ( W_ERROR_EQUAL(ntstatus_to_werror(status), WERR_NO_MORE_ITEMS) ) {
|
|
status = NT_STATUS_OK;
|
|
break;
|
|
}
|
|
|
|
if ( !NT_STATUS_IS_OK(status) )
|
|
goto out;
|
|
|
|
init_regval_buffer( &value, data, value_length );
|
|
|
|
StrnCpy( name, value_namebuf.name, MIN(max_valnamelen, sizeof(name)-1) );
|
|
name[MIN(max_valnamelen, sizeof(name)-1)] = '\0';
|
|
|
|
d_printf("Valuename = %s\n", name );
|
|
d_printf("Type = %s\n", reg_type_lookup(type));
|
|
d_printf("Data = " );
|
|
dump_regval_buffer( type, &value );
|
|
d_printf("\n" );
|
|
|
|
idx++;
|
|
}
|
|
|
|
out:
|
|
/* cleanup */
|
|
|
|
if ( strlen( subpath ) != 0 )
|
|
rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_key );
|
|
rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_hive );
|
|
|
|
return status;
|
|
}
|
|
|
|
/********************************************************************
|
|
********************************************************************/
|
|
|
|
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_save_internal(const DOM_SID *domain_sid,
|
|
const char *domain_name,
|
|
struct cli_state *cli,
|
|
struct rpc_pipe_client *pipe_hnd,
|
|
TALLOC_CTX *mem_ctx,
|
|
int argc,
|
|
const char **argv )
|
|
{
|
|
WERROR result = WERR_GENERAL_FAILURE;
|
|
uint32 hive;
|
|
pstring subpath;
|
|
POLICY_HND pol_hive, pol_key;
|
|
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
|
|
struct winreg_String subkeyname;
|
|
struct winreg_String filename;
|
|
|
|
if (argc != 2 ) {
|
|
d_printf("Usage: net rpc backup <path> <file> \n");
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
if ( !reg_split_hive( argv[0], &hive, subpath ) ) {
|
|
d_fprintf(stderr, "invalid registry path\n");
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
/* open the top level hive and then the registry key */
|
|
|
|
status = rpccli_winreg_Connect(pipe_hnd, mem_ctx, hive, MAXIMUM_ALLOWED_ACCESS, &pol_hive );
|
|
if ( !NT_STATUS_IS_OK(status) ) {
|
|
d_fprintf(stderr, "Unable to connect to remote registry\n");
|
|
return status;
|
|
}
|
|
|
|
subkeyname.name = subpath;
|
|
status = rpccli_winreg_OpenKey(pipe_hnd, mem_ctx, &pol_hive, subkeyname,
|
|
0, MAXIMUM_ALLOWED_ACCESS, &pol_key );
|
|
if ( !NT_STATUS_IS_OK(status) ) {
|
|
d_fprintf(stderr, "Unable to open [%s]\n", argv[0]);
|
|
return werror_to_ntstatus(result);
|
|
}
|
|
|
|
filename.name = argv[1];
|
|
status = rpccli_winreg_SaveKey( pipe_hnd, mem_ctx, &pol_key, &filename, NULL );
|
|
if ( !W_ERROR_IS_OK(result) ) {
|
|
d_fprintf(stderr, "Unable to save [%s] to %s:%s\n", argv[0], cli->desthost, argv[1]);
|
|
}
|
|
|
|
/* cleanup */
|
|
|
|
rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_key );
|
|
rpccli_winreg_CloseKey(pipe_hnd, mem_ctx, &pol_hive );
|
|
|
|
return status;
|
|
}
|
|
|
|
/********************************************************************
|
|
********************************************************************/
|
|
|
|
static int rpc_registry_save( int argc, const char **argv )
|
|
{
|
|
return run_rpc_command( NULL, PI_WINREG, 0,
|
|
rpc_registry_save_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; i<nk->num_values; i++ ) {
|
|
d_printf( "\"%s\" = ", nk->values[i].valuename ? nk->values[i].valuename : "(default)" );
|
|
d_printf( "(%s) ", reg_type_lookup( 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; j<data_size; j++ ) {
|
|
d_printf( "%c", nk->values[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; j<data_size; j++ ) {
|
|
d_printf( "%x", nk->values[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;
|
|
|
|
if ( !( subkeys = TALLOC_ZERO_P( infile->mem_ctx, REGSUBKEY_CTR )) ) {
|
|
DEBUG(0,("write_registry_tree: talloc() failed!\n"));
|
|
return False;
|
|
}
|
|
|
|
if ( !(values = TALLOC_ZERO_P( subkeys, REGVAL_CTR )) ) {
|
|
DEBUG(0,("write_registry_tree: talloc() failed!\n"));
|
|
return False;
|
|
}
|
|
|
|
/* copy values into the REGVAL_CTR */
|
|
|
|
for ( i=0; i<nk->num_values; i++ ) {
|
|
regval_ctr_addvalue( values, nk->values[i].valuename, nk->values[i].type,
|
|
(const char *)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 );
|
|
}
|
|
|
|
TALLOC_FREE( 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 <file> \n");
|
|
return 0;
|
|
}
|
|
|
|
d_printf("Opening %s....", argv[0]);
|
|
if ( !(registry = regfio_open( argv[0], O_RDONLY, 0)) ) {
|
|
d_fprintf(stderr, "Failed to open %s for reading\n", argv[0]);
|
|
return 1;
|
|
}
|
|
d_printf("ok\n");
|
|
|
|
/* get the root of the registry file */
|
|
|
|
if ((nk = regfio_rootkey( registry )) == NULL) {
|
|
d_fprintf(stderr, "Could not get rootkey\n");
|
|
regfio_close( registry );
|
|
return 1;
|
|
}
|
|
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 = NULL, *outfile = NULL;
|
|
REGF_NK_REC *nk;
|
|
int result = 1;
|
|
|
|
if (argc != 2 ) {
|
|
d_printf("Usage: net rpc copy <srcfile> <newfile>\n");
|
|
return 0;
|
|
}
|
|
|
|
d_printf("Opening %s....", argv[0]);
|
|
if ( !(infile = regfio_open( argv[0], O_RDONLY, 0 )) ) {
|
|
d_fprintf(stderr, "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_fprintf(stderr, "Failed to open %s for writing\n", argv[1]);
|
|
goto out;
|
|
}
|
|
d_printf("ok\n");
|
|
|
|
/* get the root of the registry file */
|
|
|
|
if ((nk = regfio_rootkey( infile )) == NULL) {
|
|
d_fprintf(stderr, "Could not get rootkey\n");
|
|
goto out;
|
|
}
|
|
d_printf("RootKey: [%s]\n", nk->keyname);
|
|
|
|
write_registry_tree( infile, nk, NULL, outfile, "" );
|
|
|
|
result = 0;
|
|
|
|
out:
|
|
|
|
d_printf("Closing %s...", argv[1]);
|
|
if (outfile) {
|
|
regfio_close( outfile );
|
|
}
|
|
d_printf("ok\n");
|
|
|
|
d_printf("Closing %s...", argv[0]);
|
|
if (infile) {
|
|
regfio_close( infile );
|
|
}
|
|
d_printf("ok\n");
|
|
|
|
return( result);
|
|
}
|
|
|
|
/********************************************************************
|
|
********************************************************************/
|
|
|
|
static int net_help_registry( int argc, const char **argv )
|
|
{
|
|
d_printf("net rpc registry enumerate <path> [recurse] Enumerate the subkeya and values for a given registry path\n");
|
|
d_printf("net rpc registry save <path> <file> Backup a registry tree to a file on the server\n");
|
|
d_printf("net rpc registry dump <file> 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},
|
|
{"save", rpc_registry_save},
|
|
{"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 );
|
|
}
|