ruby_smb 1.1.0 → 2.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 (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