ruby_smb 2.0.0 → 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +3 -3
  3. data.tar.gz.sig +5 -1
  4. data/examples/anonymous_auth.rb +3 -3
  5. data/examples/append_file.rb +10 -8
  6. data/examples/authenticate.rb +9 -5
  7. data/examples/delete_file.rb +8 -6
  8. data/examples/enum_registry_key.rb +5 -4
  9. data/examples/enum_registry_values.rb +5 -4
  10. data/examples/list_directory.rb +8 -6
  11. data/examples/negotiate_with_netbios_service.rb +9 -5
  12. data/examples/net_share_enum_all.rb +6 -4
  13. data/examples/pipes.rb +11 -12
  14. data/examples/query_service_status.rb +64 -0
  15. data/examples/read_file.rb +8 -6
  16. data/examples/read_registry_key_value.rb +6 -5
  17. data/examples/rename_file.rb +9 -7
  18. data/examples/tree_connect.rb +7 -5
  19. data/examples/write_file.rb +9 -7
  20. data/lib/ruby_smb/client.rb +117 -53
  21. data/lib/ruby_smb/client/authentication.rb +7 -12
  22. data/lib/ruby_smb/client/echo.rb +2 -4
  23. data/lib/ruby_smb/client/negotiation.rb +31 -12
  24. data/lib/ruby_smb/client/tree_connect.rb +2 -4
  25. data/lib/ruby_smb/client/utils.rb +16 -10
  26. data/lib/ruby_smb/client/winreg.rb +1 -1
  27. data/lib/ruby_smb/dcerpc.rb +4 -0
  28. data/lib/ruby_smb/dcerpc/error.rb +3 -0
  29. data/lib/ruby_smb/dcerpc/ndr.rb +306 -44
  30. data/lib/ruby_smb/dcerpc/netlogon.rb +101 -0
  31. data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb +28 -0
  32. data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response.rb +26 -0
  33. data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request.rb +27 -0
  34. data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response.rb +23 -0
  35. data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request.rb +25 -0
  36. data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response.rb +24 -0
  37. data/lib/ruby_smb/dcerpc/request.rb +19 -0
  38. data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
  39. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +9 -6
  40. data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
  41. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
  42. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
  43. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
  44. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
  45. data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
  46. data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
  47. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
  48. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
  49. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
  50. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
  51. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
  52. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
  53. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
  54. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
  55. data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
  56. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
  57. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
  58. data/lib/ruby_smb/dcerpc/winreg.rb +98 -17
  59. data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
  60. data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
  61. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +1 -1
  62. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +1 -1
  63. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +1 -1
  64. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +4 -4
  65. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
  66. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +7 -6
  67. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +10 -10
  68. data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
  69. data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
  70. data/lib/ruby_smb/dispatcher/base.rb +1 -1
  71. data/lib/ruby_smb/dispatcher/socket.rb +3 -2
  72. data/lib/ruby_smb/error.rb +21 -5
  73. data/lib/ruby_smb/field/stringz16.rb +17 -1
  74. data/lib/ruby_smb/generic_packet.rb +11 -1
  75. data/lib/ruby_smb/nbss/session_header.rb +4 -4
  76. data/lib/ruby_smb/smb1/file.rb +9 -24
  77. data/lib/ruby_smb/smb1/pipe.rb +8 -6
  78. data/lib/ruby_smb/smb1/tree.rb +22 -9
  79. data/lib/ruby_smb/smb2/file.rb +46 -46
  80. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +1 -1
  81. data/lib/ruby_smb/smb2/pipe.rb +9 -6
  82. data/lib/ruby_smb/smb2/tree.rb +30 -20
  83. data/lib/ruby_smb/version.rb +1 -1
  84. data/spec/lib/ruby_smb/client_spec.rb +248 -109
  85. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1396 -77
  86. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request_spec.rb +69 -0
  87. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response_spec.rb +53 -0
  88. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request_spec.rb +69 -0
  89. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response_spec.rb +37 -0
  90. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request_spec.rb +45 -0
  91. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response_spec.rb +37 -0
  92. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
  93. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +49 -12
  94. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
  95. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
  96. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
  97. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
  98. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
  99. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
  100. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
  101. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
  102. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
  103. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
  104. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
  105. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
  106. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
  107. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
  108. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
  109. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
  110. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
  111. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
  112. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
  113. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
  114. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +0 -4
  115. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +2 -2
  116. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +2 -2
  117. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +9 -4
  118. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
  119. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +17 -17
  120. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +11 -23
  121. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
  122. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
  123. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +227 -41
  124. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +12 -12
  125. data/spec/lib/ruby_smb/error_spec.rb +34 -5
  126. data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
  127. data/spec/lib/ruby_smb/generic_packet_spec.rb +7 -0
  128. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
  129. data/spec/lib/ruby_smb/smb1/file_spec.rb +1 -3
  130. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +30 -5
  131. data/spec/lib/ruby_smb/smb1/tree_spec.rb +22 -0
  132. data/spec/lib/ruby_smb/smb2/file_spec.rb +73 -21
  133. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +9 -5
  134. data/spec/lib/ruby_smb/smb2/tree_spec.rb +64 -7
  135. metadata +91 -2
  136. metadata.gz.sig +0 -0
@@ -0,0 +1,101 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Netlogon
4
+
5
+ # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/592edbc8-f6f1-40c0-9ab3-fe6725ac6d7e
6
+ UUID = '12345678-1234-abcd-ef00-01234567cffb'
7
+ VER_MAJOR = 1
8
+ VER_MINOR = 0
9
+
10
+ # Operation numbers
11
+ NETR_SERVER_REQ_CHALLENGE = 4
12
+ NETR_SERVER_AUTHENTICATE3 = 26
13
+ NETR_SERVER_PASSWORD_SET2 = 30
14
+
15
+ # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/3b224201-b531-43e2-8c79-b61f6dea8640
16
+ class LogonsrvHandle < Ndr::NdrLpStr; end
17
+
18
+ # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/d55e2632-7163-4f6c-b662-4b870e8cc1cd
19
+ class NetlogonCredential < Ndr::NdrFixedByteArray
20
+ default_parameters length: 8
21
+ end
22
+
23
+ # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/76c93227-942a-4687-ab9d-9d972ffabdab
24
+ class NetlogonAuthenticator < BinData::Record
25
+ endian :little
26
+
27
+ netlogon_credential :credential
28
+ uint32 :timestamp
29
+ end
30
+
31
+ # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/4d1235e3-2c96-4e9f-a147-3cb338a0d09f
32
+ class NetlogonSecureChannelType < Ndr::NdrEnum
33
+ # enum example from dmendel/bindata#38 https://github.com/dmendel/bindata/issues/38#issuecomment-46397163
34
+ ALL = {
35
+ 0 => :NullSecureChannel,
36
+ 1 => :MsvApSecureChannel,
37
+ 2 => :WorkstationSecureChannel,
38
+ 3 => :TrustedDnsDomainSecureChannel,
39
+ 4 => :TrustedDomainSecureChannel,
40
+ 5 => :UasServerSecureChannel,
41
+ 6 => :ServerSecureChannel,
42
+ 7 => :CdcServerSecureChannel
43
+ }
44
+ ALL.each_pair { |val,sym| const_set(sym.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').upcase, val) }
45
+ default_parameter assert: -> { ALL.keys.include? value }
46
+
47
+ def as_enum
48
+ ALL[value]
49
+ end
50
+
51
+ def assign(val)
52
+ if val.is_a? Symbol
53
+ val = ALL.key(val)
54
+ raise ArgumentError, 'invalid value name' if val.nil?
55
+ end
56
+
57
+ super
58
+ end
59
+ end
60
+
61
+ require 'ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request'
62
+ require 'ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response'
63
+ require 'ruby_smb/dcerpc/netlogon/netr_server_password_set2_request'
64
+ require 'ruby_smb/dcerpc/netlogon/netr_server_password_set2_response'
65
+ require 'ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request'
66
+ require 'ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response'
67
+
68
+ # Calculate the netlogon session key from the provided shared secret and
69
+ # challenges. The shared secret is an NTLM hash.
70
+ #
71
+ # @param shared_secret [String] the share secret between the client and the server
72
+ # @param client_challenge [String] the client challenge portion of the negotiation
73
+ # @param server_challenge [String] the server challenge portion of the negotiation
74
+ # @return [String] the session key for encryption
75
+ def self.calculate_session_key(shared_secret, client_challenge, server_challenge)
76
+ client_challenge = client_challenge.to_binary_s if client_challenge.is_a? NetlogonCredential
77
+ server_challenge = server_challenge.to_binary_s if server_challenge.is_a? NetlogonCredential
78
+
79
+ hmac = OpenSSL::HMAC.new(shared_secret, OpenSSL::Digest::SHA256.new)
80
+ hmac << client_challenge
81
+ hmac << server_challenge
82
+ hmac.digest.first(16)
83
+ end
84
+
85
+ # Encrypt the input data using the specified session key. This is used for
86
+ # certain Netlogon service operations including the authentication
87
+ # process. Per the specification, this uses AES-128-CFB8 with an all zero
88
+ # initialization vector.
89
+ #
90
+ # @param session_key [String] the session key to use for encryption (must be 16 bytes long)
91
+ # @param input_data [String] the data to encrypt
92
+ # @return [String] the encrypted data
93
+ def self.encrypt_credential(session_key, input_data)
94
+ cipher = OpenSSL::Cipher.new('AES-128-CFB8').encrypt
95
+ cipher.iv = "\x00" * 16
96
+ cipher.key = session_key
97
+ cipher.update(input_data) + cipher.final
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,28 @@
1
+ require 'ruby_smb/dcerpc/ndr'
2
+
3
+ module RubySMB
4
+ module Dcerpc
5
+ module Netlogon
6
+
7
+ # [3.5.4.4.2 NetrServerAuthenticate3 (Opnum 26)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/3a9ed16f-8014-45ae-80af-c0ecb06e2db9)
8
+ class NetrServerAuthenticate3Request < BinData::Record
9
+ attr_reader :opnum
10
+
11
+ endian :little
12
+
13
+ logonsrv_handle :primary_name
14
+ ndr_string :account_name
15
+ netlogon_secure_channel_type :secure_channel_type
16
+ ndr_string :computer_name
17
+ netlogon_credential :client_credential
18
+ uint32 :flags
19
+
20
+ def initialize_instance
21
+ super
22
+ @opnum = NETR_SERVER_AUTHENTICATE3
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,26 @@
1
+ require 'ruby_smb/dcerpc/ndr'
2
+
3
+ module RubySMB
4
+ module Dcerpc
5
+ module Netlogon
6
+
7
+ # [3.5.4.4.2 NetrServerAuthenticate3 (Opnum 26)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/3a9ed16f-8014-45ae-80af-c0ecb06e2db9)
8
+ class NetrServerAuthenticate3Response < BinData::Record
9
+ attr_reader :opnum
10
+
11
+ endian :little
12
+
13
+ netlogon_credential :server_credential
14
+ uint32 :negotiate_flags
15
+ uint32 :account_rid
16
+ uint32 :error_status
17
+
18
+ def initialize_instance
19
+ super
20
+ @opnum = NETR_SERVER_AUTHENTICATE3
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ require 'ruby_smb/dcerpc/ndr'
2
+
3
+ module RubySMB
4
+ module Dcerpc
5
+ module Netlogon
6
+
7
+ # [3.5.4.4.5 NetrServerPasswordSet2 (Opnum 30)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/14b020a8-0bcf-4af5-ab72-cc92bc6b1d81)
8
+ class NetrServerPasswordSet2Request < BinData::Record
9
+ attr_reader :opnum
10
+
11
+ endian :little
12
+
13
+ logonsrv_handle :primary_name
14
+ ndr_string :account_name
15
+ netlogon_secure_channel_type :secure_channel_type
16
+ ndr_string :computer_name
17
+ netlogon_authenticator :authenticator
18
+ ndr_fixed_byte_array :clear_new_password, length: 516 # this is an encrypted NL_TRUST_PASSWORD
19
+
20
+ def initialize_instance
21
+ super
22
+ @opnum = Netlogon::NETR_SERVER_PASSWORD_SET2
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ require 'ruby_smb/dcerpc/ndr'
2
+
3
+ module RubySMB
4
+ module Dcerpc
5
+ module Netlogon
6
+
7
+ # [3.5.4.4.5 NetrServerPasswordSet2 (Opnum 30)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/14b020a8-0bcf-4af5-ab72-cc92bc6b1d81)
8
+ class NetrServerPasswordSet2Response < BinData::Record
9
+ attr_reader :opnum
10
+
11
+ endian :little
12
+
13
+ netlogon_authenticator :return_authenticator
14
+ uint32 :error_status
15
+
16
+ def initialize_instance
17
+ super
18
+ @opnum = Netlogon::NETR_SERVER_PASSWORD_SET2
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ require 'ruby_smb/dcerpc/ndr'
2
+
3
+ module RubySMB
4
+ module Dcerpc
5
+ module Netlogon
6
+
7
+ # [3.5.4.4.1 NetrServerReqChallenge (Opnum 4)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/5ad9db9f-7441-4ce5-8c7b-7b771e243d32)
8
+ class NetrServerReqChallengeRequest < BinData::Record
9
+ attr_reader :opnum
10
+
11
+ endian :little
12
+
13
+ logonsrv_handle :primary_name
14
+ ndr_string :computer_name
15
+ netlogon_credential :client_challenge
16
+
17
+ def initialize_instance
18
+ super
19
+ @opnum = NETR_SERVER_REQ_CHALLENGE
20
+ end
21
+
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ require 'ruby_smb/dcerpc/ndr'
2
+
3
+ module RubySMB
4
+ module Dcerpc
5
+ module Netlogon
6
+
7
+ # [3.5.4.4.1 NetrServerReqChallenge (Opnum 4)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/5ad9db9f-7441-4ce5-8c7b-7b771e243d32)
8
+ class NetrServerReqChallengeResponse < BinData::Record
9
+ attr_reader :opnum
10
+
11
+ endian :little
12
+
13
+ netlogon_credential :server_challenge
14
+ uint32 :error_status
15
+
16
+ def initialize_instance
17
+ super
18
+ @opnum = NETR_SERVER_REQ_CHALLENGE
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -27,12 +27,31 @@ module RubySMB
27
27
  open_key_request RubySMB::Dcerpc::Winreg::REG_OPEN_KEY
28
28
  query_info_key_request RubySMB::Dcerpc::Winreg::REG_QUERY_INFO_KEY
29
29
  query_value_request RubySMB::Dcerpc::Winreg::REG_QUERY_VALUE
30
+ create_key_request RubySMB::Dcerpc::Winreg::REG_CREATE_KEY
31
+ save_key_request RubySMB::Dcerpc::Winreg::REG_SAVE_KEY
30
32
  string :default
31
33
  end
34
+ choice 'Netlogon', selection: -> { opnum } do
35
+ netr_server_authenticate3_request RubySMB::Dcerpc::Netlogon::NETR_SERVER_AUTHENTICATE3
36
+ netr_server_password_set2_request RubySMB::Dcerpc::Netlogon::NETR_SERVER_PASSWORD_SET2
37
+ netr_server_req_challenge_request RubySMB::Dcerpc::Netlogon::NETR_SERVER_REQ_CHALLENGE
38
+ string :default
39
+ end
32
40
  choice 'Srvsvc', selection: -> { opnum } do
33
41
  net_share_enum_all RubySMB::Dcerpc::Srvsvc::NET_SHARE_ENUM_ALL, host: -> { host rescue '' }
34
42
  string :default
35
43
  end
44
+ choice 'Svcctl', selection: -> { opnum } do
45
+ open_sc_manager_w_request RubySMB::Dcerpc::Svcctl::OPEN_SC_MANAGER_W
46
+ open_service_w_request RubySMB::Dcerpc::Svcctl::OPEN_SERVICE_W
47
+ query_service_status_request RubySMB::Dcerpc::Svcctl::QUERY_SERVICE_STATUS
48
+ query_service_config_w_request RubySMB::Dcerpc::Svcctl::QUERY_SERVICE_CONFIG_W
49
+ change_service_config_w_request RubySMB::Dcerpc::Svcctl::CHANGE_SERVICE_CONFIG_W
50
+ start_service_w_request RubySMB::Dcerpc::Svcctl::START_SERVICE_W
51
+ control_service_request RubySMB::Dcerpc::Svcctl::CONTROL_SERVICE
52
+ close_service_handle_request RubySMB::Dcerpc::Svcctl::CLOSE_SERVICE_HANDLE
53
+ string :default
54
+ end
36
55
  string :default
37
56
  end
38
57
 
@@ -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
+
@@ -8,8 +8,8 @@ module RubySMB
8
8
  class RrpUnicodeString < BinData::Primitive
9
9
  endian :little
10
10
 
11
- uint16 :buffer_length, initial_value: -> { buffer.to_s == "\0" ? 0 : buffer.actual_count * 2 }
12
- uint16 :maximum_length, initial_value: -> { buffer.to_s == "\0" ? 0 : buffer.max_count * 2 }
11
+ uint16 :buffer_length
12
+ uint16 :maximum_length
13
13
  ndr_lp_str :buffer
14
14
 
15
15
  def get
@@ -18,16 +18,19 @@ module RubySMB
18
18
 
19
19
  def set(buf)
20
20
  self.buffer = buf
21
- self.buffer_length = self.buffer.to_s == "\0" ? 0 : self.buffer.actual_count * 2
22
- self.maximum_length = self.buffer.to_s == "\0" ? 0 : self.buffer.max_count * 2
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
23
26
  end
24
27
  end
25
28
 
26
29
  # A pointer to a RRP_UNICODE_STRING structure
27
- class PrrpUnicodeString < Ndr::NdrTopLevelFullPointer
30
+ class PrrpUnicodeString < Ndr::NdrPointer
28
31
  endian :little
29
32
 
30
- rrp_unicode_string :referent, onlyif: -> { !is_a_null_pointer? }
33
+ rrp_unicode_string :referent, onlyif: -> { self.referent_id != 0 }
31
34
  end
32
35
 
33
36
  end
@@ -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