ruby_smb 1.0.2 → 2.0.0
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 -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 +200 -20
- 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 +160 -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 +5 -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 +41 -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 +51 -4
- 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 +1563 -104
- 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 +3 -1
- 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 :encryption_required }
|
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 encryption_required flag to false by default' do
|
77
|
+
expect(file.encryption_required).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.encryption_required = 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.encryption_required = 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.encryption_required = 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.encryption_required = 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.encryption_required = 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.encryption_required = 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.encryption_required = 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.encryption_required = 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.encryption_required = 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
|