2018-04-10 17:18:18 +02:00
/*
* Samba Unix / Linux CIFS implementation
*
* winexe
*
* Copyright ( C ) 2018 Volker Lendecke < vl @ samba . org >
*
* 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 "version.h"
2021-01-15 16:34:55 +01:00
# include <popt.h>
# include <tevent.h>
2018-04-10 17:18:18 +02:00
# include "lib/param/param.h"
# include "auth/credentials/credentials.h"
# include "lib/util/talloc_stack.h"
# include "lib/util/tevent_ntstatus.h"
# include "lib/util/sys_rw.h"
# include "libsmb/proto.h"
# include "librpc/gen_ndr/ndr_svcctl_c.h"
# include "rpc_client/cli_pipe.h"
# include "libcli/smb/smbXcli_base.h"
# include "libcli/util/werror.h"
# include "lib/async_req/async_sock.h"
2021-01-15 16:34:55 +01:00
# include "lib/cmdline/cmdline.h"
2018-04-10 17:18:18 +02:00
# include "client.h"
# define SVC_INTERACTIVE 1
# define SVC_IGNORE_INTERACTIVE 2
# define SVC_INTERACTIVE_MASK 3
# define SVC_FORCE_UPLOAD 4
# define SVC_OS64BIT 8
# define SVC_OSCHOOSE 16
# define SVC_UNINSTALL 32
# define SVC_SYSTEM 64
# define SERVICE_NAME "winexesvc"
# define PIPE_NAME "ahexec"
# define PIPE_NAME_IN "ahexec_stdin%08X"
# define PIPE_NAME_OUT "ahexec_stdout%08X"
# define PIPE_NAME_ERR "ahexec_stderr%08X"
static const char version_message_fmt [ ] = " winexe version %d.%d \n "
" This program may be freely redistributed under the terms of the "
" GNU GPLv3 \n " ;
struct program_options {
char * hostname ;
2019-07-04 20:28:33 -04:00
int port ;
2018-04-10 17:18:18 +02:00
char * cmd ;
struct cli_credentials * credentials ;
char * runas ;
char * runas_file ;
int flags ;
} ;
static void parse_args ( int argc , const char * argv [ ] ,
TALLOC_CTX * mem_ctx ,
2021-01-15 16:34:55 +01:00
struct program_options * options )
2018-04-10 17:18:18 +02:00
{
poptContext pc ;
int opt , i ;
int argc_new ;
char * * argv_new ;
2019-07-04 20:28:33 -04:00
int port = 445 ;
char * port_str = NULL ;
2018-04-10 17:18:18 +02:00
int flag_interactive = SVC_IGNORE_INTERACTIVE ;
int flag_ostype = 2 ;
int flag_reinstall = 0 ;
int flag_uninstall = 0 ;
int flag_help = 0 ;
int flag_version = 0 ;
2021-01-15 16:34:55 +01:00
bool ok ;
2018-04-10 17:18:18 +02:00
struct poptOption long_options [ ] = {
2021-01-15 16:34:55 +01:00
POPT_AUTOHELP
2019-05-23 09:16:51 +02:00
{
. longName = " uninstall " ,
. shortName = 0 ,
. argInfo = POPT_ARG_NONE ,
. arg = & flag_uninstall ,
. val = 0 ,
. descrip = " Uninstall winexe service after "
" remote execution " ,
. argDescrip = NULL ,
} , {
. longName = " reinstall " ,
. shortName = 0 ,
. argInfo = POPT_ARG_NONE ,
. arg = & flag_reinstall ,
. val = 0 ,
. descrip = " Reinstall winexe service before "
" remote execution " ,
. argDescrip = NULL ,
} , {
. longName = " runas " ,
. shortName = 0 ,
. argInfo = POPT_ARG_STRING ,
. arg = & options - > runas ,
. val = 0 ,
. descrip = " Run as the given user (BEWARE: this "
" password is sent in cleartext over "
" the network!) " ,
. argDescrip = " [DOMAIN \\ ]USERNAME%PASSWORD " ,
} , {
. longName = " runas-file " ,
. shortName = 0 ,
. argInfo = POPT_ARG_STRING ,
. arg = & options - > runas_file ,
. val = 0 ,
. descrip = " Run as user options defined in a file " ,
. argDescrip = " FILE " ,
} , {
. longName = " interactive " ,
. shortName = 0 ,
. argInfo = POPT_ARG_INT ,
. arg = & flag_interactive ,
. val = 0 ,
. descrip = " Desktop interaction: 0 - disallow, "
" 1 - allow. If allow, also use the "
" --system switch (Windows requirement). "
" Vista does not support this option. " ,
. argDescrip = " 0|1 " ,
} , {
. longName = " ostype " ,
. shortName = 0 ,
. argInfo = POPT_ARG_INT ,
. arg = & flag_ostype ,
. val = 0 ,
. descrip = " OS type: 0 - 32-bit, 1 - 64-bit, "
" 2 - winexe will decide. "
" Determines which version (32-bit or 64-bit) "
" of service will be installed. " ,
. argDescrip = " 0|1|2 " ,
} ,
2021-01-15 16:34:55 +01:00
POPT_COMMON_SAMBA
POPT_COMMON_CREDENTIALS
POPT_COMMON_VERSION
2018-04-10 17:18:18 +02:00
POPT_TABLEEND
} ;
ZERO_STRUCTP ( options ) ;
2021-01-15 16:34:55 +01:00
ok = samba_cmdline_init ( mem_ctx ,
SAMBA_CMDLINE_CONFIG_CLIENT ,
false /* require_smbconf */ ) ;
if ( ! ok ) {
DBG_ERR ( " Failed to init cmdline parser! \n " ) ;
TALLOC_FREE ( mem_ctx ) ;
exit ( 1 ) ;
}
pc = samba_popt_get_context ( getprogname ( ) ,
argc ,
argv ,
long_options ,
0 ) ;
if ( pc = = NULL ) {
DBG_ERR ( " Failed to setup popt context! \n " ) ;
TALLOC_FREE ( mem_ctx ) ;
exit ( 1 ) ;
}
2018-04-10 17:18:18 +02:00
2019-07-04 20:28:33 -04:00
poptSetOtherOptionHelp ( pc , " [OPTION]... //HOST[:PORT] COMMAND \n Options: " ) ;
2018-04-10 17:18:18 +02:00
if ( ( ( opt = poptGetNextOpt ( pc ) ) ! = - 1 ) | | flag_help | | flag_version ) {
fprintf ( stderr , version_message_fmt , SAMBA_VERSION_MAJOR ,
SAMBA_VERSION_MINOR ) ;
if ( flag_version ) {
exit ( 0 ) ;
}
poptPrintHelp ( pc , stdout , 0 ) ;
if ( flag_help ) {
exit ( 0 ) ;
}
exit ( 1 ) ;
}
argv_new = discard_const_p ( char * , poptGetArgs ( pc ) ) ;
argc_new = argc ;
for ( i = 0 ; i < argc ; i + + ) {
if ( ! argv_new | | argv_new [ i ] = = NULL ) {
argc_new = i ;
break ;
}
}
if ( argc_new ! = 2 | | argv_new [ 0 ] [ 0 ] ! = ' / ' | | argv_new [ 0 ] [ 1 ] ! = ' / ' ) {
fprintf ( stderr , version_message_fmt , SAMBA_VERSION_MAJOR ,
SAMBA_VERSION_MINOR ) ;
poptPrintHelp ( pc , stdout , 0 ) ;
exit ( 1 ) ;
}
2019-07-04 20:28:33 -04:00
port_str = strchr ( argv_new [ 0 ] , ' : ' ) ;
if ( port_str ) {
if ( sscanf ( port_str + 1 , " %d " , & port ) ! = 1 | | port < = 0 ) {
fprintf ( stderr , version_message_fmt ,
SAMBA_VERSION_MAJOR , SAMBA_VERSION_MINOR ) ;
poptPrintHelp ( pc , stdout , 0 ) ;
exit ( 1 ) ;
}
* port_str = ' \0 ' ;
}
2018-04-10 17:18:18 +02:00
if ( options - > runas = = NULL & & options - > runas_file ! = NULL ) {
struct cli_credentials * runas_cred ;
const char * user ;
const char * pass ;
runas_cred = cli_credentials_init ( mem_ctx ) ;
cli_credentials_parse_file ( runas_cred , options - > runas_file ,
CRED_SPECIFIED ) ;
user = cli_credentials_get_username ( runas_cred ) ;
pass = cli_credentials_get_password ( runas_cred ) ;
if ( user & & pass ) {
char buffer [ 1024 ] ;
const char * dom ;
dom = cli_credentials_get_domain ( runas_cred ) ;
if ( dom ) {
snprintf ( buffer , sizeof ( buffer ) , " %s \\ %s%%%s " ,
dom , user , pass ) ;
} else {
snprintf ( buffer , sizeof ( buffer ) , " %s%%%s " ,
user , pass ) ;
}
buffer [ sizeof ( buffer ) - 1 ] = ' \0 ' ;
options - > runas = talloc_strdup ( mem_ctx , buffer ) ;
}
}
2021-01-15 16:34:55 +01:00
options - > credentials = samba_cmdline_get_creds ( ) ;
2018-04-10 17:18:18 +02:00
2021-11-04 22:22:44 +01:00
options - > hostname = talloc_strdup ( mem_ctx , argv_new [ 0 ] + 2 ) ;
if ( options - > hostname = = NULL ) {
DBG_ERR ( " Out of memory \n " ) ;
exit ( 1 ) ;
}
2019-07-04 20:28:33 -04:00
options - > port = port ;
2021-11-04 22:22:44 +01:00
options - > cmd = talloc_strdup ( mem_ctx , argv_new [ 1 ] ) ;
if ( options - > cmd = = NULL ) {
DBG_ERR ( " Out of memory \n " ) ;
exit ( 1 ) ;
}
poptFreeContext ( pc ) ;
2018-04-10 17:18:18 +02:00
options - > flags = flag_interactive ;
if ( flag_reinstall ) {
options - > flags | = SVC_FORCE_UPLOAD ;
}
if ( flag_ostype = = 1 ) {
options - > flags | = SVC_OS64BIT ;
}
if ( flag_ostype = = 2 ) {
options - > flags | = SVC_OSCHOOSE ;
}
if ( flag_uninstall ) {
options - > flags | = SVC_UNINSTALL ;
}
}
static NTSTATUS winexe_svc_upload (
const char * hostname ,
2019-07-04 20:28:33 -04:00
int port ,
2018-04-10 17:18:18 +02:00
const char * service_filename ,
const DATA_BLOB * svc32_exe ,
const DATA_BLOB * svc64_exe ,
struct cli_credentials * credentials ,
int flags )
{
struct cli_state * cli ;
2020-11-25 11:38:01 +01:00
uint16_t fnum = 0xffff ;
2018-04-10 17:18:18 +02:00
NTSTATUS status ;
const DATA_BLOB * binary = NULL ;
status = cli_full_connection_creds (
& cli ,
NULL ,
hostname ,
NULL ,
2019-07-04 20:28:33 -04:00
port ,
2018-04-10 17:18:18 +02:00
" ADMIN$ " ,
" ????? " ,
credentials ,
0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " cli_full_connection_creds failed: %s \n " ,
nt_errstr ( status ) ) ;
return status ;
}
if ( flags & SVC_FORCE_UPLOAD ) {
status = cli_unlink ( cli , service_filename , 0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " cli_unlink failed: %s \n " ,
nt_errstr ( status ) ) ;
}
}
if ( flags & SVC_OSCHOOSE ) {
status = cli_chkpath ( cli , " SysWoW64 " ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
flags | = SVC_OS64BIT ;
}
}
if ( flags & SVC_OS64BIT ) {
binary = svc64_exe ;
} else {
binary = svc32_exe ;
}
if ( binary = = NULL ) {
2020-11-25 11:38:01 +01:00
goto done ;
2018-04-10 17:18:18 +02:00
}
status = cli_ntcreate (
cli ,
service_filename ,
0 , /* CreatFlags */
SEC_FILE_WRITE_DATA , /* DesiredAccess */
FILE_ATTRIBUTE_NORMAL , /* FileAttributes */
FILE_SHARE_WRITE | FILE_SHARE_READ , /* ShareAccess */
FILE_OPEN_IF , /* CreateDisposition */
FILE_NON_DIRECTORY_FILE , /* CreateOptions */
0 , /* SecurityFlags */
& fnum ,
NULL ) ; /* CreateReturns */
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " Could not create %s: %s \n " , service_filename ,
nt_errstr ( status ) ) ;
goto done ;
}
status = cli_writeall (
cli ,
fnum ,
0 ,
binary - > data ,
0 ,
binary - > length ,
NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " Could not write file: %s \n " , nt_errstr ( status ) ) ;
2020-11-25 11:38:01 +01:00
goto done ;
2018-04-10 17:18:18 +02:00
}
done :
2020-11-25 11:38:01 +01:00
if ( fnum ! = 0xffff ) {
status = cli_close ( cli , fnum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " Close(% " PRIu16 " ) failed for %s: %s \n " ,
fnum ,
service_filename ,
nt_errstr ( status ) ) ;
}
}
2018-04-10 17:18:18 +02:00
TALLOC_FREE ( cli ) ;
return status ;
}
static NTSTATUS winexe_svc_install (
struct cli_state * cli ,
const char * hostname ,
2019-07-04 20:28:33 -04:00
int port ,
2018-04-10 17:18:18 +02:00
const char * service_name ,
const char * service_filename ,
const DATA_BLOB * svc32_exe ,
const DATA_BLOB * svc64_exe ,
struct cli_credentials * credentials ,
int flags )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct rpc_pipe_client * rpccli ;
struct policy_handle scmanager_handle ;
struct policy_handle service_handle ;
struct SERVICE_STATUS service_status ;
bool need_start = false ;
bool need_conf = false ;
NTSTATUS status ;
WERROR werr ;
2021-11-18 11:31:00 +01:00
const char * remote_name = smbXcli_conn_remote_name ( cli - > conn ) ;
const struct sockaddr_storage * remote_sockaddr =
smbXcli_conn_remote_sockaddr ( cli - > conn ) ;
2018-04-10 17:18:18 +02:00
status = cli_rpc_pipe_open_noauth_transport (
cli ,
NCACN_NP ,
& ndr_table_svcctl ,
2021-11-18 11:31:00 +01:00
remote_name ,
remote_sockaddr ,
2018-04-10 17:18:18 +02:00
& rpccli ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " cli_rpc_pipe_open_noauth_transport failed: %s \n " ,
nt_errstr ( status ) ) ;
goto done ;
}
status = dcerpc_svcctl_OpenSCManagerW (
rpccli - > binding_handle ,
frame ,
2021-11-18 11:31:00 +01:00
remote_name ,
2018-04-10 17:18:18 +02:00
NULL ,
SEC_FLAG_MAXIMUM_ALLOWED ,
& scmanager_handle ,
& werr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " dcerpc_svcctl_OpenSCManagerW failed: %s \n " ,
nt_errstr ( status ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_OpenSCManagerW failed: %s \n " ,
win_errstr ( werr ) ) ;
goto done ;
}
status = dcerpc_svcctl_OpenServiceW (
rpccli - > binding_handle ,
frame ,
& scmanager_handle ,
service_name ,
SERVICE_ALL_ACCESS ,
& service_handle ,
& werr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " dcerpc_svcctl_OpenServiceW failed: %s \n " ,
nt_errstr ( status ) ) ;
goto close_scmanager ;
}
if ( W_ERROR_EQUAL ( werr , WERR_SERVICE_DOES_NOT_EXIST ) ) {
status = dcerpc_svcctl_CreateServiceW (
rpccli - > binding_handle ,
frame ,
& scmanager_handle ,
service_name ,
NULL ,
SERVICE_ALL_ACCESS ,
SERVICE_TYPE_WIN32_OWN_PROCESS |
( ( flags & SVC_INTERACTIVE ) ?
SERVICE_TYPE_INTERACTIVE_PROCESS : 0 ) ,
SVCCTL_DEMAND_START ,
SVCCTL_SVC_ERROR_NORMAL ,
service_filename ,
NULL ,
NULL ,
NULL ,
0 ,
NULL ,
NULL ,
0 ,
& service_handle ,
& werr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " dcerpc_svcctl_CreateServiceW "
" failed: %s \n " , nt_errstr ( status ) ) ;
goto close_scmanager ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_CreateServiceW "
" failed: %s \n " , win_errstr ( werr ) ) ;
status = werror_to_ntstatus ( werr ) ;
goto close_scmanager ;
}
}
status = dcerpc_svcctl_QueryServiceStatus (
rpccli - > binding_handle ,
frame ,
& service_handle ,
& service_status ,
& werr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " dcerpc_svcctl_QueryServiceStatus "
" failed: %s \n " , nt_errstr ( status ) ) ;
goto close_service ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_QueryServiceStatus "
" failed: %s \n " , win_errstr ( werr ) ) ;
status = werror_to_ntstatus ( werr ) ;
goto close_service ;
}
if ( ! ( flags & SVC_IGNORE_INTERACTIVE ) ) {
need_conf =
! ( service_status . type &
SERVICE_TYPE_INTERACTIVE_PROCESS ) ^
! ( flags & SVC_INTERACTIVE ) ;
}
if ( service_status . state = = SVCCTL_STOPPED ) {
need_start = true ;
} else if ( need_conf ) {
status = dcerpc_svcctl_ControlService (
rpccli - > binding_handle ,
frame ,
& service_handle ,
SVCCTL_CONTROL_STOP ,
& service_status ,
& werr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " dcerpc_svcctl_ControlServiceStatus "
" failed: %s \n " , nt_errstr ( status ) ) ;
goto close_service ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_ControlServiceStatus "
" failed: %s \n " , win_errstr ( werr ) ) ;
status = werror_to_ntstatus ( werr ) ;
goto close_service ;
}
do {
smb_msleep ( 100 ) ;
status = dcerpc_svcctl_QueryServiceStatus (
rpccli - > binding_handle ,
frame ,
& service_handle ,
& service_status ,
& werr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " dcerpc_svcctl_QueryServiceStatus "
" failed: %s \n " , nt_errstr ( status ) ) ;
goto close_service ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_QueryServiceStatus "
" failed: %s \n " , win_errstr ( werr ) ) ;
status = werror_to_ntstatus ( werr ) ;
goto close_service ;
}
} while ( service_status . state = = SVCCTL_STOP_PENDING ) ;
need_start = 1 ;
}
if ( need_conf ) {
status = dcerpc_svcctl_ChangeServiceConfigW (
rpccli - > binding_handle ,
frame ,
& service_handle ,
SERVICE_TYPE_WIN32_OWN_PROCESS |
( ( flags & SVC_INTERACTIVE ) ?
SERVICE_TYPE_INTERACTIVE_PROCESS : 0 ) , /* type */
UINT32_MAX , /* start_type, SERVICE_NO_CHANGE */
UINT32_MAX , /* error_control, SERVICE_NO_CHANGE */
NULL , /* binary_path */
NULL , /* load_order_group */
NULL , /* tag_id */
NULL , /* dependencies */
2020-03-04 15:23:43 +01:00
0 , /* dwDependSize */
2018-04-10 17:18:18 +02:00
NULL , /* service_start_name */
NULL , /* password */
2020-03-04 15:23:43 +01:00
0 , /* dwPwSize */
2018-04-10 17:18:18 +02:00
NULL , /* display_name */
& werr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " dcerpc_svcctl_ChangeServiceConfigW "
" failed: %s \n " , nt_errstr ( status ) ) ;
goto close_service ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_ChangeServiceConfigW "
" failed: %s \n " , win_errstr ( werr ) ) ;
status = werror_to_ntstatus ( werr ) ;
goto close_service ;
}
}
if ( need_start ) {
status = winexe_svc_upload (
hostname ,
2019-07-04 20:28:33 -04:00
port ,
2018-04-10 17:18:18 +02:00
service_filename ,
svc32_exe ,
svc64_exe ,
credentials ,
flags ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " winexe_svc_upload failed: %s \n " ,
nt_errstr ( status ) ) ;
goto close_service ;
}
status = dcerpc_svcctl_StartServiceW (
rpccli - > binding_handle ,
frame ,
& service_handle ,
0 , /* num_args */
NULL , /* arguments */
& werr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " dcerpc_svcctl_StartServiceW "
" failed: %s \n " , nt_errstr ( status ) ) ;
goto close_service ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_StartServiceW "
" failed: %s \n " , win_errstr ( werr ) ) ;
status = werror_to_ntstatus ( werr ) ;
goto close_service ;
}
do {
smb_msleep ( 100 ) ;
status = dcerpc_svcctl_QueryServiceStatus (
rpccli - > binding_handle ,
frame ,
& service_handle ,
& service_status ,
& werr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " dcerpc_svcctl_QueryServiceStatus "
" failed: %s \n " , nt_errstr ( status ) ) ;
goto close_service ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_QueryServiceStatus "
" failed: %s \n " , win_errstr ( werr ) ) ;
status = werror_to_ntstatus ( werr ) ;
goto close_service ;
}
} while ( service_status . state = = SVCCTL_START_PENDING ) ;
if ( service_status . state ! = SVCCTL_RUNNING ) {
DBG_WARNING ( " Failed to start service \n " ) ;
status = NT_STATUS_UNSUCCESSFUL ;
goto close_service ;
}
}
close_service :
{
NTSTATUS close_status ;
WERROR close_werr ;
close_status = dcerpc_svcctl_CloseServiceHandle (
rpccli - > binding_handle ,
frame ,
& service_handle ,
& close_werr ) ;
if ( ! NT_STATUS_IS_OK ( close_status ) ) {
DBG_WARNING ( " dcerpc_svcctl_CloseServiceHandle "
" failed: %s \n " , nt_errstr ( close_status ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( close_werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_CloseServiceHandle "
" failed: %s \n " , win_errstr ( close_werr ) ) ;
goto done ;
}
}
close_scmanager :
{
NTSTATUS close_status ;
WERROR close_werr ;
close_status = dcerpc_svcctl_CloseServiceHandle (
rpccli - > binding_handle ,
frame ,
& scmanager_handle ,
& close_werr ) ;
if ( ! NT_STATUS_IS_OK ( close_status ) ) {
DBG_WARNING ( " dcerpc_svcctl_CloseServiceHandle "
" failed: %s \n " , nt_errstr ( close_status ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( close_werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_CloseServiceHandle "
" failed: %s \n " , win_errstr ( close_werr ) ) ;
goto done ;
}
}
done :
TALLOC_FREE ( rpccli ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
static NTSTATUS winexe_svc_uninstall (
struct cli_state * cli ,
const char * service_name )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct rpc_pipe_client * rpccli ;
struct policy_handle scmanager_handle ;
struct policy_handle service_handle ;
struct SERVICE_STATUS service_status ;
NTSTATUS status ;
WERROR werr ;
2021-11-18 11:31:00 +01:00
const char * remote_name = smbXcli_conn_remote_name ( cli - > conn ) ;
const struct sockaddr_storage * remote_sockaddr =
smbXcli_conn_remote_sockaddr ( cli - > conn ) ;
2018-04-10 17:18:18 +02:00
status = cli_rpc_pipe_open_noauth_transport (
cli ,
NCACN_NP ,
& ndr_table_svcctl ,
2021-11-18 11:31:00 +01:00
remote_name ,
remote_sockaddr ,
2018-04-10 17:18:18 +02:00
& rpccli ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " cli_rpc_pipe_open_noauth_transport failed: %s \n " ,
nt_errstr ( status ) ) ;
goto done ;
}
status = dcerpc_svcctl_OpenSCManagerW (
rpccli - > binding_handle ,
frame ,
2021-11-18 11:31:00 +01:00
remote_name ,
2018-04-10 17:18:18 +02:00
NULL ,
SEC_FLAG_MAXIMUM_ALLOWED ,
& scmanager_handle ,
& werr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " dcerpc_svcctl_OpenSCManagerW failed: %s \n " ,
nt_errstr ( status ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_OpenSCManagerW failed: %s \n " ,
win_errstr ( werr ) ) ;
goto done ;
}
status = dcerpc_svcctl_OpenServiceW (
rpccli - > binding_handle ,
frame ,
& scmanager_handle ,
service_name ,
SERVICE_ALL_ACCESS ,
& service_handle ,
& werr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " dcerpc_svcctl_OpenServiceW failed: %s \n " ,
nt_errstr ( status ) ) ;
goto close_scmanager ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_OpenServiceW failed: %s \n " ,
win_errstr ( werr ) ) ;
status = werror_to_ntstatus ( werr ) ;
goto close_scmanager ;
}
status = dcerpc_svcctl_ControlService (
rpccli - > binding_handle ,
frame ,
& service_handle ,
SVCCTL_CONTROL_STOP ,
& service_status ,
& werr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " dcerpc_svcctl_ControlServiceStatus "
" failed: %s \n " , nt_errstr ( status ) ) ;
goto close_service ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_ControlServiceStatus "
" failed: %s \n " , win_errstr ( werr ) ) ;
status = werror_to_ntstatus ( werr ) ;
goto close_service ;
}
do {
smb_msleep ( 100 ) ;
status = dcerpc_svcctl_QueryServiceStatus (
rpccli - > binding_handle ,
frame ,
& service_handle ,
& service_status ,
& werr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " dcerpc_svcctl_QueryServiceStatus "
" failed: %s \n " , nt_errstr ( status ) ) ;
goto close_service ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_QueryServiceStatus "
" failed: %s \n " , win_errstr ( werr ) ) ;
status = werror_to_ntstatus ( werr ) ;
goto close_service ;
}
} while ( service_status . state ! = SVCCTL_STOPPED ) ;
status = dcerpc_svcctl_DeleteService (
rpccli - > binding_handle ,
frame ,
& service_handle ,
& werr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " dcerpc_svcctl_DeleteService "
" failed: %s \n " , nt_errstr ( status ) ) ;
goto close_service ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_DeleteService "
" failed: %s \n " , win_errstr ( werr ) ) ;
status = werror_to_ntstatus ( werr ) ;
goto close_service ;
}
close_service :
{
NTSTATUS close_status ;
WERROR close_werr ;
close_status = dcerpc_svcctl_CloseServiceHandle (
rpccli - > binding_handle ,
frame ,
& service_handle ,
& close_werr ) ;
if ( ! NT_STATUS_IS_OK ( close_status ) ) {
DBG_WARNING ( " dcerpc_svcctl_CloseServiceHandle "
" failed: %s \n " , nt_errstr ( close_status ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( close_werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_CloseServiceHandle "
" failed: %s \n " , win_errstr ( close_werr ) ) ;
goto done ;
}
}
close_scmanager :
{
NTSTATUS close_status ;
WERROR close_werr ;
close_status = dcerpc_svcctl_CloseServiceHandle (
rpccli - > binding_handle ,
frame ,
& scmanager_handle ,
& close_werr ) ;
if ( ! NT_STATUS_IS_OK ( close_status ) ) {
DBG_WARNING ( " dcerpc_svcctl_CloseServiceHandle "
" failed: %s \n " , nt_errstr ( close_status ) ) ;
goto done ;
}
if ( ! W_ERROR_IS_OK ( close_werr ) ) {
DBG_WARNING ( " dcerpc_svcctl_CloseServiceHandle "
" failed: %s \n " , win_errstr ( close_werr ) ) ;
goto done ;
}
}
done :
TALLOC_FREE ( rpccli ) ;
TALLOC_FREE ( frame ) ;
return status ;
}
struct winexe_out_pipe_state {
struct tevent_context * ev ;
struct cli_state * cli ;
uint16_t out_pipe ;
int out_fd ;
char out_inbuf [ 256 ] ;
} ;
static void winexe_out_pipe_opened ( struct tevent_req * subreq ) ;
static void winexe_out_pipe_got_data ( struct tevent_req * subreq ) ;
static void winexe_out_pipe_closed ( struct tevent_req * subreq ) ;
static struct tevent_req * winexe_out_pipe_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * pipe_name ,
int out_fd )
{
struct tevent_req * req , * subreq ;
struct winexe_out_pipe_state * state ;
req = tevent_req_create ( mem_ctx , & state ,
struct winexe_out_pipe_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > cli = cli ;
state - > out_fd = out_fd ;
subreq = cli_ntcreate_send (
state ,
state - > ev ,
state - > cli ,
pipe_name ,
0 ,
SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE |
SEC_RIGHTS_FILE_EXECUTE ,
0 , /* FileAttributes */
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE ,
FILE_OPEN , /* CreateDisposition */
0 , /* CreateOptions */
2018-12-07 16:38:57 +01:00
SMB2_IMPERSONATION_IMPERSONATION ,
2018-04-10 17:18:18 +02:00
0 ) ; /* SecurityFlags */
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , winexe_out_pipe_opened , req ) ;
return req ;
}
static void winexe_out_pipe_opened ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct winexe_out_pipe_state * state = tevent_req_data (
req , struct winexe_out_pipe_state ) ;
int timeout ;
NTSTATUS status ;
status = cli_ntcreate_recv ( subreq , & state - > out_pipe , NULL ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
timeout = state - > cli - > timeout ;
state - > cli - > timeout = 0 ;
subreq = cli_read_send (
state ,
state - > ev ,
state - > cli ,
state - > out_pipe ,
state - > out_inbuf ,
0 ,
sizeof ( state - > out_inbuf ) ) ;
state - > cli - > timeout = timeout ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , winexe_out_pipe_got_data , req ) ;
}
static void winexe_out_pipe_got_data ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct winexe_out_pipe_state * state = tevent_req_data (
req , struct winexe_out_pipe_state ) ;
NTSTATUS status ;
int timeout ;
size_t received ;
ssize_t written ;
status = cli_read_recv ( subreq , & received ) ;
TALLOC_FREE ( subreq ) ;
DBG_DEBUG ( " cli_read for %d gave %s \n " ,
state - > out_fd ,
nt_errstr ( status ) ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_PIPE_DISCONNECTED ) ) {
subreq = cli_close_send (
state ,
state - > ev ,
state - > cli ,
state - > out_pipe ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , winexe_out_pipe_closed , req ) ;
return ;
}
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
if ( received > 0 ) {
written = sys_write ( state - > out_fd , state - > out_inbuf , received ) ;
if ( written = = - 1 ) {
tevent_req_nterror ( req , map_nt_error_from_unix ( errno ) ) ;
return ;
}
}
timeout = state - > cli - > timeout ;
state - > cli - > timeout = 0 ;
subreq = cli_read_send (
state ,
state - > ev ,
state - > cli ,
state - > out_pipe ,
state - > out_inbuf ,
0 ,
sizeof ( state - > out_inbuf ) ) ;
state - > cli - > timeout = timeout ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , winexe_out_pipe_got_data , req ) ;
}
static void winexe_out_pipe_closed ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
NTSTATUS status ;
status = cli_close_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
tevent_req_done ( req ) ;
}
static NTSTATUS winexe_out_pipe_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
struct winexe_in_pipe_state {
struct tevent_context * ev ;
struct cli_state * cli ;
struct tevent_req * fd_read_req ;
bool close_requested ;
bool closing ;
uint16_t in_pipe ;
int in_fd ;
char inbuf [ 256 ] ;
} ;
static void winexe_in_pipe_opened ( struct tevent_req * subreq ) ;
static void winexe_in_pipe_got_data ( struct tevent_req * subreq ) ;
static void winexe_in_pipe_written ( struct tevent_req * subreq ) ;
static void winexe_in_pipe_closed ( struct tevent_req * subreq ) ;
static struct tevent_req * winexe_in_pipe_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * pipe_name ,
int in_fd )
{
struct tevent_req * req , * subreq ;
struct winexe_in_pipe_state * state ;
req = tevent_req_create ( mem_ctx , & state ,
struct winexe_in_pipe_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > cli = cli ;
state - > in_fd = in_fd ;
subreq = cli_ntcreate_send (
state ,
state - > ev ,
state - > cli ,
pipe_name ,
0 ,
SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE |
SEC_RIGHTS_FILE_EXECUTE ,
0 , /* FileAttributes */
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE ,
FILE_OPEN , /* CreateDisposition */
0 , /* CreateOptions */
2018-12-07 16:38:57 +01:00
SMB2_IMPERSONATION_IMPERSONATION ,
2018-04-10 17:18:18 +02:00
0 ) ; /* SecurityFlags */
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , winexe_in_pipe_opened , req ) ;
return req ;
}
static void winexe_in_pipe_opened ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct winexe_in_pipe_state * state = tevent_req_data (
req , struct winexe_in_pipe_state ) ;
NTSTATUS status ;
status = cli_ntcreate_recv ( subreq , & state - > in_pipe , NULL ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
subreq = wait_for_read_send (
state ,
state - > ev ,
state - > in_fd ,
true ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , winexe_in_pipe_got_data , req ) ;
state - > fd_read_req = subreq ;
}
static void winexe_in_pipe_got_data ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct winexe_in_pipe_state * state = tevent_req_data (
req , struct winexe_in_pipe_state ) ;
int err ;
bool ok ;
int timeout ;
ssize_t nread ;
ok = wait_for_read_recv ( subreq , & err ) ;
TALLOC_FREE ( subreq ) ;
if ( ! ok ) {
tevent_req_nterror ( req , map_nt_error_from_unix ( err ) ) ;
return ;
}
state - > fd_read_req = NULL ;
nread = sys_read ( state - > in_fd , & state - > inbuf , sizeof ( state - > inbuf ) ) ;
if ( nread = = - 1 ) {
tevent_req_nterror ( req , map_nt_error_from_unix ( errno ) ) ;
return ;
}
if ( nread = = 0 ) {
tevent_req_nterror ( req , NT_STATUS_CONNECTION_DISCONNECTED ) ;
return ;
}
timeout = state - > cli - > timeout ;
state - > cli - > timeout = 0 ;
subreq = cli_writeall_send (
state ,
state - > ev ,
state - > cli ,
state - > in_pipe ,
0 ,
( uint8_t * ) state - > inbuf ,
0 ,
nread ) ;
state - > cli - > timeout = timeout ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , winexe_in_pipe_written , req ) ;
}
static void winexe_in_pipe_written ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct winexe_in_pipe_state * state = tevent_req_data (
req , struct winexe_in_pipe_state ) ;
NTSTATUS status ;
status = cli_writeall_recv ( subreq , NULL ) ;
TALLOC_FREE ( subreq ) ;
DBG_DEBUG ( " cli_writeall for %d gave %s \n " ,
state - > in_fd ,
nt_errstr ( status ) ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_PIPE_DISCONNECTED ) | |
state - > close_requested ) {
subreq = cli_close_send (
state ,
state - > ev ,
state - > cli ,
state - > in_pipe ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , winexe_in_pipe_closed , req ) ;
state - > closing = true ;
return ;
}
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
subreq = wait_for_read_send (
state ,
state - > ev ,
state - > in_fd ,
true ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , winexe_in_pipe_got_data , req ) ;
state - > fd_read_req = subreq ;
}
static void winexe_in_pipe_closed ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
NTSTATUS status ;
status = cli_close_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
return tevent_req_done ( req ) ;
}
static NTSTATUS winexe_in_pipe_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
static bool winexe_in_pipe_close ( struct tevent_req * req )
{
struct winexe_in_pipe_state * state = tevent_req_data (
req , struct winexe_in_pipe_state ) ;
struct tevent_req * subreq ;
if ( state - > closing ) {
return true ;
}
if ( state - > fd_read_req = = NULL ) {
/*
* cli_writeall active , wait for it to return
*/
state - > close_requested = true ;
return true ;
}
TALLOC_FREE ( state - > fd_read_req ) ;
subreq = cli_close_send (
state ,
state - > ev ,
state - > cli ,
state - > in_pipe ) ;
if ( subreq = = NULL ) {
return false ;
}
tevent_req_set_callback ( subreq , winexe_in_pipe_closed , req ) ;
state - > closing = true ;
return true ;
}
struct winexe_pipes_state {
struct tevent_req * pipes [ 3 ] ;
} ;
static void winexe_pipes_stdin_done ( struct tevent_req * subreq ) ;
static void winexe_pipes_stdout_done ( struct tevent_req * subreq ) ;
static void winexe_pipes_stderr_done ( struct tevent_req * subreq ) ;
static struct tevent_req * winexe_pipes_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * pipe_postfix )
{
struct tevent_req * req ;
struct winexe_pipes_state * state ;
char * pipe_name ;
req = tevent_req_create ( mem_ctx , & state , struct winexe_pipes_state ) ;
if ( req = = NULL ) {
return NULL ;
}
pipe_name = talloc_asprintf ( state , " \\ ahexec_stdin%s " , pipe_postfix ) ;
if ( tevent_req_nomem ( pipe_name , req ) ) {
return tevent_req_post ( req , ev ) ;
}
state - > pipes [ 0 ] = winexe_in_pipe_send (
state ,
ev ,
cli ,
pipe_name ,
0 ) ;
if ( tevent_req_nomem ( state - > pipes [ 0 ] , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( state - > pipes [ 0 ] , winexe_pipes_stdin_done , req ) ;
pipe_name = talloc_asprintf ( state , " \\ ahexec_stdout%s " , pipe_postfix ) ;
if ( tevent_req_nomem ( pipe_name , req ) ) {
return tevent_req_post ( req , ev ) ;
}
state - > pipes [ 1 ] = winexe_out_pipe_send (
state ,
ev ,
cli ,
pipe_name ,
1 ) ;
if ( tevent_req_nomem ( state - > pipes [ 1 ] , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( state - > pipes [ 1 ] , winexe_pipes_stdout_done ,
req ) ;
pipe_name = talloc_asprintf ( state , " \\ ahexec_stderr%s " , pipe_postfix ) ;
if ( tevent_req_nomem ( pipe_name , req ) ) {
return tevent_req_post ( req , ev ) ;
}
state - > pipes [ 2 ] = winexe_out_pipe_send (
state ,
ev ,
cli ,
pipe_name ,
2 ) ;
if ( tevent_req_nomem ( state - > pipes [ 2 ] , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( state - > pipes [ 2 ] , winexe_pipes_stderr_done ,
req ) ;
DBG_DEBUG ( " pipes = %p %p %p \n " ,
state - > pipes [ 0 ] ,
state - > pipes [ 1 ] ,
state - > pipes [ 2 ] ) ;
return req ;
}
static void winexe_pipes_stdin_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct winexe_pipes_state * state = tevent_req_data (
req , struct winexe_pipes_state ) ;
NTSTATUS status ;
status = winexe_in_pipe_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
DBG_DEBUG ( " stdin returned %s \n " , nt_errstr ( status ) ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
state - > pipes [ 0 ] = NULL ;
DBG_DEBUG ( " pipes = %p %p %p \n " ,
state - > pipes [ 0 ] ,
state - > pipes [ 1 ] ,
state - > pipes [ 2 ] ) ;
if ( ( state - > pipes [ 1 ] = = NULL ) & & ( state - > pipes [ 2 ] = = NULL ) ) {
tevent_req_done ( req ) ;
}
}
static void winexe_pipes_stdout_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct winexe_pipes_state * state = tevent_req_data (
req , struct winexe_pipes_state ) ;
NTSTATUS status ;
status = winexe_out_pipe_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
DBG_DEBUG ( " stdout returned %s \n " , nt_errstr ( status ) ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
if ( state - > pipes [ 0 ] ! = NULL ) {
winexe_in_pipe_close ( state - > pipes [ 0 ] ) ;
}
state - > pipes [ 1 ] = NULL ;
DBG_DEBUG ( " pipes = %p %p %p \n " ,
state - > pipes [ 0 ] ,
state - > pipes [ 1 ] ,
state - > pipes [ 2 ] ) ;
if ( ( state - > pipes [ 0 ] = = NULL ) & & ( state - > pipes [ 2 ] = = NULL ) ) {
tevent_req_done ( req ) ;
}
}
static void winexe_pipes_stderr_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct winexe_pipes_state * state = tevent_req_data (
req , struct winexe_pipes_state ) ;
NTSTATUS status ;
status = winexe_out_pipe_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
DBG_DEBUG ( " stderr returned %s \n " , nt_errstr ( status ) ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
if ( state - > pipes [ 0 ] ! = NULL ) {
winexe_in_pipe_close ( state - > pipes [ 0 ] ) ;
}
state - > pipes [ 2 ] = NULL ;
DBG_DEBUG ( " pipes = %p %p %p \n " ,
state - > pipes [ 0 ] ,
state - > pipes [ 1 ] ,
state - > pipes [ 2 ] ) ;
if ( ( state - > pipes [ 0 ] = = NULL ) & & ( state - > pipes [ 1 ] = = NULL ) ) {
tevent_req_done ( req ) ;
}
}
static NTSTATUS winexe_pipes_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
struct winexe_ctrl_state {
struct tevent_context * ev ;
struct cli_state * cli ;
uint16_t ctrl_pipe ;
bool ctrl_pipe_done ;
char ctrl_inbuf [ 256 ] ;
char * cmd ;
int return_code ;
struct tevent_req * pipes_req ;
} ;
static void winexe_ctrl_opened ( struct tevent_req * subreq ) ;
static void winexe_ctrl_got_read ( struct tevent_req * subreq ) ;
static void winexe_ctrl_wrote_version ( struct tevent_req * subreq ) ;
static void winexe_ctrl_wrote_cmd ( struct tevent_req * subreq ) ;
static void winexe_ctrl_pipes_done ( struct tevent_req * subreq ) ;
static void winexe_ctrl_pipe_closed ( struct tevent_req * subreq ) ;
static struct tevent_req * winexe_ctrl_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * cmd )
{
struct tevent_req * req , * subreq ;
struct winexe_ctrl_state * state ;
req = tevent_req_create ( mem_ctx , & state ,
struct winexe_ctrl_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > cli = cli ;
state - > cmd = talloc_asprintf ( state , " run %s \n " , cmd ) ;
if ( tevent_req_nomem ( state - > cmd , req ) ) {
return tevent_req_post ( req , ev ) ;
}
subreq = cli_ntcreate_send (
state ,
state - > ev ,
state - > cli ,
" \\ " PIPE_NAME ,
0 ,
SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE |
SEC_RIGHTS_FILE_EXECUTE ,
0 , /* FileAttributes */
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE ,
FILE_OPEN , /* CreateDisposition */
0 , /* CreateOptions */
2018-12-07 16:38:57 +01:00
SMB2_IMPERSONATION_IMPERSONATION ,
2018-04-10 17:18:18 +02:00
0 ) ; /* SecurityFlags */
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , winexe_ctrl_opened , req ) ;
return req ;
}
static void winexe_ctrl_opened ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct winexe_ctrl_state * state = tevent_req_data (
req , struct winexe_ctrl_state ) ;
int timeout ;
NTSTATUS status ;
static const char cmd [ ] = " get codepage \n get version \n " ;
status = cli_ntcreate_recv ( subreq , & state - > ctrl_pipe , NULL ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
timeout = state - > cli - > timeout ;
state - > cli - > timeout = 0 ;
subreq = cli_read_send (
state ,
state - > ev ,
state - > cli ,
state - > ctrl_pipe ,
state - > ctrl_inbuf ,
0 ,
sizeof ( state - > ctrl_inbuf ) - 1 ) ;
state - > cli - > timeout = timeout ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , winexe_ctrl_got_read , req ) ;
subreq = cli_writeall_send (
state ,
state - > ev ,
state - > cli ,
state - > ctrl_pipe ,
0 ,
( const uint8_t * ) cmd ,
0 ,
strlen ( cmd ) ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , winexe_ctrl_wrote_version , req ) ;
}
static void winexe_ctrl_got_read ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct winexe_ctrl_state * state = tevent_req_data (
req , struct winexe_ctrl_state ) ;
NTSTATUS status ;
int timeout ;
size_t received ;
unsigned int version , return_code ;
int ret ;
status = cli_read_recv ( subreq , & received ) ;
TALLOC_FREE ( subreq ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_PIPE_DISCONNECTED ) ) {
subreq = cli_close_send (
state ,
state - > ev ,
state - > cli ,
state - > ctrl_pipe ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , winexe_ctrl_pipe_closed , req ) ;
return ;
}
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
DBG_DEBUG ( " Got %zu bytes \n " , received ) ;
timeout = state - > cli - > timeout ;
state - > cli - > timeout = 0 ;
subreq = cli_read_send (
state ,
state - > ev ,
state - > cli ,
state - > ctrl_pipe ,
state - > ctrl_inbuf ,
0 ,
sizeof ( state - > ctrl_inbuf ) - 1 ) ;
state - > cli - > timeout = timeout ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , winexe_ctrl_got_read , req ) ;
ret = sscanf ( state - > ctrl_inbuf , " version 0x%x \n " , & version ) ;
if ( ret = = 1 ) {
DBG_DEBUG ( " Got version %x \n " , version ) ;
subreq = cli_writeall_send (
state ,
state - > ev ,
state - > cli ,
state - > ctrl_pipe ,
0 ,
( const uint8_t * ) state - > cmd ,
0 ,
strlen ( state - > cmd ) ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , winexe_ctrl_wrote_cmd , req ) ;
return ;
}
ret = strncmp ( state - > ctrl_inbuf , " std_io_err " , strlen ( " std_io_err " ) ) ;
if ( ret = = 0 ) {
char * p = state - > ctrl_inbuf + 11 ;
char * q = strchr ( state - > ctrl_inbuf , ' \n ' ) ;
char * postfix ;
size_t postfix_len ;
if ( q = = NULL ) {
DBG_DEBUG ( " Got invalid pipe postfix \n " ) ;
return ;
}
postfix_len = q - p ;
postfix = talloc_strndup ( state , p , postfix_len ) ;
if ( tevent_req_nomem ( postfix , req ) ) {
return ;
}
DBG_DEBUG ( " Got pipe postfix %s \n " , postfix ) ;
subreq = winexe_pipes_send (
state ,
state - > ev ,
state - > cli ,
postfix ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , winexe_ctrl_pipes_done , req ) ;
state - > pipes_req = subreq ;
return ;
}
ret = strncmp ( state - > ctrl_inbuf , " error " , strlen ( " error " ) ) ;
if ( ret = = 0 ) {
printf ( " Error: %s " , state - > ctrl_inbuf ) ;
return ;
}
2022-07-27 21:22:49 +03:00
ret = sscanf ( state - > ctrl_inbuf , " return_code %x \n " , & return_code ) ;
2018-04-10 17:18:18 +02:00
if ( ret = = 1 ) {
state - > return_code = return_code ;
return ;
}
}
static void winexe_ctrl_wrote_version ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
NTSTATUS status ;
status = cli_writeall_recv ( subreq , NULL ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
}
static void winexe_ctrl_wrote_cmd ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
NTSTATUS status ;
status = cli_writeall_recv ( subreq , NULL ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
}
static void winexe_ctrl_pipe_closed ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct winexe_ctrl_state * state = tevent_req_data (
req , struct winexe_ctrl_state ) ;
NTSTATUS status ;
status = cli_close_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
state - > ctrl_pipe_done = true ;
if ( state - > pipes_req = = NULL ) {
tevent_req_done ( req ) ;
}
}
static void winexe_ctrl_pipes_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct winexe_ctrl_state * state = tevent_req_data (
req , struct winexe_ctrl_state ) ;
NTSTATUS status ;
status = winexe_pipes_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
state - > pipes_req = NULL ;
if ( state - > ctrl_pipe_done ) {
tevent_req_done ( req ) ;
}
}
static NTSTATUS winexe_ctrl_recv ( struct tevent_req * req ,
int * preturn_code )
{
struct winexe_ctrl_state * state = tevent_req_data (
req , struct winexe_ctrl_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
if ( preturn_code ! = NULL ) {
* preturn_code = state - > return_code ;
}
return NT_STATUS_OK ;
}
static NTSTATUS winexe_ctrl ( struct cli_state * cli ,
const char * cmd ,
int * preturn_code )
{
struct tevent_context * ev = NULL ;
struct tevent_req * req = NULL ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
bool ok ;
ev = samba_tevent_context_init ( cli ) ;
if ( ev = = NULL ) {
goto done ;
}
req = winexe_ctrl_send ( ev , ev , cli , cmd ) ;
if ( req = = NULL ) {
goto done ;
}
ok = tevent_req_poll_ntstatus ( req , ev , & status ) ;
if ( ! ok ) {
goto done ;
}
status = winexe_ctrl_recv ( req , preturn_code ) ;
done :
TALLOC_FREE ( req ) ;
TALLOC_FREE ( ev ) ;
return status ;
}
# ifdef HAVE_WINEXE_CC_WIN32
const DATA_BLOB * winexesvc32_exe_binary ( void ) ;
# endif
# ifdef HAVE_WINEXE_CC_WIN64
const DATA_BLOB * winexesvc64_exe_binary ( void ) ;
# endif
2021-01-15 16:34:55 +01:00
int main ( int argc , char * argv [ ] )
2018-04-10 17:18:18 +02:00
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2021-01-15 16:34:55 +01:00
const char * * const_argv = discard_const_p ( const char * , argv ) ;
2018-04-10 17:18:18 +02:00
struct program_options options = { 0 } ;
2021-04-08 10:16:54 +02:00
struct cli_state * cli = NULL ;
2018-04-10 17:18:18 +02:00
const char * service_name = SERVICE_NAME ;
char * service_filename = NULL ;
# ifdef HAVE_WINEXE_CC_WIN32
const DATA_BLOB * winexesvc32_exe = winexesvc32_exe_binary ( ) ;
# else
const DATA_BLOB * winexesvc32_exe = NULL ;
# endif
# ifdef HAVE_WINEXE_CC_WIN64
const DATA_BLOB * winexesvc64_exe = winexesvc64_exe_binary ( ) ;
# else
const DATA_BLOB * winexesvc64_exe = NULL ;
# endif
NTSTATUS status ;
int ret = 1 ;
int return_code = 0 ;
smb_init_locale ( ) ;
2021-01-15 16:34:55 +01:00
parse_args ( argc , const_argv , frame , & options ) ;
2018-04-10 17:18:18 +02:00
2021-01-15 16:34:55 +01:00
samba_cmdline_burn ( argc , argv ) ;
2018-04-10 17:18:18 +02:00
if ( options . cmd = = NULL ) {
fprintf ( stderr , " no cmd given \n " ) ;
goto done ;
}
service_filename = talloc_asprintf ( frame , " %s.exe " , service_name ) ;
if ( service_filename = = NULL ) {
DBG_WARNING ( " talloc_asprintf failed \n " ) ;
goto done ;
}
status = cli_full_connection_creds (
& cli ,
2021-04-08 10:16:54 +02:00
lp_netbios_name ( ) ,
2018-04-10 17:18:18 +02:00
options . hostname ,
NULL ,
2019-07-04 20:28:33 -04:00
options . port ,
2018-04-10 17:18:18 +02:00
" IPC$ " ,
2021-04-08 10:16:54 +02:00
" IPC " ,
2018-04-10 17:18:18 +02:00
options . credentials ,
2020-06-04 14:59:14 +02:00
CLI_FULL_CONNECTION_IPC ) ;
2018-04-10 17:18:18 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " cli_full_connection_creds failed: %s \n " ,
nt_errstr ( status ) ) ;
goto done ;
}
status = winexe_svc_install (
cli ,
options . hostname ,
2019-07-04 20:28:33 -04:00
options . port ,
2018-04-10 17:18:18 +02:00
service_name ,
service_filename ,
winexesvc32_exe ,
winexesvc64_exe ,
options . credentials ,
options . flags ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " winexe_svc_install failed: %s \n " ,
nt_errstr ( status ) ) ;
goto done ;
}
status = winexe_ctrl ( cli , options . cmd , & return_code ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_PIPE_DISCONNECTED ) ) {
/* Normal finish */
status = NT_STATUS_OK ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " cli_ctrl failed: %s \n " ,
nt_errstr ( status ) ) ;
goto done ;
}
if ( options . flags & SVC_UNINSTALL ) {
status = winexe_svc_uninstall (
cli ,
service_name ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " winexe_svc_uninstall failed: %s \n " ,
nt_errstr ( status ) ) ;
goto done ;
}
}
ret = return_code ;
done :
TALLOC_FREE ( frame ) ;
return ret ;
}