ruby_smb 2.0.2 → 2.0.7
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/examples/anonymous_auth.rb +3 -3
- data/examples/append_file.rb +10 -8
- data/examples/authenticate.rb +9 -5
- data/examples/delete_file.rb +8 -6
- data/examples/enum_registry_key.rb +5 -4
- data/examples/enum_registry_values.rb +5 -4
- data/examples/list_directory.rb +8 -6
- data/examples/negotiate_with_netbios_service.rb +9 -5
- data/examples/net_share_enum_all.rb +6 -4
- data/examples/pipes.rb +11 -12
- data/examples/query_service_status.rb +64 -0
- data/examples/read_file.rb +8 -6
- data/examples/read_registry_key_value.rb +6 -5
- data/examples/rename_file.rb +9 -7
- data/examples/tree_connect.rb +7 -5
- data/examples/write_file.rb +9 -7
- data/lib/ruby_smb/client.rb +81 -48
- data/lib/ruby_smb/client/authentication.rb +5 -10
- data/lib/ruby_smb/client/echo.rb +2 -4
- data/lib/ruby_smb/client/negotiation.rb +3 -4
- data/lib/ruby_smb/client/tree_connect.rb +2 -4
- data/lib/ruby_smb/client/utils.rb +16 -10
- data/lib/ruby_smb/client/winreg.rb +1 -1
- data/lib/ruby_smb/dcerpc.rb +4 -0
- data/lib/ruby_smb/dcerpc/error.rb +3 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +306 -44
- data/lib/ruby_smb/dcerpc/netlogon.rb +101 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb +37 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request.rb +37 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request.rb +32 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/request.rb +19 -0
- data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +9 -6
- data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
- data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +98 -17
- data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
- data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +4 -4
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +7 -6
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +10 -10
- data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
- data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
- data/lib/ruby_smb/dispatcher/base.rb +1 -1
- data/lib/ruby_smb/dispatcher/socket.rb +1 -1
- data/lib/ruby_smb/error.rb +21 -5
- data/lib/ruby_smb/field/stringz16.rb +17 -1
- data/lib/ruby_smb/generic_packet.rb +11 -1
- data/lib/ruby_smb/nbss/session_header.rb +4 -4
- data/lib/ruby_smb/smb1/file.rb +10 -25
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +1 -2
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +1 -13
- data/lib/ruby_smb/smb1/pipe.rb +8 -6
- data/lib/ruby_smb/smb1/tree.rb +13 -9
- data/lib/ruby_smb/smb2/file.rb +33 -33
- data/lib/ruby_smb/smb2/pipe.rb +9 -6
- data/lib/ruby_smb/smb2/tree.rb +21 -11
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +174 -68
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1396 -77
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request_spec.rb +69 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response_spec.rb +53 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request_spec.rb +69 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response_spec.rb +37 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request_spec.rb +45 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response_spec.rb +37 -0
- data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +49 -12
- data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +0 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +9 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +17 -17
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +11 -23
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +227 -41
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +10 -10
- data/spec/lib/ruby_smb/error_spec.rb +34 -5
- data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
- data/spec/lib/ruby_smb/generic_packet_spec.rb +7 -0
- data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
- data/spec/lib/ruby_smb/smb1/file_spec.rb +2 -4
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +0 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +0 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/open2_response_spec.rb +0 -5
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +0 -6
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +30 -5
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +22 -0
- data/spec/lib/ruby_smb/smb2/file_spec.rb +61 -9
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +9 -5
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +58 -1
- metadata +107 -18
- metadata.gz.sig +0 -0
data/lib/ruby_smb/smb1/tree.rb
CHANGED
@@ -49,13 +49,20 @@ module RubySMB
|
|
49
49
|
raise RubySMB::Error::InvalidPacket.new(
|
50
50
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
51
51
|
expected_cmd: RubySMB::SMB1::Packet::TreeDisconnectResponse::COMMAND,
|
52
|
-
|
53
|
-
received_cmd: response.smb_header.command
|
52
|
+
packet: response
|
54
53
|
)
|
55
54
|
end
|
56
55
|
response.status_code
|
57
56
|
end
|
58
57
|
|
58
|
+
def open_pipe(opts)
|
59
|
+
# Make sure we don't modify the caller's hash options
|
60
|
+
opts = opts.dup
|
61
|
+
opts[:filename] = opts[:filename].dup
|
62
|
+
opts[:filename].prepend('\\') unless opts[:filename].start_with?('\\')
|
63
|
+
open_file(opts)
|
64
|
+
end
|
65
|
+
|
59
66
|
# Open a file on the remote share.
|
60
67
|
#
|
61
68
|
# @example
|
@@ -135,15 +142,14 @@ module RubySMB
|
|
135
142
|
raise RubySMB::Error::InvalidPacket.new(
|
136
143
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
137
144
|
expected_cmd: RubySMB::SMB1::Packet::NtCreateAndxResponse::COMMAND,
|
138
|
-
|
139
|
-
received_cmd: response.smb_header.command
|
145
|
+
packet: response
|
140
146
|
)
|
141
147
|
end
|
142
148
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
143
149
|
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
144
150
|
end
|
145
151
|
|
146
|
-
case response.parameter_block.resource_type
|
152
|
+
case response.parameter_block.resource_type
|
147
153
|
when RubySMB::SMB1::ResourceType::BYTE_MODE_PIPE, RubySMB::SMB1::ResourceType::MESSAGE_MODE_PIPE
|
148
154
|
RubySMB::SMB1::Pipe.new(name: filename, tree: self, response: response)
|
149
155
|
when RubySMB::SMB1::ResourceType::DISK
|
@@ -195,8 +201,7 @@ module RubySMB
|
|
195
201
|
raise RubySMB::Error::InvalidPacket.new(
|
196
202
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
197
203
|
expected_cmd: RubySMB::SMB1::Packet::Trans2::FindFirst2Response::COMMAND,
|
198
|
-
|
199
|
-
received_cmd: response.smb_header.command
|
204
|
+
packet: response
|
200
205
|
)
|
201
206
|
end
|
202
207
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
@@ -230,8 +235,7 @@ module RubySMB
|
|
230
235
|
raise RubySMB::Error::InvalidPacket.new(
|
231
236
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
232
237
|
expected_cmd: RubySMB::SMB1::Packet::Trans2::FindNext2Response::COMMAND,
|
233
|
-
|
234
|
-
received_cmd: response.smb_header.command
|
238
|
+
packet: response
|
235
239
|
)
|
236
240
|
end
|
237
241
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
data/lib/ruby_smb/smb2/file.rb
CHANGED
@@ -95,8 +95,7 @@ module RubySMB
|
|
95
95
|
raise RubySMB::Error::InvalidPacket.new(
|
96
96
|
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
97
97
|
expected_cmd: RubySMB::SMB2::Packet::CloseResponse::COMMAND,
|
98
|
-
|
99
|
-
received_cmd: response.smb2_header.command
|
98
|
+
packet: response
|
100
99
|
)
|
101
100
|
end
|
102
101
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
@@ -115,21 +114,22 @@ module RubySMB
|
|
115
114
|
# @raise [RubySMB::Error::InvalidPacket] if the response is not a ReadResponse packet
|
116
115
|
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
|
117
116
|
def read(bytes: size, offset: 0)
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
117
|
+
max_read = tree.client.server_max_read_size
|
118
|
+
max_read = 65536 unless tree.client.server_supports_multi_credit
|
119
|
+
atomic_read_size = [bytes, max_read].min
|
120
|
+
credit_charge = 0
|
121
|
+
if tree.client.server_supports_multi_credit
|
122
|
+
credit_charge = (atomic_read_size - 1) / 65536 + 1
|
123
|
+
end
|
123
124
|
|
124
|
-
read_request = read_packet(read_length: atomic_read_size, offset: offset)
|
125
|
+
read_request = read_packet(read_length: atomic_read_size, offset: offset, credit_charge: credit_charge)
|
125
126
|
raw_response = tree.client.send_recv(read_request, encrypt: @tree_connect_encrypt_data)
|
126
127
|
response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
|
127
128
|
unless response.valid?
|
128
129
|
raise RubySMB::Error::InvalidPacket.new(
|
129
130
|
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
130
131
|
expected_cmd: RubySMB::SMB2::Packet::ReadResponse::COMMAND,
|
131
|
-
|
132
|
-
received_cmd: response.smb2_header.command
|
132
|
+
packet: response
|
133
133
|
)
|
134
134
|
end
|
135
135
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
@@ -142,17 +142,16 @@ module RubySMB
|
|
142
142
|
|
143
143
|
while remaining_bytes > 0
|
144
144
|
offset += atomic_read_size
|
145
|
-
atomic_read_size = remaining_bytes if remaining_bytes <
|
145
|
+
atomic_read_size = remaining_bytes if remaining_bytes < max_read
|
146
146
|
|
147
|
-
read_request = read_packet(read_length: atomic_read_size, offset: offset)
|
147
|
+
read_request = read_packet(read_length: atomic_read_size, offset: offset, credit_charge: credit_charge)
|
148
148
|
raw_response = tree.client.send_recv(read_request, encrypt: @tree_connect_encrypt_data)
|
149
149
|
response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
|
150
150
|
unless response.valid?
|
151
151
|
raise RubySMB::Error::InvalidPacket.new(
|
152
152
|
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
153
153
|
expected_cmd: RubySMB::SMB2::Packet::ReadResponse::COMMAND,
|
154
|
-
|
155
|
-
received_cmd: response.smb2_header.command
|
154
|
+
packet: response
|
156
155
|
)
|
157
156
|
end
|
158
157
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
@@ -169,11 +168,13 @@ module RubySMB
|
|
169
168
|
#
|
170
169
|
# @param bytes [Integer] the number of bytes to read
|
171
170
|
# @param offset [Integer] the byte offset in the file to start reading from
|
171
|
+
# @param credit_charge [Integer] the number of credits that this request consumes
|
172
172
|
# @return [RubySMB::SMB2::Packet::ReadRequest] the data read from the file
|
173
|
-
def read_packet(read_length: 0, offset: 0)
|
173
|
+
def read_packet(read_length: 0, offset: 0, credit_charge: 1)
|
174
174
|
read_request = set_header_fields(RubySMB::SMB2::Packet::ReadRequest.new)
|
175
175
|
read_request.read_length = read_length
|
176
176
|
read_request.offset = offset
|
177
|
+
read_request.smb2_header.credit_charge = credit_charge
|
177
178
|
read_request
|
178
179
|
end
|
179
180
|
|
@@ -185,8 +186,7 @@ module RubySMB
|
|
185
186
|
raise RubySMB::Error::InvalidPacket.new(
|
186
187
|
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
187
188
|
expected_cmd: RubySMB::SMB2::Packet::ReadResponse::COMMAND,
|
188
|
-
|
189
|
-
received_cmd: response.smb2_header.command
|
189
|
+
packet: response
|
190
190
|
)
|
191
191
|
end
|
192
192
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
@@ -206,8 +206,7 @@ module RubySMB
|
|
206
206
|
raise RubySMB::Error::InvalidPacket.new(
|
207
207
|
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
208
208
|
expected_cmd: RubySMB::SMB2::Packet::SetInfoResponse::COMMAND,
|
209
|
-
|
210
|
-
received_cmd: response.smb2_header.command
|
209
|
+
packet: response
|
211
210
|
)
|
212
211
|
end
|
213
212
|
response.smb2_header.nt_status.to_nt_status
|
@@ -240,29 +239,30 @@ module RubySMB
|
|
240
239
|
# @return [WindowsError::ErrorCode] the NTStatus code returned from the operation
|
241
240
|
# @raise [RubySMB::Error::InvalidPacket] if the response is not a WriteResponse packet
|
242
241
|
def write(data:'', offset: 0)
|
242
|
+
max_write = tree.client.server_max_write_size
|
243
|
+
max_write = 65536 unless tree.client.server_supports_multi_credit
|
243
244
|
buffer = data.dup
|
244
245
|
bytes = data.length
|
245
|
-
atomic_write_size =
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
246
|
+
atomic_write_size = [bytes, max_write].min
|
247
|
+
credit_charge = 0
|
248
|
+
if tree.client.server_supports_multi_credit
|
249
|
+
credit_charge = (atomic_write_size - 1) / 65536 + 1
|
250
|
+
end
|
250
251
|
|
251
252
|
while buffer.length > 0 do
|
252
|
-
write_request = write_packet(data: buffer.slice!(0,atomic_write_size), offset: offset)
|
253
|
+
write_request = write_packet(data: buffer.slice!(0, atomic_write_size), offset: offset, credit_charge: credit_charge)
|
253
254
|
raw_response = tree.client.send_recv(write_request, encrypt: @tree_connect_encrypt_data)
|
254
255
|
response = RubySMB::SMB2::Packet::WriteResponse.read(raw_response)
|
255
256
|
unless response.valid?
|
256
257
|
raise RubySMB::Error::InvalidPacket.new(
|
257
258
|
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
258
259
|
expected_cmd: RubySMB::SMB2::Packet::WriteResponse::COMMAND,
|
259
|
-
|
260
|
-
received_cmd: response.smb2_header.command
|
260
|
+
packet: response
|
261
261
|
)
|
262
262
|
end
|
263
263
|
status = response.smb2_header.nt_status.to_nt_status
|
264
264
|
|
265
|
-
offset+= atomic_write_size
|
265
|
+
offset += atomic_write_size
|
266
266
|
return status unless status == WindowsError::NTStatus::STATUS_SUCCESS
|
267
267
|
end
|
268
268
|
|
@@ -273,11 +273,13 @@ module RubySMB
|
|
273
273
|
#
|
274
274
|
# @param data [String] the data to write to the file
|
275
275
|
# @param offset [Integer] the offset in the file to start writing from
|
276
|
+
# @param credit_charge [Integer] the number of credits that this request consumes
|
276
277
|
# @return []RubySMB::SMB2::Packet::WriteRequest] the request packet
|
277
|
-
def write_packet(data:'', offset: 0)
|
278
|
+
def write_packet(data:'', offset: 0, credit_charge: 1)
|
278
279
|
write_request = set_header_fields(RubySMB::SMB2::Packet::WriteRequest.new)
|
279
280
|
write_request.write_offset = offset
|
280
281
|
write_request.buffer = data
|
282
|
+
write_request.smb2_header.credit_charge = credit_charge
|
281
283
|
write_request
|
282
284
|
end
|
283
285
|
|
@@ -289,8 +291,7 @@ module RubySMB
|
|
289
291
|
raise RubySMB::Error::InvalidPacket.new(
|
290
292
|
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
291
293
|
expected_cmd: RubySMB::SMB2::Packet::WriteResponse::COMMAND,
|
292
|
-
|
293
|
-
received_cmd: response.smb2_header.command
|
294
|
+
packet: response
|
294
295
|
)
|
295
296
|
end
|
296
297
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
@@ -311,8 +312,7 @@ module RubySMB
|
|
311
312
|
raise RubySMB::Error::InvalidPacket.new(
|
312
313
|
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
313
314
|
expected_cmd: RubySMB::SMB2::Packet::SetInfoResponse::COMMAND,
|
314
|
-
|
315
|
-
received_cmd: response.smb2_header.command
|
315
|
+
packet: response
|
316
316
|
)
|
317
317
|
end
|
318
318
|
response.smb2_header.nt_status.to_nt_status
|
data/lib/ruby_smb/smb2/pipe.rb
CHANGED
@@ -13,9 +13,13 @@ module RubySMB
|
|
13
13
|
def initialize(tree:, response:, name:)
|
14
14
|
raise ArgumentError, 'No Name Provided' if name.nil?
|
15
15
|
case name
|
16
|
-
when '
|
16
|
+
when 'netlogon', '\\netlogon'
|
17
|
+
extend RubySMB::Dcerpc::Netlogon
|
18
|
+
when 'srvsvc', '\\srvsvc'
|
17
19
|
extend RubySMB::Dcerpc::Srvsvc
|
18
|
-
when '
|
20
|
+
when 'svcctl', '\\svcctl'
|
21
|
+
extend RubySMB::Dcerpc::Svcctl
|
22
|
+
when 'winreg', '\\winreg'
|
19
23
|
extend RubySMB::Dcerpc::Winreg
|
20
24
|
end
|
21
25
|
super(tree: tree, response: response, name: name)
|
@@ -40,8 +44,7 @@ module RubySMB
|
|
40
44
|
raise RubySMB::Error::InvalidPacket.new(
|
41
45
|
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
42
46
|
expected_cmd: RubySMB::SMB2::Packet::IoctlResponse::COMMAND,
|
43
|
-
|
44
|
-
received_cmd: response.smb2_header.command
|
47
|
+
packet: response
|
45
48
|
)
|
46
49
|
end
|
47
50
|
|
@@ -89,6 +92,7 @@ module RubySMB
|
|
89
92
|
request = set_header_fields(RubySMB::SMB2::Packet::IoctlRequest.new(options))
|
90
93
|
request.ctl_code = 0x0011C017
|
91
94
|
request.flags.is_fsctl = 0x00000001
|
95
|
+
# TODO: handle fragmentation when the request size > MAX_XMIT_FRAG
|
92
96
|
request.buffer = action.to_binary_s
|
93
97
|
|
94
98
|
ioctl_raw_response = @tree.client.send_recv(request)
|
@@ -97,8 +101,7 @@ module RubySMB
|
|
97
101
|
raise RubySMB::Error::InvalidPacket.new(
|
98
102
|
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
99
103
|
expected_cmd: RubySMB::SMB2::Packet::IoctlRequest::COMMAND,
|
100
|
-
|
101
|
-
received_cmd: ioctl_response.smb2_header.command
|
104
|
+
packet: ioctl_response
|
102
105
|
)
|
103
106
|
end
|
104
107
|
unless [WindowsError::NTStatus::STATUS_SUCCESS,
|
data/lib/ruby_smb/smb2/tree.rb
CHANGED
@@ -50,13 +50,20 @@ module RubySMB
|
|
50
50
|
raise RubySMB::Error::InvalidPacket.new(
|
51
51
|
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
52
52
|
expected_cmd: RubySMB::SMB2::Packet::TreeDisconnectResponse::COMMAND,
|
53
|
-
|
54
|
-
received_cmd: response.smb2_header.command
|
53
|
+
packet: response
|
55
54
|
)
|
56
55
|
end
|
57
56
|
response.status_code
|
58
57
|
end
|
59
58
|
|
59
|
+
def open_pipe(opts)
|
60
|
+
# Make sure we don't modify the caller's hash options
|
61
|
+
opts = opts.dup
|
62
|
+
opts[:filename] = opts[:filename].dup
|
63
|
+
opts[:filename] = opts[:filename][1..-1] if opts[:filename].start_with? '\\'
|
64
|
+
open_file(opts)
|
65
|
+
end
|
66
|
+
|
60
67
|
def open_file(filename:, attributes: nil, options: nil, disposition: RubySMB::Dispositions::FILE_OPEN,
|
61
68
|
impersonation: RubySMB::ImpersonationLevels::SEC_IMPERSONATE, read: true, write: false, delete: false)
|
62
69
|
|
@@ -108,8 +115,7 @@ module RubySMB
|
|
108
115
|
raise RubySMB::Error::InvalidPacket.new(
|
109
116
|
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
110
117
|
expected_cmd: RubySMB::SMB2::Packet::CreateResponse::COMMAND,
|
111
|
-
|
112
|
-
received_cmd: response.smb2_header.command
|
118
|
+
packet: response
|
113
119
|
)
|
114
120
|
end
|
115
121
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
@@ -147,12 +153,19 @@ module RubySMB
|
|
147
153
|
directory_request.file_information_class = type::CLASS_LEVEL
|
148
154
|
directory_request.file_id = file_id
|
149
155
|
directory_request.name = pattern
|
150
|
-
|
156
|
+
|
157
|
+
max_read = client.server_max_read_size
|
158
|
+
max_read = 65536 unless client.server_supports_multi_credit
|
159
|
+
credit_charge = 0
|
160
|
+
if client.server_supports_multi_credit
|
161
|
+
credit_charge = (max_read - 1) / 65536 + 1
|
162
|
+
end
|
163
|
+
directory_request.output_length = max_read
|
164
|
+
directory_request.smb2_header.credit_charge = credit_charge
|
151
165
|
|
152
166
|
directory_request = set_header_fields(directory_request)
|
153
167
|
|
154
168
|
files = []
|
155
|
-
|
156
169
|
loop do
|
157
170
|
response = client.send_recv(directory_request, encrypt: @tree_connect_encrypt_data)
|
158
171
|
directory_response = RubySMB::SMB2::Packet::QueryDirectoryResponse.read(response)
|
@@ -160,8 +173,7 @@ module RubySMB
|
|
160
173
|
raise RubySMB::Error::InvalidPacket.new(
|
161
174
|
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
162
175
|
expected_cmd: RubySMB::SMB2::Packet::QueryDirectoryResponse::COMMAND,
|
163
|
-
|
164
|
-
received_cmd: directory_response.smb2_header.command
|
176
|
+
packet: directory_response
|
165
177
|
)
|
166
178
|
end
|
167
179
|
|
@@ -205,8 +217,7 @@ module RubySMB
|
|
205
217
|
raise RubySMB::Error::InvalidPacket.new(
|
206
218
|
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
207
219
|
expected_cmd: RubySMB::SMB2::Packet::CreateResponse::COMMAND,
|
208
|
-
|
209
|
-
received_cmd: response.smb2_header.command
|
220
|
+
packet: response
|
210
221
|
)
|
211
222
|
end
|
212
223
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
@@ -256,7 +267,6 @@ module RubySMB
|
|
256
267
|
# @return [RubySMB::SMB2::Packet] the modified packet.
|
257
268
|
def set_header_fields(request)
|
258
269
|
request.smb2_header.tree_id = id
|
259
|
-
request.smb2_header.credit_charge = 1
|
260
270
|
request.smb2_header.credits = 256
|
261
271
|
request
|
262
272
|
end
|
data/lib/ruby_smb/version.rb
CHANGED
@@ -65,6 +65,8 @@ RSpec.describe RubySMB::Client do
|
|
65
65
|
it { is_expected.to respond_to :verify_signature }
|
66
66
|
it { is_expected.to respond_to :auth_user }
|
67
67
|
it { is_expected.to respond_to :last_file_id }
|
68
|
+
it { is_expected.to respond_to :pid }
|
69
|
+
it { is_expected.to respond_to :server_supports_multi_credit }
|
68
70
|
|
69
71
|
describe '#initialize' do
|
70
72
|
it 'should raise an ArgumentError without a valid dispatcher' do
|
@@ -141,6 +143,18 @@ RSpec.describe RubySMB::Client do
|
|
141
143
|
it 'sets the max_buffer_size to MAX_BUFFER_SIZE' do
|
142
144
|
expect(client.max_buffer_size).to eq RubySMB::Client::MAX_BUFFER_SIZE
|
143
145
|
end
|
146
|
+
|
147
|
+
it 'sets the server_supports_multi_credit to false' do
|
148
|
+
expect(client.server_supports_multi_credit).to be false
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'sets the pid to a random value' do
|
152
|
+
100.times do
|
153
|
+
previous_pid = client.pid
|
154
|
+
client = described_class.new(dispatcher, username: username, password: password)
|
155
|
+
expect(client.pid).to_not eq(previous_pid)
|
156
|
+
end
|
157
|
+
end
|
144
158
|
end
|
145
159
|
|
146
160
|
describe '#echo' do
|
@@ -184,11 +198,13 @@ RSpec.describe RubySMB::Client do
|
|
184
198
|
describe '#send_recv' do
|
185
199
|
let(:smb1_request) { RubySMB::SMB1::Packet::TreeConnectRequest.new }
|
186
200
|
let(:smb2_request) { RubySMB::SMB2::Packet::TreeConnectRequest.new }
|
201
|
+
let(:smb2_header) { RubySMB::SMB2::SMB2Header.new }
|
187
202
|
|
188
203
|
before(:each) do
|
189
204
|
allow(client).to receive(:is_status_pending?).and_return(false)
|
190
205
|
allow(dispatcher).to receive(:send_packet).and_return(nil)
|
191
206
|
allow(dispatcher).to receive(:recv_packet).and_return('A')
|
207
|
+
allow(RubySMB::SMB2::SMB2Header).to receive(:read).and_return(smb2_header)
|
192
208
|
end
|
193
209
|
|
194
210
|
context 'when signing' do
|
@@ -199,9 +215,10 @@ RSpec.describe RubySMB::Client do
|
|
199
215
|
|
200
216
|
context 'with an SMB2 packet' do
|
201
217
|
it 'does not sign a SessionSetupRequest packet' do
|
218
|
+
allow(smb2_client).to receive(:is_status_pending?).and_return(false)
|
202
219
|
expect(smb2_client).to_not receive(:smb2_sign)
|
203
220
|
expect(smb2_client).to_not receive(:smb3_sign)
|
204
|
-
|
221
|
+
smb2_client.send_recv(RubySMB::SMB2::Packet::SessionSetupRequest.new)
|
205
222
|
end
|
206
223
|
|
207
224
|
it 'calls #smb2_sign if it is an SMB2 client' do
|
@@ -229,6 +246,29 @@ RSpec.describe RubySMB::Client do
|
|
229
246
|
expect(smb1_client).to_not receive(:is_status_pending?)
|
230
247
|
smb1_client.send_recv(smb1_request)
|
231
248
|
end
|
249
|
+
|
250
|
+
it 'set the #uid SMB header when #user_id is defined' do
|
251
|
+
smb1_client.user_id = 333
|
252
|
+
smb1_client.send_recv(smb1_request)
|
253
|
+
expect(smb1_request.smb_header.uid).to eq(333)
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'does not set the #uid SMB header when #user_id is not defined' do
|
257
|
+
smb1_client.send_recv(smb1_request)
|
258
|
+
expect(smb1_request.smb_header.uid).to eq(0)
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'set the #pid SMB header when #pid is defined' do
|
262
|
+
smb1_client.pid = 333
|
263
|
+
smb1_client.send_recv(smb1_request)
|
264
|
+
expect(smb1_request.smb_header.pid_low).to eq(333)
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'does not set the #pid SMB header when #pid is not defined' do
|
268
|
+
smb1_client.pid = nil
|
269
|
+
smb1_client.send_recv(smb1_request)
|
270
|
+
expect(smb1_request.smb_header.pid_low).to eq(0)
|
271
|
+
end
|
232
272
|
end
|
233
273
|
|
234
274
|
context 'with SMB2' do
|
@@ -251,10 +291,8 @@ RSpec.describe RubySMB::Client do
|
|
251
291
|
context 'with a SessionSetupRequest' do
|
252
292
|
it 'does not encrypt/decrypt' do
|
253
293
|
request = RubySMB::SMB2::Packet::SessionSetupRequest.new
|
254
|
-
expect(smb3_client).
|
255
|
-
expect(smb3_client).
|
256
|
-
expect(dispatcher).to receive(:send_packet).with(request)
|
257
|
-
expect(dispatcher).to receive(:recv_packet)
|
294
|
+
expect(smb3_client).to receive(:send_packet).with(request, encrypt: false)
|
295
|
+
expect(smb3_client).to receive(:recv_packet).with(encrypt: false)
|
258
296
|
smb3_client.send_recv(request)
|
259
297
|
end
|
260
298
|
end
|
@@ -262,17 +300,15 @@ RSpec.describe RubySMB::Client do
|
|
262
300
|
context 'with a NegotiateRequest' do
|
263
301
|
it 'does not encrypt/decrypt' do
|
264
302
|
request = RubySMB::SMB2::Packet::NegotiateRequest.new
|
265
|
-
expect(smb3_client).
|
266
|
-
expect(smb3_client).
|
267
|
-
expect(dispatcher).to receive(:send_packet).with(request)
|
268
|
-
expect(dispatcher).to receive(:recv_packet)
|
303
|
+
expect(smb3_client).to receive(:send_packet).with(request, encrypt: false)
|
304
|
+
expect(smb3_client).to receive(:recv_packet).with(encrypt: false)
|
269
305
|
smb3_client.send_recv(request)
|
270
306
|
end
|
271
307
|
end
|
272
308
|
|
273
309
|
it 'encrypts and decrypts' do
|
274
|
-
expect(smb3_client).to receive(:
|
275
|
-
expect(smb3_client).to receive(:
|
310
|
+
expect(smb3_client).to receive(:send_packet).with(smb2_request, encrypt: true)
|
311
|
+
expect(smb3_client).to receive(:recv_packet).with(encrypt: true)
|
276
312
|
smb3_client.send_recv(smb2_request)
|
277
313
|
end
|
278
314
|
|
@@ -280,12 +316,44 @@ RSpec.describe RubySMB::Client do
|
|
280
316
|
it 'waits 1 second and reads/decrypts again' do
|
281
317
|
allow(smb3_client).to receive(:is_status_pending?).and_return(true, false)
|
282
318
|
expect(smb3_client).to receive(:sleep).with(1)
|
283
|
-
expect(smb3_client).to receive(:
|
284
|
-
expect(smb3_client).to receive(:
|
319
|
+
expect(smb3_client).to receive(:send_packet).with(smb2_request, encrypt: true)
|
320
|
+
expect(smb3_client).to receive(:recv_packet).with(encrypt: true).twice
|
285
321
|
smb3_client.send_recv(smb2_request)
|
286
322
|
end
|
287
323
|
end
|
288
324
|
end
|
325
|
+
|
326
|
+
it 'increments the sequence counter if signing is required and the session key exist' do
|
327
|
+
allow(smb2_client).to receive(:is_status_pending?).and_return(false)
|
328
|
+
smb2_client.signing_required = true
|
329
|
+
smb2_client.session_key = 'key'
|
330
|
+
smb2_client.sequence_counter = 0
|
331
|
+
smb2_client.send_recv(smb2_request)
|
332
|
+
expect(smb2_client.sequence_counter).to eq(1)
|
333
|
+
end
|
334
|
+
|
335
|
+
it 'updates #smb2_message_id with SMB2 header #credit_charge if the server supports multi credits' do
|
336
|
+
allow(smb2_client).to receive(:is_status_pending?).and_return(false)
|
337
|
+
smb2_client.smb2_message_id = 0
|
338
|
+
smb2_client.server_supports_multi_credit = true
|
339
|
+
smb2_header.credit_charge = 5
|
340
|
+
smb2_client.send_recv(smb2_request)
|
341
|
+
expect(smb2_client.smb2_message_id).to eq(5)
|
342
|
+
end
|
343
|
+
|
344
|
+
it 'does not update #msb2_message_id with SMB2 header #credit_charge if the server does not support multi credits' do
|
345
|
+
allow(smb2_client).to receive(:is_status_pending?).and_return(false)
|
346
|
+
smb2_client.smb2_message_id = 0
|
347
|
+
smb2_client.server_supports_multi_credit = false
|
348
|
+
smb2_header.credit_charge = 5
|
349
|
+
smb2_client.send_recv(smb2_request)
|
350
|
+
expect(smb2_client.smb2_message_id).to eq(1)
|
351
|
+
end
|
352
|
+
|
353
|
+
it 'ignores errors thrown when parsing the SMB2 header' do
|
354
|
+
allow(RubySMB::SMB2::SMB2Header).to receive(:read).and_raise(IOError)
|
355
|
+
expect { smb2_client.send_recv(smb2_request) }.to_not raise_error
|
356
|
+
end
|
289
357
|
end
|
290
358
|
|
291
359
|
describe '#is_status_pending?' do
|
@@ -297,17 +365,17 @@ RSpec.describe RubySMB::Client do
|
|
297
365
|
}
|
298
366
|
|
299
367
|
it 'returns true when the response has a STATUS_PENDING status code and the async_command flag set' do
|
300
|
-
expect(client.is_status_pending?(response.
|
368
|
+
expect(client.is_status_pending?(response.smb2_header)).to be true
|
301
369
|
end
|
302
370
|
|
303
371
|
it 'returns false when the response has a STATUS_PENDING status code and the async_command flag not set' do
|
304
372
|
response.smb2_header.flags.async_command = 0
|
305
|
-
expect(client.is_status_pending?(response.
|
373
|
+
expect(client.is_status_pending?(response.smb2_header)).to be false
|
306
374
|
end
|
307
375
|
|
308
376
|
it 'returns false when the response has no STATUS_PENDING status code but the async_command flag set' do
|
309
377
|
response.smb2_header.nt_status= WindowsError::NTStatus::STATUS_SUCCESS.value
|
310
|
-
expect(client.is_status_pending?(response.
|
378
|
+
expect(client.is_status_pending?(response.smb2_header)).to be false
|
311
379
|
end
|
312
380
|
end
|
313
381
|
|
@@ -344,35 +412,47 @@ RSpec.describe RubySMB::Client do
|
|
344
412
|
end
|
345
413
|
end
|
346
414
|
|
347
|
-
describe '#
|
415
|
+
describe '#send_packet' do
|
348
416
|
let(:packet) { RubySMB::SMB2::Packet::SessionSetupRequest.new }
|
349
417
|
before :example do
|
350
418
|
allow(dispatcher).to receive(:send_packet)
|
351
419
|
client.dialect = '0x0300'
|
352
420
|
end
|
353
421
|
|
354
|
-
it '
|
355
|
-
expect(client).
|
356
|
-
client.
|
422
|
+
it 'does not encrypt the packet' do
|
423
|
+
expect(client).to_not receive(:smb3_encrypt)
|
424
|
+
client.send_packet(packet)
|
357
425
|
end
|
358
426
|
|
359
|
-
it '
|
360
|
-
|
361
|
-
expect
|
362
|
-
RubySMB::Error::EncryptionError,
|
363
|
-
"Error while encrypting #{packet.class.name} packet (SMB 0x0300): Error"
|
364
|
-
)
|
427
|
+
it 'sends the packet through the dispatcher' do
|
428
|
+
client.send_packet(packet)
|
429
|
+
expect(dispatcher).to have_received(:send_packet).with(packet)
|
365
430
|
end
|
366
431
|
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
432
|
+
context 'with encryption' do
|
433
|
+
it 'creates a Transform request' do
|
434
|
+
expect(client).to receive(:smb3_encrypt).with(packet.to_binary_s)
|
435
|
+
client.send_packet(packet, encrypt: true)
|
436
|
+
end
|
437
|
+
|
438
|
+
it 'raises an EncryptionError exception if an error occurs while encrypting' do
|
439
|
+
allow(client).to receive(:smb3_encrypt).and_raise(RubySMB::Error::RubySMBError.new('Error'))
|
440
|
+
expect { client.send_packet(packet, encrypt: true) }.to raise_error(
|
441
|
+
RubySMB::Error::EncryptionError,
|
442
|
+
"Error while encrypting #{packet.class.name} packet (SMB 0x0300): Error"
|
443
|
+
)
|
444
|
+
end
|
445
|
+
|
446
|
+
it 'sends the encrypted packet' do
|
447
|
+
encrypted_packet = double('Encrypted packet')
|
448
|
+
allow(client).to receive(:smb3_encrypt).and_return(encrypted_packet)
|
449
|
+
client.send_packet(packet, encrypt: true)
|
450
|
+
expect(dispatcher).to have_received(:send_packet).with(encrypted_packet)
|
451
|
+
end
|
372
452
|
end
|
373
453
|
end
|
374
454
|
|
375
|
-
describe '#
|
455
|
+
describe '#recv_packet' do
|
376
456
|
let(:packet) { RubySMB::SMB2::Packet::SessionSetupRequest.new }
|
377
457
|
before :example do
|
378
458
|
allow(dispatcher).to receive(:recv_packet).and_return(packet.to_binary_s)
|
@@ -381,42 +461,49 @@ RSpec.describe RubySMB::Client do
|
|
381
461
|
end
|
382
462
|
|
383
463
|
it 'reads the response packet' do
|
384
|
-
client.
|
464
|
+
client.recv_packet
|
385
465
|
expect(dispatcher).to have_received(:recv_packet)
|
386
466
|
end
|
387
467
|
|
388
|
-
it 'raises an
|
468
|
+
it 'raises an CommunicationError exception if an error occurs while receiving the response' do
|
389
469
|
allow(dispatcher).to receive(:recv_packet).and_raise(RubySMB::Error::CommunicationError)
|
390
|
-
expect { client.
|
391
|
-
RubySMB::Error::EncryptionError,
|
392
|
-
'Communication error with the remote host: RubySMB::Error::CommunicationError. '\
|
393
|
-
'The server supports encryption but was not able to handle the encrypted request.'
|
394
|
-
)
|
470
|
+
expect { client.recv_packet }.to raise_error(RubySMB::Error::CommunicationError)
|
395
471
|
end
|
396
472
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
473
|
+
context 'with encryption' do
|
474
|
+
it 'raises an EncryptionError exception if an error occurs while receiving the response' do
|
475
|
+
allow(dispatcher).to receive(:recv_packet).and_raise(RubySMB::Error::CommunicationError)
|
476
|
+
expect { client.recv_packet(encrypt: true) }.to raise_error(
|
477
|
+
RubySMB::Error::EncryptionError,
|
478
|
+
'Communication error with the remote host: RubySMB::Error::CommunicationError. '\
|
479
|
+
'The server supports encryption but was not able to handle the encrypted request.'
|
480
|
+
)
|
481
|
+
end
|
401
482
|
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
483
|
+
it 'parses the response as a Transform response packet' do
|
484
|
+
expect(RubySMB::SMB2::Packet::TransformHeader).to receive(:read).with(packet.to_binary_s)
|
485
|
+
client.recv_packet(encrypt: true)
|
486
|
+
end
|
406
487
|
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
expect(client).to have_received(:smb3_decrypt).with(transform)
|
412
|
-
end
|
488
|
+
it 'raises an InvalidPacket exception if an error occurs while parsing the response' do
|
489
|
+
allow(RubySMB::SMB2::Packet::TransformHeader).to receive(:read).and_raise(IOError)
|
490
|
+
expect { client.recv_packet(encrypt: true) }.to raise_error(RubySMB::Error::InvalidPacket, 'Not a SMB2 TransformHeader packet')
|
491
|
+
end
|
413
492
|
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
493
|
+
it 'decrypts the Transform response packet' do
|
494
|
+
transform = double('Transform header packet')
|
495
|
+
allow(RubySMB::SMB2::Packet::TransformHeader).to receive(:read).and_return(transform)
|
496
|
+
client.recv_packet(encrypt: true)
|
497
|
+
expect(client).to have_received(:smb3_decrypt).with(transform)
|
498
|
+
end
|
499
|
+
|
500
|
+
it 'raises an EncryptionError exception if an error occurs while decrypting' do
|
501
|
+
allow(client).to receive(:smb3_decrypt).and_raise(RubySMB::Error::RubySMBError)
|
502
|
+
expect { client.recv_packet(encrypt: true) }.to raise_error(
|
503
|
+
RubySMB::Error::EncryptionError,
|
504
|
+
'Error while decrypting RubySMB::SMB2::Packet::TransformHeader packet (SMB 0x0300}): RubySMB::Error::RubySMBError'
|
505
|
+
)
|
506
|
+
end
|
420
507
|
end
|
421
508
|
end
|
422
509
|
|
@@ -667,7 +754,7 @@ RSpec.describe RubySMB::Client do
|
|
667
754
|
expect(session_packet.session_header.session_packet_type).to eq RubySMB::Nbss::SESSION_REQUEST
|
668
755
|
expect(session_packet.called_name).to eq called_name
|
669
756
|
expect(session_packet.calling_name).to eq calling_name
|
670
|
-
expect(session_packet.session_header.
|
757
|
+
expect(session_packet.session_header.stream_protocol_length).to eq(
|
671
758
|
session_packet.called_name.to_binary_s.size + session_packet.calling_name.to_binary_s.size
|
672
759
|
)
|
673
760
|
end
|
@@ -1036,6 +1123,19 @@ RSpec.describe RubySMB::Client do
|
|
1036
1123
|
it 'returns the string \'SMB2\'' do
|
1037
1124
|
expect(client.parse_negotiate_response(smb2_response)).to eq ('SMB2')
|
1038
1125
|
end
|
1126
|
+
|
1127
|
+
it 'sets #server_supports_multi_credit to true when the response has #large_mtu capability set' do
|
1128
|
+
smb2_response.capabilities.large_mtu = 1
|
1129
|
+
client.parse_negotiate_response(smb2_response)
|
1130
|
+
expect(client.server_supports_multi_credit).to be true
|
1131
|
+
end
|
1132
|
+
|
1133
|
+
it 'sets #server_supports_multi_credit to false when the dialect is 0x0202' do
|
1134
|
+
smb2_response.dialect_revision = 0x0202
|
1135
|
+
smb2_response.capabilities.large_mtu = 1 # just to make sure it won't affect the result
|
1136
|
+
client.parse_negotiate_response(smb2_response)
|
1137
|
+
expect(client.server_supports_multi_credit).to be false
|
1138
|
+
end
|
1039
1139
|
end
|
1040
1140
|
|
1041
1141
|
context 'when SMB3 was negotiated' do
|
@@ -1060,6 +1160,12 @@ RSpec.describe RubySMB::Client do
|
|
1060
1160
|
expect(client.parse_negotiate_response(smb3_response)).to eq ('SMB3')
|
1061
1161
|
end
|
1062
1162
|
|
1163
|
+
it 'sets #server_supports_multi_credit to true when the response has #large_mtu capability set' do
|
1164
|
+
smb3_response.capabilities.large_mtu = 1
|
1165
|
+
client.parse_negotiate_response(smb3_response)
|
1166
|
+
expect(client.server_supports_multi_credit).to be true
|
1167
|
+
end
|
1168
|
+
|
1063
1169
|
context 'when the server supports encryption' do
|
1064
1170
|
before :example do
|
1065
1171
|
smb3_response.capabilities.encryption = 1
|
@@ -2253,7 +2359,7 @@ RSpec.describe RubySMB::Client do
|
|
2253
2359
|
let(:named_pipe){ double("Named Pipe") }
|
2254
2360
|
|
2255
2361
|
before :example do
|
2256
|
-
allow(tree).to receive(:
|
2362
|
+
allow(tree).to receive(:open_pipe).and_return(named_pipe)
|
2257
2363
|
allow(named_pipe).to receive(:net_share_enum_all)
|
2258
2364
|
end
|
2259
2365
|
|
@@ -2268,8 +2374,8 @@ RSpec.describe RubySMB::Client do
|
|
2268
2374
|
smb1_client.net_share_enum_all(sock.peeraddr)
|
2269
2375
|
end
|
2270
2376
|
|
2271
|
-
it 'it calls the Tree #
|
2272
|
-
expect(tree).to receive(:
|
2377
|
+
it 'it calls the Tree #open_pipe method to open "srvsvc" named pipe' do
|
2378
|
+
expect(tree).to receive(:open_pipe).with(filename: "srvsvc", write: true, read: true).and_return(named_pipe)
|
2273
2379
|
smb1_client.net_share_enum_all(sock.peeraddr)
|
2274
2380
|
end
|
2275
2381
|
|
@@ -2291,8 +2397,8 @@ RSpec.describe RubySMB::Client do
|
|
2291
2397
|
smb2_client.net_share_enum_all(sock.peeraddr)
|
2292
2398
|
end
|
2293
2399
|
|
2294
|
-
it 'it calls the Tree #
|
2295
|
-
expect(tree).to receive(:
|
2400
|
+
it 'it calls the Tree #open_pipe method to open "srvsvc" named pipe' do
|
2401
|
+
expect(tree).to receive(:open_pipe).with(filename: "srvsvc", write: true, read: true).and_return(named_pipe)
|
2296
2402
|
smb2_client.net_share_enum_all(sock.peeraddr)
|
2297
2403
|
end
|
2298
2404
|
|
@@ -2373,7 +2479,7 @@ RSpec.describe RubySMB::Client do
|
|
2373
2479
|
before :example do
|
2374
2480
|
allow(ipc_tree).to receive_messages(
|
2375
2481
|
:share => share,
|
2376
|
-
:
|
2482
|
+
:open_pipe => named_pipe
|
2377
2483
|
)
|
2378
2484
|
allow(client).to receive(:tree_connect).and_return(ipc_tree)
|
2379
2485
|
end
|
@@ -2395,9 +2501,9 @@ RSpec.describe RubySMB::Client do
|
|
2395
2501
|
expect(client).to have_received(:tree_connect).with(share)
|
2396
2502
|
end
|
2397
2503
|
|
2398
|
-
it 'open \'winreg\'
|
2504
|
+
it 'open \'winreg\' pipe on the IPC$ Tree' do
|
2399
2505
|
client.connect_to_winreg(host)
|
2400
|
-
expect(ipc_tree).to have_received(:
|
2506
|
+
expect(ipc_tree).to have_received(:open_pipe).with(filename: "winreg", write: true, read: true)
|
2401
2507
|
end
|
2402
2508
|
|
2403
2509
|
it 'returns the expected opened named pipe' do
|