ruby_smb 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/ruby_smb/client.rb +26 -4
- data/lib/ruby_smb/client/authentication.rb +43 -25
- data/lib/ruby_smb/client/echo.rb +20 -2
- data/lib/ruby_smb/client/negotiation.rb +27 -12
- data/lib/ruby_smb/client/tree_connect.rb +20 -14
- data/lib/ruby_smb/error.rb +40 -1
- data/lib/ruby_smb/generic_packet.rb +33 -4
- data/lib/ruby_smb/smb1/dcerpc.rb +7 -2
- data/lib/ruby_smb/smb1/file.rb +60 -11
- data/lib/ruby_smb/smb1/packet/close_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/empty_packet.rb +7 -0
- data/lib/ruby_smb/smb1/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/negotiate_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/negotiate_response.rb +3 -7
- data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +4 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/read_andx_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/read_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_request.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/trans/request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +13 -3
- data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/write_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/pipe.rb +8 -3
- data/lib/ruby_smb/smb1/tree.rb +40 -2
- data/lib/ruby_smb/smb2/dcerpc.rb +7 -2
- data/lib/ruby_smb/smb2/file.rb +97 -1
- data/lib/ruby_smb/smb2/packet/close_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/create_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/create_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/error_packet.rb +7 -0
- data/lib/ruby_smb/smb2/packet/ioctl_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/ioctl_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/query_directory_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/query_directory_response.rb +8 -2
- data/lib/ruby_smb/smb2/packet/read_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/read_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/set_info_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/set_info_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -2
- data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/write_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/write_response.rb +2 -1
- data/lib/ruby_smb/smb2/pipe.rb +9 -9
- data/lib/ruby_smb/smb2/tree.rb +44 -6
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +123 -11
- data/spec/lib/ruby_smb/generic_packet_spec.rb +52 -4
- data/spec/lib/ruby_smb/smb1/file_spec.rb +182 -1
- data/spec/lib/ruby_smb/smb1/packet/{error_packet_spec.rb → empty_packet_spec.rb} +21 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +40 -0
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +63 -2
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +44 -7
- data/spec/lib/ruby_smb/smb2/file_spec.rb +295 -2
- data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +51 -0
- data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +8 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +8 -0
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +69 -3
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +214 -0
- metadata +6 -4
- metadata.gz.sig +0 -0
@@ -4,15 +4,13 @@ module RubySMB
|
|
4
4
|
# An SMB2 TreeDisconnectRequest Packet as defined in
|
5
5
|
# [2.2.11 SMB2 TREE_DISCONNECT Request](https://msdn.microsoft.com/en-us/library/cc246500.aspx)
|
6
6
|
class TreeDisconnectRequest < RubySMB::GenericPacket
|
7
|
+
COMMAND = RubySMB::SMB2::Commands::TREE_DISCONNECT
|
8
|
+
|
7
9
|
endian :little
|
8
10
|
smb2_header :smb2_header
|
9
11
|
uint16 :structure_size, label: 'Structure Size', initial_value: 4
|
10
12
|
uint16 :reserved, label: 'Reserved', initial_value: 0
|
11
13
|
|
12
|
-
def initialize_instance
|
13
|
-
super
|
14
|
-
smb2_header.command = RubySMB::SMB2::Commands::TREE_DISCONNECT
|
15
|
-
end
|
16
14
|
end
|
17
15
|
end
|
18
16
|
end
|
@@ -4,13 +4,14 @@ module RubySMB
|
|
4
4
|
# An SMB2 TreeDisconnectResponse Packet as defined in
|
5
5
|
# [2.2.12 SMB2 TREE_DISCONNECT Response](https://msdn.microsoft.com/en-us/library/cc246501.aspx)
|
6
6
|
class TreeDisconnectResponse < RubySMB::GenericPacket
|
7
|
+
COMMAND = RubySMB::SMB2::Commands::TREE_DISCONNECT
|
8
|
+
|
7
9
|
endian :little
|
8
10
|
smb2_header :smb2_header
|
9
11
|
uint16 :structure_size, label: 'Structure Size', initial_value: 4
|
10
12
|
|
11
13
|
def initialize_instance
|
12
14
|
super
|
13
|
-
smb2_header.command = RubySMB::SMB2::Commands::TREE_DISCONNECT
|
14
15
|
smb2_header.flags.reply = 1
|
15
16
|
end
|
16
17
|
end
|
@@ -4,6 +4,8 @@ module RubySMB
|
|
4
4
|
# An SMB2 Write Request Packet as defined in
|
5
5
|
# [2.2.21 SMB2 WRITE Request](https://msdn.microsoft.com/en-us/library/cc246532.aspx)
|
6
6
|
class WriteRequest < RubySMB::GenericPacket
|
7
|
+
COMMAND = RubySMB::SMB2::Commands::WRITE
|
8
|
+
|
7
9
|
endian :little
|
8
10
|
|
9
11
|
smb2_header :smb2_header
|
@@ -19,10 +21,6 @@ module RubySMB
|
|
19
21
|
uint32 :flags, label: 'Flags'
|
20
22
|
string :buffer, label: 'Write Data Buffer'
|
21
23
|
|
22
|
-
def initialize_instance
|
23
|
-
super
|
24
|
-
smb2_header.command = RubySMB::SMB2::Commands::WRITE
|
25
|
-
end
|
26
24
|
end
|
27
25
|
end
|
28
26
|
end
|
@@ -4,6 +4,8 @@ module RubySMB
|
|
4
4
|
# An SMB2 Write Response Packet as defined in
|
5
5
|
# [2.2.22 SMB2 WRITE Response](https://msdn.microsoft.com/en-us/library/cc246533.aspx)
|
6
6
|
class WriteResponse < RubySMB::GenericPacket
|
7
|
+
COMMAND = RubySMB::SMB2::Commands::WRITE
|
8
|
+
|
7
9
|
endian :little
|
8
10
|
|
9
11
|
smb2_header :smb2_header
|
@@ -17,7 +19,6 @@ module RubySMB
|
|
17
19
|
|
18
20
|
def initialize_instance
|
19
21
|
super
|
20
|
-
smb2_header.command = RubySMB::SMB2::Commands::WRITE
|
21
22
|
smb2_header.flags.reply = 1
|
22
23
|
end
|
23
24
|
end
|
data/lib/ruby_smb/smb2/pipe.rb
CHANGED
@@ -14,7 +14,7 @@ module RubySMB
|
|
14
14
|
#
|
15
15
|
# @param peek_size [Integer] Amount of data to peek
|
16
16
|
# @return [RubySMB::SMB2::Packet::IoctlResponse]
|
17
|
-
# @raise [RubySMB::Error::InvalidPacket] if not a valid
|
17
|
+
# @raise [RubySMB::Error::InvalidPacket] if not a valid FIoctlResponse response
|
18
18
|
# @raise [RubySMB::Error::UnexpectedStatusCode] If status is not STATUS_BUFFER_OVERFLOW or STATUS_SUCCESS
|
19
19
|
def peek(peek_size: 0)
|
20
20
|
packet = RubySMB::SMB2::Packet::IoctlRequest.new
|
@@ -24,19 +24,19 @@ module RubySMB
|
|
24
24
|
packet.max_output_response = 16 + peek_size
|
25
25
|
packet = set_header_fields(packet)
|
26
26
|
raw_response = @tree.client.send_recv(packet)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
response = RubySMB::SMB2::Packet::IoctlResponse.read(raw_response)
|
28
|
+
unless response.valid?
|
29
|
+
raise RubySMB::Error::InvalidPacket.new(
|
30
|
+
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
31
|
+
expected_cmd: RubySMB::SMB2::Packet::IoctlResponse::COMMAND,
|
32
|
+
received_proto: response.smb2_header.protocol,
|
33
|
+
received_cmd: response.smb2_header.command
|
34
|
+
)
|
31
35
|
end
|
32
36
|
|
33
37
|
unless response.status_code == WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW or response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
34
38
|
raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
|
35
39
|
end
|
36
|
-
|
37
|
-
unless response.smb2_header.command == RubySMB::SMB2::Commands::IOCTL
|
38
|
-
raise RubySMB::Error::InvalidPacket, 'Not an IoctlResponse packet'
|
39
|
-
end
|
40
40
|
response
|
41
41
|
end
|
42
42
|
|
data/lib/ruby_smb/smb2/tree.rb
CHANGED
@@ -34,11 +34,20 @@ module RubySMB
|
|
34
34
|
# Disconnects this Tree from the current session
|
35
35
|
#
|
36
36
|
# @return [WindowsError::ErrorCode] the NTStatus sent back by the server.
|
37
|
+
# @raise [RubySMB::Error::InvalidPacket] if the response is not a TreeDisconnectResponse packet
|
37
38
|
def disconnect!
|
38
39
|
request = RubySMB::SMB2::Packet::TreeDisconnectRequest.new
|
39
40
|
request = set_header_fields(request)
|
40
41
|
raw_response = client.send_recv(request)
|
41
42
|
response = RubySMB::SMB2::Packet::TreeDisconnectResponse.read(raw_response)
|
43
|
+
unless response.valid?
|
44
|
+
raise RubySMB::Error::InvalidPacket.new(
|
45
|
+
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
46
|
+
expected_cmd: RubySMB::SMB2::Packet::TreeDisconnectResponse::COMMAND,
|
47
|
+
received_proto: response.smb2_header.protocol,
|
48
|
+
received_cmd: response.smb2_header.command
|
49
|
+
)
|
50
|
+
end
|
42
51
|
response.status_code
|
43
52
|
end
|
44
53
|
|
@@ -89,9 +98,16 @@ module RubySMB
|
|
89
98
|
|
90
99
|
raw_response = client.send_recv(create_request)
|
91
100
|
response = RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
|
92
|
-
|
93
|
-
|
94
|
-
|
101
|
+
unless response.valid?
|
102
|
+
raise RubySMB::Error::InvalidPacket.new(
|
103
|
+
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
104
|
+
expected_cmd: RubySMB::SMB2::Packet::CreateResponse::COMMAND,
|
105
|
+
received_proto: response.smb2_header.protocol,
|
106
|
+
received_cmd: response.smb2_header.command
|
107
|
+
)
|
108
|
+
end
|
109
|
+
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
110
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
|
95
111
|
end
|
96
112
|
|
97
113
|
case @share_type
|
@@ -102,7 +118,7 @@ module RubySMB
|
|
102
118
|
# when 0x03
|
103
119
|
# it's a printer!
|
104
120
|
else
|
105
|
-
raise RubySMB::Error::RubySMBError
|
121
|
+
raise RubySMB::Error::RubySMBError, 'Unsupported share type'
|
106
122
|
end
|
107
123
|
end
|
108
124
|
|
@@ -116,6 +132,7 @@ module RubySMB
|
|
116
132
|
# @param pattern [String] search pattern
|
117
133
|
# @param type [Class] file information class
|
118
134
|
# @return [Array] array of directory structures
|
135
|
+
# @raise [RubySMB::Error::InvalidPacket] if the response is not a QueryDirectoryResponse packet
|
119
136
|
def list(directory: nil, pattern: '*', type: RubySMB::Fscc::FileInformation::FileIdFullDirectoryInformation)
|
120
137
|
create_response = open_directory(directory: directory)
|
121
138
|
file_id = create_response.file_id
|
@@ -133,13 +150,20 @@ module RubySMB
|
|
133
150
|
loop do
|
134
151
|
response = client.send_recv(directory_request)
|
135
152
|
directory_response = RubySMB::SMB2::Packet::QueryDirectoryResponse.read(response)
|
153
|
+
unless directory_response.valid?
|
154
|
+
raise RubySMB::Error::InvalidPacket.new(
|
155
|
+
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
156
|
+
expected_cmd: RubySMB::SMB2::Packet::QueryDirectoryResponse::COMMAND,
|
157
|
+
received_proto: directory_response.smb2_header.protocol,
|
158
|
+
received_cmd: directory_response.smb2_header.command
|
159
|
+
)
|
160
|
+
end
|
136
161
|
|
137
162
|
status_code = directory_response.smb2_header.nt_status.to_nt_status
|
138
163
|
|
139
164
|
break if status_code == WindowsError::NTStatus::STATUS_NO_MORE_FILES
|
140
165
|
|
141
166
|
unless status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
142
|
-
|
143
167
|
raise RubySMB::Error::UnexpectedStatusCode, status_code.to_s
|
144
168
|
end
|
145
169
|
|
@@ -162,6 +186,7 @@ module RubySMB
|
|
162
186
|
# @param write [Boolean] whether to request write access
|
163
187
|
# @param delete [Boolean] whether to request delete access
|
164
188
|
# @return [RubySMB::SMB2::Packet::CreateResponse] the response packet returned from the server
|
189
|
+
# @raise [RubySMB::Error::InvalidPacket] if the response is not a CreateResponse packet
|
165
190
|
def open_directory(directory: nil, disposition: RubySMB::Dispositions::FILE_OPEN,
|
166
191
|
impersonation: RubySMB::ImpersonationLevels::SEC_IMPERSONATE,
|
167
192
|
read: true, write: false, delete: false)
|
@@ -169,7 +194,20 @@ module RubySMB
|
|
169
194
|
create_request = open_directory_packet(directory: directory, disposition: disposition,
|
170
195
|
impersonation: impersonation, read: read, write: write, delete: delete)
|
171
196
|
raw_response = client.send_recv(create_request)
|
172
|
-
RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
|
197
|
+
response = RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
|
198
|
+
unless response.valid?
|
199
|
+
raise RubySMB::Error::InvalidPacket.new(
|
200
|
+
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
201
|
+
expected_cmd: RubySMB::SMB2::Packet::CreateResponse::COMMAND,
|
202
|
+
received_proto: response.smb2_header.protocol,
|
203
|
+
received_cmd: response.smb2_header.command
|
204
|
+
)
|
205
|
+
end
|
206
|
+
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
207
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
|
208
|
+
end
|
209
|
+
|
210
|
+
response
|
173
211
|
end
|
174
212
|
|
175
213
|
# Creates the Packet for the #open_directory method.
|
data/lib/ruby_smb/version.rb
CHANGED
@@ -9,6 +9,7 @@ RSpec.describe RubySMB::Client do
|
|
9
9
|
let(:smb1_client) { described_class.new(dispatcher, smb2: false, username: username, password: password) }
|
10
10
|
let(:smb2_client) { described_class.new(dispatcher, smb1: false, username: username, password: password) }
|
11
11
|
let(:empty_packet) { RubySMB::SMB1::Packet::EmptyPacket.new }
|
12
|
+
let(:error_packet) { RubySMB::SMB2::Packet::ErrorPacket.new }
|
12
13
|
|
13
14
|
describe '#initialize' do
|
14
15
|
it 'should raise an ArgumentError without a valid dispatcher' do
|
@@ -153,6 +154,94 @@ RSpec.describe RubySMB::Client do
|
|
153
154
|
end
|
154
155
|
end
|
155
156
|
|
157
|
+
describe '#logoff!' do
|
158
|
+
context 'with SMB1' do
|
159
|
+
let(:raw_response) { double('Raw response') }
|
160
|
+
let(:logoff_response) {
|
161
|
+
RubySMB::SMB1::Packet::LogoffResponse.new(smb_header: {:command => RubySMB::SMB1::Commands::SMB_COM_LOGOFF} )
|
162
|
+
}
|
163
|
+
before :example do
|
164
|
+
allow(smb1_client).to receive(:send_recv).and_return(raw_response)
|
165
|
+
allow(RubySMB::SMB1::Packet::LogoffResponse).to receive(:read).and_return(logoff_response)
|
166
|
+
allow(smb1_client).to receive(:wipe_state!)
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'creates a LogoffRequest packet' do
|
170
|
+
expect(RubySMB::SMB1::Packet::LogoffRequest).to receive(:new).and_call_original
|
171
|
+
smb1_client.logoff!
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'calls #send_recv' do
|
175
|
+
expect(smb1_client).to receive(:send_recv)
|
176
|
+
smb1_client.logoff!
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'reads the raw response as a LogoffResponse packet' do
|
180
|
+
expect(RubySMB::SMB1::Packet::LogoffResponse).to receive(:read).with(raw_response)
|
181
|
+
smb1_client.logoff!
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'raise an InvalidPacket exception when the response is an empty packet' do
|
185
|
+
allow(RubySMB::SMB1::Packet::LogoffResponse).to receive(:read).and_return(RubySMB::SMB1::Packet::EmptyPacket.new)
|
186
|
+
expect {smb1_client.logoff!}.to raise_error(RubySMB::Error::InvalidPacket)
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'raise an InvalidPacket exception when the response is not valid' do
|
190
|
+
allow(logoff_response).to receive(:valid?).and_return(false)
|
191
|
+
expect {smb1_client.logoff!}.to raise_error(RubySMB::Error::InvalidPacket)
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'calls #wipe_state!' do
|
195
|
+
expect(smb1_client).to receive(:wipe_state!)
|
196
|
+
smb1_client.logoff!
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'returns the expected status code' do
|
200
|
+
logoff_response.smb_header.nt_status = WindowsError::NTStatus::STATUS_PENDING.value
|
201
|
+
allow(RubySMB::SMB1::Packet::LogoffResponse).to receive(:read).and_return(logoff_response)
|
202
|
+
expect(smb1_client.logoff!).to eq(WindowsError::NTStatus::STATUS_PENDING)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
context 'with SMB2' do
|
207
|
+
let(:raw_response) { double('Raw response') }
|
208
|
+
let(:logoff_response) {
|
209
|
+
RubySMB::SMB2::Packet::LogoffResponse.new(smb_header: {:command => RubySMB::SMB2::Commands::LOGOFF} )
|
210
|
+
}
|
211
|
+
before :example do
|
212
|
+
allow(smb2_client).to receive(:send_recv).and_return(raw_response)
|
213
|
+
allow(RubySMB::SMB2::Packet::LogoffResponse).to receive(:read).and_return(logoff_response)
|
214
|
+
allow(smb2_client).to receive(:wipe_state!)
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'creates a LogoffRequest packet' do
|
218
|
+
expect(RubySMB::SMB2::Packet::LogoffRequest).to receive(:new).and_call_original
|
219
|
+
smb2_client.logoff!
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'calls #send_recv' do
|
223
|
+
expect(smb2_client).to receive(:send_recv)
|
224
|
+
smb2_client.logoff!
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'reads the raw response as a LogoffResponse packet' do
|
228
|
+
expect(RubySMB::SMB2::Packet::LogoffResponse).to receive(:read).with(raw_response)
|
229
|
+
smb2_client.logoff!
|
230
|
+
end
|
231
|
+
|
232
|
+
it 'raise an InvalidPacket exception when the response is an error packet' do
|
233
|
+
allow(RubySMB::SMB2::Packet::LogoffResponse).to receive(:read).and_return(RubySMB::SMB2::Packet::ErrorPacket.new)
|
234
|
+
expect {smb2_client.logoff!}.to raise_error(RubySMB::Error::InvalidPacket)
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'raise an InvalidPacket exception when the response is not a LOGOFF command' do
|
238
|
+
logoff_response.smb2_header.command = RubySMB::SMB2::Commands::ECHO
|
239
|
+
allow(RubySMB::SMB2::Packet::LogoffResponse).to receive(:read).and_return(logoff_response)
|
240
|
+
expect {smb2_client.logoff!}.to raise_error(RubySMB::Error::InvalidPacket)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
156
245
|
context 'NetBIOS Session Service' do
|
157
246
|
describe '#session_request' do
|
158
247
|
let(:session_header) { RubySMB::Nbss::SessionHeader.new }
|
@@ -197,6 +286,11 @@ RSpec.describe RubySMB::Client do
|
|
197
286
|
allow(dispatcher).to receive(:recv_packet).and_return(negative_session_response.to_binary_s)
|
198
287
|
expect { client.session_request }.to raise_error(RubySMB::Error::NetBiosSessionService)
|
199
288
|
end
|
289
|
+
|
290
|
+
it 'raises an InvalidPacket exception when an error occurs while reading' do
|
291
|
+
allow(RubySMB::Nbss::SessionHeader).to receive(:read).and_raise(IOError)
|
292
|
+
expect { client.session_request }.to raise_error(RubySMB::Error::InvalidPacket)
|
293
|
+
end
|
200
294
|
end
|
201
295
|
|
202
296
|
describe '#session_request_packet' do
|
@@ -332,10 +426,15 @@ RSpec.describe RubySMB::Client do
|
|
332
426
|
expect(smb1_client.negotiate_response(smb1_extended_response_raw)).to eq smb1_extended_response
|
333
427
|
end
|
334
428
|
|
335
|
-
it 'raises an exception if the
|
429
|
+
it 'raises an exception if the response is not a SMB packet' do
|
336
430
|
expect { smb1_client.negotiate_response(random_junk) }.to raise_error(RubySMB::Error::InvalidPacket)
|
337
431
|
end
|
338
432
|
|
433
|
+
it 'raises an InvalidPacket error if the response is not a valid response' do
|
434
|
+
empty_packet.smb_header.command = RubySMB::SMB2::Commands::NEGOTIATE
|
435
|
+
expect { smb1_client.negotiate_response(empty_packet.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
|
436
|
+
end
|
437
|
+
|
339
438
|
it 'considers the response invalid if it is not an actual Negotiate Response' do
|
340
439
|
bogus_response = smb1_extended_response
|
341
440
|
bogus_response.smb_header.command = 0xff
|
@@ -357,6 +456,12 @@ RSpec.describe RubySMB::Client do
|
|
357
456
|
it 'raises an exception if the Response is invalid' do
|
358
457
|
expect { smb2_client.negotiate_response(random_junk) }.to raise_error(RubySMB::Error::InvalidPacket)
|
359
458
|
end
|
459
|
+
|
460
|
+
it 'considers the response invalid if it is not an actual Negotiate Response' do
|
461
|
+
bogus_response = smb2_response
|
462
|
+
bogus_response.smb2_header.command = RubySMB::SMB2::Commands::ECHO
|
463
|
+
expect { smb2_client.negotiate_response(bogus_response.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
|
464
|
+
end
|
360
465
|
end
|
361
466
|
|
362
467
|
context 'with SMB1 and SMB2 enabled' do
|
@@ -624,7 +729,7 @@ RSpec.describe RubySMB::Client do
|
|
624
729
|
expect { smb1_client.smb1_ntlmssp_challenge_packet(response.to_binary_s) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
625
730
|
end
|
626
731
|
|
627
|
-
it '
|
732
|
+
it 'raise an InvalidPacket exception when the response is not valid' do
|
628
733
|
expect { smb1_client.smb1_ntlmssp_challenge_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
|
629
734
|
end
|
630
735
|
end
|
@@ -645,7 +750,7 @@ RSpec.describe RubySMB::Client do
|
|
645
750
|
expect(smb1_client.smb1_ntlmssp_final_packet(response.to_binary_s)).to eq response
|
646
751
|
end
|
647
752
|
|
648
|
-
it '
|
753
|
+
it 'raise an InvalidPacket exception when the response is not valid' do
|
649
754
|
expect { smb1_client.smb1_ntlmssp_final_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
|
650
755
|
end
|
651
756
|
end
|
@@ -717,12 +822,7 @@ RSpec.describe RubySMB::Client do
|
|
717
822
|
expect(smb1_client.smb1_anonymous_auth_response(anonymous_response.to_binary_s)).to eq anonymous_response
|
718
823
|
end
|
719
824
|
|
720
|
-
it '
|
721
|
-
empty_packet.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
|
722
|
-
expect(smb1_client.smb1_anonymous_auth_response(empty_packet.to_binary_s)).to eq empty_packet
|
723
|
-
end
|
724
|
-
|
725
|
-
it 'raises an InvalidPacket error if the command is wrong' do
|
825
|
+
it 'raise an InvalidPacket exception when the response is not valid' do
|
726
826
|
anonymous_response.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_NEGOTIATE
|
727
827
|
expect { smb1_client.smb1_anonymous_auth_response(anonymous_response.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
|
728
828
|
end
|
@@ -829,7 +929,7 @@ RSpec.describe RubySMB::Client do
|
|
829
929
|
expect { smb2_client.smb2_ntlmssp_challenge_packet(response.to_binary_s) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
830
930
|
end
|
831
931
|
|
832
|
-
it '
|
932
|
+
it 'raise an InvalidPacket exception when the response is not valid' do
|
833
933
|
expect { smb2_client.smb2_ntlmssp_challenge_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
|
834
934
|
end
|
835
935
|
end
|
@@ -888,7 +988,7 @@ RSpec.describe RubySMB::Client do
|
|
888
988
|
expect(smb2_client.smb2_ntlmssp_final_packet(response.to_binary_s)).to eq response
|
889
989
|
end
|
890
990
|
|
891
|
-
it '
|
991
|
+
it 'raise an InvalidPacket exception when the response is not valid' do
|
892
992
|
expect { smb2_client.smb2_ntlmssp_final_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
|
893
993
|
end
|
894
994
|
end
|
@@ -1199,6 +1299,12 @@ RSpec.describe RubySMB::Client do
|
|
1199
1299
|
expect(smb1_client).to receive(:send_recv).and_return(echo_response.to_binary_s)
|
1200
1300
|
expect(smb1_client.echo).to eq WindowsError::NTStatus::STATUS_ABANDONED
|
1201
1301
|
end
|
1302
|
+
|
1303
|
+
it 'raise an InvalidPacket exception when the response is not valid' do
|
1304
|
+
echo_response.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
|
1305
|
+
allow(smb1_client).to receive(:send_recv).and_return(echo_response.to_binary_s)
|
1306
|
+
expect { smb1_client.echo }.to raise_error(RubySMB::Error::InvalidPacket)
|
1307
|
+
end
|
1202
1308
|
end
|
1203
1309
|
|
1204
1310
|
context 'with SMB2' do
|
@@ -1210,6 +1316,12 @@ RSpec.describe RubySMB::Client do
|
|
1210
1316
|
expect(smb2_client).to receive(:send_recv).with(echo_request).and_return(echo_response.to_binary_s)
|
1211
1317
|
expect(smb2_client.smb2_echo).to eq echo_response
|
1212
1318
|
end
|
1319
|
+
|
1320
|
+
it 'raise an InvalidPacket exception when the response is not valid' do
|
1321
|
+
echo_response.smb2_header.command = RubySMB::SMB2::Commands::SESSION_SETUP
|
1322
|
+
allow(smb2_client).to receive(:send_recv).and_return(echo_response.to_binary_s)
|
1323
|
+
expect { smb2_client.smb2_echo }.to raise_error(RubySMB::Error::InvalidPacket)
|
1324
|
+
end
|
1213
1325
|
end
|
1214
1326
|
end
|
1215
1327
|
|
@@ -63,8 +63,13 @@ RSpec.describe RubySMB::GenericPacket do
|
|
63
63
|
expect(RubySMB::SMB1::Packet::NegotiateResponse.read(smb1_error_packet.to_binary_s)).to be_a RubySMB::SMB1::Packet::EmptyPacket
|
64
64
|
end
|
65
65
|
|
66
|
-
it '
|
67
|
-
expect{RubySMB::SMB1::Packet::NegotiateResponse.read('a')}.to raise_error(
|
66
|
+
it 'raises an InvaliPacket exception if it is not a valid error packet either' do
|
67
|
+
expect{RubySMB::SMB1::Packet::NegotiateResponse.read('a')}.to raise_error(RubySMB::Error::InvalidPacket)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'sets the EmptyPacket#original_command attribute to the original COMMAND' do
|
71
|
+
packet = RubySMB::SMB1::Packet::NegotiateResponse.read(smb1_error_packet.to_binary_s)
|
72
|
+
expect(packet.original_command).to eq RubySMB::SMB1::Packet::NegotiateResponse::COMMAND
|
68
73
|
end
|
69
74
|
end
|
70
75
|
|
@@ -75,8 +80,51 @@ RSpec.describe RubySMB::GenericPacket do
|
|
75
80
|
expect(RubySMB::SMB2::Packet::NegotiateResponse.read(smb2_error_packet.to_binary_s)).to be_a RubySMB::SMB2::Packet::ErrorPacket
|
76
81
|
end
|
77
82
|
|
78
|
-
it '
|
79
|
-
expect{RubySMB::SMB2::Packet::NegotiateResponse.read('a')}.to raise_error(
|
83
|
+
it 'raises an InvaliPacket exception if it is not a valid error packet either' do
|
84
|
+
expect{RubySMB::SMB2::Packet::NegotiateResponse.read('a')}.to raise_error(RubySMB::Error::InvalidPacket)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'sets the ErrorPacket#original_command attribute to the original COMMAND' do
|
88
|
+
packet = RubySMB::SMB2::Packet::NegotiateResponse.read(smb2_error_packet.to_binary_s)
|
89
|
+
expect(packet.original_command).to eq RubySMB::SMB2::Packet::NegotiateResponse::COMMAND
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#valid?' do
|
95
|
+
context 'when reading an SMB1 packet' do
|
96
|
+
let(:packet) { RubySMB::SMB1::Packet::NegotiateResponse.new }
|
97
|
+
|
98
|
+
it 'returns true if the packet protocol ID and header command are valid' do
|
99
|
+
expect(packet).to be_valid
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'returns false if the packet protocol ID is wrong' do
|
103
|
+
packet.smb_header.protocol = RubySMB::SMB2::SMB2_PROTOCOL_ID
|
104
|
+
expect(packet).to_not be_valid
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'returns false if the packet header command is wrong' do
|
108
|
+
packet.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_TREE_CONNECT
|
109
|
+
expect(packet).to_not be_valid
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'when reading an SMB2 packet' do
|
114
|
+
let(:packet) { RubySMB::SMB2::Packet::NegotiateResponse.new }
|
115
|
+
|
116
|
+
it 'returns true if the packet protocol ID and header command are valid' do
|
117
|
+
expect(packet).to be_valid
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'returns false if the packet protocol ID is wrong' do
|
121
|
+
packet.smb2_header.protocol = RubySMB::SMB1::SMB_PROTOCOL_ID
|
122
|
+
expect(packet).to_not be_valid
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'returns false if the packet header command is wrong' do
|
126
|
+
packet.smb2_header.command = RubySMB::SMB2::Commands::TREE_CONNECT
|
127
|
+
expect(packet).to_not be_valid
|
80
128
|
end
|
81
129
|
end
|
82
130
|
end
|