diff options
-rw-r--r-- | source3/include/doserr.h | 1 | ||||
-rw-r--r-- | source3/include/rpc_svcctl.h | 5 | ||||
-rw-r--r-- | source3/libsmb/doserr.c | 1 | ||||
-rw-r--r-- | source3/rpc_client/cli_svcctl.c | 69 | ||||
-rw-r--r-- | source3/utils/net_rpc_service.c | 298 |
5 files changed, 352 insertions, 22 deletions
diff --git a/source3/include/doserr.h b/source3/include/doserr.h index 259eafc45f..60a3c335ec 100644 --- a/source3/include/doserr.h +++ b/source3/include/doserr.h @@ -186,6 +186,7 @@ #define WERR_IO_PENDING W_ERROR(997) #define WERR_CAN_NOT_COMPLETE W_ERROR(1003) #define WERR_NO_SUCH_SERVICE W_ERROR(1060) +#define WERR_INVALID_SERVICE_CONTROL W_ERROR(1052) #define WERR_INVALID_SECURITY_DESCRIPTOR W_ERROR(1338) #define WERR_SERVER_UNAVAILABLE W_ERROR(1722) #define WERR_INVALID_FORM_NAME W_ERROR(1902) diff --git a/source3/include/rpc_svcctl.h b/source3/include/rpc_svcctl.h index 6fcfd6f52d..fd24ec7ca9 100644 --- a/source3/include/rpc_svcctl.h +++ b/source3/include/rpc_svcctl.h @@ -72,6 +72,11 @@ #define SVCCTL_ACCEPT_HARDWAREPROFILECHANGE 0x00000020 #define SVCCTL_ACCEPT_POWEREVENT 0x00000040 +/* Service Controls */ + +#define SVCCTL_CONTROL_STOP 0x00000001 +#define SVCCTL_CONTROL_PAUSE 0x00000002 +#define SVCCTL_CONTROL_CONTINUE 0x00000003 /* utility structures for RPCs */ diff --git a/source3/libsmb/doserr.c b/source3/libsmb/doserr.c index daac5c4664..0dca265348 100644 --- a/source3/libsmb/doserr.c +++ b/source3/libsmb/doserr.c @@ -70,6 +70,7 @@ werror_code_struct dos_errs[] = { "WERR_INVALID_OWNER", WERR_INVALID_OWNER }, { "WERR_SERVER_UNAVAILABLE", WERR_SERVER_UNAVAILABLE }, { "WERR_IO_PENDING", WERR_IO_PENDING }, + { "WERR_INVALID_SERVICE_CONTROL", WERR_INVALID_SERVICE_CONTROL }, { NULL, W_ERROR(0) } }; diff --git a/source3/rpc_client/cli_svcctl.c b/source3/rpc_client/cli_svcctl.c index c9fdc61379..19bf419983 100644 --- a/source3/rpc_client/cli_svcctl.c +++ b/source3/rpc_client/cli_svcctl.c @@ -28,13 +28,13 @@ struct svc_state_msg { }; static struct svc_state_msg state_msg_table[] = { - { SVCCTL_STOPPED, "SVCCTL_STOPPED" }, - { SVCCTL_START_PENDING, "SVCCTL_START_PENDING" }, - { SVCCTL_STOP_PENDING, "SVCCTL_STOP_PENDING" }, - { SVCCTL_RUNNING, "SVCCTL_RUNNING" }, - { SVCCTL_CONTINUE_PENDING, "SVCCTL_CONTINUE_PENDING" }, - { SVCCTL_PAUSE_PENDING, "SVCCTL_PAUSE_PENDING" }, - { SVCCTL_PAUSED, "SVCCTL_PAUSED" }, + { SVCCTL_STOPPED, "stopped" }, + { SVCCTL_START_PENDING, "start pending" }, + { SVCCTL_STOP_PENDING, "stop pending" }, + { SVCCTL_RUNNING, "running" }, + { SVCCTL_CONTINUE_PENDING, "resume pending" }, + { SVCCTL_PAUSE_PENDING, "pause pending" }, + { SVCCTL_PAUSED, "paused" }, { 0, NULL } }; @@ -136,7 +136,7 @@ WERROR cli_svcctl_open_service( struct cli_state *cli, TALLOC_CTX *mem_ctx, /******************************************************************** ********************************************************************/ -WERROR close_service_handle( struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *hService ) +WERROR cli_svcctl_close_service( struct cli_state *cli, TALLOC_CTX *mem_ctx, POLICY_HND *hService ) { SVCCTL_Q_CLOSE_SERVICE in; SVCCTL_R_CLOSE_SERVICE out; @@ -310,19 +310,62 @@ WERROR cli_svcctl_query_config(struct cli_state *cli, TALLOC_CTX *mem_ctx, /******************************************************************* *******************************************************************/ -WERROR cli_svcctl_start_service(struct cli_state *cli, TALLOC_CTX *mem_ctx ) +WERROR cli_svcctl_start_service( struct cli_state *cli, TALLOC_CTX *mem_ctx, + POLICY_HND *hService, + const char **parm_array, uint32 parmcount ) { - - return WERR_OK; + SVCCTL_Q_START_SERVICE in; + SVCCTL_R_START_SERVICE out; + prs_struct qbuf, rbuf; + + ZERO_STRUCT(in); + ZERO_STRUCT(out); + + memcpy( &in.handle, hService, sizeof(POLICY_HND) ); + + in.parmcount = 0; + in.parameters.ref_id = 0x0; + + CLI_DO_RPC( cli, mem_ctx, PI_SVCCTL, SVCCTL_START_SERVICE_W, + in, out, + qbuf, rbuf, + svcctl_io_q_start_service, + svcctl_io_r_start_service, + WERR_GENERAL_FAILURE ); + + return out.status; } /******************************************************************* *******************************************************************/ -WERROR cli_svcctl_control_service(struct cli_state *cli, TALLOC_CTX *mem_ctx ) +WERROR cli_svcctl_control_service( struct cli_state *cli, TALLOC_CTX *mem_ctx, + POLICY_HND *hService, uint32 control, + SERVICE_STATUS *status ) { + SVCCTL_Q_CONTROL_SERVICE in; + SVCCTL_R_CONTROL_SERVICE out; + prs_struct qbuf, rbuf; + + ZERO_STRUCT(in); + ZERO_STRUCT(out); + + memcpy( &in.handle, hService, sizeof(POLICY_HND) ); + in.control = control; + + CLI_DO_RPC( cli, mem_ctx, PI_SVCCTL, SVCCTL_CONTROL_SERVICE, + in, out, + qbuf, rbuf, + svcctl_io_q_control_service, + svcctl_io_r_control_service, + WERR_GENERAL_FAILURE ); + + if ( !W_ERROR_IS_OK( out.status ) ) + return out.status; - return WERR_OK; + memcpy( status, &out.svc_status, sizeof(SERVICE_STATUS) ); + + return out.status; } diff --git a/source3/utils/net_rpc_service.c b/source3/utils/net_rpc_service.c index 5e933e76cd..94644f8dcf 100644 --- a/source3/utils/net_rpc_service.c +++ b/source3/utils/net_rpc_service.c @@ -20,6 +20,113 @@ #include "includes.h" #include "utils/net.h" + +/******************************************************************** +********************************************************************/ + +static WERROR query_service_state( struct cli_state *cli, TALLOC_CTX *mem_ctx, + POLICY_HND *hSCM, const char *service, uint32 *state ) +{ + POLICY_HND hService; + SERVICE_STATUS service_status; + WERROR result = WERR_GENERAL_FAILURE; + + /* now cycle until the status is actually 'watch_state' */ + + result = cli_svcctl_open_service( cli, mem_ctx, hSCM, &hService, + service, SC_RIGHT_SVC_QUERY_STATUS ); + + if ( !W_ERROR_IS_OK(result) ) { + d_printf("Failed to open service. [%s]\n", dos_errstr(result)); + return result; + } + + result = cli_svcctl_query_status( cli, mem_ctx, &hService, &service_status ); + if ( W_ERROR_IS_OK(result) ) { + *state = service_status.state; + } + + cli_svcctl_close_service( cli, mem_ctx, &hService ); + + return result; +} + +/******************************************************************** +********************************************************************/ + +static WERROR watch_service_state( struct cli_state *cli, TALLOC_CTX *mem_ctx, + POLICY_HND *hSCM, const char *service, + uint32 watch_state, uint32 *final_state ) +{ + uint32 i; + uint32 state = 0; + WERROR result = WERR_GENERAL_FAILURE; + + + i = 0; + while ( (state != watch_state ) && i<30 ) { + /* get the status */ + + result = query_service_state( cli, mem_ctx, hSCM, service, &state ); + if ( !W_ERROR_IS_OK(result) ) { + break; + } + + d_printf("."); + i++; + usleep( 100 ); + } + d_printf("\n"); + + *final_state = state; + + return result; +} + +/******************************************************************** +********************************************************************/ + +static WERROR control_service( struct cli_state *cli, TALLOC_CTX *mem_ctx, + POLICY_HND *hSCM, const char *service, + uint32 control, uint32 watch_state ) +{ + POLICY_HND hService; + WERROR result = WERR_GENERAL_FAILURE; + SERVICE_STATUS service_status; + uint32 state = 0; + + /* Open the Service */ + + result = cli_svcctl_open_service( cli, mem_ctx, hSCM, &hService, + service, (SC_RIGHT_SVC_STOP|SC_RIGHT_SVC_PAUSE_CONTINUE) ); + + if ( !W_ERROR_IS_OK(result) ) { + d_printf("Failed to open service. [%s]\n", dos_errstr(result)); + goto done; + } + + /* get the status */ + + result = cli_svcctl_control_service( cli, mem_ctx, &hService, + control, &service_status ); + + if ( !W_ERROR_IS_OK(result) ) { + d_printf("Control service request failed. [%s]\n", dos_errstr(result)); + goto done; + } + + /* loop -- checking the state until we are where we want to be */ + + result = watch_service_state( cli, mem_ctx, hSCM, service, watch_state, &state ); + + d_printf("%s service is %s.\n", service, svc_status_string(state)); + +done: + cli_svcctl_close_service( cli, mem_ctx, &hService ); + + return result; +} + /******************************************************************** ********************************************************************/ @@ -65,7 +172,7 @@ static NTSTATUS rpc_service_list_internal( const DOM_SID *domain_sid, const char } done: - close_service_handle( cli, mem_ctx, &hSCM ); + cli_svcctl_close_service( cli, mem_ctx, &hSCM ); return werror_to_ntstatus(result); } @@ -161,8 +268,77 @@ static NTSTATUS rpc_service_status_internal( const DOM_SID *domain_sid, const ch } done: - close_service_handle( cli, mem_ctx, &hService ); - close_service_handle( cli, mem_ctx, &hSCM ); + cli_svcctl_close_service( cli, mem_ctx, &hService ); + cli_svcctl_close_service( cli, mem_ctx, &hSCM ); + + return werror_to_ntstatus(result); +} + + +/******************************************************************** +********************************************************************/ + +static NTSTATUS rpc_service_stop_internal( const DOM_SID *domain_sid, const char *domain_name, + struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv ) +{ + POLICY_HND hSCM; + WERROR result = WERR_GENERAL_FAILURE; + fstring servicename; + + if (argc != 1 ) { + d_printf("Usage: net rpc service status <service>\n"); + return NT_STATUS_OK; + } + + fstrcpy( servicename, argv[0] ); + + /* Open the Service Control Manager */ + + result = cli_svcctl_open_scm( cli, mem_ctx, &hSCM, SC_RIGHT_MGR_ENUMERATE_SERVICE ); + if ( !W_ERROR_IS_OK(result) ) { + d_printf("Failed to open Service Control Manager. [%s]\n", dos_errstr(result)); + return werror_to_ntstatus(result); + } + + result = control_service( cli, mem_ctx, &hSCM, servicename, + SVCCTL_CONTROL_STOP, SVCCTL_STOPPED ); + + cli_svcctl_close_service( cli, mem_ctx, &hSCM ); + + return werror_to_ntstatus(result); +} + +/******************************************************************** +********************************************************************/ + +static NTSTATUS rpc_service_pause_internal( const DOM_SID *domain_sid, const char *domain_name, + struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv ) +{ + POLICY_HND hSCM; + WERROR result = WERR_GENERAL_FAILURE; + fstring servicename; + + if (argc != 1 ) { + d_printf("Usage: net rpc service status <service>\n"); + return NT_STATUS_OK; + } + + fstrcpy( servicename, argv[0] ); + + /* Open the Service Control Manager */ + + result = cli_svcctl_open_scm( cli, mem_ctx, &hSCM, SC_RIGHT_MGR_ENUMERATE_SERVICE ); + if ( !W_ERROR_IS_OK(result) ) { + d_printf("Failed to open Service Control Manager. [%s]\n", dos_errstr(result)); + return werror_to_ntstatus(result); + } + + result = control_service( cli, mem_ctx, &hSCM, servicename, + SVCCTL_CONTROL_PAUSE, SVCCTL_PAUSED ); + + cli_svcctl_close_service( cli, mem_ctx, &hSCM ); return werror_to_ntstatus(result); } @@ -170,6 +346,99 @@ done: /******************************************************************** ********************************************************************/ +static NTSTATUS rpc_service_resume_internal( const DOM_SID *domain_sid, const char *domain_name, + struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv ) +{ + POLICY_HND hSCM; + WERROR result = WERR_GENERAL_FAILURE; + fstring servicename; + + if (argc != 1 ) { + d_printf("Usage: net rpc service status <service>\n"); + return NT_STATUS_OK; + } + + fstrcpy( servicename, argv[0] ); + + /* Open the Service Control Manager */ + + result = cli_svcctl_open_scm( cli, mem_ctx, &hSCM, SC_RIGHT_MGR_ENUMERATE_SERVICE ); + if ( !W_ERROR_IS_OK(result) ) { + d_printf("Failed to open Service Control Manager. [%s]\n", dos_errstr(result)); + return werror_to_ntstatus(result); + } + + result = control_service( cli, mem_ctx, &hSCM, servicename, + SVCCTL_CONTROL_CONTINUE, SVCCTL_RUNNING ); + + cli_svcctl_close_service( cli, mem_ctx, &hSCM ); + + return werror_to_ntstatus(result); +} + +/******************************************************************** +********************************************************************/ + +static NTSTATUS rpc_service_start_internal( const DOM_SID *domain_sid, const char *domain_name, + struct cli_state *cli, TALLOC_CTX *mem_ctx, + int argc, const char **argv ) +{ + POLICY_HND hSCM, hService; + WERROR result = WERR_GENERAL_FAILURE; + fstring servicename; + uint32 state = 0; + + if (argc != 1 ) { + d_printf("Usage: net rpc service status <service>\n"); + return NT_STATUS_OK; + } + + fstrcpy( servicename, argv[0] ); + + /* Open the Service Control Manager */ + + result = cli_svcctl_open_scm( cli, mem_ctx, &hSCM, SC_RIGHT_MGR_ENUMERATE_SERVICE ); + if ( !W_ERROR_IS_OK(result) ) { + d_printf("Failed to open Service Control Manager. [%s]\n", dos_errstr(result)); + return werror_to_ntstatus(result); + } + + /* Open the Service */ + + result = cli_svcctl_open_service( cli, mem_ctx, &hSCM, &hService, + servicename, SC_RIGHT_SVC_START ); + + if ( !W_ERROR_IS_OK(result) ) { + d_printf("Failed to open service. [%s]\n", dos_errstr(result)); + goto done; + } + + /* get the status */ + + result = cli_svcctl_start_service( cli, mem_ctx, &hService, NULL, 0 ); + if ( !W_ERROR_IS_OK(result) ) { + d_printf("Query status request failed. [%s]\n", dos_errstr(result)); + goto done; + } + + result = watch_service_state( cli, mem_ctx, &hSCM, servicename, SVCCTL_RUNNING, &state ); + + if ( W_ERROR_IS_OK(result) && (state == SVCCTL_RUNNING) ) + d_printf("Successfully started service: %s\n", servicename ); + else + d_printf("Failed to start service: %s [%s]\n", servicename, dos_errstr(result) ); + +done: + cli_svcctl_close_service( cli, mem_ctx, &hService ); + cli_svcctl_close_service( cli, mem_ctx, &hSCM ); + + return werror_to_ntstatus(result); +} + +/******************************************************************** +********************************************************************/ + static int rpc_service_list( int argc, const char **argv ) { return run_rpc_command( NULL, PI_SVCCTL, 0, @@ -181,8 +450,8 @@ static int rpc_service_list( int argc, const char **argv ) static int rpc_service_start( int argc, const char **argv ) { - d_printf("not implemented\n"); - return 0; + return run_rpc_command( NULL, PI_SVCCTL, 0, + rpc_service_start_internal, argc, argv ); } /******************************************************************** @@ -190,8 +459,17 @@ static int rpc_service_start( int argc, const char **argv ) static int rpc_service_stop( int argc, const char **argv ) { - d_printf("not implemented\n"); - return 0; + return run_rpc_command( NULL, PI_SVCCTL, 0, + rpc_service_stop_internal, argc, argv ); +} + +/******************************************************************** +********************************************************************/ + +static int rpc_service_resume( int argc, const char **argv ) +{ + return run_rpc_command( NULL, PI_SVCCTL, 0, + rpc_service_resume_internal, argc, argv ); } /******************************************************************** @@ -199,8 +477,8 @@ static int rpc_service_stop( int argc, const char **argv ) static int rpc_service_pause( int argc, const char **argv ) { - d_printf("not implemented\n"); - return 0; + return run_rpc_command( NULL, PI_SVCCTL, 0, + rpc_service_pause_internal, argc, argv ); } /******************************************************************** @@ -221,6 +499,7 @@ static int net_help_service( int argc, const char **argv ) d_printf("net rpc service start <service> Start a service\n"); d_printf("net rpc service stop <service> Stop a service\n"); d_printf("net rpc service pause <service> Pause a service\n"); + d_printf("net rpc service resume <service> Resume a paused a service\n"); d_printf("net rpc service status <service> View the current status of a service\n"); return -1; @@ -236,6 +515,7 @@ int net_rpc_service(int argc, const char **argv) {"start", rpc_service_start}, {"stop", rpc_service_stop}, {"pause", rpc_service_pause}, + {"resume", rpc_service_resume}, {"status", rpc_service_status}, {NULL, NULL} }; |