ruby_smb 3.3.19 → 3.3.21
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
- data/examples/anonymous_auth.rb +5 -0
- data/examples/append_file.rb +57 -14
- data/examples/authenticate.rb +64 -16
- data/examples/delete_file.rb +53 -11
- data/examples/dump_secrets_from_sid.rb +43 -8
- data/examples/enum_domain_users.rb +51 -8
- data/examples/enum_registry_key.rb +51 -7
- data/examples/enum_registry_values.rb +51 -9
- data/examples/get_computer_info.rb +48 -8
- data/examples/list_directory.rb +54 -12
- data/examples/negotiate.rb +54 -42
- data/examples/negotiate_with_netbios_service.rb +55 -16
- data/examples/net_share_enum_all.rb +47 -8
- data/examples/pipes.rb +51 -7
- data/examples/query_service_status.rb +51 -8
- data/examples/read_file_encryption.rb +71 -26
- data/examples/read_registry_key_value.rb +54 -9
- data/examples/rename_file.rb +58 -15
- data/examples/write_file.rb +58 -15
- data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level/query_fs_cifs_unix_info.rb +31 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level.rb +4 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request.rb +12 -4
- data/lib/ruby_smb/smb1/packet/trans2/set_fs_information_level.rb +28 -0
- data/lib/ruby_smb/smb1/packet/trans2/set_fs_information_request.rb +90 -0
- data/lib/ruby_smb/smb1/packet/trans2/set_fs_information_response.rb +56 -0
- data/lib/ruby_smb/smb1/packet/trans2/set_information_level.rb +35 -0
- data/lib/ruby_smb/smb1/packet/trans2/set_path_information_request.rb +75 -0
- data/lib/ruby_smb/smb1/packet/trans2/set_path_information_response.rb +51 -0
- data/lib/ruby_smb/smb1/packet/trans2.rb +8 -0
- data/lib/ruby_smb/smb1/tree.rb +124 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request_spec.rb +6 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_fs_information_request_spec.rb +52 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_fs_information_response_spec.rb +29 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_path_information_request_spec.rb +114 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_path_information_response_spec.rb +54 -0
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +124 -0
- metadata +17 -2
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB1
|
|
3
|
+
module Packet
|
|
4
|
+
module Trans2
|
|
5
|
+
# Information Level codes valid for Trans2 SET_PATH_INFORMATION and
|
|
6
|
+
# SET_FILE_INFORMATION requests. See
|
|
7
|
+
# [MS-CIFS 2.2.2.3.4 SET Information Level Codes](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/0321265e-312a-4721-90fa-cd40a443ed86).
|
|
8
|
+
#
|
|
9
|
+
# FSCC pass-through levels are defined in
|
|
10
|
+
# {RubySMB::Fscc::FileInformation} and require
|
|
11
|
+
# `SMB_INFO_PASSTHROUGH` to be added. The constants defined here are
|
|
12
|
+
# the CIFS UNIX Extensions info levels used by Samba servers that
|
|
13
|
+
# advertise UNIX extensions support in their negotiate response. These
|
|
14
|
+
# levels fall outside MS-CIFS; their wire format is defined by the
|
|
15
|
+
# CIFS UNIX Extensions draft and implemented by Samba's
|
|
16
|
+
# `smb_set_file_unix_link` handler at
|
|
17
|
+
# [source3/smbd/smb1_trans2.c:3643-3712](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L3643-L3712).
|
|
18
|
+
module SetInformationLevel
|
|
19
|
+
# Set the symbolic link target for a file. The Trans2 parameters
|
|
20
|
+
# block carries the path being created (the symlink itself); the
|
|
21
|
+
# Trans2 data block carries the target path as a null-terminated
|
|
22
|
+
# string.
|
|
23
|
+
SMB_SET_FILE_UNIX_LINK = 0x0201
|
|
24
|
+
|
|
25
|
+
# Create a hard link. Data block carries the existing file path.
|
|
26
|
+
SMB_SET_FILE_UNIX_HLINK = 0x0203
|
|
27
|
+
|
|
28
|
+
def self.name(value)
|
|
29
|
+
constants.select { |c| c.upcase == c }.find { |c| const_get(c) == value }
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB1
|
|
3
|
+
module Packet
|
|
4
|
+
module Trans2
|
|
5
|
+
# The Trans2 Parameter Block for a SET_PATH_INFORMATION request as
|
|
6
|
+
# defined in
|
|
7
|
+
# [MS-CIFS 2.2.6.7.1 Request](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/2ca0642a-1cd4-4e72-a16f-9e804a218262).
|
|
8
|
+
class SetPathInformationRequestTrans2Parameters < BinData::Record
|
|
9
|
+
endian :little
|
|
10
|
+
|
|
11
|
+
uint16 :information_level, label: 'Information Level'
|
|
12
|
+
uint32 :reserved, label: 'Reserved'
|
|
13
|
+
choice :filename, copy_on_change: true, selection: -> { parent.parent.smb_header.flags2.unicode } do
|
|
14
|
+
stringz16 1, label: 'FileName'
|
|
15
|
+
stringz 0, label: 'FileName'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Returns the length of the Trans2Parameters struct
|
|
19
|
+
# in number of bytes
|
|
20
|
+
def length
|
|
21
|
+
do_num_bytes
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# The Trans2 Data Block for a SET_PATH_INFORMATION request as defined
|
|
26
|
+
# in
|
|
27
|
+
# [MS-CIFS 2.2.6.7.1 Request](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/2ca0642a-1cd4-4e72-a16f-9e804a218262).
|
|
28
|
+
#
|
|
29
|
+
# The data layout depends on the Information Level being set, so the
|
|
30
|
+
# block carries an opaque byte buffer that the caller fills in for the
|
|
31
|
+
# target info level. SMB_SET_FILE_UNIX_LINK (0x0201) for example
|
|
32
|
+
# carries the symlink target as a null-terminated string.
|
|
33
|
+
class SetPathInformationRequestTrans2Data < BinData::Record
|
|
34
|
+
string :buffer, read_length: -> { parent.buffer_read_length }
|
|
35
|
+
|
|
36
|
+
# Returns the length of the Trans2Data struct
|
|
37
|
+
# in number of bytes
|
|
38
|
+
def length
|
|
39
|
+
do_num_bytes
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# The {RubySMB::SMB1::DataBlock} specific to this packet type. See
|
|
44
|
+
# [MS-CIFS 2.2.6.7.1 Request](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/2ca0642a-1cd4-4e72-a16f-9e804a218262).
|
|
45
|
+
class SetPathInformationRequestDataBlock < RubySMB::SMB1::Packet::Trans2::DataBlock
|
|
46
|
+
uint8 :name, label: 'Name', initial_value: 0x00
|
|
47
|
+
string :pad1, length: -> { pad1_length }
|
|
48
|
+
set_path_information_request_trans2_parameters :trans2_parameters, label: 'Trans2 Parameters'
|
|
49
|
+
string :pad2, length: -> { pad2_length }
|
|
50
|
+
set_path_information_request_trans2_data :trans2_data, label: 'Trans2 Data'
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# A Trans2 SET_PATH_INFORMATION Request Packet as defined in
|
|
54
|
+
# [MS-CIFS 2.2.6.7.1 Request](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/2ca0642a-1cd4-4e72-a16f-9e804a218262).
|
|
55
|
+
# See also the subcommand overview at
|
|
56
|
+
# [MS-CIFS 2.2.6.7 TRANS2_SET_PATH_INFORMATION (0x0006)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/a23483d9-6543-4aaa-a996-e7c9506f8b94).
|
|
57
|
+
class SetPathInformationRequest < RubySMB::GenericPacket
|
|
58
|
+
COMMAND = RubySMB::SMB1::Commands::SMB_COM_TRANSACTION2
|
|
59
|
+
|
|
60
|
+
class ParameterBlock < RubySMB::SMB1::Packet::Trans2::Request::ParameterBlock
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
smb_header :smb_header
|
|
64
|
+
parameter_block :parameter_block
|
|
65
|
+
set_path_information_request_data_block :data_block
|
|
66
|
+
|
|
67
|
+
def initialize_instance
|
|
68
|
+
super
|
|
69
|
+
parameter_block.setup << RubySMB::SMB1::Packet::Trans2::Subcommands::SET_PATH_INFORMATION
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB1
|
|
3
|
+
module Packet
|
|
4
|
+
module Trans2
|
|
5
|
+
# The Trans2 Parameter Block for a SET_PATH_INFORMATION response as
|
|
6
|
+
# defined in
|
|
7
|
+
# [MS-CIFS 2.2.6.7.2 Response](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/cf1cd579-9687-465d-9274-08ebb5944cd3).
|
|
8
|
+
class SetPathInformationResponseTrans2Parameters < BinData::Record
|
|
9
|
+
endian :little
|
|
10
|
+
|
|
11
|
+
uint16 :ea_error_offset, label: 'Extended Attribute Error Offset'
|
|
12
|
+
|
|
13
|
+
# Returns the length of the Trans2Parameters struct
|
|
14
|
+
# in number of bytes
|
|
15
|
+
def length
|
|
16
|
+
do_num_bytes
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# The {RubySMB::SMB1::DataBlock} specific to this packet type. See
|
|
21
|
+
# [MS-CIFS 2.2.6.7.2 Response](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/cf1cd579-9687-465d-9274-08ebb5944cd3).
|
|
22
|
+
class SetPathInformationResponseDataBlock < RubySMB::SMB1::Packet::Trans2::DataBlock
|
|
23
|
+
string :pad1, length: -> { pad1_length }
|
|
24
|
+
set_path_information_response_trans2_parameters :trans2_parameters, label: 'Trans2 Parameters'
|
|
25
|
+
# trans2_data: No data is sent by this message.
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# A Trans2 SET_PATH_INFORMATION Response Packet as defined in
|
|
29
|
+
# [MS-CIFS 2.2.6.7.2 Response](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/cf1cd579-9687-465d-9274-08ebb5944cd3).
|
|
30
|
+
# See also the subcommand overview at
|
|
31
|
+
# [MS-CIFS 2.2.6.7 TRANS2_SET_PATH_INFORMATION (0x0006)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/a23483d9-6543-4aaa-a996-e7c9506f8b94).
|
|
32
|
+
class SetPathInformationResponse < RubySMB::GenericPacket
|
|
33
|
+
COMMAND = RubySMB::SMB1::Commands::SMB_COM_TRANSACTION2
|
|
34
|
+
|
|
35
|
+
class ParameterBlock < RubySMB::SMB1::Packet::Trans2::Response::ParameterBlock
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
smb_header :smb_header
|
|
39
|
+
parameter_block :parameter_block
|
|
40
|
+
set_path_information_response_data_block :data_block
|
|
41
|
+
|
|
42
|
+
def initialize_instance
|
|
43
|
+
super
|
|
44
|
+
parameter_block.setup << RubySMB::SMB1::Packet::Trans2::Subcommands::SET_PATH_INFORMATION
|
|
45
|
+
smb_header.flags.reply = 1
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -7,6 +7,8 @@ module RubySMB
|
|
|
7
7
|
require 'ruby_smb/smb1/packet/trans2/find_information_level'
|
|
8
8
|
require 'ruby_smb/smb1/packet/trans2/query_information_level'
|
|
9
9
|
require 'ruby_smb/smb1/packet/trans2/query_fs_information_level'
|
|
10
|
+
require 'ruby_smb/smb1/packet/trans2/set_information_level'
|
|
11
|
+
require 'ruby_smb/smb1/packet/trans2/set_fs_information_level'
|
|
10
12
|
require 'ruby_smb/smb1/packet/trans2/data_block'
|
|
11
13
|
require 'ruby_smb/smb1/packet/trans2/win9x_framing'
|
|
12
14
|
require 'ruby_smb/smb1/packet/trans2/subcommands'
|
|
@@ -23,6 +25,12 @@ module RubySMB
|
|
|
23
25
|
require 'ruby_smb/smb1/packet/trans2/set_file_information_response'
|
|
24
26
|
require 'ruby_smb/smb1/packet/trans2/query_path_information_request'
|
|
25
27
|
require 'ruby_smb/smb1/packet/trans2/query_path_information_response'
|
|
28
|
+
require 'ruby_smb/smb1/packet/trans2/set_path_information_request'
|
|
29
|
+
require 'ruby_smb/smb1/packet/trans2/set_path_information_response'
|
|
30
|
+
require 'ruby_smb/smb1/packet/trans2/query_fs_information_request'
|
|
31
|
+
require 'ruby_smb/smb1/packet/trans2/query_fs_information_response'
|
|
32
|
+
require 'ruby_smb/smb1/packet/trans2/set_fs_information_request'
|
|
33
|
+
require 'ruby_smb/smb1/packet/trans2/set_fs_information_response'
|
|
26
34
|
end
|
|
27
35
|
end
|
|
28
36
|
end
|
data/lib/ruby_smb/smb1/tree.rb
CHANGED
|
@@ -195,6 +195,66 @@ module RubySMB
|
|
|
195
195
|
results
|
|
196
196
|
end
|
|
197
197
|
|
|
198
|
+
# Create a UNIX symbolic link on the remote share using the CIFS UNIX
|
|
199
|
+
# Extensions SMB_SET_FILE_UNIX_LINK information level (0x0201) via a
|
|
200
|
+
# Trans2 SET_PATH_INFORMATION request.
|
|
201
|
+
#
|
|
202
|
+
# @example
|
|
203
|
+
# tree = client.tree_connect("\\\\samba\\writable")
|
|
204
|
+
# tree.set_unix_link(symlink: 'escape', target: '../../../../etc')
|
|
205
|
+
#
|
|
206
|
+
# @param symlink [String] the path, relative to the share, where the
|
|
207
|
+
# symbolic link file will be created
|
|
208
|
+
# @param target [String] the destination the symbolic link points to
|
|
209
|
+
# @return [WindowsError::ErrorCode] the NTStatus returned by the server
|
|
210
|
+
# @raise [RubySMB::Error::InvalidPacket] if the response is not a Trans2
|
|
211
|
+
# SET_PATH_INFORMATION response
|
|
212
|
+
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus
|
|
213
|
+
# is not STATUS_SUCCESS
|
|
214
|
+
def set_unix_link(symlink:, target:)
|
|
215
|
+
# Samba gates SMB_SET_FILE_UNIX_LINK behind a per-session CIFS UNIX
|
|
216
|
+
# Extensions handshake: query server capabilities, then echo them
|
|
217
|
+
# back via SMB_SET_CIFS_UNIX_INFO. Without this, Samba responds to
|
|
218
|
+
# the symlink request with STATUS_INVALID_LEVEL even when
|
|
219
|
+
# `unix extensions = yes` is set server-side.
|
|
220
|
+
enable_cifs_unix_extensions
|
|
221
|
+
|
|
222
|
+
request = RubySMB::SMB1::Packet::Trans2::SetPathInformationRequest.new
|
|
223
|
+
request = set_header_fields(request)
|
|
224
|
+
# CIFS UNIX Extensions paths are raw byte strings, not UTF-16. Clear
|
|
225
|
+
# flags2.unicode so the filename parameter and target data block are
|
|
226
|
+
# emitted as bytes — Samba rejects the UTF-16 variant with
|
|
227
|
+
# STATUS_INVALID_LEVEL.
|
|
228
|
+
request.smb_header.flags2.unicode = 0
|
|
229
|
+
|
|
230
|
+
t2_params = request.data_block.trans2_parameters
|
|
231
|
+
t2_params.information_level = RubySMB::SMB1::Packet::Trans2::SetInformationLevel::SMB_SET_FILE_UNIX_LINK
|
|
232
|
+
t2_params.filename = symlink
|
|
233
|
+
|
|
234
|
+
encoded_target = target.dup.force_encoding(Encoding::ASCII_8BIT)
|
|
235
|
+
encoded_target << "\x00".b unless encoded_target.end_with?("\x00".b)
|
|
236
|
+
request.data_block.trans2_data.buffer = encoded_target
|
|
237
|
+
|
|
238
|
+
request.parameter_block.total_parameter_count = request.parameter_block.parameter_count
|
|
239
|
+
request.parameter_block.total_data_count = request.parameter_block.data_count
|
|
240
|
+
request.parameter_block.max_parameter_count = request.parameter_block.parameter_count
|
|
241
|
+
request.parameter_block.max_data_count = 0
|
|
242
|
+
|
|
243
|
+
raw_response = client.send_recv(request)
|
|
244
|
+
response = RubySMB::SMB1::Packet::Trans2::SetPathInformationResponse.read(raw_response)
|
|
245
|
+
unless response.valid?
|
|
246
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
247
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
248
|
+
expected_cmd: RubySMB::SMB1::Packet::Trans2::SetPathInformationResponse::COMMAND,
|
|
249
|
+
packet: response
|
|
250
|
+
)
|
|
251
|
+
end
|
|
252
|
+
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
|
253
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
|
254
|
+
end
|
|
255
|
+
response.status_code
|
|
256
|
+
end
|
|
257
|
+
|
|
198
258
|
# Sets a few preset header fields that will always be set the same
|
|
199
259
|
# way for Tree operations. This is, the TreeID and Extended Attributes.
|
|
200
260
|
#
|
|
@@ -206,8 +266,72 @@ module RubySMB
|
|
|
206
266
|
request
|
|
207
267
|
end
|
|
208
268
|
|
|
269
|
+
# Perform the CIFS UNIX Extensions handshake on this tree: query the
|
|
270
|
+
# server's supported extensions (SMB_QUERY_CIFS_UNIX_INFO) and then
|
|
271
|
+
# echo the version and capability bits back via SMB_SET_CIFS_UNIX_INFO.
|
|
272
|
+
# Samba requires this round-trip to have completed on the current
|
|
273
|
+
# session before it will honor UNIX-extension info levels such as
|
|
274
|
+
# SMB_SET_FILE_UNIX_LINK.
|
|
275
|
+
#
|
|
276
|
+
# @return [WindowsError::ErrorCode] NTStatus of the SET reply
|
|
277
|
+
# @raise [RubySMB::Error::UnexpectedStatusCode] if either leg fails
|
|
278
|
+
def enable_cifs_unix_extensions
|
|
279
|
+
major, minor, capabilities = query_cifs_unix_info
|
|
280
|
+
set_cifs_unix_info(major: major, minor: minor, capabilities: capabilities)
|
|
281
|
+
end
|
|
282
|
+
|
|
209
283
|
private
|
|
210
284
|
|
|
285
|
+
def query_cifs_unix_info
|
|
286
|
+
request = RubySMB::SMB1::Packet::Trans2::QueryFsInformationRequest.new
|
|
287
|
+
request = set_header_fields(request)
|
|
288
|
+
request.smb_header.flags2.unicode = 0
|
|
289
|
+
request.data_block.trans2_parameters.information_level =
|
|
290
|
+
RubySMB::SMB1::Packet::Trans2::QueryFsInformationLevel::SMB_QUERY_CIFS_UNIX_INFO
|
|
291
|
+
request.parameter_block.total_parameter_count = request.parameter_block.parameter_count
|
|
292
|
+
request.parameter_block.total_data_count = 0
|
|
293
|
+
request.parameter_block.max_parameter_count = 0
|
|
294
|
+
request.parameter_block.max_data_count = 560
|
|
295
|
+
|
|
296
|
+
raw_response = client.send_recv(request)
|
|
297
|
+
response = RubySMB::SMB1::Packet::Trans2::QueryFsInformationResponse.read(raw_response)
|
|
298
|
+
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
|
299
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
|
300
|
+
end
|
|
301
|
+
info = RubySMB::SMB1::Packet::Trans2::QueryFsInformationLevel::QueryFsCifsUnixInfo.read(
|
|
302
|
+
response.data_block.trans2_data.buffer
|
|
303
|
+
)
|
|
304
|
+
[info.major_version.to_i, info.minor_version.to_i, info.capabilities.to_i]
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def set_cifs_unix_info(major:, minor:, capabilities:)
|
|
308
|
+
request = RubySMB::SMB1::Packet::Trans2::SetFsInformationRequest.new
|
|
309
|
+
request = set_header_fields(request)
|
|
310
|
+
request.smb_header.flags2.unicode = 0
|
|
311
|
+
request.data_block.trans2_parameters.fid = 0
|
|
312
|
+
request.data_block.trans2_parameters.information_level =
|
|
313
|
+
RubySMB::SMB1::Packet::Trans2::SetFsInformationLevel::SMB_SET_CIFS_UNIX_INFO
|
|
314
|
+
|
|
315
|
+
info = RubySMB::SMB1::Packet::Trans2::QueryFsInformationLevel::QueryFsCifsUnixInfo.new
|
|
316
|
+
info.major_version = major
|
|
317
|
+
info.minor_version = minor
|
|
318
|
+
info.capabilities = capabilities
|
|
319
|
+
request.data_block.trans2_data.buffer = info.to_binary_s
|
|
320
|
+
|
|
321
|
+
request.parameter_block.total_parameter_count = request.parameter_block.parameter_count
|
|
322
|
+
request.parameter_block.total_data_count = request.parameter_block.data_count
|
|
323
|
+
request.parameter_block.max_parameter_count = request.parameter_block.parameter_count
|
|
324
|
+
request.parameter_block.max_data_count = 0
|
|
325
|
+
|
|
326
|
+
raw_response = client.send_recv(request)
|
|
327
|
+
response = RubySMB::SMB1::Packet::Trans2::SetFsInformationResponse.read(raw_response)
|
|
328
|
+
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
|
329
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
|
330
|
+
end
|
|
331
|
+
response.status_code
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
|
|
211
335
|
def _open(filename:, flags: nil, options: nil, disposition: RubySMB::Dispositions::FILE_OPEN,
|
|
212
336
|
impersonation: RubySMB::ImpersonationLevels::SEC_IMPERSONATE, read: true, write: false, delete: false)
|
|
213
337
|
unless client.server_supports_nt_smbs
|
data/lib/ruby_smb/version.rb
CHANGED
|
@@ -40,7 +40,12 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::QueryFsInformationRequest do
|
|
|
40
40
|
|
|
41
41
|
it { is_expected.to respond_to :name }
|
|
42
42
|
it { is_expected.to respond_to :trans2_parameters }
|
|
43
|
-
it { is_expected.
|
|
43
|
+
it { is_expected.to respond_to :trans2_data }
|
|
44
|
+
|
|
45
|
+
it '#trans2_data is a zero-length placeholder (this request carries no data payload)' do
|
|
46
|
+
expect(data_block.trans2_data).to be_a BinData::String
|
|
47
|
+
expect(data_block.trans2_data.num_bytes).to eq 0
|
|
48
|
+
end
|
|
44
49
|
|
|
45
50
|
it 'should keep #trans2_parameters 4-byte aligned' do
|
|
46
51
|
expect(data_block.trans2_parameters.abs_offset % 4).to eq 0
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe RubySMB::SMB1::Packet::Trans2::SetFsInformationRequest do
|
|
4
|
+
subject(:packet) { described_class.new }
|
|
5
|
+
|
|
6
|
+
describe '#smb_header' do
|
|
7
|
+
subject(:header) { packet.smb_header }
|
|
8
|
+
|
|
9
|
+
it { is_expected.to be_a RubySMB::SMB1::SMBHeader }
|
|
10
|
+
|
|
11
|
+
it 'has the command set to SMB_COM_TRANSACTION2' do
|
|
12
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_TRANSACTION2
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe '#parameter_block' do
|
|
17
|
+
subject(:parameter_block) { packet.parameter_block }
|
|
18
|
+
|
|
19
|
+
it { is_expected.to be_a RubySMB::SMB1::Packet::Trans2::Request::ParameterBlock }
|
|
20
|
+
|
|
21
|
+
it 'uses the SET_FS_INFORMATION subcommand' do
|
|
22
|
+
expect(parameter_block.setup[0]).to eq RubySMB::SMB1::Packet::Trans2::Subcommands::SET_FS_INFORMATION
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe '#data_block' do
|
|
27
|
+
subject(:data_block) { packet.data_block }
|
|
28
|
+
|
|
29
|
+
it { is_expected.to respond_to :trans2_parameters }
|
|
30
|
+
it { is_expected.to respond_to :trans2_data }
|
|
31
|
+
|
|
32
|
+
describe '#trans2_parameters' do
|
|
33
|
+
subject(:parameters) { data_block.trans2_parameters }
|
|
34
|
+
|
|
35
|
+
it { is_expected.to respond_to :fid }
|
|
36
|
+
it { is_expected.to respond_to :information_level }
|
|
37
|
+
|
|
38
|
+
it 'is 4 bytes on the wire (fid + information_level)' do
|
|
39
|
+
parameters.fid = 0
|
|
40
|
+
parameters.information_level = RubySMB::SMB1::Packet::Trans2::SetFsInformationLevel::SMB_SET_CIFS_UNIX_INFO
|
|
41
|
+
expect(parameters.to_binary_s.bytesize).to eq 4
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe '#trans2_data' do
|
|
46
|
+
it 'carries an opaque byte buffer whose contents depend on the information level' do
|
|
47
|
+
data_block.trans2_data.buffer = "\x01\x00\x00\x00".b + "\x00".b * 8
|
|
48
|
+
expect(data_block.trans2_data.buffer.bytesize).to eq 12
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe RubySMB::SMB1::Packet::Trans2::SetFsInformationResponse do
|
|
4
|
+
subject(:packet) { described_class.new }
|
|
5
|
+
|
|
6
|
+
describe '#smb_header' do
|
|
7
|
+
subject(:header) { packet.smb_header }
|
|
8
|
+
|
|
9
|
+
it { is_expected.to be_a RubySMB::SMB1::SMBHeader }
|
|
10
|
+
|
|
11
|
+
it 'has the command set to SMB_COM_TRANSACTION2' do
|
|
12
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_TRANSACTION2
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'sets the reply flag' do
|
|
16
|
+
expect(header.flags.reply).to eq 1
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe '#parameter_block' do
|
|
21
|
+
subject(:parameter_block) { packet.parameter_block }
|
|
22
|
+
|
|
23
|
+
it { is_expected.to be_a RubySMB::SMB1::Packet::Trans2::Response::ParameterBlock }
|
|
24
|
+
|
|
25
|
+
it 'uses the SET_FS_INFORMATION subcommand' do
|
|
26
|
+
expect(parameter_block.setup[0]).to eq RubySMB::SMB1::Packet::Trans2::Subcommands::SET_FS_INFORMATION
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
RSpec.describe RubySMB::SMB1::Packet::Trans2::SetPathInformationRequest do
|
|
2
|
+
subject(:packet) { described_class.new }
|
|
3
|
+
|
|
4
|
+
describe '#smb_header' do
|
|
5
|
+
subject(:header) { packet.smb_header }
|
|
6
|
+
|
|
7
|
+
it 'is a standard SMB Header' do
|
|
8
|
+
expect(header).to be_a RubySMB::SMB1::SMBHeader
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'should have the command set to SMB_COM_TRANSACTION2' do
|
|
12
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_TRANSACTION2
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'should not have the response flag set' do
|
|
16
|
+
expect(header.flags.reply).to eq 0
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe '#parameter_block' do
|
|
21
|
+
subject(:parameter_block) { packet.parameter_block }
|
|
22
|
+
|
|
23
|
+
it 'is a standard ParameterBlock' do
|
|
24
|
+
expect(parameter_block).to be_a RubySMB::SMB1::Packet::Trans2::Request::ParameterBlock
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'should have the setup set to the SET_PATH_INFORMATION subcommand' do
|
|
28
|
+
expect(parameter_block.setup).to include RubySMB::SMB1::Packet::Trans2::Subcommands::SET_PATH_INFORMATION
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe '#data_block' do
|
|
33
|
+
subject(:data_block) { packet.data_block }
|
|
34
|
+
|
|
35
|
+
it 'is a standard DataBlock' do
|
|
36
|
+
expect(data_block).to be_a RubySMB::SMB1::DataBlock
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it { is_expected.to respond_to :name }
|
|
40
|
+
it { is_expected.to respond_to :trans2_parameters }
|
|
41
|
+
it { is_expected.to respond_to :trans2_data }
|
|
42
|
+
|
|
43
|
+
it 'should keep #trans2_parameters 4-byte aligned' do
|
|
44
|
+
expect(data_block.trans2_parameters.abs_offset % 4).to eq 0
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe '#trans2_parameters' do
|
|
48
|
+
subject(:parameters) { data_block.trans2_parameters }
|
|
49
|
+
|
|
50
|
+
it { is_expected.to respond_to :information_level }
|
|
51
|
+
it { is_expected.to respond_to :reserved }
|
|
52
|
+
it { is_expected.to respond_to :filename }
|
|
53
|
+
|
|
54
|
+
describe '#information_level' do
|
|
55
|
+
it 'is a 16-bit field' do
|
|
56
|
+
expect(parameters.information_level).to be_a BinData::Uint16le
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
describe '#reserved' do
|
|
61
|
+
it 'is a 32-bit field' do
|
|
62
|
+
expect(parameters.reserved).to be_a BinData::Uint32le
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe '#filename' do
|
|
67
|
+
it 'is a BinData::Choice' do
|
|
68
|
+
expect(parameters.filename).to be_a BinData::Choice
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'encodes the filename as OEM when the unicode flag is cleared' do
|
|
72
|
+
packet.smb_header.flags2.unicode = 0
|
|
73
|
+
parameters.filename = 'link'
|
|
74
|
+
expect(parameters.filename.to_binary_s).to eq "link\x00".b
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'encodes the filename as UTF-16LE when the unicode flag is set' do
|
|
78
|
+
packet.smb_header.flags2.unicode = 1
|
|
79
|
+
parameters.filename = 'link'
|
|
80
|
+
expect(parameters.filename.to_binary_s).to eq "link\x00".encode('UTF-16LE').b
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe '#trans2_data' do
|
|
86
|
+
subject(:data) { data_block.trans2_data }
|
|
87
|
+
|
|
88
|
+
it { is_expected.to respond_to :buffer }
|
|
89
|
+
|
|
90
|
+
it 'carries an opaque byte buffer for the info-level-specific payload' do
|
|
91
|
+
data.buffer = "target\x00"
|
|
92
|
+
expect(data.buffer.to_binary_s).to eq "target\x00".b
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe 'encoded bytes for an SMB_SET_FILE_UNIX_LINK request' do
|
|
98
|
+
it 'encodes the information level, filename and target in the expected positions' do
|
|
99
|
+
packet.smb_header.flags2.unicode = 1
|
|
100
|
+
packet.data_block.trans2_parameters.information_level =
|
|
101
|
+
RubySMB::SMB1::Packet::Trans2::SetInformationLevel::SMB_SET_FILE_UNIX_LINK
|
|
102
|
+
packet.data_block.trans2_parameters.filename = 'foo'
|
|
103
|
+
packet.data_block.trans2_data.buffer = "bar\x00".encode('UTF-16LE')
|
|
104
|
+
|
|
105
|
+
raw = packet.to_binary_s
|
|
106
|
+
# Information level (little-endian 0x0201)
|
|
107
|
+
expect(raw).to include("\x01\x02".b)
|
|
108
|
+
# Filename in UTF-16LE with null terminator
|
|
109
|
+
expect(raw).to include("foo\x00".encode('UTF-16LE').b)
|
|
110
|
+
# Target in UTF-16LE with null terminator
|
|
111
|
+
expect(raw).to include("bar\x00".encode('UTF-16LE').b)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
RSpec.describe RubySMB::SMB1::Packet::Trans2::SetPathInformationResponse do
|
|
2
|
+
subject(:packet) { described_class.new }
|
|
3
|
+
|
|
4
|
+
describe '#smb_header' do
|
|
5
|
+
subject(:header) { packet.smb_header }
|
|
6
|
+
|
|
7
|
+
it 'is a standard SMB Header' do
|
|
8
|
+
expect(header).to be_a RubySMB::SMB1::SMBHeader
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'should have the command set to SMB_COM_TRANSACTION2' do
|
|
12
|
+
expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_TRANSACTION2
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'should have the response flag set' do
|
|
16
|
+
expect(header.flags.reply).to eq 1
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe '#parameter_block' do
|
|
21
|
+
subject(:parameter_block) { packet.parameter_block }
|
|
22
|
+
|
|
23
|
+
it 'should have the setup set to the SET_PATH_INFORMATION subcommand' do
|
|
24
|
+
expect(parameter_block.setup).to include RubySMB::SMB1::Packet::Trans2::Subcommands::SET_PATH_INFORMATION
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe '#data_block' do
|
|
29
|
+
subject(:data_block) { packet.data_block }
|
|
30
|
+
|
|
31
|
+
it 'is a standard DataBlock' do
|
|
32
|
+
expect(data_block).to be_a RubySMB::SMB1::DataBlock
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it { is_expected.to respond_to :trans2_parameters }
|
|
36
|
+
it { is_expected.to_not respond_to :trans2_data }
|
|
37
|
+
|
|
38
|
+
it 'should keep #trans2_parameters 4-byte aligned' do
|
|
39
|
+
expect(data_block.trans2_parameters.abs_offset % 4).to eq 0
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe '#trans2_parameters' do
|
|
43
|
+
subject(:parameters) { data_block.trans2_parameters }
|
|
44
|
+
|
|
45
|
+
it { is_expected.to respond_to :ea_error_offset }
|
|
46
|
+
|
|
47
|
+
describe '#ea_error_offset' do
|
|
48
|
+
it 'is a 16-bit field' do
|
|
49
|
+
expect(parameters.ea_error_offset).to be_a BinData::Uint16le
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|