2013-08-05 13:01:34 +04:00
/*
Unix SMB / CIFS implementation .
RPC pipe client
Copyright ( C ) Gregor Beck 2013 - 2014
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "rpcclient.h"
# include "librpc/gen_ndr/ndr_witness_c.h"
# include <popt.h>
/*
* We have to use the same connection for each subcommand
* for the context handles to be meaningful .
*/
static void use_only_one_rpc_pipe_hack ( struct rpc_pipe_client * cli ) ;
static WERROR cmd_witness_GetInterfaceList ( struct rpc_pipe_client * cli ,
TALLOC_CTX * mem_ctx , int argc ,
const char * * argv )
{
NTSTATUS status ;
WERROR result ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct witness_interfaceList * interface_list = NULL ;
uint32_t num_interfaces , n ;
struct witness_interfaceInfo * interfaces ;
use_only_one_rpc_pipe_hack ( cli ) ;
status = dcerpc_witness_GetInterfaceList ( cli - > binding_handle , frame ,
& interface_list , & result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " dcerpc_witness_GetInterfaceList failed, status: %s \n " , nt_errstr ( status ) ) ) ;
result = ntstatus_to_werror ( status ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " dcerpc_witness_GetInterfaceList failed, error: %s \n " , win_errstr ( result ) ) ) ;
goto done ;
}
SMB_ASSERT ( interface_list ) ;
interfaces = interface_list - > interfaces ;
num_interfaces = interface_list - > num_interfaces ;
for ( n = 0 ; n < num_interfaces ; n + + ) {
char wif = ( interfaces [ n ] . flags & WITNESS_INFO_WITNESS_IF ) ? ' * ' : ' ' ;
char state = ' X ' ;
if ( interfaces [ n ] . state = = WITNESS_STATE_AVAILABLE ) {
state = ' + ' ;
} else if ( interfaces [ n ] . state = = WITNESS_STATE_UNAVAILABLE ) {
state = ' - ' ;
} else if ( interfaces [ n ] . state = = WITNESS_STATE_UNKNOWN ) {
state = ' ? ' ;
}
d_printf ( " %c%c %s " , wif , state , interfaces [ n ] . group_name ) ;
if ( interfaces [ n ] . flags & WITNESS_INFO_IPv4_VALID ) {
d_printf ( " %s " , interfaces [ n ] . ipv4 ) ;
}
if ( interfaces [ n ] . flags & WITNESS_INFO_IPv6_VALID ) {
d_printf ( " %s " , interfaces [ n ] . ipv6 ) ;
}
switch ( interfaces [ n ] . version ) {
case WITNESS_V1 :
d_printf ( " V1 " ) ;
break ;
case WITNESS_V2 :
d_printf ( " V2 " ) ;
break ;
default :
2019-08-29 22:29:58 +03:00
d_printf ( " Unsupported Version (0x%08x) " , interfaces [ n ] . version ) ;
2013-08-05 13:01:34 +04:00
}
d_printf ( " \n " ) ;
}
done :
talloc_free ( frame ) ;
return result ;
}
static WERROR cmd_witness_Register ( struct rpc_pipe_client * cli ,
TALLOC_CTX * mem_ctx , int argc ,
const char * * argv )
{
static char hostname [ MAXHOSTNAMELEN ] = { ' \0 ' } ;
NTSTATUS status ;
WERROR result = WERR_OK ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct policy_handle hnd ;
const char * net_name = NULL ;
const char * ip_addr = NULL ;
const char * client_name = hostname ;
long version = WITNESS_V1 ;
int c ;
poptContext optCon ;
struct poptOption optionsTable [ ] = {
2019-01-11 17:14:09 +03:00
{
. longName = " version " ,
. shortName = ' v ' ,
. argInfo = POPT_ARG_LONG | POPT_ARGFLAG_SHOW_DEFAULT ,
. arg = & version ,
. val = WITNESS_V2 ,
. descrip = " witness version " ,
. argDescrip = " version "
} ,
{
. longName = " V1 " ,
. shortName = ' 1 ' ,
. argInfo = POPT_ARG_LONG | POPT_ARG_VAL ,
. arg = & version ,
. val = WITNESS_V1 ,
. descrip = " witness version 1 " ,
. argDescrip = NULL
} ,
{
. longName = " V2 " ,
. shortName = ' 2 ' ,
. argInfo = POPT_ARG_LONG | POPT_ARG_VAL ,
. arg = & version ,
. val = WITNESS_V2 ,
. descrip = " witness version 2 " ,
. argDescrip = NULL
} ,
{
. longName = " net " ,
. shortName = ' n ' ,
. argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT ,
. arg = & net_name ,
. val = 0 ,
. descrip = " net name " ,
. argDescrip = NULL
} ,
{
. longName = " ip " ,
. shortName = ' i ' ,
. argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT ,
. arg = & ip_addr ,
. val = 0 ,
. descrip = " ip address " ,
. argDescrip = NULL
} ,
{
. longName = " client " ,
. shortName = ' c ' ,
. argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT | POPT_ARGFLAG_OPTIONAL ,
. arg = & client_name ,
. val = 0 ,
. descrip = " client name " ,
. argDescrip = NULL
} ,
POPT_TABLEEND
2013-08-05 13:01:34 +04:00
} ;
use_only_one_rpc_pipe_hack ( cli ) ;
if ( hostname [ 0 ] = = ' \0 ' ) {
gethostname ( hostname , sizeof ( hostname ) ) ;
}
optCon = poptGetContext ( NULL , argc , argv , optionsTable , 0 ) ;
while ( ( c = poptGetNextOpt ( optCon ) ) > = 0 ) { }
if ( c < - 1 ) {
/* an error occurred during option processing */
d_fprintf ( stderr , " %s: %s \n " ,
poptBadOption ( optCon , POPT_BADOPTION_NOALIAS ) ,
poptStrerror ( c ) ) ;
goto done ;
}
if ( argc < 2 | | poptPeekArg ( optCon ) ! = NULL ) {
poptPrintHelp ( optCon , stderr , 0 ) ;
goto done ;
}
status = dcerpc_witness_Register ( cli - > binding_handle , frame ,
& hnd ,
version ,
net_name , ip_addr , client_name ,
& result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " dcerpc_witness_Register failed, status: %s \n " , nt_errstr ( status ) ) ) ;
result = ntstatus_to_werror ( status ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " dcerpc_witness_Register failed, error: %s \n " , win_errstr ( result ) ) ) ;
goto done ;
}
d_printf ( " %x:%s \n " , hnd . handle_type , GUID_string ( frame , & hnd . uuid ) ) ;
done :
2019-08-19 15:11:54 +03:00
poptFreeContext ( optCon ) ;
2013-08-05 13:01:34 +04:00
talloc_free ( frame ) ;
return result ;
}
static WERROR cmd_witness_RegisterEx ( struct rpc_pipe_client * cli ,
TALLOC_CTX * mem_ctx , int argc ,
const char * * argv )
{
static char hostname [ MAXHOSTNAMELEN ] = { ' \0 ' } ;
NTSTATUS status ;
WERROR result = WERR_OK ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct policy_handle hnd ;
const char * net_name = NULL ;
const char * ip_addr = NULL ;
const char * share_name = NULL ;
const char * client_name = hostname ;
long version = WITNESS_V2 ;
long flags = 0 ;
long timeout = 0 ;
int c ;
poptContext optCon ;
struct poptOption optionsTable [ ] = {
2019-01-11 17:14:09 +03:00
{
. longName = " version " ,
. shortName = ' v ' ,
. argInfo = POPT_ARG_LONG | POPT_ARGFLAG_SHOW_DEFAULT ,
. arg = & version ,
. val = WITNESS_V2 ,
. descrip = " witness version " ,
. argDescrip = " version "
} ,
{
. longName = " V1 " ,
. shortName = ' 1 ' ,
. argInfo = POPT_ARG_LONG | POPT_ARG_VAL ,
. arg = & version ,
. val = WITNESS_V1 ,
. descrip = " witness version 1 " ,
} ,
{
. longName = " V2 " ,
. shortName = ' 2 ' ,
. argInfo = POPT_ARG_LONG | POPT_ARG_VAL ,
. arg = & version ,
. val = WITNESS_V2 ,
. descrip = " witness version 2 " ,
} ,
{
. longName = " net " ,
. shortName = ' n ' ,
. argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT ,
. arg = & net_name ,
. val = 0 ,
. descrip = " net name " ,
} ,
{
. longName = " ip " ,
. shortName = ' i ' ,
. argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT ,
. arg = & ip_addr ,
. val = 0 ,
. descrip = " ip address " ,
} ,
{
. longName = " share " ,
. shortName = ' s ' ,
. argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT ,
. arg = & share_name ,
. val = 0 ,
. descrip = " share name " ,
} ,
{
. longName = " client " ,
. shortName = ' c ' ,
. argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT | POPT_ARGFLAG_OPTIONAL ,
. arg = & client_name ,
. val = 0 ,
. descrip = " client name " ,
} ,
{
. longName = " flags " ,
. shortName = ' f ' ,
. argInfo = POPT_ARG_LONG | POPT_ARGFLAG_OR | POPT_ARGFLAG_SHOW_DEFAULT ,
. arg = & flags ,
. val = 0 ,
. descrip = " flags " ,
} ,
{
. longName = " timeout " ,
. shortName = ' t ' ,
. argInfo = POPT_ARG_LONG | POPT_ARGFLAG_SHOW_DEFAULT ,
. arg = & timeout ,
. val = 0 ,
. descrip = " timeout " ,
} ,
POPT_TABLEEND
2013-08-05 13:01:34 +04:00
} ;
use_only_one_rpc_pipe_hack ( cli ) ;
if ( hostname [ 0 ] = = ' \0 ' ) {
gethostname ( hostname , sizeof ( hostname ) ) ;
}
optCon = poptGetContext ( NULL , argc , argv , optionsTable , 0 ) ;
while ( ( c = poptGetNextOpt ( optCon ) ) > = 0 ) { }
if ( c < - 1 ) {
/* an error occurred during option processing */
d_fprintf ( stderr , " %s: %s \n " ,
poptBadOption ( optCon , POPT_BADOPTION_NOALIAS ) ,
poptStrerror ( c ) ) ;
goto done ;
}
if ( argc < 2 | | poptPeekArg ( optCon ) ! = NULL ) {
poptPrintHelp ( optCon , stderr , 0 ) ;
goto done ;
}
status = dcerpc_witness_RegisterEx ( cli - > binding_handle , frame ,
& hnd ,
version ,
net_name , share_name , ip_addr , client_name ,
flags , timeout ,
& result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " dcerpc_witness_RegisterEx failed, status: %s \n " , nt_errstr ( status ) ) ) ;
result = ntstatus_to_werror ( status ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " dcerpc_witness_RegisterEx failed, error: %s \n " , win_errstr ( result ) ) ) ;
goto done ;
}
d_printf ( " %x:%s \n " , hnd . handle_type , GUID_string ( frame , & hnd . uuid ) ) ;
done :
poptFreeContext ( optCon ) ;
talloc_free ( frame ) ;
return result ;
}
static bool
read_context_handle ( const char * str , struct policy_handle * hnd )
{
NTSTATUS status ;
long type ;
char * pos ;
struct GUID guid ;
type = strtol ( str , & pos , 16 ) ;
if ( * pos ! = ' : ' ) {
DEBUG ( 0 , ( " read_context_handle: failed to parse type \n " ) ) ;
return false ;
}
status = GUID_from_string ( pos + 1 , & guid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " read_context_handle: failed to parse guid %s \n " , nt_errstr ( status ) ) ) ;
return false ;
}
hnd - > handle_type = type ;
hnd - > uuid = guid ;
return true ;
}
static WERROR cmd_witness_UnRegister ( struct rpc_pipe_client * cli ,
TALLOC_CTX * mem_ctx , int argc ,
const char * * argv )
{
NTSTATUS status ;
WERROR result = WERR_OK ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct policy_handle hnd ;
use_only_one_rpc_pipe_hack ( cli ) ;
if ( argc ! = 2 ) {
d_printf ( " %s <context_handle> \n " , argv [ 0 ] ) ;
goto done ;
}
if ( ! read_context_handle ( argv [ 1 ] , & hnd ) ) {
2015-12-03 17:24:25 +03:00
result = WERR_INVALID_PARAMETER ;
2013-08-05 13:01:34 +04:00
goto done ;
}
status = dcerpc_witness_UnRegister ( cli - > binding_handle , frame ,
hnd , & result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " dcerpc_witness_UnRegister failed, status: %s \n " , nt_errstr ( status ) ) ) ;
result = ntstatus_to_werror ( status ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " dcerpc_witness_UnRegister failed, error: %s \n " , win_errstr ( result ) ) ) ;
goto done ;
}
done :
talloc_free ( frame ) ;
return result ;
}
2015-06-26 00:12:18 +03:00
static void print_notify_response_resource_change ( struct witness_ResourceChange * r )
2013-08-05 13:01:34 +04:00
{
const char * type_str ;
2015-06-26 00:12:18 +03:00
if ( r - > type = = WITNESS_RESOURCE_STATE_UNKNOWN ) {
2013-08-05 13:01:34 +04:00
type_str = " Unknown " ;
2015-06-26 00:12:18 +03:00
} else if ( r - > type = = WITNESS_RESOURCE_STATE_AVAILABLE ) {
2013-08-05 13:01:34 +04:00
type_str = " Available \n " ;
2015-06-26 00:12:18 +03:00
} else if ( r - > type = = WITNESS_RESOURCE_STATE_UNAVAILABLE ) {
2013-08-05 13:01:34 +04:00
type_str = " Unavailable " ;
} else {
2015-06-26 00:12:18 +03:00
type_str = talloc_asprintf ( r , " Invalid (%u) " , r - > type ) ;
2013-08-05 13:01:34 +04:00
}
2015-06-26 00:12:18 +03:00
d_printf ( " %s -> %s \n " , r - > name , type_str ) ;
2013-08-05 13:01:34 +04:00
}
2015-06-26 00:12:18 +03:00
static void print_notify_response_ip_addr_info_list ( struct witness_IPaddrInfoList * r )
2013-08-05 13:01:34 +04:00
{
2015-06-26 00:12:18 +03:00
int i ;
for ( i = 0 ; i < r - > num ; i + + ) {
uint32_t flags = r - > addr [ i ] . flags ;
const char * str4 = r - > addr [ i ] . ipv4 ;
const char * str6 = r - > addr [ i ] . ipv6 ;
2013-08-05 13:01:34 +04:00
d_printf ( " Flags 0x%08x " , flags ) ;
2015-06-25 22:22:20 +03:00
if ( flags & WITNESS_IPADDR_V4 ) {
2013-08-05 13:01:34 +04:00
d_printf ( " %s " , str4 ) ;
}
2015-06-25 22:22:20 +03:00
if ( flags & WITNESS_IPADDR_V6 ) {
2013-08-05 13:01:34 +04:00
d_printf ( " %s " , str6 ) ;
}
2015-06-25 22:22:20 +03:00
if ( flags & WITNESS_IPADDR_ONLINE ) {
2013-08-05 13:01:34 +04:00
d_printf ( " Online " ) ;
}
2015-06-25 22:22:20 +03:00
if ( flags & WITNESS_IPADDR_ONLINE ) {
2013-08-05 13:01:34 +04:00
d_printf ( " Offline " ) ;
}
d_printf ( " \n " ) ;
}
2015-06-26 00:12:18 +03:00
}
2013-08-05 13:01:34 +04:00
2015-06-26 00:12:18 +03:00
static void print_notify_response ( union witness_notifyResponse_message * r ,
uint32_t type )
{
switch ( type ) {
case WITNESS_NOTIFY_RESOURCE_CHANGE :
print_notify_response_resource_change ( & r - > resource_change ) ;
break ;
case WITNESS_NOTIFY_CLIENT_MOVE :
case WITNESS_NOTIFY_SHARE_MOVE :
case WITNESS_NOTIFY_IP_CHANGE :
print_notify_response_ip_addr_info_list ( & r - > client_move ) ;
break ;
default :
break ;
2013-08-05 13:01:34 +04:00
}
}
static WERROR cmd_witness_AsyncNotify ( struct rpc_pipe_client * cli ,
TALLOC_CTX * mem_ctx , int argc ,
const char * * argv )
{
NTSTATUS status ;
WERROR result = WERR_OK ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct policy_handle hnd ;
struct witness_notifyResponse * response = NULL ;
uint32_t timeout ;
2015-06-26 00:12:18 +03:00
int i ;
2013-08-05 13:01:34 +04:00
use_only_one_rpc_pipe_hack ( cli ) ;
if ( argc ! = 2 ) {
d_printf ( " %s <context_handle> \n " , argv [ 0 ] ) ;
goto done ;
}
if ( ! read_context_handle ( argv [ 1 ] , & hnd ) ) {
2015-12-03 17:24:25 +03:00
result = WERR_INVALID_PARAMETER ;
2013-08-05 13:01:34 +04:00
goto done ;
}
timeout = dcerpc_binding_handle_set_timeout ( cli - > binding_handle , UINT32_MAX ) ;
status = dcerpc_witness_AsyncNotify ( cli - > binding_handle , frame , hnd ,
& response , & result ) ;
dcerpc_binding_handle_set_timeout ( cli - > binding_handle , timeout ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " dcerpc_witness_AsyncNotify failed, status: %s \n " , nt_errstr ( status ) ) ) ;
result = ntstatus_to_werror ( status ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
DEBUG ( 0 , ( " dcerpc_witness_AsyncNotify failed, error: %s \n " , win_errstr ( result ) ) ) ;
goto done ;
}
2015-09-14 18:12:58 +03:00
if ( response = = NULL ) {
d_printf ( " Got an empty response \n " ) ;
goto done ;
}
2014-02-04 18:43:39 +04:00
switch ( response - > type ) {
2013-08-05 13:01:34 +04:00
case WITNESS_NOTIFY_RESOURCE_CHANGE :
d_printf ( " Resource change " ) ;
break ;
case WITNESS_NOTIFY_CLIENT_MOVE :
d_printf ( " Client move " ) ;
break ;
case WITNESS_NOTIFY_SHARE_MOVE :
d_printf ( " Share move " ) ;
break ;
case WITNESS_NOTIFY_IP_CHANGE :
d_printf ( " IP change " ) ;
break ;
default :
2014-02-04 18:43:39 +04:00
d_printf ( " Unknown (0x%x) " , ( int ) response - > type ) ;
2013-08-05 13:01:34 +04:00
}
2014-02-04 18:43:39 +04:00
d_printf ( " with %d messages \n " , response - > num ) ;
2013-08-05 13:01:34 +04:00
2015-06-26 00:12:18 +03:00
for ( i = 0 ; i < response - > num ; i + + ) {
print_notify_response ( & response - > messages [ i ] , response - > type ) ;
2013-08-05 13:01:34 +04:00
}
done :
talloc_free ( frame ) ;
return result ;
}
struct cmd_set witness_commands [ ] = {
2019-01-11 16:47:02 +03:00
{
. name = " WITNESS " ,
} ,
{
. name = " GetInterfaceList " ,
. returntype = RPC_RTYPE_WERROR ,
. ntfn = NULL ,
. wfn = & cmd_witness_GetInterfaceList ,
. table = & ndr_table_witness ,
. rpc_pipe = NULL ,
2021-05-19 15:51:00 +03:00
. description = " List the interfaces to which witness client connections can be made " ,
2019-01-11 16:47:02 +03:00
. usage = " " ,
} ,
{
. name = " Register " ,
. returntype = RPC_RTYPE_WERROR ,
. ntfn = NULL ,
. wfn = & cmd_witness_Register ,
. table = & ndr_table_witness ,
. rpc_pipe = NULL ,
2021-05-19 15:51:00 +03:00
. description = " Register for resource state change notifications of a NetName and IPAddress " ,
2019-01-11 16:47:02 +03:00
. usage = " " ,
} ,
{
. name = " UnRegister " ,
. returntype = RPC_RTYPE_WERROR ,
. ntfn = NULL ,
. wfn = & cmd_witness_UnRegister ,
. table = & ndr_table_witness ,
. rpc_pipe = NULL ,
2021-05-19 15:51:00 +03:00
. description = " Unregister for notifications from the server</para></listitem></varlistentry> " ,
2019-01-11 16:47:02 +03:00
. usage = " " ,
} ,
{
. name = " AsyncNotify " ,
. returntype = RPC_RTYPE_WERROR ,
. ntfn = NULL ,
. wfn = & cmd_witness_AsyncNotify ,
. table = & ndr_table_witness ,
. rpc_pipe = NULL ,
2021-05-19 15:51:00 +03:00
. description = " Request notification of registered resource changes from the server " ,
2019-01-11 16:47:02 +03:00
. usage = " " ,
} ,
{
. name = " RegisterEx " ,
. returntype = RPC_RTYPE_WERROR ,
. ntfn = NULL ,
. wfn = & cmd_witness_RegisterEx ,
. table = & ndr_table_witness ,
. rpc_pipe = NULL ,
2021-05-19 15:51:00 +03:00
. description = " Register for resource state change notifications of a NetName, ShareName and multiple IPAddresses " ,
2019-01-11 16:47:02 +03:00
. usage = " " ,
} ,
{
. name = NULL ,
}
2013-08-05 13:01:34 +04:00
} ;
/*
* We have to use the same connection for each subcommand
* for the context handles to be meaningful .
*/
static void use_only_one_rpc_pipe_hack ( struct rpc_pipe_client * cli )
{
struct cmd_set * ptr ;
for ( ptr = & witness_commands [ 0 ] ; ptr - > name ; ptr + + ) {
ptr - > rpc_pipe = cli ;
}
}