1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-15 05:57:49 +03:00
Andrew Tridgell 153cfb9c83 r23801: The FSF has moved around a lot. This fixes their Mass Ave address.
(This used to be commit 87c91e4362c51819032bfbebbb273c52e203b227)
2007-10-10 12:28:27 -05:00

1178 lines
27 KiB
C

/*
* Unix SMB/CIFS implementation.
* MS-RPC client library implementation (WINREG pipe)
* Copyright (C) Chris Nicholls 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "libmsrpc.h"
#include "libmsrpc_internal.h"
NTSTATUS cac_delete_subkeys_recursive(struct rpc_pipe_client * pipe_hnd,
TALLOC_CTX * mem_ctx, POLICY_HND * key);
int cac_RegConnect( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
struct RegConnect *op )
{
SMBCSRV *srv = NULL;
struct rpc_pipe_client *pipe_hnd = NULL;
POLICY_HND *key = NULL;
if ( !hnd )
return CAC_FAILURE;
if ( !hnd->_internal.ctx ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( !op || !op->in.root || !mem_ctx ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
srv = cac_GetServer( hnd );
if ( !srv ) {
hnd->status = NT_STATUS_INVALID_CONNECTION;
return CAC_FAILURE;
}
/*initialize for winreg pipe if we have to */
if ( !hnd->_internal.pipes[PI_WINREG] ) {
if ( !
( pipe_hnd =
cli_rpc_pipe_open_noauth( srv->cli, PI_WINREG,
&hnd->status ) ) ) {
return CAC_FAILURE;
}
hnd->_internal.pipes[PI_WINREG] = True;
}
pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
key = talloc( mem_ctx, POLICY_HND );
if ( !key ) {
hnd->status = NT_STATUS_NO_MEMORY;
return CAC_FAILURE;
}
hnd->status =
rpccli_winreg_Connect( pipe_hnd, mem_ctx, op->in.root,
op->in.access, key );
if ( !NT_STATUS_IS_OK( hnd->status ) ) {
return CAC_FAILURE;
}
op->out.key = key;
return CAC_SUCCESS;
}
int cac_RegClose( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
POLICY_HND * key )
{
struct rpc_pipe_client *pipe_hnd = NULL;
if ( !hnd )
return CAC_FAILURE;
if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( !key || !mem_ctx ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
hnd->status = rpccli_winreg_CloseKey( pipe_hnd, mem_ctx, key );
if ( !NT_STATUS_IS_OK( hnd->status ) ) {
return CAC_FAILURE;
}
return CAC_SUCCESS;
}
int cac_RegOpenKey( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
struct RegOpenKey *op )
{
struct rpc_pipe_client *pipe_hnd = NULL;
struct winreg_String key_string;
POLICY_HND *key_out;
POLICY_HND *parent_key;
char *key_name = NULL;
uint32 reg_type = 0;
struct RegConnect rc;
if ( !hnd )
return CAC_FAILURE;
if ( !hnd->_internal.ctx ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( !op || !op->in.name || !mem_ctx ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
key_out = talloc( mem_ctx, POLICY_HND );
if ( !key_out ) {
hnd->status = NT_STATUS_NO_MEMORY;
return CAC_FAILURE;
}
if ( !op->in.parent_key ) {
/*then we need to connect to the registry */
if ( !cac_ParseRegPath( op->in.name, &reg_type, &key_name ) ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
/*use cac_RegConnect because it handles the session setup */
ZERO_STRUCT( rc );
rc.in.access = op->in.access;
rc.in.root = reg_type;
if ( !cac_RegConnect( hnd, mem_ctx, &rc ) ) {
return CAC_FAILURE;
}
/**if they only specified the root key, return the key we just opened*/
if ( key_name == NULL ) {
op->out.key = rc.out.key;
return CAC_SUCCESS;
}
parent_key = rc.out.key;
} else {
parent_key = op->in.parent_key;
key_name = op->in.name;
}
pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
key_string.name = key_name;
hnd->status =
rpccli_winreg_OpenKey( pipe_hnd, mem_ctx, parent_key,
key_string, 0, op->in.access,
key_out );
if ( !NT_STATUS_IS_OK( hnd->status ) ) {
return CAC_FAILURE;
}
if ( !op->in.parent_key ) {
/*then close the one that we opened above */
hnd->status =
rpccli_winreg_CloseKey( pipe_hnd, mem_ctx,
parent_key );
if ( !NT_STATUS_IS_OK( hnd->status ) ) {
return CAC_FAILURE;
}
}
op->out.key = key_out;
return CAC_SUCCESS;
}
int cac_RegEnumKeys( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
struct RegEnumKeys *op )
{
struct rpc_pipe_client *pipe_hnd = NULL;
/*buffers for rpccli_reg_enum_key call */
fstring key_name_in;
fstring class_name_in;
/*output buffers */
char **key_names_out = NULL;
char **class_names_out = NULL;
time_t *mod_times_out = NULL;
uint32 num_keys_out = 0;
uint32 resume_idx = 0;
if ( !hnd )
return CAC_FAILURE;
/* This is to avoid useless rpc calls, if the last call
exhausted all the keys, then we don't need to go
through everything again */
if ( NT_STATUS_V( hnd->status ) ==
NT_STATUS_V( NT_STATUS_GUIDS_EXHAUSTED ) )
return CAC_FAILURE;
if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( !op || op->in.max_keys == 0 || !mem_ctx ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
/* The only way to know how many keys to expect is to
assume max_keys keys will be found */
key_names_out = TALLOC_ARRAY( mem_ctx, char *, op->in.max_keys );
if ( !key_names_out ) {
hnd->status = NT_STATUS_NO_MEMORY;
return CAC_FAILURE;
}
class_names_out = TALLOC_ARRAY( mem_ctx, char *, op->in.max_keys );
if ( !class_names_out ) {
hnd->status = NT_STATUS_NO_MEMORY;
TALLOC_FREE( key_names_out );
return CAC_FAILURE;
}
mod_times_out = TALLOC_ARRAY( mem_ctx, time_t, op->in.max_keys );
if ( !mod_times_out ) {
hnd->status = NT_STATUS_NO_MEMORY;
TALLOC_FREE( key_names_out );
TALLOC_FREE( class_names_out );
return CAC_FAILURE;
}
resume_idx = op->out.resume_idx;
do {
#if 0
hnd->status =
rpccli_winreg_EnumKey( pipe_hnd, mem_ctx, op->in.key,
resume_idx, key_name_in,
class_name_in,
&mod_times_out );
#endif
if ( !NT_STATUS_IS_OK( hnd->status ) ) {
/*don't increment any values */
break;
}
key_names_out[num_keys_out] =
talloc_strdup( mem_ctx, key_name_in );
class_names_out[num_keys_out] =
talloc_strdup( mem_ctx, class_name_in );
if ( !key_names_out[num_keys_out]
|| !class_names_out[num_keys_out] ) {
hnd->status = NT_STATUS_NO_MEMORY;
break;
}
resume_idx++;
num_keys_out++;
} while ( num_keys_out < op->in.max_keys );
if ( CAC_OP_FAILED( hnd->status ) ) {
op->out.num_keys = 0;
return CAC_FAILURE;
}
op->out.resume_idx = resume_idx;
op->out.num_keys = num_keys_out;
op->out.key_names = key_names_out;
op->out.class_names = class_names_out;
op->out.mod_times = mod_times_out;
return CAC_SUCCESS;
}
int cac_RegCreateKey( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
struct RegCreateKey *op )
{
struct rpc_pipe_client *pipe_hnd = NULL;
POLICY_HND *key_out;
struct RegOpenKey rok;
struct winreg_String key_string, class_string;
enum winreg_CreateAction action = 0;
if ( !hnd )
return CAC_FAILURE;
if ( !hnd->_internal.ctx ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( !op || !op->in.parent_key || !op->in.key_name || !mem_ctx ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
/*first try to open the key - we use cac_RegOpenKey(). this doubles as a way to ensure the winreg pipe is initialized */
ZERO_STRUCT( rok );
rok.in.name = op->in.key_name;
rok.in.access = op->in.access;
rok.in.parent_key = op->in.parent_key;
if ( cac_RegOpenKey( hnd, mem_ctx, &rok ) ) {
/*then we got the key, return */
op->out.key = rok.out.key;
return CAC_SUCCESS;
}
/*just be ultra-safe */
pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
key_out = talloc( mem_ctx, POLICY_HND );
if ( !key_out ) {
hnd->status = NT_STATUS_NO_MEMORY;
return CAC_FAILURE;
}
key_string.name = op->in.key_name;
class_string.name = op->in.class_name;
hnd->status =
rpccli_winreg_CreateKey( pipe_hnd, mem_ctx, op->in.parent_key,
key_string, class_string, 0,
op->in.access, NULL, key_out,
&action );
if ( !NT_STATUS_IS_OK( hnd->status ) ) {
return CAC_FAILURE;
}
op->out.key = key_out;
return CAC_SUCCESS;
}
NTSTATUS cac_delete_subkeys_recursive( struct rpc_pipe_client * pipe_hnd,
TALLOC_CTX * mem_ctx, POLICY_HND * key )
{
POLICY_HND subkey;
fstring subkey_name;
int cur_key = 0;
NTSTATUS status;
uint32 num_subkeys, max_subkeylen, max_classlen;
uint32 num_values, max_valnamelen, maxvalbufsize;
char *name_buffer;
struct winreg_String class_string;
NTTIME modtime;
uint32 secdescsize;
/* First get the max subkey name length */
class_string.name = NULL;
status = rpccli_winreg_QueryInfoKey( pipe_hnd, mem_ctx, key,
&class_string, &num_subkeys,
&max_subkeylen, &max_classlen,
&num_values, &max_valnamelen,
&maxvalbufsize, &secdescsize,
&modtime );
if ( !NT_STATUS_IS_OK( status ) ) {
return status;
}
if ( (name_buffer = TALLOC_ARRAY( mem_ctx, char, max_subkeylen )) == NULL ) {
d_fprintf(stderr, "Memory allocation error.\n");
return NT_STATUS_NO_MEMORY;
}
while ( NT_STATUS_IS_OK( status ) ) {
struct winreg_String key_string;
struct winreg_StringBuf subkey_string;
fstring subkeyname;
memset( name_buffer, 0x0, max_subkeylen );
subkey_string.name = name_buffer;
subkey_string.length = 0;
subkey_string.size = max_subkeylen;
status = rpccli_winreg_EnumKey(pipe_hnd, mem_ctx, key, cur_key,
&subkey_string, NULL, NULL);
if ( !NT_STATUS_IS_OK( status ) )
break;
/* copy the keyname and add the terminating NULL */
StrnCpy( subkeyname, subkey_string.name,
MIN(subkey_string.length, sizeof(subkeyname)-1) );
subkeyname[MIN(subkey_string.length, sizeof(subkeyname)-1)] = '\0';
/*try to open the key with full access */
key_string.name = subkeyname;
status = rpccli_winreg_OpenKey( pipe_hnd, mem_ctx, key,
key_string, 0, REG_KEY_ALL,
&subkey );
if ( !NT_STATUS_IS_OK( status ) )
break;
status = cac_delete_subkeys_recursive( pipe_hnd, mem_ctx,
&subkey );
if ( !W_ERROR_EQUAL( ntstatus_to_werror(status), WERR_NO_MORE_ITEMS )
&& !NT_STATUS_IS_OK( status ) )
break;
/*flush the key just to be safe */
rpccli_winreg_FlushKey( pipe_hnd, mem_ctx, key );
/*close the key that we opened */
rpccli_winreg_CloseKey( pipe_hnd, mem_ctx, &subkey );
/*now we delete the subkey */
key_string.name = subkey_name;
status = rpccli_winreg_DeleteKey( pipe_hnd, mem_ctx, key,
key_string );
cur_key++;
}
return status;
}
int cac_RegDeleteKey( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
struct RegDeleteKey *op )
{
struct rpc_pipe_client *pipe_hnd = NULL;
struct winreg_String key_string;
if ( !hnd )
return CAC_FAILURE;
if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( !op || !op->in.parent_key || !op->in.name || !mem_ctx ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( op->in.recursive ) {
/* first open the key, and then delete all of
it's subkeys recursively */
struct RegOpenKey rok;
ZERO_STRUCT( rok );
rok.in.parent_key = op->in.parent_key;
rok.in.name = op->in.name;
rok.in.access = REG_KEY_ALL;
if ( !cac_RegOpenKey( hnd, mem_ctx, &rok ) )
return CAC_FAILURE;
hnd->status = cac_delete_subkeys_recursive( pipe_hnd, mem_ctx,
rok.out.key );
/*close the key that we opened */
cac_RegClose( hnd, mem_ctx, rok.out.key );
if ( NT_STATUS_V( hnd->status ) !=
NT_STATUS_V( NT_STATUS_GUIDS_EXHAUSTED )
&& !NT_STATUS_IS_OK( hnd->status ) )
return CAC_FAILURE;
/*now go on to actually delete the key */
}
key_string.name = op->in.name;
hnd->status =
rpccli_winreg_DeleteKey( pipe_hnd, mem_ctx, op->in.parent_key,
key_string );
if ( !NT_STATUS_IS_OK( hnd->status ) ) {
return CAC_FAILURE;
}
return CAC_SUCCESS;
}
int cac_RegDeleteValue( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
struct RegDeleteValue *op )
{
struct rpc_pipe_client *pipe_hnd = NULL;
struct winreg_String value_string;
if ( !hnd )
return CAC_FAILURE;
if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( !op || !op->in.parent_key || !op->in.name || !mem_ctx ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
value_string.name = op->in.name;
hnd->status =
rpccli_winreg_DeleteValue( pipe_hnd, mem_ctx,
op->in.parent_key, value_string );
if ( !NT_STATUS_IS_OK( hnd->status ) ) {
return CAC_FAILURE;
}
return CAC_SUCCESS;
}
int cac_RegQueryKeyInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
struct RegQueryKeyInfo *op )
{
struct rpc_pipe_client *pipe_hnd = NULL;
uint32 num_subkeys_out = 0;
uint32 long_subkey_out = 0;
uint32 long_class_out = 0;
uint32 num_values_out = 0;
uint32 long_value_out = 0;
uint32 long_data_out = 0;
uint32 secdesc_size = 0;
NTTIME mod_time;
struct winreg_String class_string;
if ( !hnd )
return CAC_FAILURE;
if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( !op || !op->in.key || !mem_ctx ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
hnd->status = rpccli_winreg_QueryInfoKey( pipe_hnd, mem_ctx,
op->in.key,
&class_string,
&num_subkeys_out,
&long_subkey_out,
&long_class_out,
&num_values_out,
&long_value_out,
&long_data_out,
&secdesc_size, &mod_time );
if ( !NT_STATUS_IS_OK( hnd->status ) )
return CAC_FAILURE;
if ( !class_string.name ) {
op->out.class_name = talloc_strdup( mem_ctx, "" );
} else {
op->out.class_name = talloc_strdup( mem_ctx, class_string.name );
}
if ( !op->out.class_name ) {
hnd->status = NT_STATUS_NO_MEMORY;
return CAC_FAILURE;
}
op->out.num_subkeys = num_subkeys_out;
op->out.longest_subkey = long_subkey_out;
op->out.longest_class = long_class_out;
op->out.num_values = num_values_out;
op->out.longest_value_name = long_value_out;
op->out.longest_value_data = long_data_out;
op->out.security_desc_size = secdesc_size;
op->out.last_write_time = nt_time_to_unix( mod_time );
return CAC_FAILURE;
}
int cac_RegQueryValue( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
struct RegQueryValue *op )
{
struct rpc_pipe_client *pipe_hnd = NULL;
struct winreg_String value_string;
REGVAL_BUFFER buffer;
REG_VALUE_DATA *data_out = NULL;
enum winreg_Type val_type;
uint8 *buf;
uint32 buf_size = 4096;
uint32 length = 0;
if ( !hnd )
return CAC_FAILURE;
if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( !op || !op->in.key || !op->in.val_name || !mem_ctx ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
value_string.name = op->in.val_name;
if ( ( buf = TALLOC_ARRAY( mem_ctx, uint8, buf_size ) ) == NULL ) {
hnd->status = NT_STATUS_NO_MEMORY;
return CAC_FAILURE;
}
hnd->status = rpccli_winreg_QueryValue( pipe_hnd, mem_ctx, op->in.key,
value_string, &val_type, buf,
&buf_size, &length );
if ( !NT_STATUS_IS_OK( hnd->status ) )
return CAC_FAILURE;
init_regval_buffer( &buffer, buf, length );
data_out = cac_MakeRegValueData( mem_ctx, val_type, buffer );
if ( !data_out ) {
if ( errno == ENOMEM )
hnd->status = NT_STATUS_NO_MEMORY;
else
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
op->out.type = val_type;
op->out.data = data_out;
return CAC_SUCCESS;
}
int cac_RegEnumValues( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
struct RegEnumValues *op )
{
struct rpc_pipe_client *pipe_hnd = NULL;
char *name_buffer;
REGVAL_BUFFER val_buf;
uint32 *types_out = NULL;
REG_VALUE_DATA **values_out = NULL;
char **val_names_out = NULL;
uint32 num_values_out = 0;
uint32 resume_idx = 0;
uint32 num_subkeys, max_subkeylen, max_classlen;
uint32 num_values, max_valnamelen, maxvalbufsize;
struct winreg_String class_string;
NTTIME modtime;
uint32 secdescsize;
uint8 *buffer;
if ( !hnd )
return CAC_FAILURE;
/* This is to avoid useless rpc calls, if the last
call exhausted all the keys, then we don't need
to go through everything again */
if ( NT_STATUS_V( hnd->status ) ==
NT_STATUS_V( NT_STATUS_GUIDS_EXHAUSTED ) )
return CAC_FAILURE;
if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( !op || !op->in.key || op->in.max_values == 0 || !mem_ctx ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
/*we need to assume that the max number of values will be enumerated */
types_out = TALLOC_ARRAY( mem_ctx, uint32, op->in.max_values );
if ( !types_out ) {
hnd->status = NT_STATUS_NO_MEMORY;
return CAC_FAILURE;
}
values_out = TALLOC_ARRAY( mem_ctx, REG_VALUE_DATA *,
op->in.max_values );
if ( !values_out ) {
TALLOC_FREE( types_out );
hnd->status = NT_STATUS_NO_MEMORY;
return CAC_FAILURE;
}
val_names_out = TALLOC_ARRAY( mem_ctx, char *, op->in.max_values );
if ( !val_names_out ) {
TALLOC_FREE( types_out );
TALLOC_FREE( values_out );
hnd->status = NT_STATUS_NO_MEMORY;
return CAC_FAILURE;
}
resume_idx = op->out.resume_idx;
class_string.name = NULL;
hnd->status = rpccli_winreg_QueryInfoKey( pipe_hnd, mem_ctx, op->in.key,
&class_string, &num_subkeys,
&max_subkeylen, &max_classlen,
&num_values, &max_valnamelen,
&maxvalbufsize, &secdescsize,
&modtime );
if ( !NT_STATUS_IS_OK(hnd->status) ) {
TALLOC_FREE( types_out );
TALLOC_FREE( values_out );
return CAC_FAILURE;
}
if ( (buffer = TALLOC_ARRAY( mem_ctx, uint8, maxvalbufsize )) == NULL ) {
TALLOC_FREE( types_out );
TALLOC_FREE( values_out );
hnd->status = NT_STATUS_NO_MEMORY;
return CAC_FAILURE;
}
if ( (name_buffer = TALLOC_ARRAY(mem_ctx, char, max_valnamelen)) == NULL ) {
TALLOC_FREE( types_out );
TALLOC_FREE( values_out );
TALLOC_FREE( buffer );
hnd->status = NT_STATUS_NO_MEMORY;
return CAC_FAILURE;
}
do {
uint32 data_size = maxvalbufsize;
uint32 data_length = 0;
struct winreg_ValNameBuf name_buf;
memset( name_buffer, 0x0, max_valnamelen );
name_buf.name = name_buffer;
name_buf.size = max_valnamelen;
name_buf.length = 0;
hnd->status = rpccli_winreg_EnumValue( pipe_hnd, mem_ctx,
op->in.key,
resume_idx, &name_buf,
&types_out[num_values_out], buffer,
&data_size,
&data_length );
if ( !NT_STATUS_IS_OK( hnd->status ) )
break;
ZERO_STRUCT( val_buf );
init_regval_buffer( &val_buf, buffer, data_length );
values_out[num_values_out] = cac_MakeRegValueData( mem_ctx,
types_out[num_values_out],
val_buf );
val_names_out[num_values_out] = TALLOC_ARRAY( mem_ctx, char, name_buf.length+1 );
if ( !val_names_out[num_values_out]
|| !values_out[num_values_out] ) {
hnd->status = NT_STATUS_NO_MEMORY;
break;
}
StrnCpy( val_names_out[num_values_out], name_buf.name, name_buf.length );
(val_names_out[num_values_out])[name_buf.length] = '\0';
num_values_out++;
resume_idx++;
} while ( num_values_out < op->in.max_values );
if ( CAC_OP_FAILED( hnd->status ) )
return CAC_FAILURE;
op->out.types = types_out;
op->out.num_values = num_values_out;
op->out.value_names = val_names_out;
op->out.values = values_out;
op->out.resume_idx = resume_idx;
return CAC_SUCCESS;
}
int cac_RegSetValue( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
struct RegSetValue *op )
{
struct rpc_pipe_client *pipe_hnd = NULL;
struct winreg_String value_string;
RPC_DATA_BLOB *buffer;
if ( !hnd )
return CAC_FAILURE;
if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( !op || !op->in.key || !op->in.val_name || !mem_ctx ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
buffer = cac_MakeRpcDataBlob( mem_ctx, op->in.type, op->in.value );
if ( !buffer ) {
if ( errno == ENOMEM )
hnd->status = NT_STATUS_NO_MEMORY;
else
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
value_string.name = op->in.val_name;
hnd->status =
rpccli_winreg_SetValue( pipe_hnd, mem_ctx, op->in.key,
value_string, op->in.type,
buffer->buffer, buffer->buf_len );
if ( !NT_STATUS_IS_OK( hnd->status ) )
return CAC_FAILURE;
/*flush */
hnd->status = rpccli_winreg_FlushKey( pipe_hnd, mem_ctx, op->in.key );
if ( !NT_STATUS_IS_OK( hnd->status ) )
return CAC_FAILURE;
return CAC_SUCCESS;
}
int cac_RegGetVersion( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
struct RegGetVersion *op )
{
struct rpc_pipe_client *pipe_hnd = NULL;
uint32 version_out;
if ( !hnd )
return CAC_FAILURE;
if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( !op || !op->in.key || !mem_ctx ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
hnd->status =
rpccli_winreg_GetVersion( pipe_hnd, mem_ctx, op->in.key,
&version_out );
if ( !NT_STATUS_IS_OK( hnd->status ) )
return CAC_FAILURE;
op->out.version = version_out;
return CAC_SUCCESS;
}
int cac_RegGetKeySecurity( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
struct RegGetKeySecurity *op )
{
struct rpc_pipe_client *pipe_hnd = NULL;
struct KeySecurityData keysec;
ZERO_STRUCT( keysec );
if ( !hnd )
return CAC_FAILURE;
if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( !op || !op->in.key || op->in.info_type == 0 || !mem_ctx ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
hnd->status =
rpccli_winreg_GetKeySecurity( pipe_hnd, mem_ctx, op->in.key,
op->in.info_type, &keysec );
if ( !NT_STATUS_IS_OK( hnd->status ) ) {
return CAC_FAILURE;
}
#if 0 /* FIX ME!!!! unmarshall the security descriptor */
op->out.size = buf.sd_size;
op->out.descriptor = dup_sec_desc( mem_ctx, buf.sd );
#endif
if ( op->out.descriptor == NULL ) {
return CAC_FAILURE;
}
return CAC_SUCCESS;
}
int cac_RegSetKeySecurity( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
struct RegSetKeySecurity *op )
{
struct rpc_pipe_client *pipe_hnd = NULL;
struct KeySecurityData keysec;
ZERO_STRUCT( keysec );
if ( !hnd )
return CAC_FAILURE;
if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_WINREG] ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( !op || !op->in.key || op->in.info_type == 0 || op->in.size == 0
|| !op->in.descriptor || !mem_ctx ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
pipe_hnd = cac_GetPipe( hnd, PI_WINREG );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
/* FIXME!!! Marshall in the input sec_desc to struct KeySecurityData */
hnd->status =
rpccli_winreg_SetKeySecurity( pipe_hnd, mem_ctx, op->in.key,
op->in.info_type, &keysec );
if ( !NT_STATUS_IS_OK( hnd->status ) ) {
return CAC_FAILURE;
}
return CAC_SUCCESS;
}
int cac_Shutdown( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
struct Shutdown *op )
{
SMBCSRV *srv = NULL;
struct rpc_pipe_client *pipe_hnd = NULL;
struct initshutdown_String msg_string;
struct initshutdown_String_sub s;
char *msg;
if ( !hnd )
return CAC_FAILURE;
if ( !hnd->_internal.ctx ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
if ( !op || !mem_ctx ) {
hnd->status = NT_STATUS_INVALID_PARAMETER;
return CAC_FAILURE;
}
srv = cac_GetServer( hnd );
if ( !srv ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
/*initialize for winreg pipe if we have to */
if ( !hnd->_internal.pipes[PI_INITSHUTDOWN] ) {
if ( !
( pipe_hnd =
cli_rpc_pipe_open_noauth( srv->cli, PI_INITSHUTDOWN,
&( hnd->status ) ) ) ) {
return CAC_FAILURE;
}
hnd->_internal.pipes[PI_INITSHUTDOWN] = True;
}
pipe_hnd = cac_GetPipe( hnd, PI_INITSHUTDOWN );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
msg = ( op->in.message !=
NULL ) ? op->in.message : talloc_strdup( mem_ctx, "" );
msg_string.name = &s;
msg_string.name->name = msg;
hnd->status = NT_STATUS_OK;
if ( hnd->_internal.srv_level > SRV_WIN_NT4 ) {
hnd->status =
rpccli_initshutdown_InitEx( pipe_hnd, mem_ctx, NULL,
&msg_string,
op->in.timeout,
op->in.reboot,
op->in.force,
op->in.reason );
}
if ( hnd->_internal.srv_level < SRV_WIN_2K
|| !NT_STATUS_IS_OK( hnd->status ) ) {
hnd->status =
rpccli_initshutdown_Init( pipe_hnd, mem_ctx, NULL,
&msg_string, op->in.timeout,
op->in.reboot,
op->in.force );
hnd->_internal.srv_level = SRV_WIN_NT4;
}
if ( !NT_STATUS_IS_OK( hnd->status ) ) {
return CAC_FAILURE;
}
return CAC_SUCCESS;
}
int cac_AbortShutdown( CacServerHandle * hnd, TALLOC_CTX * mem_ctx )
{
struct rpc_pipe_client *pipe_hnd = NULL;
if ( !hnd )
return CAC_FAILURE;
if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_INITSHUTDOWN] ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
pipe_hnd = cac_GetPipe( hnd, PI_INITSHUTDOWN );
if ( !pipe_hnd ) {
hnd->status = NT_STATUS_INVALID_HANDLE;
return CAC_FAILURE;
}
hnd->status = rpccli_initshutdown_Abort( pipe_hnd, mem_ctx, NULL );
if ( !NT_STATUS_IS_OK( hnd->status ) )
return CAC_FAILURE;
return CAC_SUCCESS;
}