ruby_smb 2.0.0 → 2.0.5
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 +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
|