ruby_smb 1.0.5 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (191) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.travis.yml +3 -2
  5. data/Gemfile +6 -2
  6. data/README.md +35 -47
  7. data/examples/anonymous_auth.rb +3 -3
  8. data/examples/append_file.rb +10 -8
  9. data/examples/authenticate.rb +9 -5
  10. data/examples/delete_file.rb +8 -6
  11. data/examples/enum_registry_key.rb +29 -0
  12. data/examples/enum_registry_values.rb +31 -0
  13. data/examples/list_directory.rb +8 -6
  14. data/examples/negotiate.rb +51 -8
  15. data/examples/negotiate_with_netbios_service.rb +9 -5
  16. data/examples/net_share_enum_all.rb +6 -4
  17. data/examples/pipes.rb +13 -13
  18. data/examples/query_service_status.rb +64 -0
  19. data/examples/read_file.rb +8 -6
  20. data/examples/read_file_encryption.rb +56 -0
  21. data/examples/read_registry_key_value.rb +33 -0
  22. data/examples/rename_file.rb +9 -7
  23. data/examples/tree_connect.rb +7 -5
  24. data/examples/write_file.rb +9 -7
  25. data/lib/ruby_smb.rb +4 -1
  26. data/lib/ruby_smb/client.rb +239 -21
  27. data/lib/ruby_smb/client/authentication.rb +27 -8
  28. data/lib/ruby_smb/client/encryption.rb +62 -0
  29. data/lib/ruby_smb/client/negotiation.rb +154 -12
  30. data/lib/ruby_smb/client/signing.rb +19 -0
  31. data/lib/ruby_smb/client/tree_connect.rb +4 -4
  32. data/lib/ruby_smb/client/utils.rb +8 -7
  33. data/lib/ruby_smb/client/winreg.rb +46 -0
  34. data/lib/ruby_smb/crypto.rb +30 -0
  35. data/lib/ruby_smb/dcerpc.rb +40 -0
  36. data/lib/ruby_smb/dcerpc/bind.rb +2 -2
  37. data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
  38. data/lib/ruby_smb/dcerpc/error.rb +6 -0
  39. data/lib/ruby_smb/dcerpc/ndr.rb +260 -16
  40. data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
  41. data/lib/ruby_smb/dcerpc/request.rb +41 -9
  42. data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
  43. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +38 -0
  44. data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
  45. data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
  46. data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
  47. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
  48. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
  49. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
  50. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
  51. data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
  52. data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
  53. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
  54. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
  55. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
  56. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
  57. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
  58. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
  59. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
  60. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
  61. data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
  62. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
  63. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
  64. data/lib/ruby_smb/dcerpc/winreg.rb +421 -0
  65. data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
  66. data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
  67. data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
  68. data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
  69. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
  70. data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
  71. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
  72. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
  73. data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
  74. data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
  75. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
  76. data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
  77. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
  78. data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
  79. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +40 -0
  80. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
  81. data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
  82. data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
  83. data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
  84. data/lib/ruby_smb/dispatcher/base.rb +1 -1
  85. data/lib/ruby_smb/dispatcher/socket.rb +5 -4
  86. data/lib/ruby_smb/error.rb +28 -1
  87. data/lib/ruby_smb/field/stringz16.rb +17 -1
  88. data/lib/ruby_smb/nbss/session_header.rb +4 -4
  89. data/lib/ruby_smb/smb1/commands.rb +1 -1
  90. data/lib/ruby_smb/smb1/file.rb +8 -14
  91. data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +1 -1
  92. data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -2
  93. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
  94. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -2
  95. data/lib/ruby_smb/smb1/packet/write_andx_request.rb +1 -1
  96. data/lib/ruby_smb/smb1/pipe.rb +81 -3
  97. data/lib/ruby_smb/smb1/tree.rb +12 -3
  98. data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
  99. data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
  100. data/lib/ruby_smb/smb2/file.rb +51 -61
  101. data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
  102. data/lib/ruby_smb/smb2/packet.rb +2 -0
  103. data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
  104. data/lib/ruby_smb/smb2/packet/error_packet.rb +2 -4
  105. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -14
  106. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +50 -4
  107. data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
  108. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +92 -6
  109. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -26
  110. data/lib/ruby_smb/smb2/pipe.rb +80 -3
  111. data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
  112. data/lib/ruby_smb/smb2/tree.rb +32 -20
  113. data/lib/ruby_smb/version.rb +1 -1
  114. data/ruby_smb.gemspec +5 -3
  115. data/spec/lib/ruby_smb/client_spec.rb +1583 -102
  116. data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
  117. data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
  118. data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
  119. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1729 -0
  120. data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
  121. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
  122. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +135 -0
  123. data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
  124. data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
  125. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
  126. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
  127. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
  128. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
  129. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
  130. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
  131. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
  132. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
  133. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
  134. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
  135. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
  136. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
  137. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
  138. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
  139. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
  140. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
  141. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
  142. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
  143. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
  144. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
  145. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
  146. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
  147. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +104 -0
  148. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
  149. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
  150. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
  151. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
  152. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
  153. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +95 -0
  154. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
  155. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +35 -0
  156. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
  157. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
  158. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +138 -0
  159. data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
  160. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
  161. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
  162. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +884 -0
  163. data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
  164. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +12 -12
  165. data/spec/lib/ruby_smb/error_spec.rb +59 -0
  166. data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
  167. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
  168. data/spec/lib/ruby_smb/smb1/file_spec.rb +9 -1
  169. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
  170. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
  171. data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
  172. data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
  173. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +216 -147
  174. data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
  175. data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
  176. data/spec/lib/ruby_smb/smb2/file_spec.rb +146 -68
  177. data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
  178. data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
  179. data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +3 -24
  180. data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
  181. data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
  182. data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
  183. data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
  184. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -30
  185. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +226 -148
  186. data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
  187. data/spec/lib/ruby_smb/smb2/tree_spec.rb +88 -9
  188. metadata +257 -81
  189. metadata.gz.sig +0 -0
  190. data/lib/ruby_smb/smb1/dcerpc.rb +0 -72
  191. data/lib/ruby_smb/smb2/dcerpc.rb +0 -75
@@ -0,0 +1,34 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+
4
+ # This class represents a RPC_SECURITY_DESCRIPTOR structure as defined in
5
+ # [2.2.8 RPC_SECURITY_DESCRIPTOR](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/9729e781-8eb9-441b-82ca-e898f98d29c2)
6
+ class RpcSecurityDescriptor < BinData::Record
7
+ endian :little
8
+
9
+ ndr_lp_byte_array :lp_security_descriptor
10
+ uint32 :cb_in_security_descriptor
11
+ uint32 :cb_out_security_descriptor
12
+ end
13
+
14
+ # This class represents a RPC_SECURITY_ATTRIBUTES structure as defined in
15
+ # [2.2.7 RPC_SECURITY_ATTRIBUTES](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/bc37b8cf-8c94-4804-ad53-0aaf5eaf0ecb)
16
+ class RpcSecurityAttributes < BinData::Record
17
+ endian :little
18
+
19
+ uint32 :n_length
20
+ rpc_security_descriptor :rpc_security_descriptor
21
+ uint8 :b_inheritHandle
22
+ end
23
+
24
+ # This class represents a pointer to a RPC_SECURITY_ATTRIBUTES structure as defined in
25
+ # [2.2.7 RPC_SECURITY_ATTRIBUTES](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/bc37b8cf-8c94-4804-ad53-0aaf5eaf0ecb)
26
+ class PrpcSecurityAttributes < Ndr::NdrPointer
27
+ endian :little
28
+
29
+ rpc_security_attributes :referent, onlyif: -> { self.referent_id != 0 }
30
+ end
31
+
32
+ end
33
+ end
34
+
@@ -0,0 +1,38 @@
1
+ require 'ruby_smb/dcerpc/ndr'
2
+
3
+ module RubySMB
4
+ module Dcerpc
5
+
6
+ # A RRP_UNICODE_STRING structure as defined in
7
+ # [2.2.4 RRP_UNICODE_STRING](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/c0c90f11-a4c4-496a-ac09-8a8a3697ceef)
8
+ class RrpUnicodeString < BinData::Primitive
9
+ endian :little
10
+
11
+ uint16 :buffer_length
12
+ uint16 :maximum_length
13
+ ndr_lp_str :buffer
14
+
15
+ def get
16
+ self.buffer
17
+ end
18
+
19
+ def set(buf)
20
+ self.buffer = buf
21
+ self.buffer_length = self.buffer == :null ? 0 : self.buffer.referent.actual_count * 2
22
+ # Don't reset maximum_length if the buffer is NULL to make sure we can
23
+ # set it independently of the buffer size
24
+ return if self.maximum_length > 0 && self.buffer == :null
25
+ self.maximum_length = self.buffer.referent.max_count * 2
26
+ end
27
+ end
28
+
29
+ # A pointer to a RRP_UNICODE_STRING structure
30
+ class PrrpUnicodeString < Ndr::NdrPointer
31
+ endian :little
32
+
33
+ rrp_unicode_string :referent, onlyif: -> { self.referent_id != 0 }
34
+ end
35
+
36
+ end
37
+ end
38
+
@@ -10,6 +10,16 @@ module RubySMB
10
10
  NET_SHARE_ENUM_ALL = 0xF
11
11
 
12
12
  require 'ruby_smb/dcerpc/srvsvc/net_share_enum_all'
13
+
14
+ def net_share_enum_all(host)
15
+ bind(endpoint: RubySMB::Dcerpc::Srvsvc)
16
+
17
+ net_share_enum_all_request_packet = RubySMB::Dcerpc::Srvsvc::NetShareEnumAll.new(host: host)
18
+ response = dcerpc_request(net_share_enum_all_request_packet)
19
+
20
+ shares = RubySMB::Dcerpc::Srvsvc::NetShareEnumAll.parse_response(response)
21
+ shares.map{|s|{name: s[0], type: s[1], comment: s[2]}}
22
+ end
13
23
  end
14
24
  end
15
25
  end
@@ -5,6 +5,10 @@ module RubySMB
5
5
  #https://msdn.microsoft.com/en-us/library/cc247293.aspx
6
6
 
7
7
  class NetShareEnumAll < BinData::Record
8
+ attr_reader :opnum
9
+
10
+ mandatory_parameter :host
11
+
8
12
  endian :little
9
13
 
10
14
  uint32 :referent_id, initial_value: 0x00000001
@@ -27,6 +31,11 @@ module RubySMB
27
31
  uint32 :resume_referent_id, initial_value: 0x00000001
28
32
  uint32 :resume_handle, initial_value: 0
29
33
 
34
+ def initialize_instance
35
+ super
36
+ @opnum = NET_SHARE_ENUM_ALL
37
+ end
38
+
30
39
  def pad_length
31
40
  offset = (server_unc.abs_offset + server_unc.to_binary_s.length) % 4
32
41
  (4 - offset) % 4
@@ -0,0 +1,479 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Svcctl
4
+
5
+ UUID = '367abb81-9844-35f1-ad32-98f038001003'
6
+ VER_MAJOR = 2
7
+ VER_MINOR = 0
8
+
9
+ # Operation numbers
10
+ CLOSE_SERVICE_HANDLE = 0x0000
11
+ CONTROL_SERVICE = 0x0001
12
+ QUERY_SERVICE_STATUS = 0x0006
13
+ CHANGE_SERVICE_CONFIG_W = 0x000B
14
+ OPEN_SC_MANAGER_W = 0x000F
15
+ OPEN_SERVICE_W = 0x0010
16
+ QUERY_SERVICE_CONFIG_W = 0x0011
17
+ START_SERVICE_W = 0x0013
18
+
19
+
20
+ class ScRpcHandle < Ndr::NdrContextHandle; end
21
+
22
+
23
+ #################################
24
+ # Constants #
25
+ #################################
26
+
27
+
28
+ ################
29
+ # Service Access
30
+ # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-scmr/0d7a7011-9f41-470d-ad52-8535b47ac282
31
+
32
+ # In addition to all access rights in this table, SERVICE_ALL_ACCESS
33
+ # includes Delete (DE), Read Control (RC), Write DACL (WD), and Write
34
+ # Owner (WO) access, as specified in ACCESS_MASK (section 2.4.3) of
35
+ # [MS-DTYP].
36
+ SERVICE_ALL_ACCESS = 0x000F01FF
37
+ # Required to change the configuration of a service.
38
+ SERVICE_CHANGE_CONFIG = 0x00000002
39
+ # Required to enumerate the services installed on the server.
40
+ SERVICE_ENUMERATE_DEPENDENTS = 0x00000008
41
+ # Required to request immediate status from the service.
42
+ SERVICE_INTERROGATE = 0x00000080
43
+ # Required to pause or continue the service.
44
+ SERVICE_PAUSE_CONTINUE = 0x00000040
45
+ # Required to query the service configuration.
46
+ SERVICE_QUERY_CONFIG = 0x00000001
47
+ # Required to request the service status.
48
+ SERVICE_QUERY_STATUS = 0x00000004
49
+ # Required to start the service.
50
+ SERVICE_START = 0x00000010
51
+ # Required to stop the service.
52
+ SERVICE_STOP = 0x00000020
53
+ # Required to specify a user-defined control code.
54
+ SERVICE_USER_DEFINED_CONTROL = 0x00000100
55
+ # Required for a service to set its status.
56
+ SERVICE_SET_STATUS = 0x00008000
57
+
58
+ # Specific access types for Service Control Manager object:
59
+
60
+ # Required to lock the SCM database.
61
+ SC_MANAGER_LOCK = 0x00000008
62
+ # Required for a service to be created.
63
+ SC_MANAGER_CREATE_SERVICE = 0x00000002
64
+ # Required to enumerate a service.
65
+ SC_MANAGER_ENUMERATE_SERVICE = 0x00000004
66
+ # Required to connect to the SCM.
67
+ SC_MANAGER_CONNECT = 0x00000001
68
+ # Required to query the lock status of the SCM database.
69
+ SC_MANAGER_QUERY_LOCK_STATUS = 0x00000010
70
+ # Required to call the RNotifyBootConfigStatus method.
71
+ SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00000020
72
+
73
+
74
+ ##############
75
+ # Service Type
76
+
77
+ # A driver service. These are services that manage devices on the system.
78
+ SERVICE_KERNEL_DRIVER = 0x00000001
79
+ # A file system driver service. These are services that manage file
80
+ # systems on the system.
81
+ SERVICE_FILE_SYSTEM_DRIVER = 0x00000002
82
+ # A service that runs in its own process.
83
+ SERVICE_WIN32_OWN_PROCESS = 0x00000010
84
+ # A service that shares a process with other services.
85
+ SERVICE_WIN32_SHARE_PROCESS = 0x00000020
86
+
87
+ # The service can interact with the desktop. Only
88
+ # SERVICE_WIN32_OWN_PROCESS and SERVICE_INTERACTIVE_PROCESS OR
89
+ # SERVICE_WIN32_SHARE_PROCESS and SERVICE_INTERACTIVE_PROCESS can be
90
+ # combined.
91
+ SERVICE_INTERACTIVE_PROCESS = 0x00000100
92
+
93
+ ####################
94
+ # Service Start Type
95
+
96
+ # Starts the driver service when the system boots up. This value is valid
97
+ # only for driver services.
98
+ SERVICE_BOOT_START = 0x00000000
99
+ # Starts the driver service when the system boots up. This value is valid
100
+ # only for driver services. The services marked SERVICE_SYSTEM_START are
101
+ # started after all SERVICE_BOOT_START services have been started.
102
+ SERVICE_SYSTEM_START = 0x00000001
103
+ # A service started automatically by the SCM during system startup.
104
+ SERVICE_AUTO_START = 0x00000002
105
+ # Starts the service when a client requests the SCM to start the service.
106
+ SERVICE_DEMAND_START = 0x00000003
107
+ # A service that cannot be started. Attempts to start the service result
108
+ # in the error code ERROR_SERVICE_DISABLED.
109
+ SERVICE_DISABLED = 0x00000004
110
+
111
+
112
+ #######################
113
+ # Service Error Control
114
+
115
+ # The severity of the error if this service fails to start during startup
116
+ # and the action the SCM takes if failure occurs.
117
+
118
+ # The SCM ignores the error and continues the startup operation.
119
+ SERVICE_ERROR_IGNORE = 0x00000000
120
+ # The SCM logs the error in the event log and continues the startup
121
+ # operation.
122
+ SERVICE_ERROR_NORMAL = 0x00000001
123
+ # The SCM logs the error in the event log. If the last-known good
124
+ # configuration is being started, the startup operation continues.
125
+ # Otherwise, the system is restarted with the last-known good
126
+ # configuration.
127
+ SERVICE_ERROR_SEVERE = 0x00000002
128
+ # The SCM SHOULD log the error in the event log if possible. If the
129
+ # last-known good configuration is being started, the startup operation
130
+ # fails. Otherwise, the system is restarted with the last-known good
131
+ # configuration.
132
+ SERVICE_ERROR_CRITICAL = 0x00000003
133
+
134
+
135
+ #########################################
136
+ # Change Service Config specific constant
137
+
138
+ # Service type, start or error control does not change.
139
+ SERVICE_NO_CHANGE = 0xFFFFFFFF
140
+
141
+
142
+ ################
143
+ # Current State
144
+
145
+ SERVICE_PAUSED = 0x00000007
146
+ SERVICE_PAUSE_PENDING = 0x00000006
147
+ SERVICE_CONTINUE_PENDING = 0x00000005
148
+ SERVICE_RUNNING = 0x00000004
149
+ SERVICE_STOP_PENDING = 0x00000003
150
+ SERVICE_START_PENDING = 0x00000002
151
+ SERVICE_STOPPED = 0x00000001
152
+
153
+ ###################
154
+ # Controls Accepted
155
+
156
+ # The control codes that the service accepts and processes in its handler
157
+ # function. One or more of the following values can be set. By default,
158
+ # all services accept the SERVICE_CONTROL_INTERROGATE value. A value of
159
+ # zero indicates that no controls are accepted.
160
+
161
+ # Service can reread its startup parameters without being stopped and
162
+ # restarted. This control code allows the service to receive
163
+ # SERVICE_CONTROL_PARAMCHANGE notifications.
164
+ SERVICE_ACCEPT_PARAMCHANGE = 0x00000008
165
+ # Service can be paused and continued. This control code allows the
166
+ # service to receive SERVICE_CONTROL_PAUSE and SERVICE_CONTROL_CONTINUE
167
+ # notifications.
168
+ SERVICE_ACCEPT_PAUSE_CONTINUE = 0x00000002
169
+ # Service is notified when system shutdown occurs. This control code
170
+ # enables the service to receive SERVICE_CONTROL_SHUTDOWN notifications
171
+ # from the server.
172
+ SERVICE_ACCEPT_SHUTDOWN = 0x00000004
173
+ # Service can be stopped. This control code allows the service to receive
174
+ # SERVICE_CONTROL_STOP notifications.
175
+ SERVICE_ACCEPT_STOP = 0x00000001
176
+ # Service is notified when the computer's hardware profile changes.
177
+ SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 0x00000020
178
+ # Service is notified when the computer's power status changes.
179
+ SERVICE_ACCEPT_POWEREVENT = 0x00000040
180
+ # Service is notified when the computer's session status changes.
181
+ SERVICE_ACCEPT_SESSIONCHANGE = 0x00000080
182
+ # The service can perform preshutdown tasks. SERVICE_ACCEPT_PRESHUTDOWN
183
+ # is sent before sending SERVICE_CONTROL_SHUTDOWN to give more time to
184
+ # services that need extra time before shutdown occurs.
185
+ SERVICE_ACCEPT_PRESHUTDOWN = 0x00000100
186
+ # Service is notified when the system time changes.
187
+ SERVICE_ACCEPT_TIMECHANGE = 0x00000200
188
+ # Service is notified when an event for which the service has registered
189
+ # occurs.
190
+ SERVICE_ACCEPT_TRIGGEREVENT = 0x00000400
191
+
192
+ ###################
193
+ # Controls
194
+
195
+ # Notifies a paused service that it SHOULD resume. The
196
+ # SERVICE_PAUSE_CONTINUE access right MUST have been granted to the caller
197
+ # when the RPC control handle to the service record was created. The
198
+ # service record MUST have the SERVICE_ACCEPT_PAUSE_CONTINUE bit set in
199
+ # the ServiceStatus.dwControlsAccepted field of the service record.
200
+ SERVICE_CONTROL_CONTINUE = 0x00000003
201
+ # Notifies a service that it SHOULD report its current status information
202
+ # to the SCM. The SERVICE_INTERROGATE access right MUST have been granted
203
+ # to the caller when the RPC control handle to the service record was
204
+ # created.
205
+ SERVICE_CONTROL_INTERROGATE = 0x00000004
206
+ # Notifies a service that there is a new component for binding. The
207
+ # SERVICE_PAUSE_CONTINUE access right MUST have been granted to the
208
+ # caller when the RPC control handle to the service record was created.
209
+ # The service record MUST have the SERVICE_ACCEPT_NETBINDCHANGE bit set
210
+ # in the ServiceStatus.dwControlsAccepted field of the service record.
211
+ SERVICE_CONTROL_NETBINDADD = 0x00000007
212
+ # Notifies a network service that one of its bindings has been disabled.
213
+ # The SERVICE_PAUSE_CONTINUE access right MUST have been granted to the
214
+ # caller when the RPC control handle to the service record was created.
215
+ # The service record MUST have the SERVICE_ACCEPT_NETBINDCHANGE bit set
216
+ # in the ServiceStatus.dwControlsAccepted field of the service record.
217
+ SERVICE_CONTROL_NETBINDDISABLE = 0x0000000A
218
+ # Notifies a network service that a disabled binding has been enabled.
219
+ # The SERVICE_PAUSE_CONTINUE access right MUST have been granted to the
220
+ # caller when the RPC control handle to the service record was created.
221
+ # The service record MUST have the SERVICE_ACCEPT_NETBINDCHANGE bit set
222
+ # in the ServiceStatus.dwControlsAccepted field of the service record.
223
+ SERVICE_CONTROL_NETBINDENABLE = 0x00000009
224
+ # Notifies a network service that a component for binding has been
225
+ # removed. The SERVICE_PAUSE_CONTINUE access right MUST have been granted
226
+ # to the caller when the RPC control handle to the service record was
227
+ # created. The service record MUST have the SERVICE_ACCEPT_NETBINDCHANGE
228
+ # bit set in the ServiceStatus.dwControlsAccepted field of the service
229
+ # record.
230
+ SERVICE_CONTROL_NETBINDREMOVE = 0x00000008
231
+ # Notifies a service that its startup parameters have changed. The
232
+ # SERVICE_PAUSE_CONTINUE access right MUST have been granted to the
233
+ # caller when the RPC control handle to the service record was created.
234
+ # The service record MUST have the SERVICE_ACCEPT_PARAMCHANGE bit set in
235
+ # the ServiceStatus.dwControlsAccepted field of the service record.
236
+ SERVICE_CONTROL_PARAMCHANGE = 0x00000006
237
+ # Notifies a service that it SHOULD pause. The SERVICE_PAUSE_CONTINUE
238
+ # access right MUST have been granted to the caller when the RPC control
239
+ # handle to the service record was created. The service record MUST have
240
+ # the SERVICE_ACCEPT_PAUSE_CONTINUE bit set in the
241
+ # ServiceStatus.dwControlsAccepted field of the service record.
242
+ SERVICE_CONTROL_PAUSE = 0x00000002
243
+ # Notifies a service that it SHOULD stop. The SERVICE_STOP access right
244
+ # MUST have been granted to the caller when the RPC control handle to the
245
+ # service record was created. The service record MUST have the
246
+ # SERVICE_ACCEPT_STOP bit set in the ServiceStatus.dwControlsAccepted
247
+ # field of the service record.
248
+ SERVICE_CONTROL_STOP = 0x00000001
249
+
250
+ require 'ruby_smb/dcerpc/svcctl/service_status'
251
+ require 'ruby_smb/dcerpc/svcctl/open_sc_manager_w_request'
252
+ require 'ruby_smb/dcerpc/svcctl/open_sc_manager_w_response'
253
+ require 'ruby_smb/dcerpc/svcctl/open_service_w_request'
254
+ require 'ruby_smb/dcerpc/svcctl/open_service_w_response'
255
+ require 'ruby_smb/dcerpc/svcctl/query_service_status_request'
256
+ require 'ruby_smb/dcerpc/svcctl/query_service_status_response'
257
+ require 'ruby_smb/dcerpc/svcctl/query_service_config_w_request'
258
+ require 'ruby_smb/dcerpc/svcctl/query_service_config_w_response'
259
+ require 'ruby_smb/dcerpc/svcctl/change_service_config_w_request'
260
+ require 'ruby_smb/dcerpc/svcctl/change_service_config_w_response'
261
+ require 'ruby_smb/dcerpc/svcctl/start_service_w_request'
262
+ require 'ruby_smb/dcerpc/svcctl/start_service_w_response'
263
+ require 'ruby_smb/dcerpc/svcctl/control_service_request'
264
+ require 'ruby_smb/dcerpc/svcctl/control_service_response'
265
+ require 'ruby_smb/dcerpc/svcctl/close_service_handle_request'
266
+ require 'ruby_smb/dcerpc/svcctl/close_service_handle_response'
267
+
268
+ # Open the SCM database on the specified server.
269
+ #
270
+ # @param rhost [String] the server's machine name
271
+ # @return [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the newly opened SCM database
272
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a OpenSCManagerWResponse packet
273
+ # @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS
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)
275
+ open_sc_manager_w_request = OpenSCManagerWRequest.new(dw_desired_access: access)
276
+ open_sc_manager_w_request.lp_machine_name = rhost
277
+ open_sc_manager_w_request.lp_database_name = 'ServicesActive'
278
+ response = dcerpc_request(open_sc_manager_w_request)
279
+ begin
280
+ open_sc_manager_w_response = OpenSCManagerWResponse.read(response)
281
+ rescue IOError
282
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading OpenSCManagerWResponse'
283
+ end
284
+ unless open_sc_manager_w_response.error_status == WindowsError::Win32::ERROR_SUCCESS
285
+ raise RubySMB::Dcerpc::Error::SvcctlError,
286
+ "Error returned when opening Service Control Manager (SCM): "\
287
+ "#{WindowsError::Win32.find_by_retval(open_sc_manager_w_response.error_status.value).join(',')}"
288
+ end
289
+ open_sc_manager_w_response.lp_sc_handle
290
+ end
291
+
292
+ # Creates an RPC context handle to an existing service record.
293
+ #
294
+ # @param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the SCM database
295
+ # @param service_name [Srting] the ServiceName of the service record
296
+ # @param access [Integer] access right
297
+ # @return [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the found service record
298
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a OpenServiceWResponse packet
299
+ # @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS
300
+ def open_service_w(scm_handle, service_name, access = SERVICE_ALL_ACCESS)
301
+ open_service_w_request = OpenServiceWRequest.new(dw_desired_access: access)
302
+ open_service_w_request.lp_sc_handle = scm_handle
303
+ open_service_w_request.lp_service_name = service_name
304
+ response = dcerpc_request(open_service_w_request)
305
+ begin
306
+ open_sercice_w_response = OpenServiceWResponse.read(response)
307
+ rescue IOError
308
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading OpenServiceWResponse'
309
+ end
310
+ unless open_sercice_w_response.error_status == WindowsError::Win32::ERROR_SUCCESS
311
+ raise RubySMB::Dcerpc::Error::SvcctlError,
312
+ "Error returned when opening #{service_name} service: "\
313
+ "#{WindowsError::Win32.find_by_retval(open_sercice_w_response.error_status.value).join(',')}"
314
+ end
315
+ open_sercice_w_response.lp_sc_handle
316
+ end
317
+
318
+ # Returns the current status of the specified service
319
+ #
320
+ # @param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the service record
321
+ # @return [RubySMB::Dcerpc::Svcctl::ServiceStatus] structure that contains the status information for the service
322
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a QueryServiceStatusResponse packet
323
+ # @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS
324
+ def query_service_status(svc_handle)
325
+ qss_request = QueryServiceStatusRequest.new
326
+ qss_request.h_service = svc_handle
327
+ response = dcerpc_request(qss_request)
328
+ begin
329
+ qss_response = QueryServiceStatusResponse.read(response)
330
+ rescue IOError
331
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading QueryServiceStatusResponse'
332
+ end
333
+ unless qss_response.error_status == WindowsError::Win32::ERROR_SUCCESS
334
+ raise RubySMB::Dcerpc::Error::SvcctlError,
335
+ "Error returned when querying service status: "\
336
+ "#{WindowsError::Win32.find_by_retval(qss_response.error_status.value).join(',')}"
337
+ end
338
+ qss_response.lp_service_status
339
+ end
340
+
341
+ # Returns the configuration parameters of the specified service
342
+ #
343
+ # @param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the service record
344
+ # @return [RubySMB::Dcerpc::Svcctl::QueryServiceConfigW] structure that contains the configuration parameters for the service
345
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a QueryServiceConfigWResponse packet
346
+ # @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS
347
+ def query_service_config(svc_handle)
348
+ qsc_request = QueryServiceConfigWRequest.new
349
+ qsc_request.h_service = svc_handle
350
+ qsc_request.cb_buf_size = 0
351
+ response = dcerpc_request(qsc_request)
352
+ begin
353
+ qsc_response = QueryServiceConfigWResponse.read(response)
354
+ rescue IOError
355
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading QueryServiceConfigWResponse'
356
+ end
357
+ if qsc_response.error_status == WindowsError::Win32::ERROR_INSUFFICIENT_BUFFER
358
+ qsc_request.cb_buf_size = qsc_response.pcb_bytes_needed
359
+ response = dcerpc_request(qsc_request)
360
+ begin
361
+ qsc_response = QueryServiceConfigWResponse.read(response)
362
+ rescue IOError
363
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading QueryServiceConfigWResponse'
364
+ end
365
+ end
366
+ unless qsc_response.error_status == WindowsError::Win32::ERROR_SUCCESS
367
+ raise RubySMB::Dcerpc::Error::SvcctlError,
368
+ "Error returned when querying service configuration: "\
369
+ "#{WindowsError::Win32.find_by_retval(qsc_response.error_status.value).join(',')}"
370
+ end
371
+ qsc_response.lp_service_config
372
+ end
373
+
374
+ # Changes a service's configuration parameters in the SCM database
375
+ #
376
+ # @param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the service record
377
+ # @param opts [Hash] configuration parameters to change
378
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a ChangeServiceConfigWResponse packet
379
+ # @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS
380
+ def change_service_config_w(svc_handle, opts = {})
381
+ opts = {
382
+ h_service: svc_handle,
383
+ dw_service_type: opts[:service_type] || SERVICE_NO_CHANGE,
384
+ dw_start_type: opts[:start_type] || SERVICE_NO_CHANGE,
385
+ dw_error_control: opts[:error_control] || SERVICE_NO_CHANGE,
386
+ lp_binary_path_name: opts[:binary_path_name] || :null,
387
+ lp_load_order_group: opts[:load_order_group] || :null,
388
+ dw_tag_id: opts[:tag_id] || :null,
389
+ lp_dependencies: opts[:dependencies] || [],
390
+ lp_service_start_name: opts[:service_start_name] || :null,
391
+ lp_password: opts[:password] || [],
392
+ lp_display_name: opts[:display_name] || :null
393
+ }
394
+
395
+ csc_request = ChangeServiceConfigWRequest.new(opts)
396
+ response = dcerpc_request(csc_request)
397
+ begin
398
+ csc_response = ChangeServiceConfigWResponse.read(response)
399
+ rescue IOError
400
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading ChangeServiceConfigWResponse'
401
+ end
402
+ unless csc_response.error_status == WindowsError::Win32::ERROR_SUCCESS
403
+ raise RubySMB::Dcerpc::Error::SvcctlError,
404
+ "Error returned when changing the service configuration: "\
405
+ "#{WindowsError::Win32.find_by_retval(csc_response.error_status.value).join(',')}"
406
+ end
407
+ end
408
+
409
+ # Starts a specified service
410
+ #
411
+ # @param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the service record
412
+ # @param argv [Array<String>] arguments to the service (Array of
413
+ # strings). The first element in argv must be the name of the service.
414
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a StartServiceWResponse packet
415
+ # @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS
416
+ def start_service_w(svc_handle, argv = [])
417
+ ss_request = StartServiceWRequest.new(h_service: svc_handle)
418
+ unless argv.empty?
419
+ ss_request.argc = argv.size
420
+ ndr_string_ptrsw = RubySMB::Dcerpc::Ndr::NdrStringPtrsw.new
421
+ ndr_string_ptrsw.elements = argv
422
+ ss_request.argv = ndr_string_ptrsw
423
+ end
424
+ response = dcerpc_request(ss_request)
425
+ begin
426
+ ss_response = StartServiceWResponse.read(response)
427
+ rescue IOError
428
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading StartServiceWResponse'
429
+ end
430
+ unless ss_response.error_status == WindowsError::Win32::ERROR_SUCCESS
431
+ raise RubySMB::Dcerpc::Error::SvcctlError,
432
+ "Error returned when starting the service: "\
433
+ "#{WindowsError::Win32.find_by_retval(ss_response.error_status.value).join(',')}"
434
+ end
435
+ end
436
+
437
+ # Send a control code to a specific service handle
438
+ #
439
+ # @param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the service record
440
+ # @param control [Integer] control code
441
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a ControlServiceResponse packet
442
+ # @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS
443
+ def control_service(svc_handle, control)
444
+ cs_request = ControlServiceRequest.new(h_service: svc_handle, dw_control: control)
445
+ response = dcerpc_request(cs_request)
446
+ begin
447
+ cs_response = ControlServiceResponse.read(response)
448
+ rescue IOError
449
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading ControlServiceResponse'
450
+ end
451
+ unless cs_response.error_status == WindowsError::Win32::ERROR_SUCCESS
452
+ raise RubySMB::Dcerpc::Error::SvcctlError,
453
+ "Error returned when sending a control to the service: "\
454
+ "#{WindowsError::Win32.find_by_retval(cs_response.error_status.value).join(',')}"
455
+ end
456
+ end
457
+
458
+ # Releases the handle to the specified service or the SCM database.
459
+ #
460
+ # @param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the service record or to the SCM database
461
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a CloseServiceHandleResponse packet
462
+ # @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS
463
+ def close_service_handle(svc_handle)
464
+ csh_request = CloseServiceHandleRequest.new(h_sc_object: svc_handle)
465
+ response = dcerpc_request(csh_request)
466
+ begin
467
+ csh_response = CloseServiceHandleResponse.read(response)
468
+ rescue IOError
469
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading CloseServiceHandleResponse'
470
+ end
471
+ unless csh_response.error_status == WindowsError::Win32::ERROR_SUCCESS
472
+ raise RubySMB::Dcerpc::Error::SvcctlError,
473
+ "Error returned when closing the service: "\
474
+ "#{WindowsError::Win32.find_by_retval(csh_response.error_status.value).join(',')}"
475
+ end
476
+ end
477
+ end
478
+ end
479
+ end