ruby_smb 2.0.2 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  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 +72 -43
  21. data/lib/ruby_smb/client/negotiation.rb +1 -0
  22. data/lib/ruby_smb/dcerpc.rb +2 -0
  23. data/lib/ruby_smb/dcerpc/error.rb +3 -0
  24. data/lib/ruby_smb/dcerpc/ndr.rb +209 -44
  25. data/lib/ruby_smb/dcerpc/request.rb +13 -0
  26. data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
  27. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +9 -6
  28. data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
  29. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
  30. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
  31. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
  32. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
  33. data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
  34. data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
  35. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
  36. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
  37. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
  38. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
  39. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
  40. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
  41. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
  42. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
  43. data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
  44. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
  45. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
  46. data/lib/ruby_smb/dcerpc/winreg.rb +98 -17
  47. data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
  48. data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
  49. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +1 -1
  50. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +1 -1
  51. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +1 -1
  52. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +4 -4
  53. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
  54. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +7 -6
  55. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +10 -10
  56. data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
  57. data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
  58. data/lib/ruby_smb/dispatcher/base.rb +1 -1
  59. data/lib/ruby_smb/dispatcher/socket.rb +1 -1
  60. data/lib/ruby_smb/field/stringz16.rb +17 -1
  61. data/lib/ruby_smb/nbss/session_header.rb +4 -4
  62. data/lib/ruby_smb/smb1/file.rb +2 -10
  63. data/lib/ruby_smb/smb1/pipe.rb +2 -0
  64. data/lib/ruby_smb/smb2/file.rb +25 -17
  65. data/lib/ruby_smb/smb2/pipe.rb +3 -0
  66. data/lib/ruby_smb/smb2/tree.rb +9 -3
  67. data/lib/ruby_smb/version.rb +1 -1
  68. data/spec/lib/ruby_smb/client_spec.rb +161 -60
  69. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1396 -77
  70. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
  71. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +49 -12
  72. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
  73. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
  74. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
  75. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
  76. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
  77. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
  78. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
  79. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
  80. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
  81. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
  82. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
  83. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
  84. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
  85. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
  86. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
  87. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
  88. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
  89. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
  90. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
  91. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
  92. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +0 -4
  93. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +2 -2
  94. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +2 -2
  95. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +9 -4
  96. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
  97. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +17 -17
  98. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +11 -23
  99. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
  100. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
  101. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +215 -41
  102. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +10 -10
  103. data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
  104. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
  105. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +7 -0
  106. data/spec/lib/ruby_smb/smb2/file_spec.rb +60 -6
  107. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +7 -0
  108. data/spec/lib/ruby_smb/smb2/tree_spec.rb +35 -1
  109. metadata +72 -2
  110. metadata.gz.sig +0 -0
@@ -0,0 +1,30 @@
1
+ RSpec.describe RubySMB::Dcerpc::Svcctl::QueryServiceStatusRequest do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :h_service }
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 '#h_service' do
11
+ it 'is a ScRpcHandle structure' do
12
+ expect(packet.h_service).to be_a RubySMB::Dcerpc::Svcctl::ScRpcHandle
13
+ end
14
+ end
15
+
16
+ describe '#initialize_instance' do
17
+ it 'sets #opnum to QUERY_SERVICE_STATUS constant' do
18
+ expect(packet.opnum).to eq(RubySMB::Dcerpc::Svcctl::QUERY_SERVICE_STATUS)
19
+ end
20
+ end
21
+
22
+ it 'reads its own binary representation and outputs the same packet' do
23
+ packet = described_class.new(
24
+ h_service: {context_handle_attributes: 0, context_handle_uuid: '367abb81-9844-35f1-ad32-98f038001003'}
25
+ )
26
+ binary = packet.to_binary_s
27
+ expect(described_class.read(binary)).to eq(packet)
28
+ end
29
+ end
30
+
@@ -0,0 +1,38 @@
1
+ RSpec.describe RubySMB::Dcerpc::Svcctl::QueryServiceStatusResponse do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :lp_service_status }
5
+ it { is_expected.to respond_to :error_status }
6
+
7
+ it 'is little endian' do
8
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
9
+ end
10
+
11
+ describe '#lp_service_status' do
12
+ it 'is a ServiceStatus structure' do
13
+ expect(packet.lp_service_status).to be_a RubySMB::Dcerpc::Svcctl::ServiceStatus
14
+ end
15
+ end
16
+
17
+ describe '#error_status' do
18
+ it 'is a 32-bit unsigned integer' do
19
+ expect(packet.error_status).to be_a BinData::Uint32le
20
+ end
21
+ end
22
+
23
+ describe '#initialize_instance' do
24
+ it 'sets #opnum to QUERY_SERVICE_STATUS constant' do
25
+ expect(packet.opnum).to eq(RubySMB::Dcerpc::Svcctl::QUERY_SERVICE_STATUS)
26
+ end
27
+ end
28
+
29
+ it 'reads its own binary representation and outputs the same packet' do
30
+ packet = described_class.new(
31
+ lp_service_status: RubySMB::Dcerpc::Svcctl::ServiceStatus.new(dw_service_type: 1, dw_current_state: 3),
32
+ error_status: 3
33
+ )
34
+ binary = packet.to_binary_s
35
+ expect(described_class.read(binary)).to eq(packet)
36
+ end
37
+ end
38
+
@@ -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