ruby_smb 1.1.0 → 2.0.4
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.
- 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
|