ruby_smb 2.0.0 → 2.0.5
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 +3 -3
- data.tar.gz.sig +5 -1
- 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 +117 -53
- data/lib/ruby_smb/client/authentication.rb +7 -12
- data/lib/ruby_smb/client/echo.rb +2 -4
- data/lib/ruby_smb/client/negotiation.rb +31 -12
- 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 +28 -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 +27 -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 +25 -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 +3 -2
- 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 +9 -24
- data/lib/ruby_smb/smb1/pipe.rb +8 -6
- data/lib/ruby_smb/smb1/tree.rb +22 -9
- data/lib/ruby_smb/smb2/file.rb +46 -46
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +1 -1
- data/lib/ruby_smb/smb2/pipe.rb +9 -6
- data/lib/ruby_smb/smb2/tree.rb +30 -20
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +248 -109
- 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 +12 -12
- 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 +1 -3
- 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 +73 -21
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +9 -5
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +64 -7
- metadata +91 -2
- metadata.gz.sig +0 -0
data/lib/ruby_smb/smb2/file.rb
CHANGED
@@ -52,10 +52,10 @@ module RubySMB
|
|
52
52
|
# @return [RubySMB::SMB2::Tree]
|
53
53
|
attr_accessor :tree
|
54
54
|
|
55
|
-
# Whether or not
|
56
|
-
# @!attribute [rw]
|
55
|
+
# Whether or not the share associated with this tree connect needs to be encrypted (SMB 3.x)
|
56
|
+
# @!attribute [rw] tree_connect_encrypt_data
|
57
57
|
# @return [Boolean]
|
58
|
-
attr_accessor :
|
58
|
+
attr_accessor :tree_connect_encrypt_data
|
59
59
|
|
60
60
|
def initialize(tree:, response:, name:, encrypt: false)
|
61
61
|
raise ArgumentError, 'No Tree Provided' if tree.nil?
|
@@ -71,7 +71,7 @@ module RubySMB
|
|
71
71
|
@last_write = response.last_write.to_datetime
|
72
72
|
@size = response.end_of_file
|
73
73
|
@size_on_disk = response.allocation_size
|
74
|
-
@
|
74
|
+
@tree_connect_encrypt_data = encrypt
|
75
75
|
end
|
76
76
|
|
77
77
|
# Appends the supplied data to the end of the file.
|
@@ -89,14 +89,13 @@ module RubySMB
|
|
89
89
|
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
|
90
90
|
def close
|
91
91
|
close_request = set_header_fields(RubySMB::SMB2::Packet::CloseRequest.new)
|
92
|
-
raw_response = tree.client.send_recv(close_request, encrypt: @
|
92
|
+
raw_response = tree.client.send_recv(close_request, encrypt: @tree_connect_encrypt_data)
|
93
93
|
response = RubySMB::SMB2::Packet::CloseResponse.read(raw_response)
|
94
94
|
unless response.valid?
|
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
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
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
|
124
|
+
|
125
|
+
read_request = read_packet(read_length: atomic_read_size, offset: offset, credit_charge: credit_charge)
|
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)
|
148
|
-
raw_response = tree.client.send_recv(read_request, encrypt: @
|
147
|
+
read_request = read_packet(read_length: atomic_read_size, offset: offset, credit_charge: credit_charge)
|
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,24 +168,25 @@ 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
|
|
180
181
|
def send_recv_read(read_length: 0, offset: 0)
|
181
182
|
read_request = read_packet(read_length: read_length, offset: offset)
|
182
|
-
raw_response = tree.client.send_recv(read_request, encrypt: @
|
183
|
+
raw_response = tree.client.send_recv(read_request, encrypt: @tree_connect_encrypt_data)
|
183
184
|
response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
|
184
185
|
unless response.valid?
|
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
|
@@ -200,14 +200,13 @@ module RubySMB
|
|
200
200
|
# @return [WindowsError::ErrorCode] the NTStatus Response code
|
201
201
|
# @raise [RubySMB::Error::InvalidPacket] if the response is not a SetInfoResponse packet
|
202
202
|
def delete
|
203
|
-
raw_response = tree.client.send_recv(delete_packet, encrypt: @
|
203
|
+
raw_response = tree.client.send_recv(delete_packet, encrypt: @tree_connect_encrypt_data)
|
204
204
|
response = RubySMB::SMB2::Packet::SetInfoResponse.read(raw_response)
|
205
205
|
unless response.valid?
|
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
|
-
raw_response = tree.client.send_recv(write_request, encrypt: @
|
253
|
+
write_request = write_packet(data: buffer.slice!(0, atomic_write_size), offset: offset, credit_charge: credit_charge)
|
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,24 +273,25 @@ 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
|
|
284
286
|
def send_recv_write(data:'', offset: 0)
|
285
287
|
pkt = write_packet(data: data, offset: offset)
|
286
|
-
raw_response = tree.client.send_recv(pkt, encrypt: @
|
288
|
+
raw_response = tree.client.send_recv(pkt, encrypt: @tree_connect_encrypt_data)
|
287
289
|
response = RubySMB::SMB2::Packet::WriteResponse.read(raw_response)
|
288
290
|
unless response.valid?
|
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
|
@@ -305,14 +306,13 @@ module RubySMB
|
|
305
306
|
# @return [WindowsError::ErrorCode] the NTStatus Response code
|
306
307
|
# @raise [RubySMB::Error::InvalidPacket] if the response is not a SetInfoResponse packet
|
307
308
|
def rename(new_file_name)
|
308
|
-
raw_response = tree.client.send_recv(rename_packet(new_file_name), encrypt: @
|
309
|
+
raw_response = tree.client.send_recv(rename_packet(new_file_name), encrypt: @tree_connect_encrypt_data)
|
309
310
|
response = RubySMB::SMB2::Packet::SetInfoResponse.read(raw_response)
|
310
311
|
unless response.valid?
|
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
|
@@ -15,7 +15,7 @@ module RubySMB
|
|
15
15
|
uint16 :dialect_revision, label: 'Dialect Revision'
|
16
16
|
uint16 :negotiate_context_count, label: 'Negotiate Context Count', initial_value: -> { negotiate_context_list.size }, onlyif: -> { has_negotiate_context? }
|
17
17
|
uint16 :reserved1, label: 'Reserved', initial_value: 0, onlyif: -> { !has_negotiate_context? }
|
18
|
-
string :server_guid, label: 'Server GUID',
|
18
|
+
string :server_guid, label: 'Server GUID', length: 16
|
19
19
|
smb2_capabilities :capabilities
|
20
20
|
uint32 :max_transact_size, label: 'Max Transaction Size'
|
21
21
|
uint32 :max_read_size, label: 'Max Read Size'
|
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
@@ -23,10 +23,10 @@ module RubySMB
|
|
23
23
|
# @return [Integer]
|
24
24
|
attr_accessor :id
|
25
25
|
|
26
|
-
# Whether or not
|
27
|
-
# @!attribute [rw]
|
26
|
+
# Whether or not the share associated with this tree connect needs to be encrypted (SMB 3.x)
|
27
|
+
# @!attribute [rw] tree_connect_encrypt_data
|
28
28
|
# @return [Boolean]
|
29
|
-
attr_accessor :
|
29
|
+
attr_accessor :tree_connect_encrypt_data
|
30
30
|
|
31
31
|
def initialize(client:, share:, response:, encrypt: false)
|
32
32
|
@client = client
|
@@ -34,7 +34,7 @@ module RubySMB
|
|
34
34
|
@id = response.smb2_header.tree_id
|
35
35
|
@permissions = response.maximal_access
|
36
36
|
@share_type = response.share_type
|
37
|
-
@
|
37
|
+
@tree_connect_encrypt_data = encrypt
|
38
38
|
end
|
39
39
|
|
40
40
|
# Disconnects this Tree from the current session
|
@@ -44,19 +44,26 @@ module RubySMB
|
|
44
44
|
def disconnect!
|
45
45
|
request = RubySMB::SMB2::Packet::TreeDisconnectRequest.new
|
46
46
|
request = set_header_fields(request)
|
47
|
-
raw_response = client.send_recv(request, encrypt: @
|
47
|
+
raw_response = client.send_recv(request, encrypt: @tree_connect_encrypt_data)
|
48
48
|
response = RubySMB::SMB2::Packet::TreeDisconnectResponse.read(raw_response)
|
49
49
|
unless response.valid?
|
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
|
|
@@ -102,14 +109,13 @@ module RubySMB
|
|
102
109
|
create_request.create_disposition = disposition
|
103
110
|
create_request.name = filename
|
104
111
|
|
105
|
-
raw_response = client.send_recv(create_request, encrypt: @
|
112
|
+
raw_response = client.send_recv(create_request, encrypt: @tree_connect_encrypt_data)
|
106
113
|
response = RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
|
107
114
|
unless response.valid?
|
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
|
@@ -118,7 +124,7 @@ module RubySMB
|
|
118
124
|
|
119
125
|
case @share_type
|
120
126
|
when RubySMB::SMB2::Packet::TreeConnectResponse::SMB2_SHARE_TYPE_DISK
|
121
|
-
RubySMB::SMB2::File.new(name: filename, tree: self, response: response, encrypt: @
|
127
|
+
RubySMB::SMB2::File.new(name: filename, tree: self, response: response, encrypt: @tree_connect_encrypt_data)
|
122
128
|
when RubySMB::SMB2::Packet::TreeConnectResponse::SMB2_SHARE_TYPE_PIPE
|
123
129
|
RubySMB::SMB2::Pipe.new(name: filename, tree: self, response: response)
|
124
130
|
# when RubySMB::SMB2::TreeConnectResponse::SMB2_SHARE_TYPE_PRINT
|
@@ -147,21 +153,27 @@ 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
|
-
response = client.send_recv(directory_request, encrypt: @
|
170
|
+
response = client.send_recv(directory_request, encrypt: @tree_connect_encrypt_data)
|
158
171
|
directory_response = RubySMB::SMB2::Packet::QueryDirectoryResponse.read(response)
|
159
172
|
unless directory_response.valid?
|
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
|
|
@@ -199,14 +211,13 @@ module RubySMB
|
|
199
211
|
|
200
212
|
create_request = open_directory_packet(directory: directory, disposition: disposition,
|
201
213
|
impersonation: impersonation, read: read, write: write, delete: delete)
|
202
|
-
raw_response = client.send_recv(create_request, encrypt: @
|
214
|
+
raw_response = client.send_recv(create_request, encrypt: @tree_connect_encrypt_data)
|
203
215
|
response = RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
|
204
216
|
unless response.valid?
|
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
@@ -46,7 +46,7 @@ RSpec.describe RubySMB::Client do
|
|
46
46
|
it { is_expected.to respond_to :encryption_algorithm }
|
47
47
|
it { is_expected.to respond_to :client_encryption_key }
|
48
48
|
it { is_expected.to respond_to :server_encryption_key }
|
49
|
-
it { is_expected.to respond_to :
|
49
|
+
it { is_expected.to respond_to :session_encrypt_data }
|
50
50
|
it { is_expected.to respond_to :server_encryption_algorithms }
|
51
51
|
it { is_expected.to respond_to :server_compression_algorithms }
|
52
52
|
it { is_expected.to respond_to :negotiated_smb_version }
|
@@ -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
|
@@ -106,9 +108,9 @@ RSpec.describe RubySMB::Client do
|
|
106
108
|
expect(client.password).to eq password
|
107
109
|
end
|
108
110
|
|
109
|
-
it 'sets the
|
111
|
+
it 'sets the session_encrypt_data attribute' do
|
110
112
|
client = described_class.new(dispatcher, username: username, password: password, always_encrypt: true)
|
111
|
-
expect(client.
|
113
|
+
expect(client.session_encrypt_data).to eq true
|
112
114
|
end
|
113
115
|
|
114
116
|
it 'creates an NTLM client' do
|
@@ -125,7 +127,7 @@ RSpec.describe RubySMB::Client do
|
|
125
127
|
expect(opt[:workstation]).to eq(local_workstation)
|
126
128
|
expect(opt[:domain]).to eq(domain)
|
127
129
|
flags = Net::NTLM::Client::DEFAULT_FLAGS |
|
128
|
-
Net::NTLM::FLAGS[:TARGET_INFO] | 0x02000000
|
130
|
+
Net::NTLM::FLAGS[:TARGET_INFO] | 0x02000000 ^ Net::NTLM::FLAGS[:OEM]
|
129
131
|
expect(opt[:flags]).to eq(flags)
|
130
132
|
end
|
131
133
|
|
@@ -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,16 +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')
|
192
|
-
|
193
|
-
|
194
|
-
it 'checks the packet version' do
|
195
|
-
expect(smb1_request).to receive(:packet_smb_version).and_call_original
|
196
|
-
client.send_recv(smb1_request)
|
207
|
+
allow(RubySMB::SMB2::SMB2Header).to receive(:read).and_return(smb2_header)
|
197
208
|
end
|
198
209
|
|
199
210
|
context 'when signing' do
|
@@ -204,9 +215,10 @@ RSpec.describe RubySMB::Client do
|
|
204
215
|
|
205
216
|
context 'with an SMB2 packet' do
|
206
217
|
it 'does not sign a SessionSetupRequest packet' do
|
218
|
+
allow(smb2_client).to receive(:is_status_pending?).and_return(false)
|
207
219
|
expect(smb2_client).to_not receive(:smb2_sign)
|
208
220
|
expect(smb2_client).to_not receive(:smb3_sign)
|
209
|
-
|
221
|
+
smb2_client.send_recv(RubySMB::SMB2::Packet::SessionSetupRequest.new)
|
210
222
|
end
|
211
223
|
|
212
224
|
it 'calls #smb2_sign if it is an SMB2 client' do
|
@@ -234,6 +246,29 @@ RSpec.describe RubySMB::Client do
|
|
234
246
|
expect(smb1_client).to_not receive(:is_status_pending?)
|
235
247
|
smb1_client.send_recv(smb1_request)
|
236
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
|
237
272
|
end
|
238
273
|
|
239
274
|
context 'with SMB2' do
|
@@ -256,10 +291,8 @@ RSpec.describe RubySMB::Client do
|
|
256
291
|
context 'with a SessionSetupRequest' do
|
257
292
|
it 'does not encrypt/decrypt' do
|
258
293
|
request = RubySMB::SMB2::Packet::SessionSetupRequest.new
|
259
|
-
expect(smb3_client).
|
260
|
-
expect(smb3_client).
|
261
|
-
expect(dispatcher).to receive(:send_packet).with(request)
|
262
|
-
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)
|
263
296
|
smb3_client.send_recv(request)
|
264
297
|
end
|
265
298
|
end
|
@@ -267,17 +300,15 @@ RSpec.describe RubySMB::Client do
|
|
267
300
|
context 'with a NegotiateRequest' do
|
268
301
|
it 'does not encrypt/decrypt' do
|
269
302
|
request = RubySMB::SMB2::Packet::NegotiateRequest.new
|
270
|
-
expect(smb3_client).
|
271
|
-
expect(smb3_client).
|
272
|
-
expect(dispatcher).to receive(:send_packet).with(request)
|
273
|
-
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)
|
274
305
|
smb3_client.send_recv(request)
|
275
306
|
end
|
276
307
|
end
|
277
308
|
|
278
309
|
it 'encrypts and decrypts' do
|
279
|
-
expect(smb3_client).to receive(:
|
280
|
-
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)
|
281
312
|
smb3_client.send_recv(smb2_request)
|
282
313
|
end
|
283
314
|
|
@@ -285,12 +316,44 @@ RSpec.describe RubySMB::Client do
|
|
285
316
|
it 'waits 1 second and reads/decrypts again' do
|
286
317
|
allow(smb3_client).to receive(:is_status_pending?).and_return(true, false)
|
287
318
|
expect(smb3_client).to receive(:sleep).with(1)
|
288
|
-
expect(smb3_client).to receive(:
|
289
|
-
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
|
290
321
|
smb3_client.send_recv(smb2_request)
|
291
322
|
end
|
292
323
|
end
|
293
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
|
294
357
|
end
|
295
358
|
|
296
359
|
describe '#is_status_pending?' do
|
@@ -302,17 +365,17 @@ RSpec.describe RubySMB::Client do
|
|
302
365
|
}
|
303
366
|
|
304
367
|
it 'returns true when the response has a STATUS_PENDING status code and the async_command flag set' do
|
305
|
-
expect(client.is_status_pending?(response.
|
368
|
+
expect(client.is_status_pending?(response.smb2_header)).to be true
|
306
369
|
end
|
307
370
|
|
308
371
|
it 'returns false when the response has a STATUS_PENDING status code and the async_command flag not set' do
|
309
372
|
response.smb2_header.flags.async_command = 0
|
310
|
-
expect(client.is_status_pending?(response.
|
373
|
+
expect(client.is_status_pending?(response.smb2_header)).to be false
|
311
374
|
end
|
312
375
|
|
313
376
|
it 'returns false when the response has no STATUS_PENDING status code but the async_command flag set' do
|
314
377
|
response.smb2_header.nt_status= WindowsError::NTStatus::STATUS_SUCCESS.value
|
315
|
-
expect(client.is_status_pending?(response.
|
378
|
+
expect(client.is_status_pending?(response.smb2_header)).to be false
|
316
379
|
end
|
317
380
|
end
|
318
381
|
|
@@ -322,6 +385,11 @@ RSpec.describe RubySMB::Client do
|
|
322
385
|
expect(client.can_be_encrypted?(packet)).to be true
|
323
386
|
end
|
324
387
|
|
388
|
+
it 'returns false if it is an SMB1 packet' do
|
389
|
+
packet = RubySMB::SMB1::Packet::LogoffRequest.new
|
390
|
+
expect(client.can_be_encrypted?(packet)).to be false
|
391
|
+
end
|
392
|
+
|
325
393
|
[RubySMB::SMB2::Packet::SessionSetupRequest, RubySMB::SMB2::Packet::NegotiateRequest].each do |klass|
|
326
394
|
it "returns false if the packet is a #{klass}" do
|
327
395
|
packet = klass.new
|
@@ -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,33 +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 '
|
389
|
-
|
390
|
-
client.
|
468
|
+
it 'raises an CommunicationError exception if an error occurs while receiving the response' do
|
469
|
+
allow(dispatcher).to receive(:recv_packet).and_raise(RubySMB::Error::CommunicationError)
|
470
|
+
expect { client.recv_packet }.to raise_error(RubySMB::Error::CommunicationError)
|
391
471
|
end
|
392
472
|
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
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
|
397
482
|
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
expect(client).to have_received(:smb3_decrypt).with(transform)
|
403
|
-
end
|
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
|
404
487
|
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
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
|
492
|
+
|
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
|
411
507
|
end
|
412
508
|
end
|
413
509
|
|
@@ -658,7 +754,7 @@ RSpec.describe RubySMB::Client do
|
|
658
754
|
expect(session_packet.session_header.session_packet_type).to eq RubySMB::Nbss::SESSION_REQUEST
|
659
755
|
expect(session_packet.called_name).to eq called_name
|
660
756
|
expect(session_packet.calling_name).to eq calling_name
|
661
|
-
expect(session_packet.session_header.
|
757
|
+
expect(session_packet.session_header.stream_protocol_length).to eq(
|
662
758
|
session_packet.called_name.to_binary_s.size + session_packet.calling_name.to_binary_s.size
|
663
759
|
)
|
664
760
|
end
|
@@ -1027,6 +1123,19 @@ RSpec.describe RubySMB::Client do
|
|
1027
1123
|
it 'returns the string \'SMB2\'' do
|
1028
1124
|
expect(client.parse_negotiate_response(smb2_response)).to eq ('SMB2')
|
1029
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
|
1030
1139
|
end
|
1031
1140
|
|
1032
1141
|
context 'when SMB3 was negotiated' do
|
@@ -1050,6 +1159,53 @@ RSpec.describe RubySMB::Client do
|
|
1050
1159
|
it 'returns the string \'SMB2\'' do
|
1051
1160
|
expect(client.parse_negotiate_response(smb3_response)).to eq ('SMB3')
|
1052
1161
|
end
|
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
|
+
|
1169
|
+
context 'when the server supports encryption' do
|
1170
|
+
before :example do
|
1171
|
+
smb3_response.capabilities.encryption = 1
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
it 'sets the expected encryption algorithm' do
|
1175
|
+
client.parse_negotiate_response(smb3_response)
|
1176
|
+
expect(client.encryption_algorithm).to eq(RubySMB::SMB2::EncryptionCapabilities::ENCRYPTION_ALGORITHM_MAP[RubySMB::SMB2::EncryptionCapabilities::AES_128_CCM])
|
1177
|
+
end
|
1178
|
+
|
1179
|
+
it 'keeps session encryption enabled if it was already' do
|
1180
|
+
client.session_encrypt_data = true
|
1181
|
+
client.parse_negotiate_response(smb3_response)
|
1182
|
+
expect(client.session_encrypt_data).to be true
|
1183
|
+
end
|
1184
|
+
|
1185
|
+
it 'keeps session encryption disabled if it was already' do
|
1186
|
+
client.session_encrypt_data = false
|
1187
|
+
client.parse_negotiate_response(smb3_response)
|
1188
|
+
expect(client.session_encrypt_data).to be false
|
1189
|
+
end
|
1190
|
+
end
|
1191
|
+
|
1192
|
+
context 'when the server does not support encryption' do
|
1193
|
+
before :example do
|
1194
|
+
smb3_response.capabilities.encryption = 0
|
1195
|
+
end
|
1196
|
+
|
1197
|
+
it 'disables session encryption if it was already enabled' do
|
1198
|
+
client.session_encrypt_data = true
|
1199
|
+
client.parse_negotiate_response(smb3_response)
|
1200
|
+
expect(client.session_encrypt_data).to be false
|
1201
|
+
end
|
1202
|
+
|
1203
|
+
it 'keeps session encryption disabled if it was already' do
|
1204
|
+
client.session_encrypt_data = false
|
1205
|
+
client.parse_negotiate_response(smb3_response)
|
1206
|
+
expect(client.session_encrypt_data).to be false
|
1207
|
+
end
|
1208
|
+
end
|
1053
1209
|
end
|
1054
1210
|
|
1055
1211
|
context 'when the response contains the SMB2 wildcard revision number dialect' do
|
@@ -1121,26 +1277,15 @@ RSpec.describe RubySMB::Client do
|
|
1121
1277
|
end
|
1122
1278
|
end
|
1123
1279
|
|
1124
|
-
['0x0300', '0x0302'].each do |dialect|
|
1125
|
-
context "with #{dialect} dialect" do
|
1126
|
-
before :example do
|
1127
|
-
client.dialect = dialect
|
1128
|
-
end
|
1129
|
-
|
1130
|
-
it 'sets the expected encryption algorithm' do
|
1131
|
-
client.negotiate
|
1132
|
-
expect(client.encryption_algorithm).to eq(RubySMB::SMB2::EncryptionCapabilities::ENCRYPTION_ALGORITHM_MAP[RubySMB::SMB2::EncryptionCapabilities::AES_128_CCM])
|
1133
|
-
end
|
1134
|
-
end
|
1135
|
-
end
|
1136
|
-
|
1137
1280
|
context "with 0x0311 dialect" do
|
1138
|
-
it 'calls #
|
1281
|
+
it 'calls #parse_negotiate_response and updates the preauth hash' do
|
1139
1282
|
client.dialect = '0x0311'
|
1140
1283
|
request_packet = client.smb2_3_negotiate_request
|
1141
1284
|
allow(client).to receive(:negotiate_request).and_return(request_packet)
|
1142
1285
|
allow(client).to receive(:negotiate_response).and_return(smb3_response)
|
1143
|
-
expect(client).to receive(:
|
1286
|
+
expect(client).to receive(:parse_negotiate_response).with(smb3_response)
|
1287
|
+
expect(client).to receive(:update_preauth_hash).with(request_packet)
|
1288
|
+
expect(client).to receive(:update_preauth_hash).with(smb3_response)
|
1144
1289
|
client.negotiate
|
1145
1290
|
end
|
1146
1291
|
end
|
@@ -1213,7 +1358,7 @@ RSpec.describe RubySMB::Client do
|
|
1213
1358
|
end
|
1214
1359
|
end
|
1215
1360
|
|
1216
|
-
describe '#
|
1361
|
+
describe '#parse_smb3_capabilities' do
|
1217
1362
|
let(:request_packet) { client.smb2_3_negotiate_request }
|
1218
1363
|
let(:smb3_response) { RubySMB::SMB2::Packet::NegotiateResponse.new(dialect_revision: 0x311) }
|
1219
1364
|
let(:nc_encryption) do
|
@@ -1240,7 +1385,7 @@ RSpec.describe RubySMB::Client do
|
|
1240
1385
|
context 'when selecting the integrity hash algorithm' do
|
1241
1386
|
context 'with one algorithm' do
|
1242
1387
|
it 'selects the expected algorithm' do
|
1243
|
-
smb3_client.
|
1388
|
+
smb3_client.parse_smb3_capabilities(smb3_response)
|
1244
1389
|
expect(smb3_client.preauth_integrity_hash_algorithm).to eq('SHA512')
|
1245
1390
|
end
|
1246
1391
|
end
|
@@ -1251,7 +1396,7 @@ RSpec.describe RubySMB::Client do
|
|
1251
1396
|
RubySMB::SMB2::NegotiateContext::SMB2_PREAUTH_INTEGRITY_CAPABILITIES
|
1252
1397
|
)
|
1253
1398
|
nc.data.hash_algorithms << 3
|
1254
|
-
smb3_client.
|
1399
|
+
smb3_client.parse_smb3_capabilities(smb3_response)
|
1255
1400
|
expect(smb3_client.preauth_integrity_hash_algorithm).to eq('SHA512')
|
1256
1401
|
end
|
1257
1402
|
end
|
@@ -1260,7 +1405,7 @@ RSpec.describe RubySMB::Client do
|
|
1260
1405
|
it 'raises the expected exception' do
|
1261
1406
|
smb3_response = RubySMB::SMB2::Packet::NegotiateResponse.new(dialect_revision: 0x311)
|
1262
1407
|
smb3_response.add_negotiate_context(nc_encryption)
|
1263
|
-
expect { smb3_client.
|
1408
|
+
expect { smb3_client.parse_smb3_capabilities(smb3_response) }.to raise_error(
|
1264
1409
|
RubySMB::Error::EncryptionError,
|
1265
1410
|
'Unable to retrieve the Preauth Integrity Hash Algorithm from the Negotiate response'
|
1266
1411
|
)
|
@@ -1276,7 +1421,7 @@ RSpec.describe RubySMB::Client do
|
|
1276
1421
|
)
|
1277
1422
|
nc.data.hash_algorithms << 5
|
1278
1423
|
smb3_response.add_negotiate_context(nc)
|
1279
|
-
expect { smb3_client.
|
1424
|
+
expect { smb3_client.parse_smb3_capabilities(smb3_response) }.to raise_error(
|
1280
1425
|
RubySMB::Error::EncryptionError,
|
1281
1426
|
'Unable to retrieve the Preauth Integrity Hash Algorithm from the Negotiate response'
|
1282
1427
|
)
|
@@ -1287,7 +1432,7 @@ RSpec.describe RubySMB::Client do
|
|
1287
1432
|
context 'when selecting the encryption algorithm' do
|
1288
1433
|
context 'with one algorithm' do
|
1289
1434
|
it 'selects the expected algorithm' do
|
1290
|
-
smb3_client.
|
1435
|
+
smb3_client.parse_smb3_capabilities(smb3_response)
|
1291
1436
|
expect(smb3_client.encryption_algorithm).to eq('AES-128-CCM')
|
1292
1437
|
end
|
1293
1438
|
end
|
@@ -1298,7 +1443,7 @@ RSpec.describe RubySMB::Client do
|
|
1298
1443
|
RubySMB::SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES
|
1299
1444
|
)
|
1300
1445
|
nc.data.ciphers << RubySMB::SMB2::EncryptionCapabilities::AES_128_GCM
|
1301
|
-
smb3_client.
|
1446
|
+
smb3_client.parse_smb3_capabilities(smb3_response)
|
1302
1447
|
expect(smb3_client.encryption_algorithm).to eq('AES-128-GCM')
|
1303
1448
|
end
|
1304
1449
|
|
@@ -1307,7 +1452,7 @@ RSpec.describe RubySMB::Client do
|
|
1307
1452
|
RubySMB::SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES
|
1308
1453
|
)
|
1309
1454
|
nc.data.ciphers << 3
|
1310
|
-
smb3_client.
|
1455
|
+
smb3_client.parse_smb3_capabilities(smb3_response)
|
1311
1456
|
expect(smb3_client.encryption_algorithm).to eq('AES-128-CCM')
|
1312
1457
|
end
|
1313
1458
|
|
@@ -1316,7 +1461,7 @@ RSpec.describe RubySMB::Client do
|
|
1316
1461
|
RubySMB::SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES
|
1317
1462
|
)
|
1318
1463
|
nc.data.ciphers << RubySMB::SMB2::EncryptionCapabilities::AES_128_GCM
|
1319
|
-
smb3_client.
|
1464
|
+
smb3_client.parse_smb3_capabilities(smb3_response)
|
1320
1465
|
expect(smb3_client.server_encryption_algorithms).to eq([1, 2])
|
1321
1466
|
end
|
1322
1467
|
end
|
@@ -1325,7 +1470,7 @@ RSpec.describe RubySMB::Client do
|
|
1325
1470
|
it 'raises the expected exception' do
|
1326
1471
|
smb3_response = RubySMB::SMB2::Packet::NegotiateResponse.new(dialect_revision: 0x311)
|
1327
1472
|
smb3_response.add_negotiate_context(nc_integrity)
|
1328
|
-
expect { smb3_client.
|
1473
|
+
expect { smb3_client.parse_smb3_capabilities(smb3_response) }.to raise_error(
|
1329
1474
|
RubySMB::Error::EncryptionError,
|
1330
1475
|
'Unable to retrieve the encryption cipher list supported by the server from the Negotiate response'
|
1331
1476
|
)
|
@@ -1341,7 +1486,7 @@ RSpec.describe RubySMB::Client do
|
|
1341
1486
|
)
|
1342
1487
|
nc.data.ciphers << 14
|
1343
1488
|
smb3_response.add_negotiate_context(nc)
|
1344
|
-
expect { smb3_client.
|
1489
|
+
expect { smb3_client.parse_smb3_capabilities(smb3_response) }.to raise_error(
|
1345
1490
|
RubySMB::Error::EncryptionError,
|
1346
1491
|
'Unable to retrieve the encryption cipher list supported by the server from the Negotiate response'
|
1347
1492
|
)
|
@@ -1359,16 +1504,10 @@ RSpec.describe RubySMB::Client do
|
|
1359
1504
|
nc.data.compression_algorithms << RubySMB::SMB2::CompressionCapabilities::LZ77_Huffman
|
1360
1505
|
nc.data.compression_algorithms << RubySMB::SMB2::CompressionCapabilities::Pattern_V1
|
1361
1506
|
smb3_response.add_negotiate_context(nc)
|
1362
|
-
smb3_client.
|
1507
|
+
smb3_client.parse_smb3_capabilities(smb3_response)
|
1363
1508
|
expect(smb3_client.server_compression_algorithms).to eq([1, 2, 3, 4])
|
1364
1509
|
end
|
1365
1510
|
end
|
1366
|
-
|
1367
|
-
it 'updates the preauth hash' do
|
1368
|
-
expect(smb3_client).to receive(:update_preauth_hash).with(request_packet)
|
1369
|
-
expect(smb3_client).to receive(:update_preauth_hash).with(smb3_response)
|
1370
|
-
smb3_client.parse_smb3_encryption_data(request_packet, smb3_response)
|
1371
|
-
end
|
1372
1511
|
end
|
1373
1512
|
end
|
1374
1513
|
end
|
@@ -1710,22 +1849,22 @@ RSpec.describe RubySMB::Client do
|
|
1710
1849
|
smb2_client.smb2_authenticate
|
1711
1850
|
end
|
1712
1851
|
|
1713
|
-
context 'when setting the
|
1852
|
+
context 'when setting the session_encrypt_data parameter' do
|
1714
1853
|
before :example do
|
1715
1854
|
smb2_client.smb3 = true
|
1716
|
-
smb2_client.
|
1855
|
+
smb2_client.session_encrypt_data = false
|
1717
1856
|
end
|
1718
1857
|
|
1719
|
-
it 'sets the
|
1858
|
+
it 'sets the session_encrypt_data parameter to true if the server requires encryption' do
|
1720
1859
|
final_response_packet.session_flags.encrypt_data = 1
|
1721
1860
|
smb2_client.smb2_authenticate
|
1722
|
-
expect(smb2_client.
|
1861
|
+
expect(smb2_client.session_encrypt_data).to be true
|
1723
1862
|
end
|
1724
1863
|
|
1725
|
-
it 'does not set the
|
1864
|
+
it 'does not set the session_encrypt_data parameter if the server does not require encryption' do
|
1726
1865
|
final_response_packet.session_flags.encrypt_data = 0
|
1727
1866
|
smb2_client.smb2_authenticate
|
1728
|
-
expect(smb2_client.
|
1867
|
+
expect(smb2_client.session_encrypt_data).to be false
|
1729
1868
|
end
|
1730
1869
|
end
|
1731
1870
|
end
|
@@ -2220,7 +2359,7 @@ RSpec.describe RubySMB::Client do
|
|
2220
2359
|
let(:named_pipe){ double("Named Pipe") }
|
2221
2360
|
|
2222
2361
|
before :example do
|
2223
|
-
allow(tree).to receive(:
|
2362
|
+
allow(tree).to receive(:open_pipe).and_return(named_pipe)
|
2224
2363
|
allow(named_pipe).to receive(:net_share_enum_all)
|
2225
2364
|
end
|
2226
2365
|
|
@@ -2235,8 +2374,8 @@ RSpec.describe RubySMB::Client do
|
|
2235
2374
|
smb1_client.net_share_enum_all(sock.peeraddr)
|
2236
2375
|
end
|
2237
2376
|
|
2238
|
-
it 'it calls the Tree #
|
2239
|
-
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)
|
2240
2379
|
smb1_client.net_share_enum_all(sock.peeraddr)
|
2241
2380
|
end
|
2242
2381
|
|
@@ -2258,8 +2397,8 @@ RSpec.describe RubySMB::Client do
|
|
2258
2397
|
smb2_client.net_share_enum_all(sock.peeraddr)
|
2259
2398
|
end
|
2260
2399
|
|
2261
|
-
it 'it calls the Tree #
|
2262
|
-
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)
|
2263
2402
|
smb2_client.net_share_enum_all(sock.peeraddr)
|
2264
2403
|
end
|
2265
2404
|
|
@@ -2340,7 +2479,7 @@ RSpec.describe RubySMB::Client do
|
|
2340
2479
|
before :example do
|
2341
2480
|
allow(ipc_tree).to receive_messages(
|
2342
2481
|
:share => share,
|
2343
|
-
:
|
2482
|
+
:open_pipe => named_pipe
|
2344
2483
|
)
|
2345
2484
|
allow(client).to receive(:tree_connect).and_return(ipc_tree)
|
2346
2485
|
end
|
@@ -2362,9 +2501,9 @@ RSpec.describe RubySMB::Client do
|
|
2362
2501
|
expect(client).to have_received(:tree_connect).with(share)
|
2363
2502
|
end
|
2364
2503
|
|
2365
|
-
it 'open \'winreg\'
|
2504
|
+
it 'open \'winreg\' pipe on the IPC$ Tree' do
|
2366
2505
|
client.connect_to_winreg(host)
|
2367
|
-
expect(ipc_tree).to have_received(:
|
2506
|
+
expect(ipc_tree).to have_received(:open_pipe).with(filename: "winreg", write: true, read: true)
|
2368
2507
|
end
|
2369
2508
|
|
2370
2509
|
it 'returns the expected opened named pipe' do
|