Module: RubySMB::Dcerpc::Svcctl

Defined in:
lib/ruby_smb/dcerpc/svcctl.rb,
lib/ruby_smb/dcerpc/svcctl/service_status.rb,
lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb,
lib/ruby_smb/dcerpc/svcctl/control_service_request.rb,
lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb,
lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb,
lib/ruby_smb/dcerpc/svcctl/control_service_response.rb,
lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb,
lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb,
lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb,
lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb,
lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb,
lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb,
lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb,
lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb,
lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb,
lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb,
lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb

Defined Under Namespace

Classes: ChangeServiceConfigWRequest, ChangeServiceConfigWResponse, CloseServiceHandleRequest, CloseServiceHandleResponse, ControlServiceRequest, ControlServiceResponse, LpBoundedDword8k, OpenSCManagerWRequest, OpenSCManagerWResponse, OpenServiceWRequest, OpenServiceWResponse, QueryServiceConfigW, QueryServiceConfigWRequest, QueryServiceConfigWResponse, QueryServiceStatusRequest, QueryServiceStatusResponse, ScRpcHandle, ServiceStatus, StartServiceWRequest, StartServiceWResponse, SvcctlHandleW

Constant Summary collapse

UUID =
'367abb81-9844-35f1-ad32-98f038001003'
VER_MAJOR =
2
VER_MINOR =
0
CLOSE_SERVICE_HANDLE =

Operation numbers

0x0000
CONTROL_SERVICE =
0x0001
QUERY_SERVICE_STATUS =
0x0006
CHANGE_SERVICE_CONFIG_W =
0x000B
OPEN_SC_MANAGER_W =
0x000F
OPEN_SERVICE_W =
0x0010
QUERY_SERVICE_CONFIG_W =
0x0011
START_SERVICE_W =
0x0013
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].

0x000F01FF
SERVICE_CHANGE_CONFIG =

Required to change the configuration of a service.

0x00000002
SERVICE_ENUMERATE_DEPENDENTS =

Required to enumerate the services installed on the server.

0x00000008
SERVICE_INTERROGATE =

Required to request immediate status from the service.

0x00000080
SERVICE_PAUSE_CONTINUE =

Required to pause or continue the service.

0x00000040
SERVICE_QUERY_CONFIG =

Required to query the service configuration.

0x00000001
SERVICE_QUERY_STATUS =

Required to request the service status.

0x00000004
SERVICE_START =

Required to start the service.

0x00000010
SERVICE_STOP =

Required to stop the service.

0x00000020
SERVICE_USER_DEFINED_CONTROL =

Required to specify a user-defined control code.

0x00000100
SERVICE_SET_STATUS =

Required for a service to set its status.

0x00008000
SC_MANAGER_LOCK =

Required to lock the SCM database.

0x00000008
SC_MANAGER_CREATE_SERVICE =

Required for a service to be created.

0x00000002
SC_MANAGER_ENUMERATE_SERVICE =

Required to enumerate a service.

0x00000004
SC_MANAGER_CONNECT =

Required to connect to the SCM.

0x00000001
SC_MANAGER_QUERY_LOCK_STATUS =

Required to query the lock status of the SCM database.

0x00000010
SC_MANAGER_MODIFY_BOOT_CONFIG =

Required to call the RNotifyBootConfigStatus method.

0x00000020
SERVICE_KERNEL_DRIVER =

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

0x00000001
SERVICE_FILE_SYSTEM_DRIVER =

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

0x00000002
SERVICE_WIN32_OWN_PROCESS =

A service that runs in its own process.

0x00000010
SERVICE_WIN32_SHARE_PROCESS =

A service that shares a process with other services.

0x00000020
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.

0x00000100
SERVICE_BOOT_START =

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

0x00000000
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.

0x00000001
SERVICE_AUTO_START =

A service started automatically by the SCM during system startup.

0x00000002
SERVICE_DEMAND_START =

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

0x00000003
SERVICE_DISABLED =

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

0x00000004
SERVICE_ERROR_IGNORE =

The SCM ignores the error and continues the startup operation.

0x00000000
SERVICE_ERROR_NORMAL =

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

0x00000001
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.

0x00000002
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.

0x00000003
SERVICE_NO_CHANGE =

Service type, start or error control does not change.

0xFFFFFFFF
SERVICE_PAUSED =

Current State

0x00000007
SERVICE_PAUSE_PENDING =
0x00000006
SERVICE_CONTINUE_PENDING =
0x00000005
SERVICE_RUNNING =
0x00000004
SERVICE_STOP_PENDING =
0x00000003
SERVICE_START_PENDING =
0x00000002
SERVICE_STOPPED =
0x00000001
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.

0x00000008
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.

0x00000002
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.

0x00000004
SERVICE_ACCEPT_STOP =

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

0x00000001
SERVICE_ACCEPT_HARDWAREPROFILECHANGE =

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

0x00000020
SERVICE_ACCEPT_POWEREVENT =

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

0x00000040
SERVICE_ACCEPT_SESSIONCHANGE =

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

0x00000080
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.

0x00000100
SERVICE_ACCEPT_TIMECHANGE =

Service is notified when the system time changes.

0x00000200
SERVICE_ACCEPT_TRIGGEREVENT =

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

0x00000400
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.

0x00000003
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.

0x00000004
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.

0x00000007
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.

0x0000000A
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.

0x00000009
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.

0x00000008
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.

0x00000006
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.

0x00000002
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.

0x00000001

Instance Method Summary collapse

Instance Method Details

#change_service_config_w(svc_handle, opts = {}) ⇒ Object

Changes a service's configuration parameters in the SCM database

Parameters:

Raises:



380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
# 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) ⇒ Object

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

Parameters:

Raises:



463
464
465
466
467
468
469
470
471
472
473
474
475
476
# 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) ⇒ Object

Send a control code to a specific service handle

Parameters:

Raises:



443
444
445
446
447
448
449
450
451
452
453
454
455
456
# 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) ⇒ RubySMB::Dcerpc::Svcctl::ScRpcHandle

Open the SCM database on the specified server.

Parameters:

  • rhost (String)

    the server's machine name

Returns:

Raises:



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# 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) ⇒ RubySMB::Dcerpc::Svcctl::ScRpcHandle

Creates an RPC context handle to an existing service record.

Parameters:

  • scm_handle (RubySMB::Dcerpc::Svcctl::ScRpcHandle)

    handle to the SCM database

  • service_name (Srting)

    the ServiceName of the service record

  • access (Integer) (defaults to: SERVICE_ALL_ACCESS)

    access right

Returns:

Raises:



300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# 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) ⇒ RubySMB::Dcerpc::Svcctl::QueryServiceConfigW

Returns the configuration parameters of the specified service

Parameters:

Returns:

Raises:



347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# 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) ⇒ RubySMB::Dcerpc::Svcctl::ServiceStatus

Returns the current status of the specified service

Parameters:

Returns:

Raises:



324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# 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 = []) ⇒ Object

Starts a specified service

Parameters:

  • scm_handle (RubySMB::Dcerpc::Svcctl::ScRpcHandle)

    handle to the service record

  • argv (Array<String>) (defaults to: [])

    arguments to the service (Array of strings). The first element in argv must be the name of the service.

Raises:



416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
# 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