module RubySMB::Dcerpc::Svcctl

Constants

CHANGE_SERVICE_CONFIG_W
CLOSE_SERVICE_HANDLE

Operation numbers

CONTROL_SERVICE
OPEN_SC_MANAGER_W
OPEN_SERVICE_W
QUERY_SERVICE_CONFIG_W
QUERY_SERVICE_STATUS
SC_MANAGER_CONNECT

Required to connect to the SCM.

SC_MANAGER_CREATE_SERVICE

Required for a service to be created.

SC_MANAGER_ENUMERATE_SERVICE

Required to enumerate a service.

SC_MANAGER_LOCK

Required to lock the SCM database.

SC_MANAGER_MODIFY_BOOT_CONFIG

Required to call the RNotifyBootConfigStatus method.

SC_MANAGER_QUERY_LOCK_STATUS

Required to query the lock status of the SCM database.

SERVICE_ACCEPT_HARDWAREPROFILECHANGE

Service is notified when the computer's hardware profile changes.

SERVICE_ACCEPT_PARAMCHANGE

Service can reread its startup parameters without being stopped and restarted. This control code allows the service to receive SERVICE_CONTROL_PARAMCHANGE notifications.

SERVICE_ACCEPT_PAUSE_CONTINUE

Service can be paused and continued. This control code allows the service to receive SERVICE_CONTROL_PAUSE and SERVICE_CONTROL_CONTINUE notifications.

SERVICE_ACCEPT_POWEREVENT

Service is notified when the computer's power status changes.

SERVICE_ACCEPT_PRESHUTDOWN

The service can perform preshutdown tasks. SERVICE_ACCEPT_PRESHUTDOWN is sent before sending SERVICE_CONTROL_SHUTDOWN to give more time to services that need extra time before shutdown occurs.

SERVICE_ACCEPT_SESSIONCHANGE

Service is notified when the computer's session status changes.

SERVICE_ACCEPT_SHUTDOWN

Service is notified when system shutdown occurs. This control code enables the service to receive SERVICE_CONTROL_SHUTDOWN notifications from the server.

SERVICE_ACCEPT_STOP

Service can be stopped. This control code allows the service to receive SERVICE_CONTROL_STOP notifications.

SERVICE_ACCEPT_TIMECHANGE

Service is notified when the system time changes.

SERVICE_ACCEPT_TRIGGEREVENT

Service is notified when an event for which the service has registered occurs.

SERVICE_ALL_ACCESS

In addition to all access rights in this table, SERVICE_ALL_ACCESS includes Delete (DE), Read Control (RC), Write DACL (WD), and Write Owner (WO) access, as specified in ACCESS_MASK (section 2.4.3) of [MS-DTYP].

SERVICE_AUTO_START

A service started automatically by the SCM during system startup.

SERVICE_BOOT_START

Starts the driver service when the system boots up. This value is valid only for driver services.

SERVICE_CHANGE_CONFIG

Required to change the configuration of a service.

SERVICE_CONTINUE_PENDING
SERVICE_CONTROL_CONTINUE

Notifies a paused service that it SHOULD resume. The SERVICE_PAUSE_CONTINUE access right MUST have been granted to the caller when the RPC control handle to the service record was created. The service record MUST have the SERVICE_ACCEPT_PAUSE_CONTINUE bit set in the ServiceStatus.dwControlsAccepted field of the service record.

SERVICE_CONTROL_INTERROGATE

Notifies a service that it SHOULD report its current status information to the SCM. The SERVICE_INTERROGATE access right MUST have been granted to the caller when the RPC control handle to the service record was created.

SERVICE_CONTROL_NETBINDADD

Notifies a service that there is a new component for binding. The SERVICE_PAUSE_CONTINUE access right MUST have been granted to the caller when the RPC control handle to the service record was created. The service record MUST have the SERVICE_ACCEPT_NETBINDCHANGE bit set in the ServiceStatus.dwControlsAccepted field of the service record.

SERVICE_CONTROL_NETBINDDISABLE

Notifies a network service that one of its bindings has been disabled. The SERVICE_PAUSE_CONTINUE access right MUST have been granted to the caller when the RPC control handle to the service record was created. The service record MUST have the SERVICE_ACCEPT_NETBINDCHANGE bit set in the ServiceStatus.dwControlsAccepted field of the service record.

SERVICE_CONTROL_NETBINDENABLE

Notifies a network service that a disabled binding has been enabled. The SERVICE_PAUSE_CONTINUE access right MUST have been granted to the caller when the RPC control handle to the service record was created. The service record MUST have the SERVICE_ACCEPT_NETBINDCHANGE bit set in the ServiceStatus.dwControlsAccepted field of the service record.

SERVICE_CONTROL_NETBINDREMOVE

Notifies a network service that a component for binding has been removed. The SERVICE_PAUSE_CONTINUE access right MUST have been granted to the caller when the RPC control handle to the service record was created. The service record MUST have the SERVICE_ACCEPT_NETBINDCHANGE bit set in the ServiceStatus.dwControlsAccepted field of the service record.

SERVICE_CONTROL_PARAMCHANGE

Notifies a service that its startup parameters have changed. The SERVICE_PAUSE_CONTINUE access right MUST have been granted to the caller when the RPC control handle to the service record was created. The service record MUST have the SERVICE_ACCEPT_PARAMCHANGE bit set in the ServiceStatus.dwControlsAccepted field of the service record.

SERVICE_CONTROL_PAUSE

Notifies a service that it SHOULD pause. The SERVICE_PAUSE_CONTINUE access right MUST have been granted to the caller when the RPC control handle to the service record was created. The service record MUST have the SERVICE_ACCEPT_PAUSE_CONTINUE bit set in the ServiceStatus.dwControlsAccepted field of the service record.

SERVICE_CONTROL_STOP

Notifies a service that it SHOULD stop. The SERVICE_STOP access right MUST have been granted to the caller when the RPC control handle to the service record was created. The service record MUST have the SERVICE_ACCEPT_STOP bit set in the ServiceStatus.dwControlsAccepted field of the service record.

SERVICE_DEMAND_START

Starts the service when a client requests the SCM to start the service.

SERVICE_DISABLED

A service that cannot be started. Attempts to start the service result in the error code ERROR_SERVICE_DISABLED.

SERVICE_ENUMERATE_DEPENDENTS

Required to enumerate the services installed on the server.

SERVICE_ERROR_CRITICAL

The SCM SHOULD log the error in the event log if possible. If the last-known good configuration is being started, the startup operation fails. Otherwise, the system is restarted with the last-known good configuration.

SERVICE_ERROR_IGNORE

The SCM ignores the error and continues the startup operation.

SERVICE_ERROR_NORMAL

The SCM logs the error in the event log and continues the startup operation.

SERVICE_ERROR_SEVERE

The SCM logs the error in the event log. If the last-known good configuration is being started, the startup operation continues. Otherwise, the system is restarted with the last-known good configuration.

SERVICE_FILE_SYSTEM_DRIVER

A file system driver service. These are services that manage file systems on the system.

SERVICE_INTERACTIVE_PROCESS

The service can interact with the desktop. Only SERVICE_WIN32_OWN_PROCESS and SERVICE_INTERACTIVE_PROCESS OR SERVICE_WIN32_SHARE_PROCESS and SERVICE_INTERACTIVE_PROCESS can be combined.

SERVICE_INTERROGATE

Required to request immediate status from the service.

SERVICE_KERNEL_DRIVER

A driver service. These are services that manage devices on the system.

SERVICE_NO_CHANGE

Service type, start or error control does not change.

SERVICE_PAUSED

Current State

SERVICE_PAUSE_CONTINUE

Required to pause or continue the service.

SERVICE_PAUSE_PENDING
SERVICE_QUERY_CONFIG

Required to query the service configuration.

SERVICE_QUERY_STATUS

Required to request the service status.

SERVICE_RUNNING
SERVICE_SET_STATUS

Required for a service to set its status.

SERVICE_START

Required to start the service.

SERVICE_START_PENDING
SERVICE_STOP

Required to stop the service.

SERVICE_STOPPED
SERVICE_STOP_PENDING
SERVICE_SYSTEM_START

Starts the driver service when the system boots up. This value is valid only for driver services. The services marked SERVICE_SYSTEM_START are started after all SERVICE_BOOT_START services have been started.

SERVICE_USER_DEFINED_CONTROL

Required to specify a user-defined control code.

SERVICE_WIN32_OWN_PROCESS

A service that runs in its own process.

SERVICE_WIN32_SHARE_PROCESS

A service that shares a process with other services.

START_SERVICE_W
UUID
VER_MAJOR
VER_MINOR

Public Instance Methods

change_service_config_w(svc_handle, opts = {}) click to toggle source

Changes a service's configuration parameters in the SCM database

@param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the service record @param opts [Hash] configuration parameters to change @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a ChangeServiceConfigWResponse packet @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS

# File lib/ruby_smb/dcerpc/svcctl.rb, line 380
def change_service_config_w(svc_handle, opts = {})
  opts = {
    h_service:             svc_handle,
    dw_service_type:       opts[:service_type] || SERVICE_NO_CHANGE,
    dw_start_type:         opts[:start_type] || SERVICE_NO_CHANGE,
    dw_error_control:      opts[:error_control] || SERVICE_NO_CHANGE,
    lp_binary_path_name:   opts[:binary_path_name] || :null,
    lp_load_order_group:   opts[:load_order_group] || :null,
    dw_tag_id:             opts[:tag_id] || :null,
    lp_dependencies:       opts[:dependencies] || [],
    lp_service_start_name: opts[:service_start_name] || :null,
    lp_password:           opts[:password] || [],
    lp_display_name:       opts[:display_name] || :null
  }

  csc_request = ChangeServiceConfigWRequest.new(opts)
  response = dcerpc_request(csc_request)
  begin
    csc_response = ChangeServiceConfigWResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading ChangeServiceConfigWResponse'
  end
  unless csc_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::SvcctlError,
      "Error returned when changing the service configuration: "\
      "#{WindowsError::Win32.find_by_retval(csc_response.error_status.value).join(',')}"
  end
end
close_service_handle(svc_handle) click to toggle source

Releases the handle to the specified service or the SCM database.

@param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the service record or to the SCM database @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a CloseServiceHandleResponse packet @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS

# File lib/ruby_smb/dcerpc/svcctl.rb, line 463
def close_service_handle(svc_handle)
  csh_request = CloseServiceHandleRequest.new(h_sc_object: svc_handle)
  response = dcerpc_request(csh_request)
  begin
    csh_response = CloseServiceHandleResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading CloseServiceHandleResponse'
  end
  unless csh_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::SvcctlError,
      "Error returned when closing the service: "\
      "#{WindowsError::Win32.find_by_retval(csh_response.error_status.value).join(',')}"
  end
end
control_service(svc_handle, control) click to toggle source

Send a control code to a specific service handle

@param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the service record @param control [Integer] control code @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a ControlServiceResponse packet @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS

# File lib/ruby_smb/dcerpc/svcctl.rb, line 443
def control_service(svc_handle, control)
  cs_request = ControlServiceRequest.new(h_service: svc_handle, dw_control: control)
  response = dcerpc_request(cs_request)
  begin
    cs_response = ControlServiceResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading ControlServiceResponse'
  end
  unless cs_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::SvcctlError,
      "Error returned when sending a control to the service: "\
      "#{WindowsError::Win32.find_by_retval(cs_response.error_status.value).join(',')}"
  end
end
open_sc_manager_w(rhost, access = SERVICE_START | SERVICE_STOP | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SC_MANAGER_ENUMERATE_SERVICE) click to toggle source

Open the SCM database on the specified server.

@param rhost [String] the server's machine name @return [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the newly opened SCM database @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a OpenSCManagerWResponse packet @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS

# File lib/ruby_smb/dcerpc/svcctl.rb, line 274
def open_sc_manager_w(rhost, access = SERVICE_START | SERVICE_STOP | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SC_MANAGER_ENUMERATE_SERVICE)
  open_sc_manager_w_request = OpenSCManagerWRequest.new(dw_desired_access: access)
  open_sc_manager_w_request.lp_machine_name = rhost
  open_sc_manager_w_request.lp_database_name = 'ServicesActive'
  response = dcerpc_request(open_sc_manager_w_request)
  begin
    open_sc_manager_w_response = OpenSCManagerWResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading OpenSCManagerWResponse'
  end
  unless open_sc_manager_w_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::SvcctlError,
      "Error returned when opening Service Control Manager (SCM): "\
      "#{WindowsError::Win32.find_by_retval(open_sc_manager_w_response.error_status.value).join(',')}"
  end
  open_sc_manager_w_response.lp_sc_handle
end
open_service_w(scm_handle, service_name, access = SERVICE_ALL_ACCESS) click to toggle source

Creates an RPC context handle to an existing service record.

@param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the SCM database @param service_name [Srting] the ServiceName of the service record @param access [Integer] access right @return [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the found service record @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a OpenServiceWResponse packet @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS

# File lib/ruby_smb/dcerpc/svcctl.rb, line 300
def open_service_w(scm_handle, service_name, access = SERVICE_ALL_ACCESS)
  open_service_w_request = OpenServiceWRequest.new(dw_desired_access: access)
  open_service_w_request.lp_sc_handle = scm_handle
  open_service_w_request.lp_service_name = service_name
  response = dcerpc_request(open_service_w_request)
  begin
    open_sercice_w_response = OpenServiceWResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading OpenServiceWResponse'
  end
  unless open_sercice_w_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::SvcctlError,
      "Error returned when opening #{service_name} service: "\
      "#{WindowsError::Win32.find_by_retval(open_sercice_w_response.error_status.value).join(',')}"
  end
  open_sercice_w_response.lp_sc_handle
end
query_service_config(svc_handle) click to toggle source

Returns the configuration parameters of the specified service

@param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the service record @return [RubySMB::Dcerpc::Svcctl::QueryServiceConfigW] structure that contains the configuration parameters for the service @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a QueryServiceConfigWResponse packet @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS

# File lib/ruby_smb/dcerpc/svcctl.rb, line 347
def query_service_config(svc_handle)
  qsc_request = QueryServiceConfigWRequest.new
  qsc_request.h_service = svc_handle
  qsc_request.cb_buf_size = 0
  response = dcerpc_request(qsc_request)
  begin
    qsc_response = QueryServiceConfigWResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading QueryServiceConfigWResponse'
  end
  if qsc_response.error_status == WindowsError::Win32::ERROR_INSUFFICIENT_BUFFER
    qsc_request.cb_buf_size = qsc_response.pcb_bytes_needed
    response = dcerpc_request(qsc_request)
    begin
      qsc_response = QueryServiceConfigWResponse.read(response)
    rescue IOError
      raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading QueryServiceConfigWResponse'
    end
  end
  unless qsc_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::SvcctlError,
      "Error returned when querying service configuration: "\
      "#{WindowsError::Win32.find_by_retval(qsc_response.error_status.value).join(',')}"
  end
  qsc_response.lp_service_config
end
query_service_status(svc_handle) click to toggle source

Returns the current status of the specified service

@param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the service record @return [RubySMB::Dcerpc::Svcctl::ServiceStatus] structure that contains the status information for the service @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a QueryServiceStatusResponse packet @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS

# File lib/ruby_smb/dcerpc/svcctl.rb, line 324
def query_service_status(svc_handle)
  qss_request = QueryServiceStatusRequest.new
  qss_request.h_service = svc_handle
  response = dcerpc_request(qss_request)
  begin
    qss_response = QueryServiceStatusResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading QueryServiceStatusResponse'
  end
  unless qss_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::SvcctlError,
      "Error returned when querying service status: "\
      "#{WindowsError::Win32.find_by_retval(qss_response.error_status.value).join(',')}"
  end
  qss_response.lp_service_status
end
start_service_w(svc_handle, argv = []) click to toggle source

Starts a specified service

@param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the service record @param argv [Array<String>] arguments to the service (Array of

strings). The first element in argv must be the name of the service.

@raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a StartServiceWResponse packet @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS

# File lib/ruby_smb/dcerpc/svcctl.rb, line 416
def start_service_w(svc_handle, argv = [])
  ss_request = StartServiceWRequest.new(h_service: svc_handle)
  unless argv.empty?
    ss_request.argc = argv.size
    ndr_string_ptrsw = RubySMB::Dcerpc::Ndr::NdrStringPtrsw.new
    ndr_string_ptrsw.elements = argv
    ss_request.argv = ndr_string_ptrsw
  end
  response = dcerpc_request(ss_request)
  begin
    ss_response = StartServiceWResponse.read(response)
  rescue IOError
    raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading StartServiceWResponse'
  end
  unless ss_response.error_status == WindowsError::Win32::ERROR_SUCCESS
    raise RubySMB::Dcerpc::Error::SvcctlError,
      "Error returned when starting the service: "\
      "#{WindowsError::Win32.find_by_retval(ss_response.error_status.value).join(',')}"
  end
end