ruby_smb 1.1.0 → 2.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.travis.yml +3 -5
- data/Gemfile +6 -2
- data/examples/anonymous_auth.rb +3 -3
- data/examples/append_file.rb +10 -8
- data/examples/authenticate.rb +9 -5
- data/examples/delete_file.rb +8 -6
- data/examples/enum_registry_key.rb +5 -4
- data/examples/enum_registry_values.rb +5 -4
- data/examples/list_directory.rb +8 -6
- data/examples/negotiate.rb +51 -8
- data/examples/negotiate_with_netbios_service.rb +9 -5
- data/examples/net_share_enum_all.rb +6 -4
- data/examples/pipes.rb +11 -12
- data/examples/query_service_status.rb +64 -0
- data/examples/read_file.rb +8 -6
- data/examples/read_file_encryption.rb +56 -0
- data/examples/read_registry_key_value.rb +6 -5
- data/examples/rename_file.rb +9 -7
- data/examples/tree_connect.rb +7 -5
- data/examples/write_file.rb +9 -7
- data/lib/ruby_smb.rb +4 -0
- data/lib/ruby_smb/client.rb +246 -26
- data/lib/ruby_smb/client/authentication.rb +32 -18
- data/lib/ruby_smb/client/echo.rb +2 -4
- data/lib/ruby_smb/client/encryption.rb +62 -0
- data/lib/ruby_smb/client/negotiation.rb +156 -16
- data/lib/ruby_smb/client/signing.rb +19 -0
- data/lib/ruby_smb/client/tree_connect.rb +6 -8
- data/lib/ruby_smb/client/utils.rb +24 -17
- data/lib/ruby_smb/client/winreg.rb +1 -1
- data/lib/ruby_smb/crypto.rb +30 -0
- data/lib/ruby_smb/dcerpc.rb +2 -0
- data/lib/ruby_smb/dcerpc/error.rb +3 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +209 -44
- data/lib/ruby_smb/dcerpc/request.rb +13 -0
- data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +9 -6
- data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
- data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +98 -17
- data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
- data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +4 -4
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +7 -6
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +10 -10
- data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
- data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
- data/lib/ruby_smb/dispatcher/base.rb +1 -1
- data/lib/ruby_smb/dispatcher/socket.rb +5 -4
- data/lib/ruby_smb/error.rb +49 -6
- data/lib/ruby_smb/field/stringz16.rb +17 -1
- data/lib/ruby_smb/generic_packet.rb +11 -1
- data/lib/ruby_smb/nbss/session_header.rb +4 -4
- data/lib/ruby_smb/smb1/commands.rb +1 -1
- data/lib/ruby_smb/smb1/file.rb +13 -28
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -2
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -2
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +1 -1
- data/lib/ruby_smb/smb1/pipe.rb +8 -8
- data/lib/ruby_smb/smb1/tree.rb +25 -12
- data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
- data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
- data/lib/ruby_smb/smb2/file.rb +59 -77
- data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
- data/lib/ruby_smb/smb2/packet.rb +2 -0
- data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -14
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +50 -4
- data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +92 -6
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -26
- data/lib/ruby_smb/smb2/pipe.rb +8 -20
- data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
- data/lib/ruby_smb/smb2/tree.rb +44 -28
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +3 -1
- data/spec/lib/ruby_smb/client_spec.rb +1408 -70
- data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1396 -77
- data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +49 -12
- data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +0 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +9 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +17 -17
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +11 -23
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +227 -41
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +12 -12
- data/spec/lib/ruby_smb/error_spec.rb +88 -0
- data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
- data/spec/lib/ruby_smb/generic_packet_spec.rb +7 -0
- data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
- data/spec/lib/ruby_smb/smb1/file_spec.rb +1 -3
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +30 -5
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +22 -0
- data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
- data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
- data/spec/lib/ruby_smb/smb2/file_spec.rb +147 -71
- data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
- data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
- data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
- data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
- data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -30
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +9 -45
- data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +111 -9
- metadata +194 -75
- metadata.gz.sig +2 -1
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe RubySMB::Error::InvalidPacket do
|
4
|
+
context 'with a String' do
|
5
|
+
it 'outputs the expected error message' do
|
6
|
+
ex = described_class.new('My exception')
|
7
|
+
expect(ex.to_s).to eq('My exception')
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'with a Hash' do
|
12
|
+
let(:ex) do
|
13
|
+
described_class.new(
|
14
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
15
|
+
expected_cmd: RubySMB::SMB1::Packet::NegotiateResponseExtended::COMMAND,
|
16
|
+
expected_custom: "extended_security=1",
|
17
|
+
packet: packet,
|
18
|
+
received_custom: "extended_security=0"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with an SMB2 packet' do
|
23
|
+
let(:packet) { RubySMB::SMB2::Packet::NegotiateResponse.new }
|
24
|
+
|
25
|
+
it 'outputs the expected error message' do
|
26
|
+
expect(ex.to_s).to eq('Expecting SMB1 protocol with command=114 (extended_security=1), got SMB2 protocol with command=0 (extended_security=0), Status: (0x00000000) STATUS_SUCCESS: The operation completed successfully.')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'with an SMB1 packet' do
|
31
|
+
let(:packet) { RubySMB::SMB1::Packet::ReadAndxRequest.new }
|
32
|
+
|
33
|
+
it 'outputs the expected error message' do
|
34
|
+
expect(ex.to_s).to eq('Expecting SMB1 protocol with command=114 (extended_security=1), got SMB1 protocol with command=46 (extended_security=0), Status: (0x00000000) STATUS_SUCCESS: The operation completed successfully.')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'without packet' do
|
39
|
+
let(:ex) do
|
40
|
+
described_class.new(
|
41
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
42
|
+
expected_cmd: RubySMB::SMB1::Packet::NegotiateResponseExtended::COMMAND,
|
43
|
+
expected_custom: "extended_security=1",
|
44
|
+
received_custom: "extended_security=0"
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'outputs the expected error message' do
|
49
|
+
expect(ex.to_s).to eq('Expecting SMB1 protocol with command=114 (extended_security=1), got ??? protocol with command=??? (extended_security=0)')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'with an unsupported type' do
|
55
|
+
it 'raises the expected exception' do
|
56
|
+
expect { described_class.new(['wrong']) }.to raise_error(
|
57
|
+
ArgumentError,
|
58
|
+
'InvalidPacket expects a String or a Hash, got a Array'
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
RSpec.describe RubySMB::Error::UnexpectedStatusCode do
|
66
|
+
context 'with a WindowsError::ErrorCode' do
|
67
|
+
it 'outputs the expected error message' do
|
68
|
+
ex = described_class.new(WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW)
|
69
|
+
expect(ex.to_s).to eq('The server responded with an unexpected status code: STATUS_BUFFER_OVERFLOW')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'with an Integer' do
|
74
|
+
it 'outputs the expected error message' do
|
75
|
+
ex = described_class.new(0x80000005)
|
76
|
+
expect(ex.to_s).to eq('The server responded with an unexpected status code: STATUS_BUFFER_OVERFLOW')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'with an unsupported type' do
|
81
|
+
it 'raises the expected exception' do
|
82
|
+
expect { described_class.new(['wrong']) }.to raise_error(
|
83
|
+
ArgumentError,
|
84
|
+
'Status code must be a WindowsError::ErrorCode or an Integer, got Array'
|
85
|
+
)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -44,5 +44,17 @@ RSpec.describe RubySMB::Field::Stringz16 do
|
|
44
44
|
io = StringIO.new("A\x00B\x00C\x00D\x00")
|
45
45
|
expect { stringz16.read(io) }.to raise_error(EOFError)
|
46
46
|
end
|
47
|
+
|
48
|
+
it 'trims the string to #max_length and makes sure it ends with a null terminator' do
|
49
|
+
io = StringIO.new("A\x00B\x00C\x00D\x00")
|
50
|
+
str = described_class.new(max_length: 6)
|
51
|
+
expect(str.read(io).to_binary_s).to eq("A\x00B\x00\x00\x00".b)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'raises an exception when #max_length is not a multiple of two' do
|
55
|
+
io = StringIO.new("A\x00B\x00C\x00D\x00")
|
56
|
+
str = described_class.new(max_length: 5)
|
57
|
+
expect { str.read(io) }.to raise_error(ArgumentError)
|
58
|
+
end
|
47
59
|
end
|
48
60
|
end
|
@@ -88,6 +88,13 @@ RSpec.describe RubySMB::GenericPacket do
|
|
88
88
|
packet = RubySMB::SMB2::Packet::NegotiateResponse.read(smb2_error_packet.to_binary_s)
|
89
89
|
expect(packet.original_command).to eq RubySMB::SMB2::Packet::NegotiateResponse::COMMAND
|
90
90
|
end
|
91
|
+
|
92
|
+
context 'when the server returns an SMB1 error packet' do
|
93
|
+
let(:smb1_error_packet) { RubySMB::SMB1::Packet::EmptyPacket.new }
|
94
|
+
it 'returns the empty packet instead of the asked for class' do
|
95
|
+
expect(RubySMB::SMB2::Packet::NegotiateResponse.read(smb1_error_packet.to_binary_s)).to be_a RubySMB::SMB1::Packet::EmptyPacket
|
96
|
+
end
|
97
|
+
end
|
91
98
|
end
|
92
99
|
end
|
93
100
|
|
@@ -2,8 +2,7 @@ RSpec.describe RubySMB::Nbss::SessionHeader do
|
|
2
2
|
subject(:session_header) { described_class.new }
|
3
3
|
|
4
4
|
it { is_expected.to respond_to :session_packet_type }
|
5
|
-
it { is_expected.to respond_to :
|
6
|
-
it { is_expected.to respond_to :packet_length }
|
5
|
+
it { is_expected.to respond_to :stream_protocol_length }
|
7
6
|
|
8
7
|
it 'is big endian' do
|
9
8
|
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :big
|
@@ -15,15 +14,9 @@ RSpec.describe RubySMB::Nbss::SessionHeader do
|
|
15
14
|
end
|
16
15
|
end
|
17
16
|
|
18
|
-
describe '#
|
19
|
-
it 'is a
|
20
|
-
expect(session_header.
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
describe '#packet_length' do
|
25
|
-
it 'is a 17-bit Unsigned Integer' do
|
26
|
-
expect(session_header.packet_length).to be_a BinData::Bit17
|
17
|
+
describe '#stream_protocol_length' do
|
18
|
+
it 'is a 24-bit Unsigned Integer' do
|
19
|
+
expect(session_header.stream_protocol_length).to be_a BinData::Uint24be
|
27
20
|
end
|
28
21
|
end
|
29
22
|
end
|
@@ -521,9 +521,7 @@ RSpec.describe RubySMB::SMB1::File do
|
|
521
521
|
|
522
522
|
it 'raises an InvalidPacket exception if the response is not valid' do
|
523
523
|
allow(response).to receive(:valid?).and_return(false)
|
524
|
-
|
525
|
-
allow(response).to receive(:smb_header).and_return(smb_header)
|
526
|
-
allow(smb_header).to receive_messages(:protocol => nil, :command => nil)
|
524
|
+
allow(response).to receive(:packet_smb_version)
|
527
525
|
expect { file.close }.to raise_error(RubySMB::Error::InvalidPacket)
|
528
526
|
end
|
529
527
|
|
@@ -10,8 +10,8 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupLegacyRequest do
|
|
10
10
|
expect(header).to be_a RubySMB::SMB1::SMBHeader
|
11
11
|
end
|
12
12
|
|
13
|
-
it 'should have the command set to
|
14
|
-
expect(header.command).to eq RubySMB::SMB1::Commands::
|
13
|
+
it 'should have the command set to SMB_COM_SESSION_SETUP_ANDX' do
|
14
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should not have the response flag set' do
|
@@ -10,8 +10,8 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupLegacyResponse do
|
|
10
10
|
expect(header).to be_a RubySMB::SMB1::SMBHeader
|
11
11
|
end
|
12
12
|
|
13
|
-
it 'should have the command set to
|
14
|
-
expect(header.command).to eq RubySMB::SMB1::Commands::
|
13
|
+
it 'should have the command set to SMB_COM_SESSION_SETUP_ANDX' do
|
14
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should have the response flag set' do
|
@@ -10,8 +10,8 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupRequest do
|
|
10
10
|
expect(header).to be_a RubySMB::SMB1::SMBHeader
|
11
11
|
end
|
12
12
|
|
13
|
-
it 'should have the command set to
|
14
|
-
expect(header.command).to eq RubySMB::SMB1::Commands::
|
13
|
+
it 'should have the command set to SMB_COM_SESSION_SETUP_ANDX' do
|
14
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should not have the response flag set' do
|
@@ -11,7 +11,7 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupResponse do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
it 'should have the command set to SMB_COM_NEGOTIATE' do
|
14
|
-
expect(header.command).to eq RubySMB::SMB1::Commands::
|
14
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should have the response flag set' do
|
@@ -80,9 +80,7 @@ RSpec.describe RubySMB::SMB1::Pipe do
|
|
80
80
|
|
81
81
|
it 'raises an InvalidPacket exception if the response is not valid' do
|
82
82
|
allow(response).to receive(:valid?).and_return(false)
|
83
|
-
|
84
|
-
allow(response).to receive(:smb_header).and_return(smb_header)
|
85
|
-
allow(smb_header).to receive_messages(:protocol => nil, :command => nil)
|
83
|
+
allow(response).to receive(:packet_smb_version)
|
86
84
|
expect { pipe.peek }.to raise_error(RubySMB::Error::InvalidPacket)
|
87
85
|
end
|
88
86
|
|
@@ -149,12 +147,40 @@ RSpec.describe RubySMB::SMB1::Pipe do
|
|
149
147
|
end
|
150
148
|
end
|
151
149
|
|
150
|
+
context 'with \'\\srvsvc\' filename' do
|
151
|
+
it 'extends Srvsvc class' do
|
152
|
+
pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: '\\srvsvc')
|
153
|
+
expect(pipe.respond_to?(:net_share_enum_all)).to be true
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
152
157
|
context 'with \'winreg\' filename' do
|
153
158
|
it 'extends Winreg class' do
|
154
159
|
pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: 'winreg')
|
155
160
|
expect(pipe.respond_to?(:has_registry_key?)).to be true
|
156
161
|
end
|
157
162
|
end
|
163
|
+
|
164
|
+
context 'with \'\\winreg\' filename' do
|
165
|
+
it 'extends Winreg class' do
|
166
|
+
pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: '\\winreg')
|
167
|
+
expect(pipe.respond_to?(:has_registry_key?)).to be true
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context 'with \'svcctl\' filename' do
|
172
|
+
it 'extends svcctl class' do
|
173
|
+
pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: 'svcctl')
|
174
|
+
expect(pipe.respond_to?(:query_service_config)).to be true
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'with \'\\svcctl\' filename' do
|
179
|
+
it 'extends svcctl class' do
|
180
|
+
pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: '\\svcctl')
|
181
|
+
expect(pipe.respond_to?(:query_service_config)).to be true
|
182
|
+
end
|
183
|
+
end
|
158
184
|
end
|
159
185
|
|
160
186
|
describe '#dcerpc_request' do
|
@@ -238,8 +264,7 @@ RSpec.describe RubySMB::SMB1::Pipe do
|
|
238
264
|
|
239
265
|
context 'when the response is not a Trans packet' do
|
240
266
|
it 'raises an InvalidPacket exception' do
|
241
|
-
allow(trans_nmpipe_response).to
|
242
|
-
allow(trans_nmpipe_response).to receive_message_chain(:smb_header, :command)
|
267
|
+
allow(trans_nmpipe_response).to receive(:packet_smb_version)
|
243
268
|
allow(trans_nmpipe_response).to receive(:valid?).and_return(false)
|
244
269
|
expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Error::InvalidPacket)
|
245
270
|
end
|
@@ -492,4 +492,26 @@ RSpec.describe RubySMB::SMB1::Tree do
|
|
492
492
|
end
|
493
493
|
end
|
494
494
|
|
495
|
+
describe '#open_pipe' do
|
496
|
+
let(:opts) { { filename: 'test', write: true } }
|
497
|
+
before :example do
|
498
|
+
allow(tree).to receive(:open_file)
|
499
|
+
end
|
500
|
+
|
501
|
+
it 'calls #open_file with the provided options' do
|
502
|
+
opts[:filename] ='\\test'
|
503
|
+
expect(tree).to receive(:open_file).with(opts)
|
504
|
+
tree.open_pipe(opts)
|
505
|
+
end
|
506
|
+
|
507
|
+
it 'prepends the filename with \\ if needed' do
|
508
|
+
expect(tree).to receive(:open_file).with( { filename: '\\test', write: true } )
|
509
|
+
tree.open_pipe(opts)
|
510
|
+
end
|
511
|
+
|
512
|
+
it 'does not modify the original option hash' do
|
513
|
+
tree.open_pipe(opts)
|
514
|
+
expect(opts).to eq( { filename: 'test', write: true } )
|
515
|
+
end
|
516
|
+
end
|
495
517
|
end
|
@@ -5,6 +5,7 @@ RSpec.describe RubySMB::SMB2::BitField::SessionFlags do
|
|
5
5
|
|
6
6
|
it { is_expected.to respond_to :guest }
|
7
7
|
it { is_expected.to respond_to :null }
|
8
|
+
it { is_expected.to respond_to :encrypt_data }
|
8
9
|
|
9
10
|
it 'is little endian' do
|
10
11
|
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
@@ -25,4 +26,12 @@ RSpec.describe RubySMB::SMB2::BitField::SessionFlags do
|
|
25
26
|
|
26
27
|
it_behaves_like 'bit field with one flag set', :null, 'v', 0x00000002
|
27
28
|
end
|
29
|
+
|
30
|
+
describe '#encrypt_data' do
|
31
|
+
it 'should be a 1-bit field per the SMB spec' do
|
32
|
+
expect(flags.encrypt_data).to be_a BinData::Bit1
|
33
|
+
end
|
34
|
+
|
35
|
+
it_behaves_like 'bit field with one flag set', :encrypt_data, 'v', 0x00000004
|
36
|
+
end
|
28
37
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
RSpec.describe RubySMB::SMB2::BitField::ShareFlags do
|
2
2
|
subject(:flags) { described_class.new }
|
3
3
|
|
4
|
+
it { is_expected.to respond_to :vdo_caching }
|
5
|
+
it { is_expected.to respond_to :auto_caching }
|
4
6
|
it { is_expected.to respond_to :dfs_root }
|
5
7
|
it { is_expected.to respond_to :dfs }
|
6
8
|
it { is_expected.to respond_to :encrypt }
|
@@ -11,11 +13,28 @@ RSpec.describe RubySMB::SMB2::BitField::ShareFlags do
|
|
11
13
|
it { is_expected.to respond_to :namespace_caching }
|
12
14
|
it { is_expected.to respond_to :shared_delete }
|
13
15
|
it { is_expected.to respond_to :restrict_exclusive_opens }
|
16
|
+
it { is_expected.to respond_to :identity_remoting }
|
14
17
|
|
15
18
|
it 'is little endian' do
|
16
19
|
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
17
20
|
end
|
18
21
|
|
22
|
+
describe '#vdo_caching' do
|
23
|
+
it 'should be a 1-bit field per the SMB spec' do
|
24
|
+
expect(flags.vdo_caching).to be_a BinData::Bit1
|
25
|
+
end
|
26
|
+
|
27
|
+
it_behaves_like 'bit field with one flag set', :vdo_caching, 'V', 0x00000020
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#auto_caching' do
|
31
|
+
it 'should be a 1-bit field per the SMB spec' do
|
32
|
+
expect(flags.auto_caching).to be_a BinData::Bit1
|
33
|
+
end
|
34
|
+
|
35
|
+
it_behaves_like 'bit field with one flag set', :auto_caching, 'V', 0x00000010
|
36
|
+
end
|
37
|
+
|
19
38
|
describe '#dfs' do
|
20
39
|
it 'should be a 1-bit field per the SMB spec' do
|
21
40
|
expect(flags.dfs).to be_a BinData::Bit1
|
@@ -96,6 +115,14 @@ RSpec.describe RubySMB::SMB2::BitField::ShareFlags do
|
|
96
115
|
it_behaves_like 'bit field with one flag set', :encrypt, 'V', 0x00008000
|
97
116
|
end
|
98
117
|
|
118
|
+
describe '#identity_remoting' do
|
119
|
+
it 'should be a 1-bit field per the SMB spec' do
|
120
|
+
expect(flags.identity_remoting).to be_a BinData::Bit1
|
121
|
+
end
|
122
|
+
|
123
|
+
it_behaves_like 'bit field with one flag set', :identity_remoting, 'V', 0x00040000
|
124
|
+
end
|
125
|
+
|
99
126
|
describe '#set_manual_caching' do
|
100
127
|
it 'turns off the caching bits' do
|
101
128
|
flags.set_manual_caching
|
@@ -43,6 +43,7 @@ RSpec.describe RubySMB::SMB2::File do
|
|
43
43
|
it { is_expected.to respond_to :size }
|
44
44
|
it { is_expected.to respond_to :size_on_disk }
|
45
45
|
it { is_expected.to respond_to :tree }
|
46
|
+
it { is_expected.to respond_to :tree_connect_encrypt_data }
|
46
47
|
|
47
48
|
it 'pulls the attributes from the response packet' do
|
48
49
|
expect(file.attributes).to eq create_response.file_attributes
|
@@ -52,10 +53,18 @@ RSpec.describe RubySMB::SMB2::File do
|
|
52
53
|
expect(file.guid).to eq create_response.file_id
|
53
54
|
end
|
54
55
|
|
55
|
-
it 'pulls the timestamps from the response packet' do
|
56
|
+
it 'pulls the last access timestamps from the response packet' do
|
56
57
|
expect(file.last_access).to eq create_response.last_access.to_datetime
|
57
58
|
end
|
58
59
|
|
60
|
+
it 'pulls the last change timestamps from the response packet' do
|
61
|
+
expect(file.last_change).to eq create_response.last_change.to_datetime
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'pulls the last write timestamps from the response packet' do
|
65
|
+
expect(file.last_write).to eq create_response.last_write.to_datetime
|
66
|
+
end
|
67
|
+
|
59
68
|
it 'pulls the size from the response packet' do
|
60
69
|
expect(file.size).to eq create_response.end_of_file
|
61
70
|
end
|
@@ -64,6 +73,10 @@ RSpec.describe RubySMB::SMB2::File do
|
|
64
73
|
expect(file.size_on_disk).to eq create_response.allocation_size
|
65
74
|
end
|
66
75
|
|
76
|
+
it 'sets the tree_connect_encrypt_data flag to false by default' do
|
77
|
+
expect(file.tree_connect_encrypt_data).to be false
|
78
|
+
end
|
79
|
+
|
67
80
|
describe '#set_header_fields' do
|
68
81
|
let(:request) { RubySMB::SMB2::Packet::ReadRequest.new }
|
69
82
|
it 'calls the set_header_field method from the Tree' do
|
@@ -94,6 +107,10 @@ RSpec.describe RubySMB::SMB2::File do
|
|
94
107
|
it 'sets the offset of the packet' do
|
95
108
|
expect(file.read_packet(offset: 55).offset).to eq 55
|
96
109
|
end
|
110
|
+
|
111
|
+
it 'sets the credit_charge of the packet' do
|
112
|
+
expect(file.read_packet(credit_charge: 3).smb2_header.credit_charge).to eq 3
|
113
|
+
end
|
97
114
|
end
|
98
115
|
|
99
116
|
describe '#read' do
|
@@ -112,12 +129,18 @@ RSpec.describe RubySMB::SMB2::File do
|
|
112
129
|
end
|
113
130
|
|
114
131
|
it 'uses a single packet to read the entire file' do
|
115
|
-
expect(file).to receive(:read_packet).with(read_length: 108, offset: 0).and_return(small_read)
|
116
|
-
expect(client).to receive(:send_recv).with(small_read).and_return 'fake data'
|
132
|
+
expect(file).to receive(:read_packet).with(read_length: 108, offset: 0, credit_charge: 0).and_return(small_read)
|
133
|
+
expect(client).to receive(:send_recv).with(small_read, encrypt: false).and_return 'fake data'
|
117
134
|
expect(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).with('fake data').and_return(small_response)
|
118
135
|
expect(file.read).to eq 'fake data'
|
119
136
|
end
|
120
137
|
|
138
|
+
it 'calls Client #send_recv with encryption set if required' do
|
139
|
+
file.tree_connect_encrypt_data = true
|
140
|
+
expect(client).to receive(:send_recv).with(small_read, encrypt: true)
|
141
|
+
file.read
|
142
|
+
end
|
143
|
+
|
121
144
|
context 'when the response is not valid' do
|
122
145
|
it 'raise an InvalidPacket exception' do
|
123
146
|
small_response.smb2_header.command = RubySMB::SMB2::Commands::LOGOFF
|
@@ -142,22 +165,31 @@ RSpec.describe RubySMB::SMB2::File do
|
|
142
165
|
}
|
143
166
|
|
144
167
|
before :example do
|
168
|
+
client.server_supports_multi_credit = 1
|
145
169
|
allow(file).to receive(:read_packet)
|
146
170
|
allow(client).to receive(:send_recv)
|
147
171
|
allow(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).and_return(big_response)
|
148
172
|
end
|
149
173
|
|
150
|
-
it 'uses
|
151
|
-
expect(file).to receive(:read_packet).once.with(read_length: described_class::MAX_PACKET_SIZE, offset: 0).and_return(big_read)
|
152
|
-
expect(file).to receive(:read_packet).once.with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE).and_return(big_read)
|
174
|
+
it 'uses multiple packets to read the file in chunks' do
|
175
|
+
expect(file).to receive(:read_packet).once.with(read_length: described_class::MAX_PACKET_SIZE, offset: 0, credit_charge: 1).and_return(big_read)
|
176
|
+
expect(file).to receive(:read_packet).once.with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE, credit_charge: 1).and_return(big_read)
|
153
177
|
expect(client).to receive(:send_recv).twice.and_return 'fake data'
|
154
178
|
expect(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).twice.with('fake data').and_return(big_response)
|
155
179
|
file.read(bytes: (described_class::MAX_PACKET_SIZE * 2))
|
156
180
|
end
|
157
181
|
|
182
|
+
it 'calls Client #send_recv with encryption set if required' do
|
183
|
+
read_request = double('Read Request')
|
184
|
+
allow(file).to receive(:read_packet).and_return(read_request)
|
185
|
+
file.tree_connect_encrypt_data = true
|
186
|
+
expect(client).to receive(:send_recv).twice.with(read_request, encrypt: true)
|
187
|
+
file.read(bytes: (described_class::MAX_PACKET_SIZE * 2))
|
188
|
+
end
|
189
|
+
|
158
190
|
context 'when the second response is not valid' do
|
159
191
|
it 'raise an InvalidPacket exception' do
|
160
|
-
allow(file).to receive(:read_packet).with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE) do
|
192
|
+
allow(file).to receive(:read_packet).with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE, credit_charge: 1) do
|
161
193
|
big_response.smb2_header.command = RubySMB::SMB2::Commands::LOGOFF
|
162
194
|
end
|
163
195
|
expect { file.read(bytes: (described_class::MAX_PACKET_SIZE * 2)) }.to raise_error(RubySMB::Error::InvalidPacket)
|
@@ -166,12 +198,31 @@ RSpec.describe RubySMB::SMB2::File do
|
|
166
198
|
|
167
199
|
context 'when the second response status code is not STATUS_SUCCESS' do
|
168
200
|
it 'raise an UnexpectedStatusCode exception' do
|
169
|
-
allow(file).to receive(:read_packet).with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE) do
|
201
|
+
allow(file).to receive(:read_packet).with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE, credit_charge: 1) do
|
170
202
|
big_response.smb2_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_HANDLE.value
|
171
203
|
end
|
172
204
|
expect { file.read(bytes: (described_class::MAX_PACKET_SIZE * 2)) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
173
205
|
end
|
174
206
|
end
|
207
|
+
|
208
|
+
context 'when the server does not support multi credits' do
|
209
|
+
it 'reads 65536 bytes at a time with no credit charge' do
|
210
|
+
client.server_supports_multi_credit = false
|
211
|
+
expect(file).to receive(:read_packet).once.with(read_length: 65536, offset: 0, credit_charge: 0).and_return(big_read)
|
212
|
+
expect(file).to receive(:read_packet).once.with(read_length: 65536, offset: 65536, credit_charge: 0).and_return(big_read)
|
213
|
+
file.read(bytes: (described_class::MAX_PACKET_SIZE * 4))
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
context 'when the server supports multi credits' do
|
218
|
+
it 'reads a number of bytes equal to #server_max_read_size, with the expected credit charge' do
|
219
|
+
credit_charge = (90000 - 1) / 65536 + 1
|
220
|
+
client.server_max_read_size = 90000
|
221
|
+
expect(file).to receive(:read_packet).once.with(read_length: 90000, offset: 0, credit_charge: credit_charge).and_return(big_read)
|
222
|
+
expect(file).to receive(:read_packet).once.with(read_length: (described_class::MAX_PACKET_SIZE * 4 - 90000), offset: 90000, credit_charge: credit_charge).and_return(big_read)
|
223
|
+
file.read(bytes: (described_class::MAX_PACKET_SIZE * 4))
|
224
|
+
end
|
225
|
+
end
|
175
226
|
end
|
176
227
|
end
|
177
228
|
|
@@ -195,6 +246,10 @@ RSpec.describe RubySMB::SMB2::File do
|
|
195
246
|
it 'sets the buffer on the packet' do
|
196
247
|
expect(file.write_packet(data:'hello').buffer).to eq 'hello'
|
197
248
|
end
|
249
|
+
|
250
|
+
it 'sets the credit_charge on the packet header' do
|
251
|
+
expect(file.write_packet(credit_charge: 5).smb2_header.credit_charge).to eq 5
|
252
|
+
end
|
198
253
|
end
|
199
254
|
|
200
255
|
describe '#write' do
|
@@ -204,13 +259,55 @@ RSpec.describe RubySMB::SMB2::File do
|
|
204
259
|
expect(client).to receive(:send_recv).once.and_return(write_response.to_binary_s)
|
205
260
|
file.write(data: 'test')
|
206
261
|
end
|
262
|
+
|
263
|
+
it 'calls Client #send_recv with encryption set if required' do
|
264
|
+
write_request = double('Write Request')
|
265
|
+
allow(file).to receive(:write_packet).and_return(write_request)
|
266
|
+
file.tree_connect_encrypt_data = true
|
267
|
+
expect(client).to receive(:send_recv).once.with(write_request, encrypt: true).and_return(write_response.to_binary_s)
|
268
|
+
file.write(data: 'test')
|
269
|
+
end
|
207
270
|
end
|
208
271
|
|
209
272
|
context 'for a large write' do
|
273
|
+
before :example do
|
274
|
+
allow(client).to receive(:send_recv).and_return(write_response.to_binary_s)
|
275
|
+
client.server_supports_multi_credit = 1
|
276
|
+
end
|
277
|
+
|
210
278
|
it 'sends multiple packets' do
|
211
279
|
expect(client).to receive(:send_recv).twice.and_return(write_response.to_binary_s)
|
212
280
|
file.write(data: SecureRandom.random_bytes(described_class::MAX_PACKET_SIZE + 1))
|
213
281
|
end
|
282
|
+
|
283
|
+
it 'calls Client #send_recv with encryption set if required' do
|
284
|
+
write_request = double('Write Request')
|
285
|
+
allow(file).to receive(:write_packet).and_return(write_request)
|
286
|
+
file.tree_connect_encrypt_data = true
|
287
|
+
expect(client).to receive(:send_recv).twice.with(write_request, encrypt: true).and_return(write_response.to_binary_s)
|
288
|
+
file.write(data: SecureRandom.random_bytes(described_class::MAX_PACKET_SIZE + 1))
|
289
|
+
end
|
290
|
+
|
291
|
+
context 'when the server does not support multi credits' do
|
292
|
+
it 'writes 65536 bytes at a time with no credit charge' do
|
293
|
+
client.server_supports_multi_credit = false
|
294
|
+
data = SecureRandom.random_bytes(65536 * 2)
|
295
|
+
expect(file).to receive(:write_packet).once.with(data: data[0, 65536], offset: 0, credit_charge: 0)
|
296
|
+
expect(file).to receive(:write_packet).once.with(data: data[65536, (data.size - 65536)], offset: 65536, credit_charge: 0)
|
297
|
+
file.write(data: data)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
context 'when the server supports multi credits' do
|
302
|
+
it 'reads a number of bytes equal to #server_max_write_size, with the expected credit charge' do
|
303
|
+
data = SecureRandom.random_bytes(90000 * 2)
|
304
|
+
credit_charge = (90000 - 1) / 65536 + 1
|
305
|
+
client.server_max_write_size = 90000
|
306
|
+
expect(file).to receive(:write_packet).once.with(data: data[0, 90000], offset: 0, credit_charge: credit_charge)
|
307
|
+
expect(file).to receive(:write_packet).once.with(data: data[90000, (data.size - 90000)], offset: 90000, credit_charge: credit_charge)
|
308
|
+
file.write(data: data)
|
309
|
+
end
|
310
|
+
end
|
214
311
|
end
|
215
312
|
|
216
313
|
it 'raises an InvalidPacket exception if the response is not valid' do
|
@@ -248,7 +345,7 @@ RSpec.describe RubySMB::SMB2::File do
|
|
248
345
|
|
249
346
|
it 'uses a single packet to delete the entire file' do
|
250
347
|
expect(file).to receive(:delete_packet).and_return(small_delete)
|
251
|
-
expect(client).to receive(:send_recv).with(small_delete).and_return 'raw_response'
|
348
|
+
expect(client).to receive(:send_recv).with(small_delete, encrypt: false).and_return 'raw_response'
|
252
349
|
expect(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).with('raw_response').and_return(small_response)
|
253
350
|
expect(file.delete).to eq WindowsError::NTStatus::STATUS_SUCCESS
|
254
351
|
end
|
@@ -260,6 +357,14 @@ RSpec.describe RubySMB::SMB2::File do
|
|
260
357
|
allow(small_response).to receive(:valid?).and_return(false)
|
261
358
|
expect { file.delete }.to raise_error(RubySMB::Error::InvalidPacket)
|
262
359
|
end
|
360
|
+
|
361
|
+
it 'calls Client #send_recv with encryption set if required' do
|
362
|
+
allow(file).to receive(:delete_packet)
|
363
|
+
allow(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).and_return(small_response)
|
364
|
+
file.tree_connect_encrypt_data = true
|
365
|
+
expect(client).to receive(:send_recv).with(small_delete, encrypt: true)
|
366
|
+
file.delete
|
367
|
+
end
|
263
368
|
end
|
264
369
|
end
|
265
370
|
|
@@ -291,11 +396,18 @@ RSpec.describe RubySMB::SMB2::File do
|
|
291
396
|
|
292
397
|
it 'uses a single packet to rename the entire file' do
|
293
398
|
expect(file).to receive(:rename_packet).and_return(small_rename)
|
294
|
-
expect(client).to receive(:send_recv).with(small_rename).and_return 'raw_response'
|
399
|
+
expect(client).to receive(:send_recv).with(small_rename, encrypt: false).and_return 'raw_response'
|
295
400
|
expect(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).with('raw_response').and_return(small_response)
|
296
401
|
expect(file.rename('new_file.txt')).to eq WindowsError::NTStatus::STATUS_SUCCESS
|
297
402
|
end
|
298
403
|
|
404
|
+
it 'calls Client #send_recv with encryption set if required' do
|
405
|
+
allow(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).and_return(small_response)
|
406
|
+
file.tree_connect_encrypt_data = true
|
407
|
+
expect(client).to receive(:send_recv).with(small_rename, encrypt: true)
|
408
|
+
file.rename('new_file.txt')
|
409
|
+
end
|
410
|
+
|
299
411
|
it 'raises an InvalidPacket exception if the response is not valid' do
|
300
412
|
allow(client).to receive(:send_recv)
|
301
413
|
allow(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).and_return(small_response)
|
@@ -330,7 +442,13 @@ RSpec.describe RubySMB::SMB2::File do
|
|
330
442
|
end
|
331
443
|
|
332
444
|
it 'calls Client #send_recv with the expected request' do
|
333
|
-
expect(client).to receive(:send_recv).with(request)
|
445
|
+
expect(client).to receive(:send_recv).with(request, encrypt: false)
|
446
|
+
file.close
|
447
|
+
end
|
448
|
+
|
449
|
+
it 'calls Client #send_recv with encryption set if required' do
|
450
|
+
file.tree_connect_encrypt_data = true
|
451
|
+
expect(client).to receive(:send_recv).with(request, encrypt: true)
|
334
452
|
file.close
|
335
453
|
end
|
336
454
|
|
@@ -341,9 +459,7 @@ RSpec.describe RubySMB::SMB2::File do
|
|
341
459
|
|
342
460
|
it 'raises an InvalidPacket exception if the response is not valid' do
|
343
461
|
allow(response).to receive(:valid?).and_return(false)
|
344
|
-
|
345
|
-
allow(response).to receive(:smb2_header).and_return(smb2_header)
|
346
|
-
allow(smb2_header).to receive_messages(:protocol => nil, :command => nil)
|
462
|
+
allow(response).to receive(:packet_smb_version)
|
347
463
|
expect { file.close }.to raise_error(RubySMB::Error::InvalidPacket)
|
348
464
|
end
|
349
465
|
|
@@ -394,7 +510,15 @@ RSpec.describe RubySMB::SMB2::File do
|
|
394
510
|
it 'calls Client #send_recv with the expected request' do
|
395
511
|
request = double('Request')
|
396
512
|
allow(file).to receive(:read_packet).and_return(request)
|
397
|
-
expect(client).to receive(:send_recv).with(request)
|
513
|
+
expect(client).to receive(:send_recv).with(request, encrypt: false)
|
514
|
+
file.send_recv_read
|
515
|
+
end
|
516
|
+
|
517
|
+
it 'calls Client #send_recv with encryption set if required' do
|
518
|
+
request = double('Request')
|
519
|
+
allow(file).to receive(:read_packet).and_return(request)
|
520
|
+
file.tree_connect_encrypt_data = true
|
521
|
+
expect(client).to receive(:send_recv).with(request, encrypt: true)
|
398
522
|
file.send_recv_read
|
399
523
|
end
|
400
524
|
|
@@ -408,33 +532,6 @@ RSpec.describe RubySMB::SMB2::File do
|
|
408
532
|
expect { file.send_recv_read }.to raise_error(RubySMB::Error::InvalidPacket)
|
409
533
|
end
|
410
534
|
|
411
|
-
context 'when the response status code is STATUS_PENDING' do
|
412
|
-
before :example do
|
413
|
-
allow(file).to receive(:sleep)
|
414
|
-
allow(read_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_PENDING)
|
415
|
-
allow(dispatcher).to receive(:recv_packet).and_return(raw_response)
|
416
|
-
end
|
417
|
-
|
418
|
-
it 'wait 1 second and calls Client dispatcher #recv_packet method one more time' do
|
419
|
-
expect(file).to receive(:sleep).with(1)
|
420
|
-
expect(dispatcher).to receive(:recv_packet)
|
421
|
-
file.send_recv_read
|
422
|
-
end
|
423
|
-
|
424
|
-
it 'parses the response as a SMB2 ReadResponse packet' do
|
425
|
-
expect(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).twice.with(raw_response)
|
426
|
-
file.send_recv_read
|
427
|
-
end
|
428
|
-
|
429
|
-
it 'raises an InvalidPacket exception if the response is not valid' do
|
430
|
-
allow(dispatcher).to receive(:recv_packet) do
|
431
|
-
allow(read_response).to receive(:valid?).and_return(false)
|
432
|
-
raw_response
|
433
|
-
end
|
434
|
-
expect { file.send_recv_read }.to raise_error(RubySMB::Error::InvalidPacket)
|
435
|
-
end
|
436
|
-
end
|
437
|
-
|
438
535
|
it 'raises an UnexpectedStatusCode exception if the response status code is not STATUS_SUCCESS' do
|
439
536
|
allow(read_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_OBJECT_NAME_NOT_FOUND)
|
440
537
|
expect { file.send_recv_read }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
@@ -457,7 +554,7 @@ RSpec.describe RubySMB::SMB2::File do
|
|
457
554
|
|
458
555
|
before :example do
|
459
556
|
allow(file).to receive(:write_packet).and_return(request)
|
460
|
-
allow(client).to receive(:send_recv).and_return(raw_response)
|
557
|
+
allow(client).to receive(:send_recv).and_return(raw_response, encrypt: false)
|
461
558
|
allow(RubySMB::SMB2::Packet::WriteResponse).to receive(:read).with(raw_response).and_return(write_response)
|
462
559
|
end
|
463
560
|
|
@@ -478,40 +575,19 @@ RSpec.describe RubySMB::SMB2::File do
|
|
478
575
|
end
|
479
576
|
|
480
577
|
it 'calls Client #send_recv with the expected request' do
|
481
|
-
expect(client).to receive(:send_recv).with(request)
|
578
|
+
expect(client).to receive(:send_recv).with(request, encrypt: false)
|
482
579
|
file.send_recv_write
|
483
580
|
end
|
484
581
|
|
485
|
-
it '
|
486
|
-
|
582
|
+
it 'calls Client #send_recv with encryption set if required' do
|
583
|
+
file.tree_connect_encrypt_data = true
|
584
|
+
expect(client).to receive(:send_recv).with(request, encrypt: true)
|
487
585
|
file.send_recv_write
|
488
586
|
end
|
489
587
|
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
allow(write_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_PENDING)
|
494
|
-
allow(dispatcher).to receive(:recv_packet).and_return(raw_response)
|
495
|
-
end
|
496
|
-
|
497
|
-
it 'wait 1 second and calls Client dispatcher #recv_packet method one more time' do
|
498
|
-
expect(file).to receive(:sleep).with(1)
|
499
|
-
expect(dispatcher).to receive(:recv_packet)
|
500
|
-
file.send_recv_write
|
501
|
-
end
|
502
|
-
|
503
|
-
it 'parses the response as a SMB2 WriteResponse packet' do
|
504
|
-
expect(RubySMB::SMB2::Packet::WriteResponse).to receive(:read).twice.with(raw_response)
|
505
|
-
file.send_recv_write
|
506
|
-
end
|
507
|
-
|
508
|
-
it 'raises an InvalidPacket exception if the response is not valid' do
|
509
|
-
allow(dispatcher).to receive(:recv_packet) do
|
510
|
-
allow(write_response).to receive(:valid?).and_return(false)
|
511
|
-
raw_response
|
512
|
-
end
|
513
|
-
expect { file.send_recv_write }.to raise_error(RubySMB::Error::InvalidPacket)
|
514
|
-
end
|
588
|
+
it 'parses the response as a SMB1 WriteResponse packet' do
|
589
|
+
expect(RubySMB::SMB2::Packet::WriteResponse).to receive(:read).with(raw_response)
|
590
|
+
file.send_recv_write
|
515
591
|
end
|
516
592
|
|
517
593
|
it 'raises an InvalidPacket exception if the response is not valid' do
|