ruby_smb 1.0.3 → 1.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/ruby_smb/client.rb +26 -4
- data/lib/ruby_smb/client/authentication.rb +43 -25
- data/lib/ruby_smb/client/echo.rb +20 -2
- data/lib/ruby_smb/client/negotiation.rb +27 -12
- data/lib/ruby_smb/client/tree_connect.rb +20 -14
- data/lib/ruby_smb/error.rb +40 -1
- data/lib/ruby_smb/generic_packet.rb +33 -4
- data/lib/ruby_smb/smb1/dcerpc.rb +7 -2
- data/lib/ruby_smb/smb1/file.rb +60 -11
- 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 +7 -0
- 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 +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -1
- 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 +2 -5
- data/lib/ruby_smb/smb1/packet/write_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/pipe.rb +8 -3
- data/lib/ruby_smb/smb1/tree.rb +40 -2
- data/lib/ruby_smb/smb2/dcerpc.rb +7 -2
- data/lib/ruby_smb/smb2/file.rb +97 -1
- 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/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 +7 -0
- 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 +2 -5
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +2 -1
- 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/tree_connect_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -2
- 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 +9 -9
- data/lib/ruby_smb/smb2/tree.rb +44 -6
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +123 -11
- data/spec/lib/ruby_smb/generic_packet_spec.rb +52 -4
- data/spec/lib/ruby_smb/smb1/file_spec.rb +182 -1
- data/spec/lib/ruby_smb/smb1/packet/{error_packet_spec.rb → empty_packet_spec.rb} +21 -0
- 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 +63 -2
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +44 -7
- data/spec/lib/ruby_smb/smb2/file_spec.rb +295 -2
- data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +51 -0
- data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +8 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +8 -0
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +69 -3
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +214 -0
- metadata +6 -4
- metadata.gz.sig +0 -0
@@ -163,7 +163,7 @@ RSpec.describe RubySMB::SMB1::File do
|
|
163
163
|
end
|
164
164
|
|
165
165
|
context 'when sending the request packet and gets a response back' do
|
166
|
-
context 'when the response is not
|
166
|
+
context 'when the response is not valid' do
|
167
167
|
it 'raise an InvalidPacket exception' do
|
168
168
|
read_andx_response.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_ECHO
|
169
169
|
expect { file.read }.to raise_error(RubySMB::Error::InvalidPacket)
|
@@ -181,6 +181,7 @@ RSpec.describe RubySMB::SMB1::File do
|
|
181
181
|
let(:empty_packet) do
|
182
182
|
empty_packet = RubySMB::SMB1::Packet::EmptyPacket.new
|
183
183
|
empty_packet.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_READ_ANDX
|
184
|
+
empty_packet.original_command = RubySMB::SMB1::Commands::SMB_COM_READ_ANDX
|
184
185
|
empty_packet
|
185
186
|
end
|
186
187
|
|
@@ -345,6 +346,11 @@ RSpec.describe RubySMB::SMB1::File do
|
|
345
346
|
set_info_res.smb_header.nt_status = status.value
|
346
347
|
expect(file.delete).to eq status
|
347
348
|
end
|
349
|
+
|
350
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
351
|
+
allow(set_info_res).to receive(:valid?).and_return(false)
|
352
|
+
expect { file.delete }.to raise_error(RubySMB::Error::InvalidPacket)
|
353
|
+
end
|
348
354
|
end
|
349
355
|
|
350
356
|
describe '#delete_packet' do
|
@@ -415,6 +421,11 @@ RSpec.describe RubySMB::SMB1::File do
|
|
415
421
|
set_info_res.smb_header.nt_status = status.value
|
416
422
|
expect(file.rename(filename)).to eq status
|
417
423
|
end
|
424
|
+
|
425
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
426
|
+
allow(set_info_res).to receive(:valid?).and_return(false)
|
427
|
+
expect { file.rename(filename) }.to raise_error(RubySMB::Error::InvalidPacket)
|
428
|
+
end
|
418
429
|
end
|
419
430
|
|
420
431
|
describe '#rename_packet' do
|
@@ -465,5 +476,175 @@ RSpec.describe RubySMB::SMB1::File do
|
|
465
476
|
expect(parameter_block.max_data_count).to eq 16_384
|
466
477
|
end
|
467
478
|
end
|
479
|
+
|
480
|
+
describe '#close' do
|
481
|
+
let(:request) { double('CloseRequest') }
|
482
|
+
let(:response) { double('CloseResponse') }
|
483
|
+
let(:raw_response) { double('Raw response') }
|
484
|
+
|
485
|
+
before :example do
|
486
|
+
allow(RubySMB::SMB1::Packet::CloseRequest).to receive(:new).and_return(request)
|
487
|
+
allow(file).to receive(:set_header_fields).and_return(request)
|
488
|
+
allow(client).to receive(:send_recv).and_return(raw_response)
|
489
|
+
allow(RubySMB::SMB1::Packet::CloseResponse).to receive(:read).and_return(response)
|
490
|
+
allow(response).to receive(:valid?).and_return(true)
|
491
|
+
allow(response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_SUCCESS)
|
492
|
+
end
|
493
|
+
|
494
|
+
it 'creates a new SMB1 CloseRequest packet' do
|
495
|
+
expect(RubySMB::SMB1::Packet::CloseRequest).to receive(:new)
|
496
|
+
file.close
|
497
|
+
end
|
498
|
+
|
499
|
+
it 'calls Tree #set_header_fields to set SetFileInformationRequest headers' do
|
500
|
+
expect(file).to receive(:set_header_fields).with(request)
|
501
|
+
file.close
|
502
|
+
end
|
503
|
+
|
504
|
+
it 'calls Client #send_recv with the expected request' do
|
505
|
+
expect(client).to receive(:send_recv).with(request)
|
506
|
+
file.close
|
507
|
+
end
|
508
|
+
|
509
|
+
it 'parses the response as a SMB1 CloseResponse packet' do
|
510
|
+
expect(RubySMB::SMB1::Packet::CloseResponse).to receive(:read).with(raw_response)
|
511
|
+
file.close
|
512
|
+
end
|
513
|
+
|
514
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
515
|
+
allow(response).to receive(:valid?).and_return(false)
|
516
|
+
smb_header = double('SMB Header')
|
517
|
+
allow(response).to receive(:smb_header).and_return(smb_header)
|
518
|
+
allow(smb_header).to receive_messages(:protocol => nil, :command => nil)
|
519
|
+
expect { file.close }.to raise_error(RubySMB::Error::InvalidPacket)
|
520
|
+
end
|
521
|
+
|
522
|
+
it 'raises an UnexpectedStatusCode exception if the response status code is not STATUS_SUCCESS' do
|
523
|
+
allow(response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_OBJECT_NAME_NOT_FOUND)
|
524
|
+
expect { file.close }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
525
|
+
end
|
526
|
+
|
527
|
+
it 'returns the response status code' do
|
528
|
+
expect(file.close).to eq WindowsError::NTStatus::STATUS_SUCCESS
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
describe '#send_recv_read' do
|
533
|
+
let(:read_data) { 'read data' }
|
534
|
+
let(:raw_response) { double('fake raw response data') }
|
535
|
+
let(:read_andx_response) {
|
536
|
+
res = RubySMB::SMB1::Packet::ReadAndxResponse.new
|
537
|
+
res.data_block.data = read_data
|
538
|
+
res
|
539
|
+
}
|
540
|
+
|
541
|
+
before :example do
|
542
|
+
allow(client).to receive(:send_recv).and_return(raw_response)
|
543
|
+
allow(RubySMB::SMB1::Packet::ReadAndxResponse).to receive(:read).with(raw_response).and_return(read_andx_response)
|
544
|
+
end
|
545
|
+
|
546
|
+
context 'when the number of bytes to read is not provided' do
|
547
|
+
it 'reads 0 bytes by default' do
|
548
|
+
expect(file).to receive(:read_packet).with(read_length: 0, offset: 0).once.and_call_original
|
549
|
+
file.send_recv_read
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
it 'only reads the number of bytes provided as argument' do
|
554
|
+
bytes = 5
|
555
|
+
expect(file).to receive(:read_packet).with(read_length: bytes, offset: 0).once.and_call_original
|
556
|
+
file.send_recv_read(read_length: bytes)
|
557
|
+
end
|
558
|
+
|
559
|
+
it 'reads from the offset provided as argument' do
|
560
|
+
offset = 3
|
561
|
+
expect(file).to receive(:read_packet).with(read_length: 0, offset: offset).once.and_call_original
|
562
|
+
file.send_recv_read(offset: offset)
|
563
|
+
end
|
564
|
+
|
565
|
+
it 'calls Client #send_recv with the expected request' do
|
566
|
+
request = double('Request')
|
567
|
+
allow(file).to receive(:read_packet).and_return(request)
|
568
|
+
expect(client).to receive(:send_recv).with(request)
|
569
|
+
file.send_recv_read
|
570
|
+
end
|
571
|
+
|
572
|
+
it 'parses the response as a SMB1 ReadAndxResponse packet' do
|
573
|
+
expect(RubySMB::SMB1::Packet::ReadAndxResponse).to receive(:read).with(raw_response)
|
574
|
+
file.send_recv_read
|
575
|
+
end
|
576
|
+
|
577
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
578
|
+
allow(read_andx_response).to receive(:valid?).and_return(false)
|
579
|
+
expect { file.send_recv_read }.to raise_error(RubySMB::Error::InvalidPacket)
|
580
|
+
end
|
581
|
+
|
582
|
+
it 'raises an UnexpectedStatusCode exception if the response status code is not STATUS_SUCCESS' do
|
583
|
+
allow(read_andx_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_OBJECT_NAME_NOT_FOUND)
|
584
|
+
expect { file.send_recv_read }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
585
|
+
end
|
586
|
+
|
587
|
+
it 'returns the expected string' do
|
588
|
+
expect(file.send_recv_read).to eq(read_data)
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
describe '#send_recv_write' do
|
593
|
+
let(:write_data) { 'write data' }
|
594
|
+
let(:request) { double('Request') }
|
595
|
+
let(:raw_response) { double('fake raw response data') }
|
596
|
+
let(:write_andx_response) {
|
597
|
+
res = RubySMB::SMB1::Packet::WriteAndxResponse.new
|
598
|
+
res.parameter_block.count_low = write_data.size
|
599
|
+
res
|
600
|
+
}
|
601
|
+
|
602
|
+
before :example do
|
603
|
+
allow(file).to receive(:write_packet).and_return(request)
|
604
|
+
allow(request).to receive(:set_64_bit_offset)
|
605
|
+
allow(client).to receive(:send_recv).and_return(raw_response)
|
606
|
+
allow(RubySMB::SMB1::Packet::WriteAndxResponse).to receive(:read).with(raw_response).and_return(write_andx_response)
|
607
|
+
end
|
608
|
+
|
609
|
+
it 'reads 0 bytes from offset 0 by default' do
|
610
|
+
expect(file).to receive(:write_packet).with(data: '', offset: 0).once.and_call_original
|
611
|
+
file.send_recv_write
|
612
|
+
end
|
613
|
+
|
614
|
+
it 'writes the data provided as argument' do
|
615
|
+
expect(file).to receive(:write_packet).with(data: write_data, offset: 0).once.and_call_original
|
616
|
+
file.send_recv_write(data: write_data)
|
617
|
+
end
|
618
|
+
|
619
|
+
it 'reads from the offset provided as argument' do
|
620
|
+
offset = 3
|
621
|
+
expect(file).to receive(:write_packet).with(data: '', offset: offset).once.and_call_original
|
622
|
+
file.send_recv_write(offset: offset)
|
623
|
+
end
|
624
|
+
|
625
|
+
it 'sets the 64 bit offset to true' do
|
626
|
+
expect(request).to receive(:set_64_bit_offset).with(true)
|
627
|
+
file.send_recv_write
|
628
|
+
end
|
629
|
+
|
630
|
+
it 'calls Client #send_recv with the expected request' do
|
631
|
+
expect(client).to receive(:send_recv).with(request)
|
632
|
+
file.send_recv_write
|
633
|
+
end
|
634
|
+
|
635
|
+
it 'parses the response as a SMB1 WriteAndxResponse packet' do
|
636
|
+
expect(RubySMB::SMB1::Packet::WriteAndxResponse).to receive(:read).with(raw_response)
|
637
|
+
file.send_recv_write
|
638
|
+
end
|
639
|
+
|
640
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
641
|
+
allow(write_andx_response).to receive(:valid?).and_return(false)
|
642
|
+
expect { file.send_recv_write }.to raise_error(RubySMB::Error::InvalidPacket)
|
643
|
+
end
|
644
|
+
|
645
|
+
it 'returns the expected response #count_low value' do
|
646
|
+
expect(file.send_recv_write).to eq(write_data.size)
|
647
|
+
end
|
648
|
+
end
|
468
649
|
end
|
469
650
|
|
@@ -34,4 +34,25 @@ RSpec.describe RubySMB::SMB1::Packet::EmptyPacket do
|
|
34
34
|
expect(data_block.to_binary_s).to eq "\x00\x00"
|
35
35
|
end
|
36
36
|
end
|
37
|
+
|
38
|
+
describe '#valid?' do
|
39
|
+
before :example do
|
40
|
+
packet.original_command = RubySMB::SMB1::Commands::SMB_COM_TREE_CONNECT
|
41
|
+
packet.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_TREE_CONNECT
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns true if the packet protocol ID and header command are valid' do
|
45
|
+
expect(packet).to be_valid
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns false if the packet protocol ID is wrong' do
|
49
|
+
packet.smb_header.protocol = RubySMB::SMB2::SMB2_PROTOCOL_ID
|
50
|
+
expect(packet).to_not be_valid
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'returns false if the packet header command is wrong' do
|
54
|
+
packet.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_NEGOTIATE
|
55
|
+
expect(packet).to_not be_valid
|
56
|
+
end
|
57
|
+
end
|
37
58
|
end
|
@@ -80,6 +80,8 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindFirst2Response do
|
|
80
80
|
|
81
81
|
let(:names_blob) { names_array.collect(&:to_binary_s).join('') }
|
82
82
|
|
83
|
+
let(:find_info) { FindFileFullDirectoryInfo.new }
|
84
|
+
|
83
85
|
it 'returns an array of parsed FindFileFullDirectoryInfo structs' do
|
84
86
|
packet.data_block.trans2_data.buffer = names_blob
|
85
87
|
expect(packet.results(FindFileFullDirectoryInfo, unicode: false)).to eq names_array
|
@@ -87,7 +89,6 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindFirst2Response do
|
|
87
89
|
|
88
90
|
it 'sets the FindFileFullDirectoryInfo unicode attribute when unicode argument is true' do
|
89
91
|
packet.data_block.trans2_data.buffer = names1.to_binary_s
|
90
|
-
find_info = FindFileFullDirectoryInfo.new
|
91
92
|
allow(FindFileFullDirectoryInfo).to receive(:new).and_return find_info
|
92
93
|
expect(find_info).to receive(:unicode=).with(true).once
|
93
94
|
packet.results(FindFileFullDirectoryInfo, unicode: true)
|
@@ -95,10 +96,18 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindFirst2Response do
|
|
95
96
|
|
96
97
|
it 'does not set the FindFileFullDirectoryInfo unicode attribute when unicode argument is false' do
|
97
98
|
packet.data_block.trans2_data.buffer = names1.to_binary_s
|
98
|
-
find_info = FindFileFullDirectoryInfo.new
|
99
99
|
allow(FindFileFullDirectoryInfo).to receive(:new).and_return find_info
|
100
100
|
expect(find_info).to receive(:unicode=).with(false).once
|
101
101
|
packet.results(FindFileFullDirectoryInfo, unicode: false)
|
102
102
|
end
|
103
|
+
|
104
|
+
context 'when the File Information is not a valid' do
|
105
|
+
it 'raises an InvalidPacket exception' do
|
106
|
+
packet.data_block.trans2_data.buffer = names1.to_binary_s
|
107
|
+
allow(FindFileFullDirectoryInfo).to receive(:new).and_return(find_info)
|
108
|
+
allow(find_info).to receive(:read).and_raise(IOError)
|
109
|
+
expect { packet.results(FindFileFullDirectoryInfo, unicode: false) }.to raise_error(RubySMB::Error::InvalidPacket)
|
110
|
+
end
|
111
|
+
end
|
103
112
|
end
|
104
113
|
end
|
@@ -78,6 +78,8 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindNext2Response do
|
|
78
78
|
|
79
79
|
let(:names_blob) { names_array.collect(&:to_binary_s).join('') }
|
80
80
|
|
81
|
+
let(:find_info) { FindFileFullDirectoryInfo.new }
|
82
|
+
|
81
83
|
it 'returns an array of parsed FindFileFullDirectoryInfo structs' do
|
82
84
|
packet.data_block.trans2_data.buffer = names_blob
|
83
85
|
expect(packet.results(FindFileFullDirectoryInfo, unicode: false)).to eq names_array
|
@@ -85,7 +87,6 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindNext2Response do
|
|
85
87
|
|
86
88
|
it 'sets the FindFileFullDirectoryInfo unicode attribute when unicode argument is true' do
|
87
89
|
packet.data_block.trans2_data.buffer = names1.to_binary_s
|
88
|
-
find_info = FindFileFullDirectoryInfo.new
|
89
90
|
allow(FindFileFullDirectoryInfo).to receive(:new).and_return find_info
|
90
91
|
expect(find_info).to receive(:unicode=).with(true).once
|
91
92
|
packet.results(FindFileFullDirectoryInfo, unicode: true)
|
@@ -93,10 +94,18 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindNext2Response do
|
|
93
94
|
|
94
95
|
it 'does not set the FindFileFullDirectoryInfo unicode attribute when unicode argument is false' do
|
95
96
|
packet.data_block.trans2_data.buffer = names1.to_binary_s
|
96
|
-
find_info = FindFileFullDirectoryInfo.new
|
97
97
|
allow(FindFileFullDirectoryInfo).to receive(:new).and_return find_info
|
98
98
|
expect(find_info).to receive(:unicode=).with(false).once
|
99
99
|
packet.results(FindFileFullDirectoryInfo, unicode: false)
|
100
100
|
end
|
101
|
+
|
102
|
+
context 'when the File Information is not a valid' do
|
103
|
+
it 'raises an InvalidPacket exception' do
|
104
|
+
packet.data_block.trans2_data.buffer = names1.to_binary_s
|
105
|
+
allow(FindFileFullDirectoryInfo).to receive(:new).and_return(find_info)
|
106
|
+
allow(find_info).to receive(:read).and_raise(IOError)
|
107
|
+
expect { packet.results(FindFileFullDirectoryInfo, unicode: false) }.to raise_error(RubySMB::Error::InvalidPacket)
|
108
|
+
end
|
109
|
+
end
|
101
110
|
end
|
102
111
|
end
|
@@ -104,4 +104,44 @@ RSpec.describe RubySMB::SMB1::Packet::TreeConnectResponse do
|
|
104
104
|
expect(file_response.guest_access_rights).to be_a RubySMB::SMB1::BitField::FileAccessMask
|
105
105
|
end
|
106
106
|
end
|
107
|
+
|
108
|
+
describe '#access_rights' do
|
109
|
+
it 'is a DirectoryAccessMask if the Tree is a directory' do
|
110
|
+
allow(packet).to receive(:is_directory?).and_return(true)
|
111
|
+
expect(packet.access_rights).to be_a RubySMB::SMB1::BitField::DirectoryAccessMask
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'is a FileAccessMask if the Tree is not a directory' do
|
115
|
+
allow(packet).to receive(:is_directory?).and_return(false)
|
116
|
+
expect(packet.access_rights).to be_a RubySMB::SMB1::BitField::FileAccessMask
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'when it is not a valid FileAccessMask' do
|
120
|
+
it 'raises an InvalidBitField exception' do
|
121
|
+
allow(packet).to receive(:is_directory?).and_return(false)
|
122
|
+
allow(RubySMB::SMB1::BitField::FileAccessMask).to receive(:read).and_raise(IOError)
|
123
|
+
expect { packet.access_rights }.to raise_error(RubySMB::Error::InvalidBitField)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe '#guest_access_rights' do
|
129
|
+
it 'is a DirectoryAccessMask if the Tree is a directory' do
|
130
|
+
allow(packet).to receive(:is_directory?).and_return(true)
|
131
|
+
expect(packet.guest_access_rights).to be_a RubySMB::SMB1::BitField::DirectoryAccessMask
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'is a FileAccessMask if the Tree is not a directory' do
|
135
|
+
allow(packet).to receive(:is_directory?).and_return(false)
|
136
|
+
expect(packet.guest_access_rights).to be_a RubySMB::SMB1::BitField::FileAccessMask
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'when it is not a valid FileAccessMask' do
|
140
|
+
it 'raises an InvalidBitField exception' do
|
141
|
+
allow(packet).to receive(:is_directory?).and_return(false)
|
142
|
+
allow(RubySMB::SMB1::BitField::FileAccessMask).to receive(:read).and_raise(IOError)
|
143
|
+
expect { packet.guest_access_rights }.to raise_error(RubySMB::Error::InvalidBitField)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
107
147
|
end
|
@@ -37,6 +37,68 @@ RSpec.describe RubySMB::SMB1::Pipe do
|
|
37
37
|
described_class.new(tree: tree, response: nt_create_andx_response, name: filename)
|
38
38
|
}
|
39
39
|
|
40
|
+
describe '#peek' do
|
41
|
+
let(:request) { RubySMB::SMB1::Packet::Trans::PeekNmpipeRequest.new }
|
42
|
+
let(:raw_response) { double('Raw response') }
|
43
|
+
let(:response) { double('Response') }
|
44
|
+
|
45
|
+
before :example do
|
46
|
+
allow(RubySMB::SMB1::Packet::Trans::PeekNmpipeRequest).to receive(:new).and_return(request)
|
47
|
+
allow(client).to receive(:send_recv).and_return(raw_response)
|
48
|
+
allow(RubySMB::SMB1::Packet::Trans::PeekNmpipeResponse).to receive(:read).and_return(response)
|
49
|
+
allow(response).to receive(:valid?).and_return(true)
|
50
|
+
allow(response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_SUCCESS)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'creates a PeekNmpipeRequest'do
|
54
|
+
expect(RubySMB::SMB1::Packet::Trans::PeekNmpipeRequest).to receive(:new)
|
55
|
+
pipe.peek
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'sets the request #fid field' do
|
59
|
+
expect(request).to receive(:fid=).with(pipe.fid)
|
60
|
+
pipe.peek
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'sets the request #max_data_count fieldto the peek_size argument' do
|
64
|
+
peek_size = 5
|
65
|
+
pipe.peek(peek_size: peek_size)
|
66
|
+
expect(request.parameter_block.max_data_count).to eq(peek_size)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'calls Tree #set_header_fields' do
|
70
|
+
expect(tree).to receive(:set_header_fields).with(request)
|
71
|
+
pipe.peek
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'calls Client #send_recv' do
|
75
|
+
expect(client).to receive(:send_recv).with(request)
|
76
|
+
pipe.peek
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'parses the response as a SMB1 PeekNmpipeResponse packet' do
|
80
|
+
expect(RubySMB::SMB1::Packet::Trans::PeekNmpipeResponse).to receive(:read).with(raw_response)
|
81
|
+
pipe.peek
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
85
|
+
allow(response).to receive(:valid?).and_return(false)
|
86
|
+
smb_header = double('SMB Header')
|
87
|
+
allow(response).to receive(:smb_header).and_return(smb_header)
|
88
|
+
allow(smb_header).to receive_messages(:protocol => nil, :command => nil)
|
89
|
+
expect { pipe.peek }.to raise_error(RubySMB::Error::InvalidPacket)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'raises an UnexpectedStatusCode exception if the response status code is not STATUS_SUCCESS or STATUS_BUFFER_OVERFLOW' do
|
93
|
+
allow(response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_OBJECT_NAME_NOT_FOUND)
|
94
|
+
expect { pipe.peek }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'returns the expected response' do
|
98
|
+
expect(pipe.peek).to eq(response)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
40
102
|
describe '#peek_available' do
|
41
103
|
it 'reads the correct number of bytes available' do
|
42
104
|
allow(pipe).to receive(:peek) { peek_nmpipe_response }
|
@@ -227,8 +289,7 @@ RSpec.describe RubySMB::SMB1::Pipe do
|
|
227
289
|
end
|
228
290
|
|
229
291
|
it 'raises the expected exception when it is not a Trans packet' do
|
230
|
-
|
231
|
-
allow(RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse).to receive(:read).and_return(response)
|
292
|
+
nmpipe_response.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_TRANSACTION2
|
232
293
|
expect { pipe.request(opnum, options) }.to raise_error(RubySMB::Error::InvalidPacket)
|
233
294
|
end
|
234
295
|
|
@@ -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
|
|