mirror of
https://github.com/samba-team/samba.git
synced 2025-02-15 05:57:49 +03:00
1178 lines
27 KiB
C
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, ®_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;
|
|
}
|