ruby_smb 2.0.1 → 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -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 +81 -48
  21. data/lib/ruby_smb/client/authentication.rb +5 -10
  22. data/lib/ruby_smb/client/echo.rb +2 -4
  23. data/lib/ruby_smb/client/negotiation.rb +21 -14
  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 +1 -1
  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 +10 -25
  77. data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +0 -1
  78. data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +0 -1
  79. data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +1 -2
  80. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +1 -13
  81. data/lib/ruby_smb/smb1/pipe.rb +8 -6
  82. data/lib/ruby_smb/smb1/tree.rb +13 -9
  83. data/lib/ruby_smb/smb2/file.rb +33 -33
  84. data/lib/ruby_smb/smb2/pipe.rb +9 -6
  85. data/lib/ruby_smb/smb2/tree.rb +21 -11
  86. data/lib/ruby_smb/version.rb +1 -1
  87. data/spec/lib/ruby_smb/client_spec.rb +195 -101
  88. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1396 -77
  89. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request_spec.rb +69 -0
  90. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response_spec.rb +53 -0
  91. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request_spec.rb +69 -0
  92. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response_spec.rb +37 -0
  93. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request_spec.rb +45 -0
  94. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response_spec.rb +37 -0
  95. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
  96. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +49 -12
  97. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
  98. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
  99. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
  100. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
  101. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
  102. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
  103. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
  104. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
  105. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
  106. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
  107. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
  108. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
  109. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
  110. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
  111. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
  112. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
  113. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
  114. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
  115. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
  116. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
  117. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +0 -4
  118. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +2 -2
  119. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +2 -2
  120. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +9 -4
  121. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
  122. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +17 -17
  123. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +11 -23
  124. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
  125. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
  126. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +227 -41
  127. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +10 -10
  128. data/spec/lib/ruby_smb/error_spec.rb +34 -5
  129. data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
  130. data/spec/lib/ruby_smb/generic_packet_spec.rb +7 -0
  131. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
  132. data/spec/lib/ruby_smb/smb1/file_spec.rb +2 -4
  133. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +0 -1
  134. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +0 -1
  135. data/spec/lib/ruby_smb/smb1/packet/trans2/open2_response_spec.rb +0 -5
  136. data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +0 -6
  137. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +30 -5
  138. data/spec/lib/ruby_smb/smb1/tree_spec.rb +22 -0
  139. data/spec/lib/ruby_smb/smb2/file_spec.rb +61 -9
  140. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +9 -5
  141. data/spec/lib/ruby_smb/smb2/tree_spec.rb +58 -1
  142. metadata +91 -2
  143. metadata.gz.sig +0 -0
@@ -0,0 +1,72 @@
1
+ RSpec.describe RubySMB::Dcerpc::Svcctl::ServiceStatus do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :dw_service_type }
5
+ it { is_expected.to respond_to :dw_current_state }
6
+ it { is_expected.to respond_to :dw_controls_accepted }
7
+ it { is_expected.to respond_to :dw_win32_exit_code }
8
+ it { is_expected.to respond_to :dw_service_specific_exit_code }
9
+ it { is_expected.to respond_to :dw_check_point }
10
+ it { is_expected.to respond_to :dw_wait_hint }
11
+
12
+ it 'is little endian' do
13
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
14
+ end
15
+
16
+ describe '#dw_service_type' do
17
+ it 'is a 32-bit unsigned integer' do
18
+ expect(packet.dw_service_type).to be_a BinData::Uint32le
19
+ end
20
+ end
21
+
22
+ describe '#dw_current_state' do
23
+ it 'is a 32-bit unsigned integer' do
24
+ expect(packet.dw_current_state).to be_a BinData::Uint32le
25
+ end
26
+ end
27
+
28
+ describe '#dw_controls_accepted' do
29
+ it 'is a 32-bit unsigned integer' do
30
+ expect(packet.dw_controls_accepted).to be_a BinData::Uint32le
31
+ end
32
+ end
33
+
34
+ describe '#dw_win32_exit_code' do
35
+ it 'is a 32-bit unsigned integer' do
36
+ expect(packet.dw_win32_exit_code).to be_a BinData::Uint32le
37
+ end
38
+ end
39
+
40
+ describe '#dw_service_specific_exit_code' do
41
+ it 'is a 32-bit unsigned integer' do
42
+ expect(packet.dw_service_specific_exit_code).to be_a BinData::Uint32le
43
+ end
44
+ end
45
+
46
+ describe '#dw_check_point' do
47
+ it 'is a 32-bit unsigned integer' do
48
+ expect(packet.dw_check_point).to be_a BinData::Uint32le
49
+ end
50
+ end
51
+
52
+ describe '#dw_wait_hint' do
53
+ it 'is a 32-bit unsigned integer' do
54
+ expect(packet.dw_wait_hint).to be_a BinData::Uint32le
55
+ end
56
+ end
57
+
58
+ it 'reads its own binary representation and outputs the same packet' do
59
+ packet = described_class.new(
60
+ dw_desired_access: 2,
61
+ dw_current_state: 3,
62
+ dw_controls_accepted: 4,
63
+ dw_win32_exit_code: 5,
64
+ dw_service_specific_exit_code: 6,
65
+ dw_check_point: 7,
66
+ dw_wait_hint: 8
67
+ )
68
+ binary = packet.to_binary_s
69
+ expect(described_class.read(binary)).to eq(packet)
70
+ end
71
+ end
72
+
@@ -0,0 +1,46 @@
1
+ RSpec.describe RubySMB::Dcerpc::Svcctl::StartServiceWRequest do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :h_service }
5
+ it { is_expected.to respond_to :argc }
6
+ it { is_expected.to respond_to :argv }
7
+
8
+ it 'is little endian' do
9
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
10
+ end
11
+
12
+ describe '#h_service' do
13
+ it 'is a ScRpcHandle structure' do
14
+ expect(packet.h_service).to be_a RubySMB::Dcerpc::Svcctl::ScRpcHandle
15
+ end
16
+ end
17
+
18
+ describe '#argc' do
19
+ it 'is a 32-bit unsigned integer' do
20
+ expect(packet.argc).to be_a BinData::Uint32le
21
+ end
22
+ end
23
+
24
+ describe '#argv' do
25
+ it 'is a NdrLpStringPtrsw structure' do
26
+ expect(packet.argv).to be_a RubySMB::Dcerpc::Ndr::NdrLpStringPtrsw
27
+ end
28
+ end
29
+
30
+ describe '#initialize_instance' do
31
+ it 'sets #opnum to START_SERVICE_W constant' do
32
+ expect(packet.opnum).to eq(RubySMB::Dcerpc::Svcctl::START_SERVICE_W)
33
+ end
34
+ end
35
+
36
+ it 'reads its own binary representation and outputs the same packet' do
37
+ packet = described_class.new(
38
+ h_service: {context_handle_attributes: 0, context_handle_uuid: '367abb81-9844-35f1-ad32-98f038001003'},
39
+ argc: 3,
40
+ argv: ['test', '-c', '-e']
41
+ )
42
+ binary = packet.to_binary_s
43
+ expect(described_class.read(binary)).to eq(packet)
44
+ end
45
+ end
46
+
@@ -0,0 +1,30 @@
1
+ RSpec.describe RubySMB::Dcerpc::Svcctl::StartServiceWResponse do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :error_status }
5
+
6
+ it 'is little endian' do
7
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
8
+ end
9
+
10
+ describe '#error_status' do
11
+ it 'is a 32-bit unsigned integer' do
12
+ expect(packet.error_status).to be_a BinData::Uint32le
13
+ end
14
+ end
15
+
16
+ describe '#initialize_instance' do
17
+ it 'sets #opnum to START_SERVICE_W constant' do
18
+ expect(packet.opnum).to eq(RubySMB::Dcerpc::Svcctl::START_SERVICE_W)
19
+ end
20
+ end
21
+
22
+ it 'reads its own binary representation and outputs the same packet' do
23
+ packet = described_class.new(
24
+ error_status: 3
25
+ )
26
+ binary = packet.to_binary_s
27
+ expect(described_class.read(binary)).to eq(packet)
28
+ end
29
+ end
30
+
@@ -0,0 +1,512 @@
1
+ RSpec.describe RubySMB::Dcerpc::Svcctl do
2
+ let(:svcctl) do
3
+ RubySMB::SMB1::Pipe.new(
4
+ tree: double('Tree'),
5
+ response: RubySMB::SMB1::Packet::NtCreateAndxResponse.new,
6
+ name: 'svcctl'
7
+ )
8
+ end
9
+ it 'fail' do
10
+ expect(true).to be true
11
+ end
12
+
13
+ describe '#open_sc_manager_w' do
14
+ let(:rhost) { '1.2.3.4' }
15
+ let(:open_sc_manager_w_request) { double('OpenSCManagerW Request Packet') }
16
+ let(:response) { double('Response') }
17
+ let(:open_sc_manager_w_response) { double('OpenSCManagerW Response Packet') }
18
+ let(:lp_sc_handle) { double('LpScHandle') }
19
+ before :example do
20
+ allow(described_class::OpenSCManagerWRequest).to receive(:new).and_return(open_sc_manager_w_request)
21
+ allow(open_sc_manager_w_request).to receive_messages(
22
+ :lp_machine_name= => nil,
23
+ :lp_database_name= => nil,
24
+ )
25
+ allow(svcctl).to receive(:dcerpc_request).and_return(response)
26
+ allow(described_class::OpenSCManagerWResponse).to receive(:read).and_return(open_sc_manager_w_response)
27
+ allow(open_sc_manager_w_response).to receive_messages(
28
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
29
+ :lp_sc_handle => lp_sc_handle
30
+ )
31
+ end
32
+
33
+ it 'create the expected OpenSCManagerWRequest packet with the default desired access' do
34
+ access =
35
+ described_class::SERVICE_START |
36
+ described_class::SERVICE_STOP |
37
+ described_class::SERVICE_CHANGE_CONFIG |
38
+ described_class::SERVICE_QUERY_CONFIG |
39
+ described_class::SERVICE_QUERY_STATUS |
40
+ described_class::SERVICE_ENUMERATE_DEPENDENTS |
41
+ described_class::SC_MANAGER_ENUMERATE_SERVICE
42
+ svcctl.open_sc_manager_w(rhost)
43
+ expect(described_class::OpenSCManagerWRequest).to have_received(:new).with(dw_desired_access: access)
44
+ end
45
+
46
+ it 'create the expected OpenSCManagerWRequest packet with custom desired access' do
47
+ access =
48
+ described_class::SERVICE_QUERY_CONFIG |
49
+ described_class::SERVICE_ENUMERATE_DEPENDENTS |
50
+ described_class::SC_MANAGER_ENUMERATE_SERVICE
51
+ svcctl.open_sc_manager_w(rhost, access)
52
+ expect(described_class::OpenSCManagerWRequest).to have_received(:new).with(dw_desired_access: access)
53
+ end
54
+
55
+ it 'sets the expected fields on the request packet' do
56
+ svcctl.open_sc_manager_w(rhost)
57
+ expect(open_sc_manager_w_request).to have_received(:lp_machine_name=).with(rhost)
58
+ expect(open_sc_manager_w_request).to have_received(:lp_database_name=).with('ServicesActive')
59
+ end
60
+
61
+ it 'sends the expected dcerpc request' do
62
+ svcctl.open_sc_manager_w(rhost)
63
+ expect(svcctl).to have_received(:dcerpc_request).with(open_sc_manager_w_request)
64
+ end
65
+
66
+ it 'creates a OpenSCManagerWResponse structure from the expected dcerpc response' do
67
+ svcctl.open_sc_manager_w(rhost)
68
+ expect(described_class::OpenSCManagerWResponse).to have_received(:read).with(response)
69
+ end
70
+
71
+ context 'when an IOError occurs while parsing the response' do
72
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
73
+ allow(described_class::OpenSCManagerWResponse).to receive(:read).and_raise(IOError)
74
+ expect { svcctl.open_sc_manager_w(rhost) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
75
+ end
76
+ end
77
+
78
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
79
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
80
+ allow(open_sc_manager_w_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
81
+ expect { svcctl.open_sc_manager_w(rhost) }.to raise_error(RubySMB::Dcerpc::Error::SvcctlError)
82
+ end
83
+ end
84
+
85
+ it 'returns the expected handler' do
86
+ expect(svcctl.open_sc_manager_w(rhost)).to eq(lp_sc_handle)
87
+ end
88
+ end
89
+
90
+ describe '#open_service_w' do
91
+ let(:scm_handle) { '1.2.3.4' }
92
+ let(:service_name) { 'MyService' }
93
+ let(:open_service_w_request) { double('OpenServiceW Request Packet') }
94
+ let(:response) { double('Response') }
95
+ let(:open_service_w_response) { double('OpenServiceW Response Packet') }
96
+ let(:lp_sc_handle) { double('LpScHandle') }
97
+ before :example do
98
+ allow(described_class::OpenServiceWRequest).to receive(:new).and_return(open_service_w_request)
99
+ allow(open_service_w_request).to receive_messages(
100
+ :lp_sc_handle= => nil,
101
+ :lp_service_name= => nil,
102
+ )
103
+ allow(svcctl).to receive(:dcerpc_request).and_return(response)
104
+ allow(described_class::OpenServiceWResponse).to receive(:read).and_return(open_service_w_response)
105
+ allow(open_service_w_response).to receive_messages(
106
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
107
+ :lp_sc_handle => lp_sc_handle
108
+ )
109
+ end
110
+
111
+ it 'create the expected OpenServiceWRequest packet with the default desired access' do
112
+ access = described_class::SERVICE_ALL_ACCESS
113
+ svcctl.open_service_w(scm_handle, service_name)
114
+ expect(described_class::OpenServiceWRequest).to have_received(:new).with(dw_desired_access: access)
115
+ end
116
+
117
+ it 'create the expected OpenServiceWRequest packet with custom desired access' do
118
+ access =
119
+ described_class::SERVICE_QUERY_CONFIG |
120
+ described_class::SERVICE_ENUMERATE_DEPENDENTS |
121
+ described_class::SC_MANAGER_ENUMERATE_SERVICE
122
+ svcctl.open_service_w(scm_handle, service_name, access)
123
+ expect(described_class::OpenServiceWRequest).to have_received(:new).with(dw_desired_access: access)
124
+ end
125
+
126
+ it 'sets the expected fields on the request packet' do
127
+ svcctl.open_service_w(scm_handle, service_name)
128
+ expect(open_service_w_request).to have_received(:lp_sc_handle=).with(scm_handle)
129
+ expect(open_service_w_request).to have_received(:lp_service_name=).with(service_name)
130
+ end
131
+
132
+ it 'sends the expected dcerpc request' do
133
+ svcctl.open_service_w(scm_handle, service_name)
134
+ expect(svcctl).to have_received(:dcerpc_request).with(open_service_w_request)
135
+ end
136
+
137
+ it 'creates a OpenServiceWResponse structure from the expected dcerpc response' do
138
+ svcctl.open_service_w(scm_handle, service_name)
139
+ expect(described_class::OpenServiceWResponse).to have_received(:read).with(response)
140
+ end
141
+
142
+ context 'when an IOError occurs while parsing the response' do
143
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
144
+ allow(described_class::OpenServiceWResponse).to receive(:read).and_raise(IOError)
145
+ expect { svcctl.open_service_w(scm_handle, service_name) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
146
+ end
147
+ end
148
+
149
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
150
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
151
+ allow(open_service_w_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
152
+ expect { svcctl.open_service_w(scm_handle, service_name) }.to raise_error(RubySMB::Dcerpc::Error::SvcctlError)
153
+ end
154
+ end
155
+
156
+ it 'returns the expected handler' do
157
+ expect(svcctl.open_service_w(scm_handle, service_name)).to eq(lp_sc_handle)
158
+ end
159
+ end
160
+
161
+ describe '#query_service_status' do
162
+ let(:svc_handle) { double('Service Handle') }
163
+ let(:query_service_status_request) { double('QueryServiceStatus Request Packet') }
164
+ let(:response) { double('Response') }
165
+ let(:query_service_status_response) { double('QueryServiceStatus Response Packet') }
166
+ let(:lp_service_status) { double('LpServiceStatus') }
167
+ before :example do
168
+ allow(described_class::QueryServiceStatusRequest).to receive(:new).and_return(query_service_status_request)
169
+ allow(query_service_status_request).to receive_messages(
170
+ :h_service= => nil,
171
+ )
172
+ allow(svcctl).to receive(:dcerpc_request).and_return(response)
173
+ allow(described_class::QueryServiceStatusResponse).to receive(:read).and_return(query_service_status_response)
174
+ allow(query_service_status_response).to receive_messages(
175
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
176
+ :lp_service_status => lp_service_status
177
+ )
178
+ end
179
+
180
+ it 'create the expected QueryServiceStatusRequest packet' do
181
+ svcctl.query_service_status(svc_handle)
182
+ expect(described_class::QueryServiceStatusRequest).to have_received(:new)
183
+ end
184
+
185
+ it 'sets the expected fields on the request packet' do
186
+ svcctl.query_service_status(svc_handle)
187
+ expect(query_service_status_request).to have_received(:h_service=).with(svc_handle)
188
+ end
189
+
190
+ it 'sends the expected dcerpc request' do
191
+ svcctl.query_service_status(svc_handle)
192
+ expect(svcctl).to have_received(:dcerpc_request).with(query_service_status_request)
193
+ end
194
+
195
+ it 'creates a QueryServiceStatusResponse structure from the expected dcerpc response' do
196
+ svcctl.query_service_status(svc_handle)
197
+ expect(described_class::QueryServiceStatusResponse).to have_received(:read).with(response)
198
+ end
199
+
200
+ context 'when an IOError occurs while parsing the response' do
201
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
202
+ allow(described_class::QueryServiceStatusResponse).to receive(:read).and_raise(IOError)
203
+ expect { svcctl.query_service_status(svc_handle) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
204
+ end
205
+ end
206
+
207
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
208
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
209
+ allow(query_service_status_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
210
+ expect { svcctl.query_service_status(svc_handle) }.to raise_error(RubySMB::Dcerpc::Error::SvcctlError)
211
+ end
212
+ end
213
+
214
+ it 'returns the expected handler' do
215
+ expect(svcctl.query_service_status(svc_handle)).to eq(lp_service_status)
216
+ end
217
+ end
218
+
219
+ describe '#query_service_config' do
220
+ let(:svc_handle) { double('Service Handle') }
221
+ let(:query_service_config_request) { double('QueryServiceConfigW Request Packet') }
222
+ let(:response) { double('Response') }
223
+ let(:query_service_config_response) { double('QueryServiceConfigW Response Packet') }
224
+ let(:lp_service_config) { double('LpServiceConfig') }
225
+ before :example do
226
+ allow(described_class::QueryServiceConfigWRequest).to receive(:new).and_return(query_service_config_request)
227
+ allow(query_service_config_request).to receive_messages(
228
+ :h_service= => nil,
229
+ :cb_buf_size= => nil,
230
+ )
231
+ allow(svcctl).to receive(:dcerpc_request).and_return(response)
232
+ allow(described_class::QueryServiceConfigWResponse).to receive(:read).and_return(query_service_config_response)
233
+ allow(query_service_config_response).to receive_messages(
234
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
235
+ :lp_service_config => lp_service_config
236
+ )
237
+ end
238
+
239
+ it 'create the expected QueryServiceConfigWRequest packet' do
240
+ svcctl.query_service_config(svc_handle)
241
+ expect(described_class::QueryServiceConfigWRequest).to have_received(:new)
242
+ end
243
+
244
+ it 'sets the expected fields on the request packet' do
245
+ svcctl.query_service_config(svc_handle)
246
+ expect(query_service_config_request).to have_received(:h_service=).with(svc_handle)
247
+ expect(query_service_config_request).to have_received(:cb_buf_size=).with(0)
248
+ end
249
+
250
+ it 'sends the expected dcerpc request' do
251
+ svcctl.query_service_config(svc_handle)
252
+ expect(svcctl).to have_received(:dcerpc_request).with(query_service_config_request)
253
+ end
254
+
255
+ it 'creates a QueryServiceConfigWResponse structure from the expected dcerpc response' do
256
+ svcctl.query_service_config(svc_handle)
257
+ expect(described_class::QueryServiceConfigWResponse).to have_received(:read).with(response)
258
+ end
259
+
260
+ context 'when an IOError occurs while parsing the response' do
261
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
262
+ allow(described_class::QueryServiceConfigWResponse).to receive(:read).and_raise(IOError)
263
+ expect { svcctl.query_service_config(svc_handle) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
264
+ end
265
+ end
266
+
267
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
268
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
269
+ allow(query_service_config_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
270
+ expect { svcctl.query_service_config(svc_handle) }.to raise_error(RubySMB::Dcerpc::Error::SvcctlError)
271
+ end
272
+ end
273
+
274
+ it 'returns the expected handler' do
275
+ expect(svcctl.query_service_config(svc_handle)).to eq(lp_service_config)
276
+ end
277
+ end
278
+
279
+ describe '#change_service_config_w' do
280
+ let(:svc_handle) { double('Service Handle') }
281
+ let(:change_service_config_w_request) { double('ChangeServiceConfigW Request Packet') }
282
+ let(:response) { double('Response') }
283
+ let(:change_service_config_w_response) { double('ChangeServiceConfigW Response Packet') }
284
+ before :example do
285
+ allow(described_class::ChangeServiceConfigWRequest).to receive(:new).and_return(change_service_config_w_request)
286
+ allow(svcctl).to receive(:dcerpc_request).and_return(response)
287
+ allow(described_class::ChangeServiceConfigWResponse).to receive(:read).and_return(change_service_config_w_response)
288
+ allow(change_service_config_w_response).to receive_messages(
289
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
290
+ )
291
+ end
292
+
293
+ it 'create the expected ChangeServiceConfigWRequest packet with the default options' do
294
+ opts = {
295
+ h_service: svc_handle,
296
+ dw_service_type: described_class::SERVICE_NO_CHANGE,
297
+ dw_start_type: described_class::SERVICE_NO_CHANGE,
298
+ dw_error_control: described_class::SERVICE_NO_CHANGE,
299
+ lp_binary_path_name: :null,
300
+ lp_load_order_group: :null,
301
+ dw_tag_id: :null,
302
+ lp_dependencies: [],
303
+ lp_service_start_name: :null,
304
+ lp_password: [],
305
+ lp_display_name: :null
306
+ }
307
+ svcctl.change_service_config_w(svc_handle)
308
+ expect(described_class::ChangeServiceConfigWRequest).to have_received(:new).with(opts)
309
+ end
310
+
311
+ it 'create the expected ChangeServiceConfigWRequest packet with custom options' do
312
+ opts = {
313
+ service: svc_handle,
314
+ service_type: described_class::SERVICE_KERNEL_DRIVER,
315
+ start_type: described_class::SERVICE_SYSTEM_START,
316
+ error_control: described_class::SERVICE_ERROR_SEVERE,
317
+ binary_path_name: '\\path\\to\\binary',
318
+ load_order_group: 'load order',
319
+ tag_id: 2,
320
+ dependencies: [1, 2, 3],
321
+ service_start_name: 'My service',
322
+ password: [1, 2, 3],
323
+ display_name: 'Name'
324
+ }
325
+ opts2 = {
326
+ h_service: svc_handle,
327
+ dw_service_type: opts[:service_type],
328
+ dw_start_type: opts[:start_type],
329
+ dw_error_control: opts[:error_control],
330
+ lp_binary_path_name: opts[:binary_path_name],
331
+ lp_load_order_group: opts[:load_order_group],
332
+ dw_tag_id: opts[:tag_id],
333
+ lp_dependencies: opts[:dependencies],
334
+ lp_service_start_name: opts[:service_start_name],
335
+ lp_password: opts[:password],
336
+ lp_display_name: opts[:display_name]
337
+ }
338
+ svcctl.change_service_config_w(svc_handle, opts)
339
+ expect(described_class::ChangeServiceConfigWRequest).to have_received(:new).with(opts2)
340
+ end
341
+
342
+ it 'sends the expected dcerpc request' do
343
+ svcctl.change_service_config_w(svc_handle)
344
+ expect(svcctl).to have_received(:dcerpc_request).with(change_service_config_w_request)
345
+ end
346
+
347
+ it 'creates a ChangeServiceConfigWResponse structure from the expected dcerpc response' do
348
+ svcctl.change_service_config_w(svc_handle)
349
+ expect(described_class::ChangeServiceConfigWResponse).to have_received(:read).with(response)
350
+ end
351
+
352
+ context 'when an IOError occurs while parsing the response' do
353
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
354
+ allow(described_class::ChangeServiceConfigWResponse).to receive(:read).and_raise(IOError)
355
+ expect { svcctl.change_service_config_w(svc_handle) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
356
+ end
357
+ end
358
+
359
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
360
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
361
+ allow(change_service_config_w_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
362
+ expect { svcctl.change_service_config_w(svc_handle) }.to raise_error(RubySMB::Dcerpc::Error::SvcctlError)
363
+ end
364
+ end
365
+ end
366
+
367
+ describe '#start_service_w' do
368
+ let(:svc_handle) { double('Service Handle') }
369
+ let(:start_service_w_request) { double('StartServiceW Request Packet') }
370
+ let(:response) { double('Response') }
371
+ let(:start_service_w_response) { double('StartServiceW Response Packet') }
372
+ before :example do
373
+ allow(described_class::StartServiceWRequest).to receive(:new).and_return(start_service_w_request)
374
+ allow(start_service_w_request).to receive_messages(
375
+ :h_service= => nil,
376
+ :argc= => nil,
377
+ :argv= => nil,
378
+ )
379
+ allow(svcctl).to receive(:dcerpc_request).and_return(response)
380
+ allow(described_class::StartServiceWResponse).to receive(:read).and_return(start_service_w_response)
381
+ allow(start_service_w_response).to receive_messages(
382
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
383
+ )
384
+ end
385
+
386
+ it 'create the expected StartServiceWRequest packet' do
387
+ svcctl.start_service_w(svc_handle)
388
+ expect(described_class::StartServiceWRequest).to have_received(:new)
389
+ end
390
+
391
+ it 'sets the provided Service start arguments' do
392
+ argv = ['my', 'arguments', 'to', 'test']
393
+ ndr_string_ptrsw = RubySMB::Dcerpc::Ndr::NdrStringPtrsw.new(elements: argv)
394
+ svcctl.start_service_w(svc_handle, argv)
395
+ expect(start_service_w_request).to have_received(:argc=).with(argv.size)
396
+ expect(start_service_w_request).to have_received(:argv=).with(ndr_string_ptrsw)
397
+ end
398
+
399
+ it 'sends the expected dcerpc request' do
400
+ svcctl.start_service_w(svc_handle)
401
+ expect(svcctl).to have_received(:dcerpc_request).with(start_service_w_request)
402
+ end
403
+
404
+ it 'creates a StartServiceWResponse structure from the expected dcerpc response' do
405
+ svcctl.start_service_w(svc_handle)
406
+ expect(described_class::StartServiceWResponse).to have_received(:read).with(response)
407
+ end
408
+
409
+ context 'when an IOError occurs while parsing the response' do
410
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
411
+ allow(described_class::StartServiceWResponse).to receive(:read).and_raise(IOError)
412
+ expect { svcctl.start_service_w(svc_handle) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
413
+ end
414
+ end
415
+
416
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
417
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
418
+ allow(start_service_w_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
419
+ expect { svcctl.start_service_w(svc_handle) }.to raise_error(RubySMB::Dcerpc::Error::SvcctlError)
420
+ end
421
+ end
422
+ end
423
+
424
+ describe '#control_service' do
425
+ let(:svc_handle) { double('Service Handle') }
426
+ let(:control) { double('Control') }
427
+ let(:control_service_request) { double('ControlService Request Packet') }
428
+ let(:response) { double('Response') }
429
+ let(:control_service_response) { double('ControlService Response Packet') }
430
+ before :example do
431
+ allow(described_class::ControlServiceRequest).to receive(:new).and_return(control_service_request)
432
+ allow(svcctl).to receive(:dcerpc_request).and_return(response)
433
+ allow(described_class::ControlServiceResponse).to receive(:read).and_return(control_service_response)
434
+ allow(control_service_response).to receive_messages(
435
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
436
+ )
437
+ end
438
+
439
+ it 'create the expected ControlServiceRequest packet' do
440
+ svcctl.control_service(svc_handle, control)
441
+ expect(described_class::ControlServiceRequest).to have_received(:new).with(h_service: svc_handle, dw_control: control)
442
+ end
443
+
444
+ it 'sends the expected dcerpc request' do
445
+ svcctl.control_service(svc_handle, control)
446
+ expect(svcctl).to have_received(:dcerpc_request).with(control_service_request)
447
+ end
448
+
449
+ it 'creates a ControlServiceResponse structure from the expected dcerpc response' do
450
+ svcctl.control_service(svc_handle, control)
451
+ expect(described_class::ControlServiceResponse).to have_received(:read).with(response)
452
+ end
453
+
454
+ context 'when an IOError occurs while parsing the response' do
455
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
456
+ allow(described_class::ControlServiceResponse).to receive(:read).and_raise(IOError)
457
+ expect { svcctl.control_service(svc_handle, control) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
458
+ end
459
+ end
460
+
461
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
462
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
463
+ allow(control_service_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
464
+ expect { svcctl.control_service(svc_handle, control) }.to raise_error(RubySMB::Dcerpc::Error::SvcctlError)
465
+ end
466
+ end
467
+ end
468
+
469
+ describe '#close_service_handle' do
470
+ let(:svc_handle) { double('Service Handle') }
471
+ let(:close_service_handle_request) { double('CloseServiceHandle Request Packet') }
472
+ let(:response) { double('Response') }
473
+ let(:close_service_handle_response) { double('CloseServiceHandle Response Packet') }
474
+ before :example do
475
+ allow(described_class::CloseServiceHandleRequest).to receive(:new).and_return(close_service_handle_request)
476
+ allow(svcctl).to receive(:dcerpc_request).and_return(response)
477
+ allow(described_class::CloseServiceHandleResponse).to receive(:read).and_return(close_service_handle_response)
478
+ allow(close_service_handle_response).to receive_messages(
479
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
480
+ )
481
+ end
482
+
483
+ it 'create the expected CloseServiceHandleRequest packet' do
484
+ svcctl.close_service_handle(svc_handle)
485
+ expect(described_class::CloseServiceHandleRequest).to have_received(:new).with(h_sc_object: svc_handle)
486
+ end
487
+
488
+ it 'sends the expected dcerpc request' do
489
+ svcctl.close_service_handle(svc_handle)
490
+ expect(svcctl).to have_received(:dcerpc_request).with(close_service_handle_request)
491
+ end
492
+
493
+ it 'creates a CloseServiceHandleResponse structure from the expected dcerpc response' do
494
+ svcctl.close_service_handle(svc_handle)
495
+ expect(described_class::CloseServiceHandleResponse).to have_received(:read).with(response)
496
+ end
497
+
498
+ context 'when an IOError occurs while parsing the response' do
499
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
500
+ allow(described_class::CloseServiceHandleResponse).to receive(:read).and_raise(IOError)
501
+ expect { svcctl.close_service_handle(svc_handle) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
502
+ end
503
+ end
504
+
505
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
506
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
507
+ allow(close_service_handle_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
508
+ expect { svcctl.close_service_handle(svc_handle) }.to raise_error(RubySMB::Dcerpc::Error::SvcctlError)
509
+ end
510
+ end
511
+ end
512
+ end