ruby_smb 2.0.2 → 2.0.7
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/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
|