ruby_smb 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/ruby_smb/client.rb +26 -4
- data/lib/ruby_smb/client/authentication.rb +43 -25
- data/lib/ruby_smb/client/echo.rb +20 -2
- data/lib/ruby_smb/client/negotiation.rb +27 -12
- data/lib/ruby_smb/client/tree_connect.rb +20 -14
- data/lib/ruby_smb/error.rb +40 -1
- data/lib/ruby_smb/generic_packet.rb +33 -4
- data/lib/ruby_smb/smb1/dcerpc.rb +7 -2
- data/lib/ruby_smb/smb1/file.rb +60 -11
- data/lib/ruby_smb/smb1/packet/close_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/empty_packet.rb +7 -0
- data/lib/ruby_smb/smb1/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/negotiate_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/negotiate_response.rb +3 -7
- data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +4 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/read_andx_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/read_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_request.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/trans/request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +13 -3
- data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/write_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/pipe.rb +8 -3
- data/lib/ruby_smb/smb1/tree.rb +40 -2
- data/lib/ruby_smb/smb2/dcerpc.rb +7 -2
- data/lib/ruby_smb/smb2/file.rb +97 -1
- data/lib/ruby_smb/smb2/packet/close_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/create_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/create_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/error_packet.rb +7 -0
- data/lib/ruby_smb/smb2/packet/ioctl_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/ioctl_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/query_directory_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/query_directory_response.rb +8 -2
- data/lib/ruby_smb/smb2/packet/read_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/read_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/set_info_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/set_info_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -2
- data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/write_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/write_response.rb +2 -1
- data/lib/ruby_smb/smb2/pipe.rb +9 -9
- data/lib/ruby_smb/smb2/tree.rb +44 -6
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +123 -11
- data/spec/lib/ruby_smb/generic_packet_spec.rb +52 -4
- data/spec/lib/ruby_smb/smb1/file_spec.rb +182 -1
- data/spec/lib/ruby_smb/smb1/packet/{error_packet_spec.rb → empty_packet_spec.rb} +21 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +40 -0
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +63 -2
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +44 -7
- data/spec/lib/ruby_smb/smb2/file_spec.rb +295 -2
- data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +51 -0
- data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +8 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +8 -0
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +69 -3
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +214 -0
- metadata +6 -4
- metadata.gz.sig +0 -0
@@ -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
|