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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/ruby_smb/client.rb +26 -4
  5. data/lib/ruby_smb/client/authentication.rb +43 -25
  6. data/lib/ruby_smb/client/echo.rb +20 -2
  7. data/lib/ruby_smb/client/negotiation.rb +27 -12
  8. data/lib/ruby_smb/client/tree_connect.rb +20 -14
  9. data/lib/ruby_smb/error.rb +40 -1
  10. data/lib/ruby_smb/generic_packet.rb +33 -4
  11. data/lib/ruby_smb/smb1/dcerpc.rb +7 -2
  12. data/lib/ruby_smb/smb1/file.rb +60 -11
  13. data/lib/ruby_smb/smb1/packet/close_request.rb +2 -5
  14. data/lib/ruby_smb/smb1/packet/close_response.rb +2 -1
  15. data/lib/ruby_smb/smb1/packet/echo_request.rb +2 -4
  16. data/lib/ruby_smb/smb1/packet/echo_response.rb +2 -1
  17. data/lib/ruby_smb/smb1/packet/empty_packet.rb +7 -0
  18. data/lib/ruby_smb/smb1/packet/logoff_request.rb +2 -4
  19. data/lib/ruby_smb/smb1/packet/logoff_response.rb +2 -1
  20. data/lib/ruby_smb/smb1/packet/negotiate_request.rb +2 -5
  21. data/lib/ruby_smb/smb1/packet/negotiate_response.rb +3 -7
  22. data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +4 -4
  23. data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +2 -4
  24. data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +2 -1
  25. data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +2 -1
  26. data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +2 -1
  27. data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +2 -4
  28. data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +2 -1
  29. data/lib/ruby_smb/smb1/packet/read_andx_request.rb +2 -5
  30. data/lib/ruby_smb/smb1/packet/read_andx_response.rb +2 -1
  31. data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -1
  32. data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -1
  33. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +2 -5
  34. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -1
  35. data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_request.rb +0 -1
  36. data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_response.rb +3 -2
  37. data/lib/ruby_smb/smb1/packet/trans/request.rb +2 -5
  38. data/lib/ruby_smb/smb1/packet/trans/response.rb +2 -1
  39. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +1 -1
  40. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +1 -1
  41. data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +2 -1
  42. data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +8 -2
  43. data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +2 -1
  44. data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +8 -2
  45. data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +2 -1
  46. data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +2 -1
  47. data/lib/ruby_smb/smb1/packet/trans2/request.rb +2 -4
  48. data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +2 -4
  49. data/lib/ruby_smb/smb1/packet/trans2/response.rb +2 -1
  50. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +2 -1
  51. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +2 -1
  52. data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +2 -4
  53. data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +13 -3
  54. data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
  55. data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -1
  56. data/lib/ruby_smb/smb1/packet/write_andx_request.rb +2 -5
  57. data/lib/ruby_smb/smb1/packet/write_andx_response.rb +2 -1
  58. data/lib/ruby_smb/smb1/pipe.rb +8 -3
  59. data/lib/ruby_smb/smb1/tree.rb +40 -2
  60. data/lib/ruby_smb/smb2/dcerpc.rb +7 -2
  61. data/lib/ruby_smb/smb2/file.rb +97 -1
  62. data/lib/ruby_smb/smb2/packet/close_request.rb +2 -4
  63. data/lib/ruby_smb/smb2/packet/close_response.rb +2 -1
  64. data/lib/ruby_smb/smb2/packet/create_request.rb +2 -4
  65. data/lib/ruby_smb/smb2/packet/create_response.rb +2 -1
  66. data/lib/ruby_smb/smb2/packet/echo_request.rb +2 -4
  67. data/lib/ruby_smb/smb2/packet/echo_response.rb +2 -1
  68. data/lib/ruby_smb/smb2/packet/error_packet.rb +7 -0
  69. data/lib/ruby_smb/smb2/packet/ioctl_request.rb +2 -5
  70. data/lib/ruby_smb/smb2/packet/ioctl_response.rb +2 -1
  71. data/lib/ruby_smb/smb2/packet/logoff_request.rb +2 -4
  72. data/lib/ruby_smb/smb2/packet/logoff_response.rb +2 -1
  73. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +2 -5
  74. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +2 -1
  75. data/lib/ruby_smb/smb2/packet/query_directory_request.rb +2 -4
  76. data/lib/ruby_smb/smb2/packet/query_directory_response.rb +8 -2
  77. data/lib/ruby_smb/smb2/packet/read_request.rb +2 -4
  78. data/lib/ruby_smb/smb2/packet/read_response.rb +2 -1
  79. data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
  80. data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -1
  81. data/lib/ruby_smb/smb2/packet/set_info_request.rb +2 -4
  82. data/lib/ruby_smb/smb2/packet/set_info_response.rb +2 -1
  83. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +2 -5
  84. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -2
  85. data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +2 -4
  86. data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +2 -1
  87. data/lib/ruby_smb/smb2/packet/write_request.rb +2 -4
  88. data/lib/ruby_smb/smb2/packet/write_response.rb +2 -1
  89. data/lib/ruby_smb/smb2/pipe.rb +9 -9
  90. data/lib/ruby_smb/smb2/tree.rb +44 -6
  91. data/lib/ruby_smb/version.rb +1 -1
  92. data/spec/lib/ruby_smb/client_spec.rb +123 -11
  93. data/spec/lib/ruby_smb/generic_packet_spec.rb +52 -4
  94. data/spec/lib/ruby_smb/smb1/file_spec.rb +182 -1
  95. data/spec/lib/ruby_smb/smb1/packet/{error_packet_spec.rb → empty_packet_spec.rb} +21 -0
  96. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +11 -2
  97. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +11 -2
  98. data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +40 -0
  99. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +63 -2
  100. data/spec/lib/ruby_smb/smb1/tree_spec.rb +44 -7
  101. data/spec/lib/ruby_smb/smb2/file_spec.rb +295 -2
  102. data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +51 -0
  103. data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +8 -0
  104. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +8 -0
  105. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +69 -3
  106. data/spec/lib/ruby_smb/smb2/tree_spec.rb +214 -0
  107. metadata +6 -4
  108. 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 a ReadAndxResponse packet' do
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
- response = RubySMB::SMB1::Packet::Trans2::Response.new
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
- it 'calls #set_header_fields' do
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(client).to receive(:send_recv).and_return(disco_resp.to_binary_s)
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).and_return(disco_resp.to_binary_s)
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 'raise an InvalidPacket exception' do
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 'raise an UnexpectedStatusCode exception' do
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