ruby_smb 1.0.3 → 2.0.1
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 -2
- data/Gemfile +6 -2
- data/README.md +35 -47
- data/examples/enum_registry_key.rb +28 -0
- data/examples/enum_registry_values.rb +30 -0
- data/examples/negotiate.rb +51 -8
- data/examples/pipes.rb +2 -1
- data/examples/read_file_encryption.rb +56 -0
- data/examples/read_registry_key_value.rb +32 -0
- data/lib/ruby_smb.rb +4 -1
- data/lib/ruby_smb/client.rb +233 -22
- data/lib/ruby_smb/client/authentication.rb +70 -33
- data/lib/ruby_smb/client/echo.rb +20 -2
- data/lib/ruby_smb/client/encryption.rb +62 -0
- data/lib/ruby_smb/client/negotiation.rb +172 -24
- data/lib/ruby_smb/client/signing.rb +19 -0
- data/lib/ruby_smb/client/tree_connect.rb +24 -18
- data/lib/ruby_smb/client/utils.rb +8 -7
- data/lib/ruby_smb/client/winreg.rb +46 -0
- data/lib/ruby_smb/crypto.rb +30 -0
- data/lib/ruby_smb/dcerpc.rb +38 -0
- data/lib/ruby_smb/dcerpc/bind.rb +2 -2
- data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
- data/lib/ruby_smb/dcerpc/error.rb +3 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +95 -16
- data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
- data/lib/ruby_smb/dcerpc/request.rb +28 -9
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +35 -0
- data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
- data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +340 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
- data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
- data/lib/ruby_smb/dispatcher/socket.rb +4 -3
- data/lib/ruby_smb/error.rb +68 -2
- data/lib/ruby_smb/generic_packet.rb +33 -4
- data/lib/ruby_smb/smb1/commands.rb +1 -1
- data/lib/ruby_smb/smb1/file.rb +66 -15
- data/lib/ruby_smb/smb1/packet/close_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/empty_packet.rb +10 -1
- data/lib/ruby_smb/smb1/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/negotiate_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/negotiate_response.rb +3 -7
- data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +4 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/read_andx_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/read_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_request.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/trans/request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +13 -3
- data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +3 -6
- data/lib/ruby_smb/smb1/packet/write_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/pipe.rb +87 -6
- data/lib/ruby_smb/smb1/tree.rb +50 -3
- 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 +103 -25
- 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/close_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
- data/lib/ruby_smb/smb2/packet/create_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/create_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/error_packet.rb +15 -3
- data/lib/ruby_smb/smb2/packet/ioctl_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/ioctl_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -17
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +52 -5
- data/lib/ruby_smb/smb2/packet/query_directory_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/query_directory_response.rb +8 -2
- data/lib/ruby_smb/smb2/packet/read_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/read_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/set_info_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/set_info_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +93 -10
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +10 -22
- data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/write_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/write_response.rb +2 -1
- data/lib/ruby_smb/smb2/pipe.rb +86 -12
- data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
- data/lib/ruby_smb/smb2/tree.rb +65 -21
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +5 -3
- data/spec/lib/ruby_smb/client_spec.rb +1612 -108
- data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
- data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +410 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +98 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +108 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +90 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +39 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +150 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +710 -0
- data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +2 -2
- data/spec/lib/ruby_smb/error_spec.rb +59 -0
- data/spec/lib/ruby_smb/generic_packet_spec.rb +52 -4
- data/spec/lib/ruby_smb/smb1/file_spec.rb +191 -2
- data/spec/lib/ruby_smb/smb1/packet/empty_packet_spec.rb +68 -0
- 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/packet/trans2/find_first2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +40 -0
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +272 -149
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +44 -7
- 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 +323 -6
- 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/error_packet_spec.rb +78 -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/query_directory_response_spec.rb +8 -0
- 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 -22
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +286 -149
- data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +261 -2
- metadata +191 -83
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/dcerpc.rb +0 -67
- data/lib/ruby_smb/smb2/dcerpc.rb +0 -70
- data/spec/lib/ruby_smb/smb1/packet/error_packet_spec.rb +0 -37
@@ -46,25 +46,34 @@ RSpec.describe RubySMB::SMB1::Tree do
|
|
46
46
|
end
|
47
47
|
|
48
48
|
describe '#disconnect!' do
|
49
|
-
|
49
|
+
let(:disco_response) { double('Response') }
|
50
|
+
|
51
|
+
before :example do
|
50
52
|
allow(RubySMB::SMB1::Packet::TreeDisconnectRequest).to receive(:new).and_return(disco_req)
|
51
|
-
allow(
|
53
|
+
allow(RubySMB::SMB1::Packet::TreeDisconnectResponse).to receive(:read).and_return(disco_resp)
|
54
|
+
allow(client).to receive(:send_recv)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'calls #set_header_fields' do
|
52
58
|
expect(tree).to receive(:set_header_fields).with(disco_req)
|
53
59
|
tree.disconnect!
|
54
60
|
end
|
55
61
|
|
56
62
|
it 'sends a TreeDisconnectRequest with the Tree ID in the header' do
|
57
|
-
allow(RubySMB::SMB1::Packet::TreeDisconnectRequest).to receive(:new).and_return(disco_req)
|
58
63
|
modified_req = disco_req
|
59
64
|
modified_req.smb_header.tid = tree.id
|
60
|
-
expect(client).to receive(:send_recv).with(modified_req)
|
65
|
+
expect(client).to receive(:send_recv).with(modified_req)
|
61
66
|
tree.disconnect!
|
62
67
|
end
|
63
68
|
|
64
69
|
it 'returns the NTStatus code from the response' do
|
65
|
-
allow(client).to receive(:send_recv).and_return(disco_resp.to_binary_s)
|
66
70
|
expect(tree.disconnect!).to eq disco_resp.status_code
|
67
71
|
end
|
72
|
+
|
73
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
74
|
+
allow(disco_resp).to receive(:valid?).and_return(false)
|
75
|
+
expect { tree.disconnect! }.to raise_error(RubySMB::Error::InvalidPacket)
|
76
|
+
end
|
68
77
|
end
|
69
78
|
|
70
79
|
describe '#open_file' do
|
@@ -239,14 +248,14 @@ RSpec.describe RubySMB::SMB1::Tree do
|
|
239
248
|
end
|
240
249
|
|
241
250
|
context 'when the response is not a NtCreateAndxResponse packet' do
|
242
|
-
it '
|
251
|
+
it 'raises an InvalidPacket exception' do
|
243
252
|
nt_create_andx_response.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_ECHO
|
244
253
|
expect { tree.open_file(filename: filename) }.to raise_error(RubySMB::Error::InvalidPacket)
|
245
254
|
end
|
246
255
|
end
|
247
256
|
|
248
257
|
context 'when the response status code is not STATUS_SUCCESS' do
|
249
|
-
it '
|
258
|
+
it 'raises an UnexpectedStatusCode exception' do
|
250
259
|
nt_create_andx_response.smb_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_HANDLE.value
|
251
260
|
expect { tree.open_file(filename: filename) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
252
261
|
end
|
@@ -342,6 +351,20 @@ RSpec.describe RubySMB::SMB1::Tree do
|
|
342
351
|
expect(tree.list).to eq([file_info1, file_info2])
|
343
352
|
end
|
344
353
|
|
354
|
+
context 'when the response is not a valid Trans2 FindFirst2Response' do
|
355
|
+
it 'raises an InvalidPacket exception' do
|
356
|
+
find_first2_res.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_ECHO
|
357
|
+
expect { tree.list }.to raise_error(RubySMB::Error::InvalidPacket)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
context 'when the response status code is not STATUS_SUCCESS' do
|
362
|
+
it 'raises an UnexpectedStatusCode exception' do
|
363
|
+
find_first2_res.smb_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_HANDLE.value
|
364
|
+
expect { tree.list }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
345
368
|
context 'when more requests are needed to get all the information' do
|
346
369
|
let(:find_next2_req) { RubySMB::SMB1::Packet::Trans2::FindNext2Request.new }
|
347
370
|
let(:file_info2) do
|
@@ -414,6 +437,20 @@ RSpec.describe RubySMB::SMB1::Tree do
|
|
414
437
|
it 'returns the expected FindFileFullDirectoryInfo structures' do
|
415
438
|
expect(tree.list).to eq([file_info1, file_info2])
|
416
439
|
end
|
440
|
+
|
441
|
+
context 'when the response is not a valid Trans2 FindNext2Response' do
|
442
|
+
it 'raises an InvalidPacket exception' do
|
443
|
+
find_next2_res.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_ECHO
|
444
|
+
expect { tree.list }.to raise_error(RubySMB::Error::InvalidPacket)
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
context 'when the response status code is not STATUS_SUCCESS' do
|
449
|
+
it 'raises an UnexpectedStatusCode exception' do
|
450
|
+
find_next2_res.smb_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_HANDLE.value
|
451
|
+
expect { tree.list }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
452
|
+
end
|
453
|
+
end
|
417
454
|
end
|
418
455
|
end
|
419
456
|
|
@@ -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
|
@@ -99,19 +112,59 @@ RSpec.describe RubySMB::SMB2::File do
|
|
99
112
|
describe '#read' do
|
100
113
|
context 'for a small file' do
|
101
114
|
let(:small_read) { file.read_packet(read_length: 108) }
|
102
|
-
let(:small_response) {
|
115
|
+
let(:small_response) {
|
116
|
+
response = RubySMB::SMB2::Packet::ReadResponse.new(data_length: 9, buffer: 'fake data')
|
117
|
+
response.smb2_header.command = RubySMB::SMB2::Commands::READ
|
118
|
+
response
|
119
|
+
}
|
120
|
+
|
121
|
+
before :example do
|
122
|
+
allow(file).to receive(:read_packet)
|
123
|
+
allow(client).to receive(:send_recv)
|
124
|
+
allow(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).and_return(small_response)
|
125
|
+
end
|
103
126
|
|
104
127
|
it 'uses a single packet to read the entire file' do
|
105
128
|
expect(file).to receive(:read_packet).with(read_length: 108, offset: 0).and_return(small_read)
|
106
|
-
expect(client).to receive(:send_recv).with(small_read).and_return 'fake data'
|
129
|
+
expect(client).to receive(:send_recv).with(small_read, encrypt: false).and_return 'fake data'
|
107
130
|
expect(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).with('fake data').and_return(small_response)
|
108
131
|
expect(file.read).to eq 'fake data'
|
109
132
|
end
|
133
|
+
|
134
|
+
it 'calls Client #send_recv with encryption set if required' do
|
135
|
+
file.tree_connect_encrypt_data = true
|
136
|
+
expect(client).to receive(:send_recv).with(small_read, encrypt: true)
|
137
|
+
file.read
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'when the response is not valid' do
|
141
|
+
it 'raise an InvalidPacket exception' do
|
142
|
+
small_response.smb2_header.command = RubySMB::SMB2::Commands::LOGOFF
|
143
|
+
expect { file.read }.to raise_error(RubySMB::Error::InvalidPacket)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'when the response status code is not STATUS_SUCCESS' do
|
148
|
+
it 'raise an UnexpectedStatusCode exception' do
|
149
|
+
small_response.smb2_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_HANDLE.value
|
150
|
+
expect { file.read }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
151
|
+
end
|
152
|
+
end
|
110
153
|
end
|
111
154
|
|
112
155
|
context 'for a larger file' do
|
113
156
|
let(:big_read) { file.read_packet(read_length: 108) }
|
114
|
-
let(:big_response) {
|
157
|
+
let(:big_response) {
|
158
|
+
response = RubySMB::SMB2::Packet::ReadResponse.new(data_length: 9, buffer: 'fake data')
|
159
|
+
response.smb2_header.command = RubySMB::SMB2::Commands::READ
|
160
|
+
response
|
161
|
+
}
|
162
|
+
|
163
|
+
before :example do
|
164
|
+
allow(file).to receive(:read_packet)
|
165
|
+
allow(client).to receive(:send_recv)
|
166
|
+
allow(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).and_return(big_response)
|
167
|
+
end
|
115
168
|
|
116
169
|
it 'uses a multiple packet to read the file in chunks' do
|
117
170
|
expect(file).to receive(:read_packet).once.with(read_length: described_class::MAX_PACKET_SIZE, offset: 0).and_return(big_read)
|
@@ -120,6 +173,32 @@ RSpec.describe RubySMB::SMB2::File do
|
|
120
173
|
expect(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).twice.with('fake data').and_return(big_response)
|
121
174
|
file.read(bytes: (described_class::MAX_PACKET_SIZE * 2))
|
122
175
|
end
|
176
|
+
|
177
|
+
it 'calls Client #send_recv with encryption set if required' do
|
178
|
+
read_request = double('Read Request')
|
179
|
+
allow(file).to receive(:read_packet).and_return(read_request)
|
180
|
+
file.tree_connect_encrypt_data = true
|
181
|
+
expect(client).to receive(:send_recv).twice.with(read_request, encrypt: true)
|
182
|
+
file.read(bytes: (described_class::MAX_PACKET_SIZE * 2))
|
183
|
+
end
|
184
|
+
|
185
|
+
context 'when the second response is not valid' do
|
186
|
+
it 'raise an InvalidPacket exception' do
|
187
|
+
allow(file).to receive(:read_packet).with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE) do
|
188
|
+
big_response.smb2_header.command = RubySMB::SMB2::Commands::LOGOFF
|
189
|
+
end
|
190
|
+
expect { file.read(bytes: (described_class::MAX_PACKET_SIZE * 2)) }.to raise_error(RubySMB::Error::InvalidPacket)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
context 'when the second response status code is not STATUS_SUCCESS' do
|
195
|
+
it 'raise an UnexpectedStatusCode exception' do
|
196
|
+
allow(file).to receive(:read_packet).with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE) do
|
197
|
+
big_response.smb2_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_HANDLE.value
|
198
|
+
end
|
199
|
+
expect { file.read(bytes: (described_class::MAX_PACKET_SIZE * 2)) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
200
|
+
end
|
201
|
+
end
|
123
202
|
end
|
124
203
|
end
|
125
204
|
|
@@ -152,6 +231,14 @@ RSpec.describe RubySMB::SMB2::File do
|
|
152
231
|
expect(client).to receive(:send_recv).once.and_return(write_response.to_binary_s)
|
153
232
|
file.write(data: 'test')
|
154
233
|
end
|
234
|
+
|
235
|
+
it 'calls Client #send_recv with encryption set if required' do
|
236
|
+
write_request = double('Write Request')
|
237
|
+
allow(file).to receive(:write_packet).and_return(write_request)
|
238
|
+
file.tree_connect_encrypt_data = true
|
239
|
+
expect(client).to receive(:send_recv).once.with(write_request, encrypt: true).and_return(write_response.to_binary_s)
|
240
|
+
file.write(data: 'test')
|
241
|
+
end
|
155
242
|
end
|
156
243
|
|
157
244
|
context 'for a large write' do
|
@@ -159,6 +246,21 @@ RSpec.describe RubySMB::SMB2::File do
|
|
159
246
|
expect(client).to receive(:send_recv).twice.and_return(write_response.to_binary_s)
|
160
247
|
file.write(data: SecureRandom.random_bytes(described_class::MAX_PACKET_SIZE + 1))
|
161
248
|
end
|
249
|
+
|
250
|
+
it 'calls Client #send_recv with encryption set if required' do
|
251
|
+
write_request = double('Write Request')
|
252
|
+
allow(file).to receive(:write_packet).and_return(write_request)
|
253
|
+
file.tree_connect_encrypt_data = true
|
254
|
+
expect(client).to receive(:send_recv).twice.with(write_request, encrypt: true).and_return(write_response.to_binary_s)
|
255
|
+
file.write(data: SecureRandom.random_bytes(described_class::MAX_PACKET_SIZE + 1))
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
260
|
+
allow(client).to receive(:send_recv)
|
261
|
+
allow(RubySMB::SMB2::Packet::WriteResponse).to receive(:read).and_return(write_response)
|
262
|
+
allow(write_response).to receive(:valid?).and_return(false)
|
263
|
+
expect { file.write(data: 'test') }.to raise_error(RubySMB::Error::InvalidPacket)
|
162
264
|
end
|
163
265
|
end
|
164
266
|
|
@@ -189,10 +291,26 @@ RSpec.describe RubySMB::SMB2::File do
|
|
189
291
|
|
190
292
|
it 'uses a single packet to delete the entire file' do
|
191
293
|
expect(file).to receive(:delete_packet).and_return(small_delete)
|
192
|
-
expect(client).to receive(:send_recv).with(small_delete).and_return 'raw_response'
|
294
|
+
expect(client).to receive(:send_recv).with(small_delete, encrypt: false).and_return 'raw_response'
|
193
295
|
expect(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).with('raw_response').and_return(small_response)
|
194
296
|
expect(file.delete).to eq WindowsError::NTStatus::STATUS_SUCCESS
|
195
297
|
end
|
298
|
+
|
299
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
300
|
+
allow(file).to receive(:delete_packet)
|
301
|
+
allow(client).to receive(:send_recv)
|
302
|
+
allow(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).and_return(small_response)
|
303
|
+
allow(small_response).to receive(:valid?).and_return(false)
|
304
|
+
expect { file.delete }.to raise_error(RubySMB::Error::InvalidPacket)
|
305
|
+
end
|
306
|
+
|
307
|
+
it 'calls Client #send_recv with encryption set if required' do
|
308
|
+
allow(file).to receive(:delete_packet)
|
309
|
+
allow(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).and_return(small_response)
|
310
|
+
file.tree_connect_encrypt_data = true
|
311
|
+
expect(client).to receive(:send_recv).with(small_delete, encrypt: true)
|
312
|
+
file.delete
|
313
|
+
end
|
196
314
|
end
|
197
315
|
end
|
198
316
|
|
@@ -224,10 +342,209 @@ RSpec.describe RubySMB::SMB2::File do
|
|
224
342
|
|
225
343
|
it 'uses a single packet to rename the entire file' do
|
226
344
|
expect(file).to receive(:rename_packet).and_return(small_rename)
|
227
|
-
expect(client).to receive(:send_recv).with(small_rename).and_return 'raw_response'
|
345
|
+
expect(client).to receive(:send_recv).with(small_rename, encrypt: false).and_return 'raw_response'
|
228
346
|
expect(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).with('raw_response').and_return(small_response)
|
229
347
|
expect(file.rename('new_file.txt')).to eq WindowsError::NTStatus::STATUS_SUCCESS
|
230
348
|
end
|
349
|
+
|
350
|
+
it 'calls Client #send_recv with encryption set if required' do
|
351
|
+
allow(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).and_return(small_response)
|
352
|
+
file.tree_connect_encrypt_data = true
|
353
|
+
expect(client).to receive(:send_recv).with(small_rename, encrypt: true)
|
354
|
+
file.rename('new_file.txt')
|
355
|
+
end
|
356
|
+
|
357
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
358
|
+
allow(client).to receive(:send_recv)
|
359
|
+
allow(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).and_return(small_response)
|
360
|
+
allow(small_response).to receive(:valid?).and_return(false)
|
361
|
+
expect { file.rename('new_file.txt') }.to raise_error(RubySMB::Error::InvalidPacket)
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
describe '#close' do
|
367
|
+
let(:request) { double('CloseRequest') }
|
368
|
+
let(:response) { double('CloseResponse') }
|
369
|
+
let(:raw_response) { double('Raw response') }
|
370
|
+
|
371
|
+
before :example do
|
372
|
+
allow(RubySMB::SMB2::Packet::CloseRequest).to receive(:new).and_return(request)
|
373
|
+
allow(file).to receive(:set_header_fields).and_return(request)
|
374
|
+
allow(client).to receive(:send_recv).and_return(raw_response)
|
375
|
+
allow(RubySMB::SMB2::Packet::CloseResponse).to receive(:read).and_return(response)
|
376
|
+
allow(response).to receive(:valid?).and_return(true)
|
377
|
+
allow(response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_SUCCESS)
|
378
|
+
end
|
379
|
+
|
380
|
+
it 'creates a new SMB2 CloseRequest packet' do
|
381
|
+
expect(RubySMB::SMB2::Packet::CloseRequest).to receive(:new)
|
382
|
+
file.close
|
383
|
+
end
|
384
|
+
|
385
|
+
it 'calls Tree #set_header_fields to set SetFileInformationRequest headers' do
|
386
|
+
expect(file).to receive(:set_header_fields).with(request)
|
387
|
+
file.close
|
388
|
+
end
|
389
|
+
|
390
|
+
it 'calls Client #send_recv with the expected request' do
|
391
|
+
expect(client).to receive(:send_recv).with(request, encrypt: false)
|
392
|
+
file.close
|
393
|
+
end
|
394
|
+
|
395
|
+
it 'calls Client #send_recv with encryption set if required' do
|
396
|
+
file.tree_connect_encrypt_data = true
|
397
|
+
expect(client).to receive(:send_recv).with(request, encrypt: true)
|
398
|
+
file.close
|
399
|
+
end
|
400
|
+
|
401
|
+
it 'parses the response as a SMB2 CloseResponse packet' do
|
402
|
+
expect(RubySMB::SMB2::Packet::CloseResponse).to receive(:read).with(raw_response)
|
403
|
+
file.close
|
404
|
+
end
|
405
|
+
|
406
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
407
|
+
allow(response).to receive(:valid?).and_return(false)
|
408
|
+
smb2_header = double('SMB2 Header')
|
409
|
+
allow(response).to receive(:smb2_header).and_return(smb2_header)
|
410
|
+
allow(smb2_header).to receive_messages(:protocol => nil, :command => nil)
|
411
|
+
expect { file.close }.to raise_error(RubySMB::Error::InvalidPacket)
|
412
|
+
end
|
413
|
+
|
414
|
+
it 'raises an UnexpectedStatusCode exception if the response status code is not STATUS_SUCCESS' do
|
415
|
+
allow(response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_OBJECT_NAME_NOT_FOUND)
|
416
|
+
expect { file.close }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
417
|
+
end
|
418
|
+
|
419
|
+
it 'returns the response status code' do
|
420
|
+
expect(file.close).to eq WindowsError::NTStatus::STATUS_SUCCESS
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
describe '#send_recv_read' do
|
425
|
+
let(:read_data) { 'read data' }
|
426
|
+
let(:raw_response) { double('fake raw response data') }
|
427
|
+
let(:read_response) {
|
428
|
+
res = RubySMB::SMB2::Packet::ReadResponse.new
|
429
|
+
res.data_length = read_data.size
|
430
|
+
res.buffer = read_data
|
431
|
+
res
|
432
|
+
}
|
433
|
+
|
434
|
+
before :example do
|
435
|
+
allow(client).to receive(:send_recv).and_return(raw_response)
|
436
|
+
allow(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).with(raw_response).and_return(read_response)
|
437
|
+
end
|
438
|
+
|
439
|
+
context 'when the number of bytes to read is not provided' do
|
440
|
+
it 'reads 0 bytes by default' do
|
441
|
+
expect(file).to receive(:read_packet).with(read_length: 0, offset: 0).once.and_call_original
|
442
|
+
file.send_recv_read
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
it 'only reads the number of bytes provided as argument' do
|
447
|
+
bytes = 5
|
448
|
+
expect(file).to receive(:read_packet).with(read_length: bytes, offset: 0).once.and_call_original
|
449
|
+
file.send_recv_read(read_length: bytes)
|
450
|
+
end
|
451
|
+
|
452
|
+
it 'reads from the offset provided as argument' do
|
453
|
+
offset = 3
|
454
|
+
expect(file).to receive(:read_packet).with(read_length: 0, offset: offset).once.and_call_original
|
455
|
+
file.send_recv_read(offset: offset)
|
456
|
+
end
|
457
|
+
|
458
|
+
it 'calls Client #send_recv with the expected request' do
|
459
|
+
request = double('Request')
|
460
|
+
allow(file).to receive(:read_packet).and_return(request)
|
461
|
+
expect(client).to receive(:send_recv).with(request, encrypt: false)
|
462
|
+
file.send_recv_read
|
463
|
+
end
|
464
|
+
|
465
|
+
it 'calls Client #send_recv with encryption set if required' do
|
466
|
+
request = double('Request')
|
467
|
+
allow(file).to receive(:read_packet).and_return(request)
|
468
|
+
file.tree_connect_encrypt_data = true
|
469
|
+
expect(client).to receive(:send_recv).with(request, encrypt: true)
|
470
|
+
file.send_recv_read
|
471
|
+
end
|
472
|
+
|
473
|
+
it 'parses the response as a SMB2 ReadResponse packet' do
|
474
|
+
expect(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).with(raw_response)
|
475
|
+
file.send_recv_read
|
476
|
+
end
|
477
|
+
|
478
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
479
|
+
allow(read_response).to receive(:valid?).and_return(false)
|
480
|
+
expect { file.send_recv_read }.to raise_error(RubySMB::Error::InvalidPacket)
|
481
|
+
end
|
482
|
+
|
483
|
+
it 'raises an UnexpectedStatusCode exception if the response status code is not STATUS_SUCCESS' do
|
484
|
+
allow(read_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_OBJECT_NAME_NOT_FOUND)
|
485
|
+
expect { file.send_recv_read }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
486
|
+
end
|
487
|
+
|
488
|
+
it 'returns the expected string' do
|
489
|
+
expect(file.send_recv_read).to eq(read_data)
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
describe '#send_recv_write' do
|
494
|
+
let(:write_data) { 'write data' }
|
495
|
+
let(:request) { double('Request') }
|
496
|
+
let(:raw_response) { double('fake raw response data') }
|
497
|
+
let(:write_response) {
|
498
|
+
res = RubySMB::SMB2::Packet::WriteResponse.new
|
499
|
+
res.write_count = write_data.size
|
500
|
+
res
|
501
|
+
}
|
502
|
+
|
503
|
+
before :example do
|
504
|
+
allow(file).to receive(:write_packet).and_return(request)
|
505
|
+
allow(client).to receive(:send_recv).and_return(raw_response, encrypt: false)
|
506
|
+
allow(RubySMB::SMB2::Packet::WriteResponse).to receive(:read).with(raw_response).and_return(write_response)
|
507
|
+
end
|
508
|
+
|
509
|
+
it 'reads 0 bytes from offset 0 by default' do
|
510
|
+
expect(file).to receive(:write_packet).with(data: '', offset: 0).once.and_call_original
|
511
|
+
file.send_recv_write
|
512
|
+
end
|
513
|
+
|
514
|
+
it 'writes the data provided as argument' do
|
515
|
+
expect(file).to receive(:write_packet).with(data: write_data, offset: 0).once.and_call_original
|
516
|
+
file.send_recv_write(data: write_data)
|
517
|
+
end
|
518
|
+
|
519
|
+
it 'reads from the offset provided as argument' do
|
520
|
+
offset = 3
|
521
|
+
expect(file).to receive(:write_packet).with(data: '', offset: offset).once.and_call_original
|
522
|
+
file.send_recv_write(offset: offset)
|
523
|
+
end
|
524
|
+
|
525
|
+
it 'calls Client #send_recv with the expected request' do
|
526
|
+
expect(client).to receive(:send_recv).with(request, encrypt: false)
|
527
|
+
file.send_recv_write
|
528
|
+
end
|
529
|
+
|
530
|
+
it 'calls Client #send_recv with encryption set if required' do
|
531
|
+
file.tree_connect_encrypt_data = true
|
532
|
+
expect(client).to receive(:send_recv).with(request, encrypt: true)
|
533
|
+
file.send_recv_write
|
534
|
+
end
|
535
|
+
|
536
|
+
it 'parses the response as a SMB1 WriteResponse packet' do
|
537
|
+
expect(RubySMB::SMB2::Packet::WriteResponse).to receive(:read).with(raw_response)
|
538
|
+
file.send_recv_write
|
539
|
+
end
|
540
|
+
|
541
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
542
|
+
allow(write_response).to receive(:valid?).and_return(false)
|
543
|
+
expect { file.send_recv_write }.to raise_error(RubySMB::Error::InvalidPacket)
|
544
|
+
end
|
545
|
+
|
546
|
+
it 'returns the expected response #write_count value' do
|
547
|
+
expect(file.send_recv_write).to eq(write_data.size)
|
231
548
|
end
|
232
549
|
end
|
233
550
|
end
|