ruby_smb 1.1.0 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.travis.yml +3 -5
  5. data/Gemfile +6 -2
  6. data/examples/anonymous_auth.rb +3 -3
  7. data/examples/append_file.rb +10 -8
  8. data/examples/authenticate.rb +9 -5
  9. data/examples/delete_file.rb +8 -6
  10. data/examples/enum_registry_key.rb +5 -4
  11. data/examples/enum_registry_values.rb +5 -4
  12. data/examples/list_directory.rb +8 -6
  13. data/examples/negotiate.rb +51 -8
  14. data/examples/negotiate_with_netbios_service.rb +9 -5
  15. data/examples/net_share_enum_all.rb +6 -4
  16. data/examples/pipes.rb +11 -12
  17. data/examples/query_service_status.rb +64 -0
  18. data/examples/read_file.rb +8 -6
  19. data/examples/read_file_encryption.rb +56 -0
  20. data/examples/read_registry_key_value.rb +6 -5
  21. data/examples/rename_file.rb +9 -7
  22. data/examples/tree_connect.rb +7 -5
  23. data/examples/write_file.rb +9 -7
  24. data/lib/ruby_smb.rb +4 -0
  25. data/lib/ruby_smb/client.rb +246 -26
  26. data/lib/ruby_smb/client/authentication.rb +32 -18
  27. data/lib/ruby_smb/client/echo.rb +2 -4
  28. data/lib/ruby_smb/client/encryption.rb +62 -0
  29. data/lib/ruby_smb/client/negotiation.rb +156 -16
  30. data/lib/ruby_smb/client/signing.rb +19 -0
  31. data/lib/ruby_smb/client/tree_connect.rb +6 -8
  32. data/lib/ruby_smb/client/utils.rb +24 -17
  33. data/lib/ruby_smb/client/winreg.rb +1 -1
  34. data/lib/ruby_smb/crypto.rb +30 -0
  35. data/lib/ruby_smb/dcerpc.rb +2 -0
  36. data/lib/ruby_smb/dcerpc/error.rb +3 -0
  37. data/lib/ruby_smb/dcerpc/ndr.rb +209 -44
  38. data/lib/ruby_smb/dcerpc/request.rb +13 -0
  39. data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
  40. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +9 -6
  41. data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
  42. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
  43. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
  44. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
  45. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
  46. data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
  47. data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
  48. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
  49. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
  50. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
  51. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
  52. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
  53. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
  54. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
  55. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
  56. data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
  57. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
  58. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
  59. data/lib/ruby_smb/dcerpc/winreg.rb +98 -17
  60. data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
  61. data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
  62. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +1 -1
  63. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +1 -1
  64. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +1 -1
  65. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +4 -4
  66. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
  67. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +7 -6
  68. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +10 -10
  69. data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
  70. data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
  71. data/lib/ruby_smb/dispatcher/base.rb +1 -1
  72. data/lib/ruby_smb/dispatcher/socket.rb +5 -4
  73. data/lib/ruby_smb/error.rb +49 -6
  74. data/lib/ruby_smb/field/stringz16.rb +17 -1
  75. data/lib/ruby_smb/generic_packet.rb +11 -1
  76. data/lib/ruby_smb/nbss/session_header.rb +4 -4
  77. data/lib/ruby_smb/smb1/commands.rb +1 -1
  78. data/lib/ruby_smb/smb1/file.rb +13 -28
  79. data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +1 -1
  80. data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -2
  81. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
  82. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -2
  83. data/lib/ruby_smb/smb1/packet/write_andx_request.rb +1 -1
  84. data/lib/ruby_smb/smb1/pipe.rb +8 -8
  85. data/lib/ruby_smb/smb1/tree.rb +25 -12
  86. data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
  87. data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
  88. data/lib/ruby_smb/smb2/file.rb +59 -77
  89. data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
  90. data/lib/ruby_smb/smb2/packet.rb +2 -0
  91. data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
  92. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -14
  93. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +50 -4
  94. data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
  95. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +92 -6
  96. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -26
  97. data/lib/ruby_smb/smb2/pipe.rb +8 -20
  98. data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
  99. data/lib/ruby_smb/smb2/tree.rb +44 -28
  100. data/lib/ruby_smb/version.rb +1 -1
  101. data/ruby_smb.gemspec +3 -1
  102. data/spec/lib/ruby_smb/client_spec.rb +1408 -70
  103. data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
  104. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1396 -77
  105. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
  106. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +49 -12
  107. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
  108. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
  109. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
  110. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
  111. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
  112. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
  113. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
  114. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
  115. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
  116. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
  117. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
  118. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
  119. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
  120. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
  121. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
  122. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
  123. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
  124. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
  125. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
  126. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
  127. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +0 -4
  128. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +2 -2
  129. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +2 -2
  130. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +9 -4
  131. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
  132. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +17 -17
  133. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +11 -23
  134. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
  135. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
  136. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +227 -41
  137. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +12 -12
  138. data/spec/lib/ruby_smb/error_spec.rb +88 -0
  139. data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
  140. data/spec/lib/ruby_smb/generic_packet_spec.rb +7 -0
  141. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
  142. data/spec/lib/ruby_smb/smb1/file_spec.rb +1 -3
  143. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
  144. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
  145. data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
  146. data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
  147. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +30 -5
  148. data/spec/lib/ruby_smb/smb1/tree_spec.rb +22 -0
  149. data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
  150. data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
  151. data/spec/lib/ruby_smb/smb2/file_spec.rb +147 -71
  152. data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
  153. data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
  154. data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
  155. data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
  156. data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
  157. data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
  158. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -30
  159. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +9 -45
  160. data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
  161. data/spec/lib/ruby_smb/smb2/tree_spec.rb +111 -9
  162. metadata +194 -75
  163. metadata.gz.sig +2 -1
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe RubySMB::Error::InvalidPacket do
4
+ context 'with a String' do
5
+ it 'outputs the expected error message' do
6
+ ex = described_class.new('My exception')
7
+ expect(ex.to_s).to eq('My exception')
8
+ end
9
+ end
10
+
11
+ context 'with a Hash' do
12
+ let(:ex) do
13
+ described_class.new(
14
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
15
+ expected_cmd: RubySMB::SMB1::Packet::NegotiateResponseExtended::COMMAND,
16
+ expected_custom: "extended_security=1",
17
+ packet: packet,
18
+ received_custom: "extended_security=0"
19
+ )
20
+ end
21
+
22
+ context 'with an SMB2 packet' do
23
+ let(:packet) { RubySMB::SMB2::Packet::NegotiateResponse.new }
24
+
25
+ it 'outputs the expected error message' do
26
+ expect(ex.to_s).to eq('Expecting SMB1 protocol with command=114 (extended_security=1), got SMB2 protocol with command=0 (extended_security=0), Status: (0x00000000) STATUS_SUCCESS: The operation completed successfully.')
27
+ end
28
+ end
29
+
30
+ context 'with an SMB1 packet' do
31
+ let(:packet) { RubySMB::SMB1::Packet::ReadAndxRequest.new }
32
+
33
+ it 'outputs the expected error message' do
34
+ expect(ex.to_s).to eq('Expecting SMB1 protocol with command=114 (extended_security=1), got SMB1 protocol with command=46 (extended_security=0), Status: (0x00000000) STATUS_SUCCESS: The operation completed successfully.')
35
+ end
36
+ end
37
+
38
+ context 'without packet' do
39
+ let(:ex) do
40
+ described_class.new(
41
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
42
+ expected_cmd: RubySMB::SMB1::Packet::NegotiateResponseExtended::COMMAND,
43
+ expected_custom: "extended_security=1",
44
+ received_custom: "extended_security=0"
45
+ )
46
+ end
47
+
48
+ it 'outputs the expected error message' do
49
+ expect(ex.to_s).to eq('Expecting SMB1 protocol with command=114 (extended_security=1), got ??? protocol with command=??? (extended_security=0)')
50
+ end
51
+ end
52
+ end
53
+
54
+ context 'with an unsupported type' do
55
+ it 'raises the expected exception' do
56
+ expect { described_class.new(['wrong']) }.to raise_error(
57
+ ArgumentError,
58
+ 'InvalidPacket expects a String or a Hash, got a Array'
59
+ )
60
+ end
61
+ end
62
+ end
63
+
64
+
65
+ RSpec.describe RubySMB::Error::UnexpectedStatusCode do
66
+ context 'with a WindowsError::ErrorCode' do
67
+ it 'outputs the expected error message' do
68
+ ex = described_class.new(WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW)
69
+ expect(ex.to_s).to eq('The server responded with an unexpected status code: STATUS_BUFFER_OVERFLOW')
70
+ end
71
+ end
72
+
73
+ context 'with an Integer' do
74
+ it 'outputs the expected error message' do
75
+ ex = described_class.new(0x80000005)
76
+ expect(ex.to_s).to eq('The server responded with an unexpected status code: STATUS_BUFFER_OVERFLOW')
77
+ end
78
+ end
79
+
80
+ context 'with an unsupported type' do
81
+ it 'raises the expected exception' do
82
+ expect { described_class.new(['wrong']) }.to raise_error(
83
+ ArgumentError,
84
+ 'Status code must be a WindowsError::ErrorCode or an Integer, got Array'
85
+ )
86
+ end
87
+ end
88
+ end
@@ -44,5 +44,17 @@ RSpec.describe RubySMB::Field::Stringz16 do
44
44
  io = StringIO.new("A\x00B\x00C\x00D\x00")
45
45
  expect { stringz16.read(io) }.to raise_error(EOFError)
46
46
  end
47
+
48
+ it 'trims the string to #max_length and makes sure it ends with a null terminator' do
49
+ io = StringIO.new("A\x00B\x00C\x00D\x00")
50
+ str = described_class.new(max_length: 6)
51
+ expect(str.read(io).to_binary_s).to eq("A\x00B\x00\x00\x00".b)
52
+ end
53
+
54
+ it 'raises an exception when #max_length is not a multiple of two' do
55
+ io = StringIO.new("A\x00B\x00C\x00D\x00")
56
+ str = described_class.new(max_length: 5)
57
+ expect { str.read(io) }.to raise_error(ArgumentError)
58
+ end
47
59
  end
48
60
  end
@@ -88,6 +88,13 @@ RSpec.describe RubySMB::GenericPacket do
88
88
  packet = RubySMB::SMB2::Packet::NegotiateResponse.read(smb2_error_packet.to_binary_s)
89
89
  expect(packet.original_command).to eq RubySMB::SMB2::Packet::NegotiateResponse::COMMAND
90
90
  end
91
+
92
+ context 'when the server returns an SMB1 error packet' do
93
+ let(:smb1_error_packet) { RubySMB::SMB1::Packet::EmptyPacket.new }
94
+ it 'returns the empty packet instead of the asked for class' do
95
+ expect(RubySMB::SMB2::Packet::NegotiateResponse.read(smb1_error_packet.to_binary_s)).to be_a RubySMB::SMB1::Packet::EmptyPacket
96
+ end
97
+ end
91
98
  end
92
99
  end
93
100
 
@@ -2,8 +2,7 @@ RSpec.describe RubySMB::Nbss::SessionHeader do
2
2
  subject(:session_header) { described_class.new }
3
3
 
4
4
  it { is_expected.to respond_to :session_packet_type }
5
- it { is_expected.to respond_to :flags }
6
- it { is_expected.to respond_to :packet_length }
5
+ it { is_expected.to respond_to :stream_protocol_length }
7
6
 
8
7
  it 'is big endian' do
9
8
  expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :big
@@ -15,15 +14,9 @@ RSpec.describe RubySMB::Nbss::SessionHeader do
15
14
  end
16
15
  end
17
16
 
18
- describe '#flags' do
19
- it 'is a 7-bit Unsigned Integer' do
20
- expect(session_header.flags).to be_a BinData::Bit7
21
- end
22
- end
23
-
24
- describe '#packet_length' do
25
- it 'is a 17-bit Unsigned Integer' do
26
- expect(session_header.packet_length).to be_a BinData::Bit17
17
+ describe '#stream_protocol_length' do
18
+ it 'is a 24-bit Unsigned Integer' do
19
+ expect(session_header.stream_protocol_length).to be_a BinData::Uint24be
27
20
  end
28
21
  end
29
22
  end
@@ -521,9 +521,7 @@ RSpec.describe RubySMB::SMB1::File do
521
521
 
522
522
  it 'raises an InvalidPacket exception if the response is not valid' do
523
523
  allow(response).to receive(:valid?).and_return(false)
524
- smb_header = double('SMB Header')
525
- allow(response).to receive(:smb_header).and_return(smb_header)
526
- allow(smb_header).to receive_messages(:protocol => nil, :command => nil)
524
+ allow(response).to receive(:packet_smb_version)
527
525
  expect { file.close }.to raise_error(RubySMB::Error::InvalidPacket)
528
526
  end
529
527
 
@@ -10,8 +10,8 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupLegacyRequest do
10
10
  expect(header).to be_a RubySMB::SMB1::SMBHeader
11
11
  end
12
12
 
13
- it 'should have the command set to SMB_COM_NEGOTIATE' do
14
- expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
13
+ it 'should have the command set to SMB_COM_SESSION_SETUP_ANDX' do
14
+ expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
15
15
  end
16
16
 
17
17
  it 'should not have the response flag set' do
@@ -10,8 +10,8 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupLegacyResponse do
10
10
  expect(header).to be_a RubySMB::SMB1::SMBHeader
11
11
  end
12
12
 
13
- it 'should have the command set to SMB_COM_NEGOTIATE' do
14
- expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
13
+ it 'should have the command set to SMB_COM_SESSION_SETUP_ANDX' do
14
+ expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
15
15
  end
16
16
 
17
17
  it 'should have the response flag set' do
@@ -10,8 +10,8 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupRequest do
10
10
  expect(header).to be_a RubySMB::SMB1::SMBHeader
11
11
  end
12
12
 
13
- it 'should have the command set to SMB_COM_NEGOTIATE' do
14
- expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
13
+ it 'should have the command set to SMB_COM_SESSION_SETUP_ANDX' do
14
+ expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
15
15
  end
16
16
 
17
17
  it 'should not have the response flag set' do
@@ -11,7 +11,7 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupResponse do
11
11
  end
12
12
 
13
13
  it 'should have the command set to SMB_COM_NEGOTIATE' do
14
- expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
14
+ expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
15
15
  end
16
16
 
17
17
  it 'should have the response flag set' do
@@ -80,9 +80,7 @@ RSpec.describe RubySMB::SMB1::Pipe do
80
80
 
81
81
  it 'raises an InvalidPacket exception if the response is not valid' do
82
82
  allow(response).to receive(:valid?).and_return(false)
83
- smb_header = double('SMB Header')
84
- allow(response).to receive(:smb_header).and_return(smb_header)
85
- allow(smb_header).to receive_messages(:protocol => nil, :command => nil)
83
+ allow(response).to receive(:packet_smb_version)
86
84
  expect { pipe.peek }.to raise_error(RubySMB::Error::InvalidPacket)
87
85
  end
88
86
 
@@ -149,12 +147,40 @@ RSpec.describe RubySMB::SMB1::Pipe do
149
147
  end
150
148
  end
151
149
 
150
+ context 'with \'\\srvsvc\' filename' do
151
+ it 'extends Srvsvc class' do
152
+ pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: '\\srvsvc')
153
+ expect(pipe.respond_to?(:net_share_enum_all)).to be true
154
+ end
155
+ end
156
+
152
157
  context 'with \'winreg\' filename' do
153
158
  it 'extends Winreg class' do
154
159
  pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: 'winreg')
155
160
  expect(pipe.respond_to?(:has_registry_key?)).to be true
156
161
  end
157
162
  end
163
+
164
+ context 'with \'\\winreg\' filename' do
165
+ it 'extends Winreg class' do
166
+ pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: '\\winreg')
167
+ expect(pipe.respond_to?(:has_registry_key?)).to be true
168
+ end
169
+ end
170
+
171
+ context 'with \'svcctl\' filename' do
172
+ it 'extends svcctl class' do
173
+ pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: 'svcctl')
174
+ expect(pipe.respond_to?(:query_service_config)).to be true
175
+ end
176
+ end
177
+
178
+ context 'with \'\\svcctl\' filename' do
179
+ it 'extends svcctl class' do
180
+ pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: '\\svcctl')
181
+ expect(pipe.respond_to?(:query_service_config)).to be true
182
+ end
183
+ end
158
184
  end
159
185
 
160
186
  describe '#dcerpc_request' do
@@ -238,8 +264,7 @@ RSpec.describe RubySMB::SMB1::Pipe do
238
264
 
239
265
  context 'when the response is not a Trans packet' do
240
266
  it 'raises an InvalidPacket exception' do
241
- allow(trans_nmpipe_response).to receive_message_chain(:smb_header, :protocol)
242
- allow(trans_nmpipe_response).to receive_message_chain(:smb_header, :command)
267
+ allow(trans_nmpipe_response).to receive(:packet_smb_version)
243
268
  allow(trans_nmpipe_response).to receive(:valid?).and_return(false)
244
269
  expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Error::InvalidPacket)
245
270
  end
@@ -492,4 +492,26 @@ RSpec.describe RubySMB::SMB1::Tree do
492
492
  end
493
493
  end
494
494
 
495
+ describe '#open_pipe' do
496
+ let(:opts) { { filename: 'test', write: true } }
497
+ before :example do
498
+ allow(tree).to receive(:open_file)
499
+ end
500
+
501
+ it 'calls #open_file with the provided options' do
502
+ opts[:filename] ='\\test'
503
+ expect(tree).to receive(:open_file).with(opts)
504
+ tree.open_pipe(opts)
505
+ end
506
+
507
+ it 'prepends the filename with \\ if needed' do
508
+ expect(tree).to receive(:open_file).with( { filename: '\\test', write: true } )
509
+ tree.open_pipe(opts)
510
+ end
511
+
512
+ it 'does not modify the original option hash' do
513
+ tree.open_pipe(opts)
514
+ expect(opts).to eq( { filename: 'test', write: true } )
515
+ end
516
+ end
495
517
  end
@@ -5,6 +5,7 @@ RSpec.describe RubySMB::SMB2::BitField::SessionFlags do
5
5
 
6
6
  it { is_expected.to respond_to :guest }
7
7
  it { is_expected.to respond_to :null }
8
+ it { is_expected.to respond_to :encrypt_data }
8
9
 
9
10
  it 'is little endian' do
10
11
  expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
@@ -25,4 +26,12 @@ RSpec.describe RubySMB::SMB2::BitField::SessionFlags do
25
26
 
26
27
  it_behaves_like 'bit field with one flag set', :null, 'v', 0x00000002
27
28
  end
29
+
30
+ describe '#encrypt_data' do
31
+ it 'should be a 1-bit field per the SMB spec' do
32
+ expect(flags.encrypt_data).to be_a BinData::Bit1
33
+ end
34
+
35
+ it_behaves_like 'bit field with one flag set', :encrypt_data, 'v', 0x00000004
36
+ end
28
37
  end
@@ -1,6 +1,8 @@
1
1
  RSpec.describe RubySMB::SMB2::BitField::ShareFlags do
2
2
  subject(:flags) { described_class.new }
3
3
 
4
+ it { is_expected.to respond_to :vdo_caching }
5
+ it { is_expected.to respond_to :auto_caching }
4
6
  it { is_expected.to respond_to :dfs_root }
5
7
  it { is_expected.to respond_to :dfs }
6
8
  it { is_expected.to respond_to :encrypt }
@@ -11,11 +13,28 @@ RSpec.describe RubySMB::SMB2::BitField::ShareFlags do
11
13
  it { is_expected.to respond_to :namespace_caching }
12
14
  it { is_expected.to respond_to :shared_delete }
13
15
  it { is_expected.to respond_to :restrict_exclusive_opens }
16
+ it { is_expected.to respond_to :identity_remoting }
14
17
 
15
18
  it 'is little endian' do
16
19
  expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
17
20
  end
18
21
 
22
+ describe '#vdo_caching' do
23
+ it 'should be a 1-bit field per the SMB spec' do
24
+ expect(flags.vdo_caching).to be_a BinData::Bit1
25
+ end
26
+
27
+ it_behaves_like 'bit field with one flag set', :vdo_caching, 'V', 0x00000020
28
+ end
29
+
30
+ describe '#auto_caching' do
31
+ it 'should be a 1-bit field per the SMB spec' do
32
+ expect(flags.auto_caching).to be_a BinData::Bit1
33
+ end
34
+
35
+ it_behaves_like 'bit field with one flag set', :auto_caching, 'V', 0x00000010
36
+ end
37
+
19
38
  describe '#dfs' do
20
39
  it 'should be a 1-bit field per the SMB spec' do
21
40
  expect(flags.dfs).to be_a BinData::Bit1
@@ -96,6 +115,14 @@ RSpec.describe RubySMB::SMB2::BitField::ShareFlags do
96
115
  it_behaves_like 'bit field with one flag set', :encrypt, 'V', 0x00008000
97
116
  end
98
117
 
118
+ describe '#identity_remoting' do
119
+ it 'should be a 1-bit field per the SMB spec' do
120
+ expect(flags.identity_remoting).to be_a BinData::Bit1
121
+ end
122
+
123
+ it_behaves_like 'bit field with one flag set', :identity_remoting, 'V', 0x00040000
124
+ end
125
+
99
126
  describe '#set_manual_caching' do
100
127
  it 'turns off the caching bits' do
101
128
  flags.set_manual_caching
@@ -43,6 +43,7 @@ RSpec.describe RubySMB::SMB2::File do
43
43
  it { is_expected.to respond_to :size }
44
44
  it { is_expected.to respond_to :size_on_disk }
45
45
  it { is_expected.to respond_to :tree }
46
+ it { is_expected.to respond_to :tree_connect_encrypt_data }
46
47
 
47
48
  it 'pulls the attributes from the response packet' do
48
49
  expect(file.attributes).to eq create_response.file_attributes
@@ -52,10 +53,18 @@ RSpec.describe RubySMB::SMB2::File do
52
53
  expect(file.guid).to eq create_response.file_id
53
54
  end
54
55
 
55
- it 'pulls the timestamps from the response packet' do
56
+ it 'pulls the last access timestamps from the response packet' do
56
57
  expect(file.last_access).to eq create_response.last_access.to_datetime
57
58
  end
58
59
 
60
+ it 'pulls the last change timestamps from the response packet' do
61
+ expect(file.last_change).to eq create_response.last_change.to_datetime
62
+ end
63
+
64
+ it 'pulls the last write timestamps from the response packet' do
65
+ expect(file.last_write).to eq create_response.last_write.to_datetime
66
+ end
67
+
59
68
  it 'pulls the size from the response packet' do
60
69
  expect(file.size).to eq create_response.end_of_file
61
70
  end
@@ -64,6 +73,10 @@ RSpec.describe RubySMB::SMB2::File do
64
73
  expect(file.size_on_disk).to eq create_response.allocation_size
65
74
  end
66
75
 
76
+ it 'sets the tree_connect_encrypt_data flag to false by default' do
77
+ expect(file.tree_connect_encrypt_data).to be false
78
+ end
79
+
67
80
  describe '#set_header_fields' do
68
81
  let(:request) { RubySMB::SMB2::Packet::ReadRequest.new }
69
82
  it 'calls the set_header_field method from the Tree' do
@@ -94,6 +107,10 @@ RSpec.describe RubySMB::SMB2::File do
94
107
  it 'sets the offset of the packet' do
95
108
  expect(file.read_packet(offset: 55).offset).to eq 55
96
109
  end
110
+
111
+ it 'sets the credit_charge of the packet' do
112
+ expect(file.read_packet(credit_charge: 3).smb2_header.credit_charge).to eq 3
113
+ end
97
114
  end
98
115
 
99
116
  describe '#read' do
@@ -112,12 +129,18 @@ RSpec.describe RubySMB::SMB2::File do
112
129
  end
113
130
 
114
131
  it 'uses a single packet to read the entire file' do
115
- expect(file).to receive(:read_packet).with(read_length: 108, offset: 0).and_return(small_read)
116
- expect(client).to receive(:send_recv).with(small_read).and_return 'fake data'
132
+ expect(file).to receive(:read_packet).with(read_length: 108, offset: 0, credit_charge: 0).and_return(small_read)
133
+ expect(client).to receive(:send_recv).with(small_read, encrypt: false).and_return 'fake data'
117
134
  expect(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).with('fake data').and_return(small_response)
118
135
  expect(file.read).to eq 'fake data'
119
136
  end
120
137
 
138
+ it 'calls Client #send_recv with encryption set if required' do
139
+ file.tree_connect_encrypt_data = true
140
+ expect(client).to receive(:send_recv).with(small_read, encrypt: true)
141
+ file.read
142
+ end
143
+
121
144
  context 'when the response is not valid' do
122
145
  it 'raise an InvalidPacket exception' do
123
146
  small_response.smb2_header.command = RubySMB::SMB2::Commands::LOGOFF
@@ -142,22 +165,31 @@ RSpec.describe RubySMB::SMB2::File do
142
165
  }
143
166
 
144
167
  before :example do
168
+ client.server_supports_multi_credit = 1
145
169
  allow(file).to receive(:read_packet)
146
170
  allow(client).to receive(:send_recv)
147
171
  allow(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).and_return(big_response)
148
172
  end
149
173
 
150
- it 'uses a multiple packet to read the file in chunks' do
151
- expect(file).to receive(:read_packet).once.with(read_length: described_class::MAX_PACKET_SIZE, offset: 0).and_return(big_read)
152
- expect(file).to receive(:read_packet).once.with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE).and_return(big_read)
174
+ it 'uses multiple packets to read the file in chunks' do
175
+ expect(file).to receive(:read_packet).once.with(read_length: described_class::MAX_PACKET_SIZE, offset: 0, credit_charge: 1).and_return(big_read)
176
+ expect(file).to receive(:read_packet).once.with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE, credit_charge: 1).and_return(big_read)
153
177
  expect(client).to receive(:send_recv).twice.and_return 'fake data'
154
178
  expect(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).twice.with('fake data').and_return(big_response)
155
179
  file.read(bytes: (described_class::MAX_PACKET_SIZE * 2))
156
180
  end
157
181
 
182
+ it 'calls Client #send_recv with encryption set if required' do
183
+ read_request = double('Read Request')
184
+ allow(file).to receive(:read_packet).and_return(read_request)
185
+ file.tree_connect_encrypt_data = true
186
+ expect(client).to receive(:send_recv).twice.with(read_request, encrypt: true)
187
+ file.read(bytes: (described_class::MAX_PACKET_SIZE * 2))
188
+ end
189
+
158
190
  context 'when the second response is not valid' do
159
191
  it 'raise an InvalidPacket exception' do
160
- allow(file).to receive(:read_packet).with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE) do
192
+ allow(file).to receive(:read_packet).with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE, credit_charge: 1) do
161
193
  big_response.smb2_header.command = RubySMB::SMB2::Commands::LOGOFF
162
194
  end
163
195
  expect { file.read(bytes: (described_class::MAX_PACKET_SIZE * 2)) }.to raise_error(RubySMB::Error::InvalidPacket)
@@ -166,12 +198,31 @@ RSpec.describe RubySMB::SMB2::File do
166
198
 
167
199
  context 'when the second response status code is not STATUS_SUCCESS' do
168
200
  it 'raise an UnexpectedStatusCode exception' do
169
- allow(file).to receive(:read_packet).with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE) do
201
+ allow(file).to receive(:read_packet).with(read_length: described_class::MAX_PACKET_SIZE, offset: described_class::MAX_PACKET_SIZE, credit_charge: 1) do
170
202
  big_response.smb2_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_HANDLE.value
171
203
  end
172
204
  expect { file.read(bytes: (described_class::MAX_PACKET_SIZE * 2)) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
173
205
  end
174
206
  end
207
+
208
+ context 'when the server does not support multi credits' do
209
+ it 'reads 65536 bytes at a time with no credit charge' do
210
+ client.server_supports_multi_credit = false
211
+ expect(file).to receive(:read_packet).once.with(read_length: 65536, offset: 0, credit_charge: 0).and_return(big_read)
212
+ expect(file).to receive(:read_packet).once.with(read_length: 65536, offset: 65536, credit_charge: 0).and_return(big_read)
213
+ file.read(bytes: (described_class::MAX_PACKET_SIZE * 4))
214
+ end
215
+ end
216
+
217
+ context 'when the server supports multi credits' do
218
+ it 'reads a number of bytes equal to #server_max_read_size, with the expected credit charge' do
219
+ credit_charge = (90000 - 1) / 65536 + 1
220
+ client.server_max_read_size = 90000
221
+ expect(file).to receive(:read_packet).once.with(read_length: 90000, offset: 0, credit_charge: credit_charge).and_return(big_read)
222
+ expect(file).to receive(:read_packet).once.with(read_length: (described_class::MAX_PACKET_SIZE * 4 - 90000), offset: 90000, credit_charge: credit_charge).and_return(big_read)
223
+ file.read(bytes: (described_class::MAX_PACKET_SIZE * 4))
224
+ end
225
+ end
175
226
  end
176
227
  end
177
228
 
@@ -195,6 +246,10 @@ RSpec.describe RubySMB::SMB2::File do
195
246
  it 'sets the buffer on the packet' do
196
247
  expect(file.write_packet(data:'hello').buffer).to eq 'hello'
197
248
  end
249
+
250
+ it 'sets the credit_charge on the packet header' do
251
+ expect(file.write_packet(credit_charge: 5).smb2_header.credit_charge).to eq 5
252
+ end
198
253
  end
199
254
 
200
255
  describe '#write' do
@@ -204,13 +259,55 @@ RSpec.describe RubySMB::SMB2::File do
204
259
  expect(client).to receive(:send_recv).once.and_return(write_response.to_binary_s)
205
260
  file.write(data: 'test')
206
261
  end
262
+
263
+ it 'calls Client #send_recv with encryption set if required' do
264
+ write_request = double('Write Request')
265
+ allow(file).to receive(:write_packet).and_return(write_request)
266
+ file.tree_connect_encrypt_data = true
267
+ expect(client).to receive(:send_recv).once.with(write_request, encrypt: true).and_return(write_response.to_binary_s)
268
+ file.write(data: 'test')
269
+ end
207
270
  end
208
271
 
209
272
  context 'for a large write' do
273
+ before :example do
274
+ allow(client).to receive(:send_recv).and_return(write_response.to_binary_s)
275
+ client.server_supports_multi_credit = 1
276
+ end
277
+
210
278
  it 'sends multiple packets' do
211
279
  expect(client).to receive(:send_recv).twice.and_return(write_response.to_binary_s)
212
280
  file.write(data: SecureRandom.random_bytes(described_class::MAX_PACKET_SIZE + 1))
213
281
  end
282
+
283
+ it 'calls Client #send_recv with encryption set if required' do
284
+ write_request = double('Write Request')
285
+ allow(file).to receive(:write_packet).and_return(write_request)
286
+ file.tree_connect_encrypt_data = true
287
+ expect(client).to receive(:send_recv).twice.with(write_request, encrypt: true).and_return(write_response.to_binary_s)
288
+ file.write(data: SecureRandom.random_bytes(described_class::MAX_PACKET_SIZE + 1))
289
+ end
290
+
291
+ context 'when the server does not support multi credits' do
292
+ it 'writes 65536 bytes at a time with no credit charge' do
293
+ client.server_supports_multi_credit = false
294
+ data = SecureRandom.random_bytes(65536 * 2)
295
+ expect(file).to receive(:write_packet).once.with(data: data[0, 65536], offset: 0, credit_charge: 0)
296
+ expect(file).to receive(:write_packet).once.with(data: data[65536, (data.size - 65536)], offset: 65536, credit_charge: 0)
297
+ file.write(data: data)
298
+ end
299
+ end
300
+
301
+ context 'when the server supports multi credits' do
302
+ it 'reads a number of bytes equal to #server_max_write_size, with the expected credit charge' do
303
+ data = SecureRandom.random_bytes(90000 * 2)
304
+ credit_charge = (90000 - 1) / 65536 + 1
305
+ client.server_max_write_size = 90000
306
+ expect(file).to receive(:write_packet).once.with(data: data[0, 90000], offset: 0, credit_charge: credit_charge)
307
+ expect(file).to receive(:write_packet).once.with(data: data[90000, (data.size - 90000)], offset: 90000, credit_charge: credit_charge)
308
+ file.write(data: data)
309
+ end
310
+ end
214
311
  end
215
312
 
216
313
  it 'raises an InvalidPacket exception if the response is not valid' do
@@ -248,7 +345,7 @@ RSpec.describe RubySMB::SMB2::File do
248
345
 
249
346
  it 'uses a single packet to delete the entire file' do
250
347
  expect(file).to receive(:delete_packet).and_return(small_delete)
251
- expect(client).to receive(:send_recv).with(small_delete).and_return 'raw_response'
348
+ expect(client).to receive(:send_recv).with(small_delete, encrypt: false).and_return 'raw_response'
252
349
  expect(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).with('raw_response').and_return(small_response)
253
350
  expect(file.delete).to eq WindowsError::NTStatus::STATUS_SUCCESS
254
351
  end
@@ -260,6 +357,14 @@ RSpec.describe RubySMB::SMB2::File do
260
357
  allow(small_response).to receive(:valid?).and_return(false)
261
358
  expect { file.delete }.to raise_error(RubySMB::Error::InvalidPacket)
262
359
  end
360
+
361
+ it 'calls Client #send_recv with encryption set if required' do
362
+ allow(file).to receive(:delete_packet)
363
+ allow(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).and_return(small_response)
364
+ file.tree_connect_encrypt_data = true
365
+ expect(client).to receive(:send_recv).with(small_delete, encrypt: true)
366
+ file.delete
367
+ end
263
368
  end
264
369
  end
265
370
 
@@ -291,11 +396,18 @@ RSpec.describe RubySMB::SMB2::File do
291
396
 
292
397
  it 'uses a single packet to rename the entire file' do
293
398
  expect(file).to receive(:rename_packet).and_return(small_rename)
294
- expect(client).to receive(:send_recv).with(small_rename).and_return 'raw_response'
399
+ expect(client).to receive(:send_recv).with(small_rename, encrypt: false).and_return 'raw_response'
295
400
  expect(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).with('raw_response').and_return(small_response)
296
401
  expect(file.rename('new_file.txt')).to eq WindowsError::NTStatus::STATUS_SUCCESS
297
402
  end
298
403
 
404
+ it 'calls Client #send_recv with encryption set if required' do
405
+ allow(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).and_return(small_response)
406
+ file.tree_connect_encrypt_data = true
407
+ expect(client).to receive(:send_recv).with(small_rename, encrypt: true)
408
+ file.rename('new_file.txt')
409
+ end
410
+
299
411
  it 'raises an InvalidPacket exception if the response is not valid' do
300
412
  allow(client).to receive(:send_recv)
301
413
  allow(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).and_return(small_response)
@@ -330,7 +442,13 @@ RSpec.describe RubySMB::SMB2::File do
330
442
  end
331
443
 
332
444
  it 'calls Client #send_recv with the expected request' do
333
- expect(client).to receive(:send_recv).with(request)
445
+ expect(client).to receive(:send_recv).with(request, encrypt: false)
446
+ file.close
447
+ end
448
+
449
+ it 'calls Client #send_recv with encryption set if required' do
450
+ file.tree_connect_encrypt_data = true
451
+ expect(client).to receive(:send_recv).with(request, encrypt: true)
334
452
  file.close
335
453
  end
336
454
 
@@ -341,9 +459,7 @@ RSpec.describe RubySMB::SMB2::File do
341
459
 
342
460
  it 'raises an InvalidPacket exception if the response is not valid' do
343
461
  allow(response).to receive(:valid?).and_return(false)
344
- smb2_header = double('SMB2 Header')
345
- allow(response).to receive(:smb2_header).and_return(smb2_header)
346
- allow(smb2_header).to receive_messages(:protocol => nil, :command => nil)
462
+ allow(response).to receive(:packet_smb_version)
347
463
  expect { file.close }.to raise_error(RubySMB::Error::InvalidPacket)
348
464
  end
349
465
 
@@ -394,7 +510,15 @@ RSpec.describe RubySMB::SMB2::File do
394
510
  it 'calls Client #send_recv with the expected request' do
395
511
  request = double('Request')
396
512
  allow(file).to receive(:read_packet).and_return(request)
397
- expect(client).to receive(:send_recv).with(request)
513
+ expect(client).to receive(:send_recv).with(request, encrypt: false)
514
+ file.send_recv_read
515
+ end
516
+
517
+ it 'calls Client #send_recv with encryption set if required' do
518
+ request = double('Request')
519
+ allow(file).to receive(:read_packet).and_return(request)
520
+ file.tree_connect_encrypt_data = true
521
+ expect(client).to receive(:send_recv).with(request, encrypt: true)
398
522
  file.send_recv_read
399
523
  end
400
524
 
@@ -408,33 +532,6 @@ RSpec.describe RubySMB::SMB2::File do
408
532
  expect { file.send_recv_read }.to raise_error(RubySMB::Error::InvalidPacket)
409
533
  end
410
534
 
411
- context 'when the response status code is STATUS_PENDING' do
412
- before :example do
413
- allow(file).to receive(:sleep)
414
- allow(read_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_PENDING)
415
- allow(dispatcher).to receive(:recv_packet).and_return(raw_response)
416
- end
417
-
418
- it 'wait 1 second and calls Client dispatcher #recv_packet method one more time' do
419
- expect(file).to receive(:sleep).with(1)
420
- expect(dispatcher).to receive(:recv_packet)
421
- file.send_recv_read
422
- end
423
-
424
- it 'parses the response as a SMB2 ReadResponse packet' do
425
- expect(RubySMB::SMB2::Packet::ReadResponse).to receive(:read).twice.with(raw_response)
426
- file.send_recv_read
427
- end
428
-
429
- it 'raises an InvalidPacket exception if the response is not valid' do
430
- allow(dispatcher).to receive(:recv_packet) do
431
- allow(read_response).to receive(:valid?).and_return(false)
432
- raw_response
433
- end
434
- expect { file.send_recv_read }.to raise_error(RubySMB::Error::InvalidPacket)
435
- end
436
- end
437
-
438
535
  it 'raises an UnexpectedStatusCode exception if the response status code is not STATUS_SUCCESS' do
439
536
  allow(read_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_OBJECT_NAME_NOT_FOUND)
440
537
  expect { file.send_recv_read }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
@@ -457,7 +554,7 @@ RSpec.describe RubySMB::SMB2::File do
457
554
 
458
555
  before :example do
459
556
  allow(file).to receive(:write_packet).and_return(request)
460
- allow(client).to receive(:send_recv).and_return(raw_response)
557
+ allow(client).to receive(:send_recv).and_return(raw_response, encrypt: false)
461
558
  allow(RubySMB::SMB2::Packet::WriteResponse).to receive(:read).with(raw_response).and_return(write_response)
462
559
  end
463
560
 
@@ -478,40 +575,19 @@ RSpec.describe RubySMB::SMB2::File do
478
575
  end
479
576
 
480
577
  it 'calls Client #send_recv with the expected request' do
481
- expect(client).to receive(:send_recv).with(request)
578
+ expect(client).to receive(:send_recv).with(request, encrypt: false)
482
579
  file.send_recv_write
483
580
  end
484
581
 
485
- it 'parses the response as a SMB1 WriteResponse packet' do
486
- expect(RubySMB::SMB2::Packet::WriteResponse).to receive(:read).with(raw_response)
582
+ it 'calls Client #send_recv with encryption set if required' do
583
+ file.tree_connect_encrypt_data = true
584
+ expect(client).to receive(:send_recv).with(request, encrypt: true)
487
585
  file.send_recv_write
488
586
  end
489
587
 
490
- context 'when the response status code is STATUS_PENDING' do
491
- before :example do
492
- allow(file).to receive(:sleep)
493
- allow(write_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_PENDING)
494
- allow(dispatcher).to receive(:recv_packet).and_return(raw_response)
495
- end
496
-
497
- it 'wait 1 second and calls Client dispatcher #recv_packet method one more time' do
498
- expect(file).to receive(:sleep).with(1)
499
- expect(dispatcher).to receive(:recv_packet)
500
- file.send_recv_write
501
- end
502
-
503
- it 'parses the response as a SMB2 WriteResponse packet' do
504
- expect(RubySMB::SMB2::Packet::WriteResponse).to receive(:read).twice.with(raw_response)
505
- file.send_recv_write
506
- end
507
-
508
- it 'raises an InvalidPacket exception if the response is not valid' do
509
- allow(dispatcher).to receive(:recv_packet) do
510
- allow(write_response).to receive(:valid?).and_return(false)
511
- raw_response
512
- end
513
- expect { file.send_recv_write }.to raise_error(RubySMB::Error::InvalidPacket)
514
- end
588
+ it 'parses the response as a SMB1 WriteResponse packet' do
589
+ expect(RubySMB::SMB2::Packet::WriteResponse).to receive(:read).with(raw_response)
590
+ file.send_recv_write
515
591
  end
516
592
 
517
593
  it 'raises an InvalidPacket exception if the response is not valid' do