ruby_smb 2.0.13 → 3.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/examples/anonymous_auth.rb +29 -6
- data/examples/auth_capture.rb +28 -0
- data/examples/file_server.rb +76 -0
- data/examples/read_file.rb +51 -10
- data/examples/tree_connect.rb +49 -8
- data/lib/ruby_smb/client/authentication.rb +11 -3
- data/lib/ruby_smb/client.rb +11 -2
- data/lib/ruby_smb/create_actions.rb +21 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_request.rb +20 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_response.rb +20 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_request.rb +21 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_response.rb +21 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system.rb +44 -0
- data/lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_request.rb +22 -0
- data/lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_response.rb +20 -0
- data/lib/ruby_smb/dcerpc/print_system/rpc_enum_printer_drivers_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/print_system/rpc_enum_printer_drivers_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/print_system/rpc_get_printer_driver_directory_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/print_system/rpc_get_printer_driver_directory_response.rb +22 -0
- data/lib/ruby_smb/dcerpc/print_system.rb +69 -0
- data/lib/ruby_smb/dcerpc.rb +2 -2
- data/lib/ruby_smb/field/nt_status.rb +20 -1
- data/lib/ruby_smb/fscc/file_information/file_ea_information.rb +14 -0
- data/lib/ruby_smb/fscc/file_information/file_network_open_information.rb +22 -0
- data/lib/ruby_smb/fscc/file_information/file_stream_information.rb +16 -0
- data/lib/ruby_smb/fscc/file_information.rb +29 -0
- data/lib/ruby_smb/fscc/file_system_information/file_fs_attribute_information.rb +46 -0
- data/lib/ruby_smb/fscc/file_system_information/file_fs_volume_information.rb +19 -0
- data/lib/ruby_smb/fscc/file_system_information.rb +22 -0
- data/lib/ruby_smb/fscc.rb +1 -0
- data/lib/ruby_smb/generic_packet.rb +6 -0
- data/lib/ruby_smb/gss/provider/authenticator.rb +4 -0
- data/lib/ruby_smb/gss/provider/ntlm.rb +13 -3
- data/lib/ruby_smb/server/server_client/negotiation.rb +0 -2
- data/lib/ruby_smb/server/server_client/session_setup.rb +43 -32
- data/lib/ruby_smb/server/server_client/share_io.rb +28 -0
- data/lib/ruby_smb/server/server_client/tree_connect.rb +60 -0
- data/lib/ruby_smb/server/server_client.rb +214 -24
- data/lib/ruby_smb/server/session.rb +71 -0
- data/lib/ruby_smb/server/share/provider/disk.rb +437 -0
- data/lib/ruby_smb/server/share/provider/pipe.rb +27 -0
- data/lib/ruby_smb/server/share/provider/processor.rb +76 -0
- data/lib/ruby_smb/server/share/provider.rb +38 -0
- data/lib/ruby_smb/server/share.rb +11 -0
- data/lib/ruby_smb/server.rb +35 -3
- data/lib/ruby_smb/signing.rb +37 -11
- data/lib/ruby_smb/smb1/commands.rb +4 -0
- data/lib/ruby_smb/smb1/tree.rb +87 -79
- data/lib/ruby_smb/smb1.rb +0 -1
- data/lib/ruby_smb/smb2/bit_field/smb2_header_flags.rb +2 -1
- data/lib/ruby_smb/smb2/commands.rb +4 -0
- data/lib/ruby_smb/smb2/create_context/request.rb +64 -0
- data/lib/ruby_smb/smb2/create_context/response.rb +62 -0
- data/lib/ruby_smb/smb2/create_context.rb +74 -22
- data/lib/ruby_smb/smb2/packet/create_request.rb +44 -11
- data/lib/ruby_smb/smb2/packet/create_response.rb +17 -3
- data/lib/ruby_smb/smb2/packet/query_directory_request.rb +1 -1
- data/lib/ruby_smb/smb2/packet/query_directory_response.rb +2 -2
- data/lib/ruby_smb/smb2/packet/query_info_request.rb +43 -0
- data/lib/ruby_smb/smb2/packet/query_info_response.rb +23 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +1 -1
- data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +1 -0
- data/lib/ruby_smb/smb2/packet.rb +2 -0
- data/lib/ruby_smb/smb2/tree.rb +80 -70
- data/lib/ruby_smb/smb2.rb +11 -0
- data/lib/ruby_smb/smb_error.rb +110 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/lib/ruby_smb.rb +2 -0
- data/ruby_smb.gemspec +1 -1
- data/spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_response_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_request_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/driver_container_spec.rb +41 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/driver_info2_spec.rb +64 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_request_spec.rb +59 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_response_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/rpc_enum_printer_drivers_request_spec.rb +62 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/rpc_enum_printer_drivers_response_spec.rb +54 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/rpc_get_printer_driver_directory_request_spec.rb +62 -0
- data/spec/lib/ruby_smb/dcerpc/print_system/rpc_get_printer_driver_directory_response_spec.rb +46 -0
- data/spec/lib/ruby_smb/field/nt_status_spec.rb +6 -2
- data/spec/lib/ruby_smb/gss/provider/ntlm/authenticator_spec.rb +4 -0
- data/spec/lib/ruby_smb/server/server_client_spec.rb +36 -53
- data/spec/lib/ruby_smb/server/session_spec.rb +38 -0
- data/spec/lib/ruby_smb/server/share/provider/disk_spec.rb +61 -0
- data/spec/lib/ruby_smb/server/share/provider/pipe_spec.rb +31 -0
- data/spec/lib/ruby_smb/server/share/provider_spec.rb +13 -0
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +3 -3
- data/spec/lib/ruby_smb/smb2/bit_field/header_flags_spec.rb +8 -2
- data/spec/lib/ruby_smb/smb2/{create_context_spec.rb → create_context/create_context_request_spec.rb} +1 -1
- data/spec/lib/ruby_smb/smb2/packet/create_request_spec.rb +5 -5
- data/spec/lib/ruby_smb/smb2/packet/create_response_spec.rb +9 -5
- data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +3 -2
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +3 -3
- data.tar.gz.sig +3 -2
- metadata +71 -7
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/create_actions.rb +0 -20
@@ -9,8 +9,8 @@ module RubySMB
|
|
9
9
|
endian :little
|
10
10
|
smb2_header :smb2_header
|
11
11
|
uint16 :structure_size, label: 'Structure Size', initial_value: 9
|
12
|
-
uint16 :buffer_offset, label: 'Output Buffer Offset', initial_value: -> { buffer.abs_offset }
|
13
|
-
uint32 :buffer_length, label: 'Output Buffer Length', initial_value: -> { buffer.do_num_bytes }
|
12
|
+
uint16 :buffer_offset, label: 'Output Buffer Offset', initial_value: -> { buffer.empty? ? 0 : buffer.abs_offset }
|
13
|
+
uint32 :buffer_length, label: 'Output Buffer Length', initial_value: -> { buffer.empty? ? 0 : buffer.do_num_bytes }
|
14
14
|
string :buffer, read_length: -> { buffer_length }
|
15
15
|
|
16
16
|
def initialize_instance
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module SMB2
|
3
|
+
module Packet
|
4
|
+
# An SMB2 Query Info Request Packet as defined in
|
5
|
+
# [2.2.37 SMB2 QUERY_INFO Request](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/d623b2f7-a5cd-4639-8cc9-71fa7d9f9ba9)
|
6
|
+
class QueryInfoRequest < RubySMB::GenericPacket
|
7
|
+
COMMAND = RubySMB::SMB2::Commands::QUERY_INFO
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
smb2_header :smb2_header
|
11
|
+
uint16 :structure_size, label: 'Structure Size', initial_value: 41
|
12
|
+
uint8 :info_type, label: 'Information Type'
|
13
|
+
uint8 :file_information_class, label: 'File Information Class'
|
14
|
+
uint32 :output_buffer_length, label: 'Output Buffer Length'
|
15
|
+
uint16 :input_buffer_offset, label: 'Input Buffer Offset'
|
16
|
+
uint16 :reserved, label: 'Reserved Space'
|
17
|
+
uint32 :input_buffer_length, label: 'Input Buffer Length'
|
18
|
+
struct :additional_information do
|
19
|
+
bit1 :reserved1
|
20
|
+
bit1 :scope_security_information, label: 'Scope Security Information'
|
21
|
+
bit1 :attribute_security_information, label: 'Attribute Security Information'
|
22
|
+
bit1 :label_security_information, label: 'Label Security Information'
|
23
|
+
bit1 :sacl_security_information, label: 'SACL Security Information'
|
24
|
+
bit1 :dacl_security_information, label: 'DACL Security Information'
|
25
|
+
bit1 :group_security_information, label: 'Group Security Information'
|
26
|
+
bit1 :owner_security_information, label: 'Owner Security Information'
|
27
|
+
bit7 :reserved2
|
28
|
+
bit1 :backup_security_information, label: 'Backup Security Information'
|
29
|
+
skip length: 2
|
30
|
+
end
|
31
|
+
struct :flags do
|
32
|
+
bit5 :reserved
|
33
|
+
bit1 :sl_index_specified, label: 'Index Specified'
|
34
|
+
bit1 :sl_return_single_entry, label: 'Return Single Entry'
|
35
|
+
bit1 :sl_restart_scan, label: 'Restart Scan'
|
36
|
+
skip length: 3
|
37
|
+
end
|
38
|
+
smb2_fileid :file_id, label: 'File ID'
|
39
|
+
string :buffer, label: 'Buffer'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module SMB2
|
3
|
+
module Packet
|
4
|
+
# An SMB2 Query Info Response Packet as defined in
|
5
|
+
# [2.2.38 SMB2 QUERY_INFO Response](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/3b1b3598-a898-44ca-bfac-2dcae065247f)
|
6
|
+
class QueryInfoResponse < RubySMB::GenericPacket
|
7
|
+
COMMAND = RubySMB::SMB2::Commands::QUERY_INFO
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
smb2_header :smb2_header
|
11
|
+
uint16 :structure_size, label: 'Structure Size', initial_value: 9
|
12
|
+
uint16 :buffer_offset, label: 'Output Buffer Offset', initial_value: -> { buffer.empty? ? 0 : buffer.abs_offset }
|
13
|
+
uint32 :buffer_length, label: 'Output Buffer Length', initial_value: -> { buffer.empty? ? 0 : buffer.do_num_bytes }
|
14
|
+
string :buffer, read_length: -> { buffer_length }
|
15
|
+
|
16
|
+
def initialize_instance
|
17
|
+
super
|
18
|
+
smb2_header.flags.reply = 1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -21,7 +21,7 @@ module RubySMB
|
|
21
21
|
uint8 :reserved, label: 'Reserved Space', initial_value: 0x00
|
22
22
|
share_flags :share_flags
|
23
23
|
share_capabilities :capabilities
|
24
|
-
|
24
|
+
file_access_mask :maximal_access, label: 'Maximal Access'
|
25
25
|
|
26
26
|
def initialize_instance
|
27
27
|
super
|
data/lib/ruby_smb/smb2/packet.rb
CHANGED
@@ -32,6 +32,8 @@ module RubySMB
|
|
32
32
|
require 'ruby_smb/smb2/packet/ioctl_response'
|
33
33
|
require 'ruby_smb/smb2/packet/transform_header'
|
34
34
|
require 'ruby_smb/smb2/packet/compression_transform_header'
|
35
|
+
require 'ruby_smb/smb2/packet/query_info_request'
|
36
|
+
require 'ruby_smb/smb2/packet/query_info_response'
|
35
37
|
end
|
36
38
|
end
|
37
39
|
end
|
data/lib/ruby_smb/smb2/tree.rb
CHANGED
@@ -60,78 +60,16 @@ module RubySMB
|
|
60
60
|
# Make sure we don't modify the caller's hash options
|
61
61
|
opts = opts.dup
|
62
62
|
opts[:filename] = opts[:filename].dup
|
63
|
-
opts[:filename] = opts[:filename][1..-1] if opts[:filename].start_with?
|
64
|
-
|
63
|
+
opts[:filename] = opts[:filename][1..-1] if opts[:filename].start_with?('\\'.encode(opts[:filename].encoding))
|
64
|
+
_open(**opts)
|
65
65
|
end
|
66
66
|
|
67
|
-
def open_file(
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
# If the user supplied file attributes, use those, otherwise set some
|
74
|
-
# sane defaults.
|
75
|
-
if attributes
|
76
|
-
create_request.file_attributes = attributes
|
77
|
-
else
|
78
|
-
create_request.file_attributes.directory = 0
|
79
|
-
create_request.file_attributes.normal = 1
|
80
|
-
end
|
81
|
-
|
82
|
-
# If the user supplied Create Options, use those, otherwise set some
|
83
|
-
# sane defaults.
|
84
|
-
if options
|
85
|
-
create_request.create_options = options
|
86
|
-
else
|
87
|
-
create_request.create_options.directory_file = 0
|
88
|
-
create_request.create_options.non_directory_file = 1
|
89
|
-
end
|
90
|
-
|
91
|
-
if read
|
92
|
-
create_request.share_access.read_access = 1
|
93
|
-
create_request.desired_access.read_data = 1
|
94
|
-
end
|
95
|
-
|
96
|
-
if write
|
97
|
-
create_request.share_access.write_access = 1
|
98
|
-
create_request.desired_access.write_data = 1
|
99
|
-
create_request.desired_access.append_data = 1
|
100
|
-
end
|
101
|
-
|
102
|
-
if delete
|
103
|
-
create_request.share_access.delete_access = 1
|
104
|
-
create_request.desired_access.delete_access = 1
|
105
|
-
end
|
106
|
-
|
107
|
-
create_request.requested_oplock = 0xff
|
108
|
-
create_request.impersonation_level = impersonation
|
109
|
-
create_request.create_disposition = disposition
|
110
|
-
create_request.name = filename
|
111
|
-
|
112
|
-
raw_response = client.send_recv(create_request, encrypt: @tree_connect_encrypt_data)
|
113
|
-
response = RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
|
114
|
-
unless response.valid?
|
115
|
-
raise RubySMB::Error::InvalidPacket.new(
|
116
|
-
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
117
|
-
expected_cmd: RubySMB::SMB2::Packet::CreateResponse::COMMAND,
|
118
|
-
packet: response
|
119
|
-
)
|
120
|
-
end
|
121
|
-
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
122
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
123
|
-
end
|
124
|
-
|
125
|
-
case @share_type
|
126
|
-
when RubySMB::SMB2::Packet::TreeConnectResponse::SMB2_SHARE_TYPE_DISK
|
127
|
-
RubySMB::SMB2::File.new(name: filename, tree: self, response: response, encrypt: @tree_connect_encrypt_data)
|
128
|
-
when RubySMB::SMB2::Packet::TreeConnectResponse::SMB2_SHARE_TYPE_PIPE
|
129
|
-
RubySMB::SMB2::Pipe.new(name: filename, tree: self, response: response)
|
130
|
-
# when RubySMB::SMB2::TreeConnectResponse::SMB2_SHARE_TYPE_PRINT
|
131
|
-
# it's a printer!
|
132
|
-
else
|
133
|
-
raise RubySMB::Error::RubySMBError, 'Unsupported share type'
|
134
|
-
end
|
67
|
+
def open_file(opts)
|
68
|
+
# Make sure we don't modify the caller's hash options
|
69
|
+
opts = opts.dup
|
70
|
+
opts[:filename] = opts[:filename].dup
|
71
|
+
opts[:filename] = opts[:filename][1..-1] if opts[:filename].start_with?('\\'.encode(opts[:filename].encoding))
|
72
|
+
_open(**opts)
|
135
73
|
end
|
136
74
|
|
137
75
|
# List `directory` on the remote share.
|
@@ -270,6 +208,78 @@ module RubySMB
|
|
270
208
|
request.smb2_header.credits = 256
|
271
209
|
request
|
272
210
|
end
|
211
|
+
|
212
|
+
private
|
213
|
+
|
214
|
+
def _open(filename:, attributes: nil, options: nil, disposition: RubySMB::Dispositions::FILE_OPEN,
|
215
|
+
impersonation: RubySMB::ImpersonationLevels::SEC_IMPERSONATE, read: true, write: false, delete: false)
|
216
|
+
|
217
|
+
create_request = RubySMB::SMB2::Packet::CreateRequest.new
|
218
|
+
create_request = set_header_fields(create_request)
|
219
|
+
|
220
|
+
# If the user supplied file attributes, use those, otherwise set some
|
221
|
+
# sane defaults.
|
222
|
+
if attributes
|
223
|
+
create_request.file_attributes = attributes
|
224
|
+
else
|
225
|
+
create_request.file_attributes.directory = 0
|
226
|
+
create_request.file_attributes.normal = 1
|
227
|
+
end
|
228
|
+
|
229
|
+
# If the user supplied Create Options, use those, otherwise set some
|
230
|
+
# sane defaults.
|
231
|
+
if options
|
232
|
+
create_request.create_options = options
|
233
|
+
else
|
234
|
+
create_request.create_options.directory_file = 0
|
235
|
+
create_request.create_options.non_directory_file = 1
|
236
|
+
end
|
237
|
+
|
238
|
+
if read
|
239
|
+
create_request.share_access.read_access = 1
|
240
|
+
create_request.desired_access.read_data = 1
|
241
|
+
end
|
242
|
+
|
243
|
+
if write
|
244
|
+
create_request.share_access.write_access = 1
|
245
|
+
create_request.desired_access.write_data = 1
|
246
|
+
create_request.desired_access.append_data = 1
|
247
|
+
end
|
248
|
+
|
249
|
+
if delete
|
250
|
+
create_request.share_access.delete_access = 1
|
251
|
+
create_request.desired_access.delete_access = 1
|
252
|
+
end
|
253
|
+
|
254
|
+
create_request.requested_oplock = 0xff
|
255
|
+
create_request.impersonation_level = impersonation
|
256
|
+
create_request.create_disposition = disposition
|
257
|
+
create_request.name = filename
|
258
|
+
|
259
|
+
raw_response = client.send_recv(create_request, encrypt: @tree_connect_encrypt_data)
|
260
|
+
response = RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
|
261
|
+
unless response.valid?
|
262
|
+
raise RubySMB::Error::InvalidPacket.new(
|
263
|
+
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
264
|
+
expected_cmd: RubySMB::SMB2::Packet::CreateResponse::COMMAND,
|
265
|
+
packet: response
|
266
|
+
)
|
267
|
+
end
|
268
|
+
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
269
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
270
|
+
end
|
271
|
+
|
272
|
+
case @share_type
|
273
|
+
when RubySMB::SMB2::Packet::TreeConnectResponse::SMB2_SHARE_TYPE_DISK
|
274
|
+
RubySMB::SMB2::File.new(name: filename, tree: self, response: response, encrypt: @tree_connect_encrypt_data)
|
275
|
+
when RubySMB::SMB2::Packet::TreeConnectResponse::SMB2_SHARE_TYPE_PIPE
|
276
|
+
RubySMB::SMB2::Pipe.new(name: filename, tree: self, response: response)
|
277
|
+
# when RubySMB::SMB2::TreeConnectResponse::SMB2_SHARE_TYPE_PRINT
|
278
|
+
# it's a printer!
|
279
|
+
else
|
280
|
+
raise RubySMB::Error::RubySMBError, 'Unsupported share type'
|
281
|
+
end
|
282
|
+
end
|
273
283
|
end
|
274
284
|
end
|
275
285
|
end
|
data/lib/ruby_smb/smb2.rb
CHANGED
@@ -8,6 +8,17 @@ module RubySMB
|
|
8
8
|
# Wildcard revision, see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/63abf97c-0d09-47e2-88d6-6bfa552949a5
|
9
9
|
SMB2_WILDCARD_REVISION = 0x02ff
|
10
10
|
|
11
|
+
# Channel types, see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/320f04f3-1b28-45cd-aaa1-9e5aed810dca
|
12
|
+
SMB2_CHANNEL_NONE = 0
|
13
|
+
SMB2_CHANNEL_RDMA_V1 = 1
|
14
|
+
SMB2_CHANNEL_RDMA_V1_INVALIDATE = 2
|
15
|
+
|
16
|
+
# Information types, see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/d623b2f7-a5cd-4639-8cc9-71fa7d9f9ba9
|
17
|
+
SMB2_INFO_FILE = 1
|
18
|
+
SMB2_INFO_FILESYSTEM = 2
|
19
|
+
SMB2_INFO_SECURITY = 3
|
20
|
+
SMB2_INFO_QUOTA = 4
|
21
|
+
|
11
22
|
require 'ruby_smb/smb2/info_type'
|
12
23
|
require 'ruby_smb/smb2/commands'
|
13
24
|
require 'ruby_smb/smb2/create_context'
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'windows_error'
|
2
|
+
|
3
|
+
module RubySMB
|
4
|
+
# SMB Error codes as defined in
|
5
|
+
# [2.2.2.4 SMB Error Classes and Codes](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb/6ab6ca20-b404-41fd-b91a-2ed39e3762ea)
|
6
|
+
module SMBError
|
7
|
+
# Returns all the {WindowsError::ErrorCode} objects that match
|
8
|
+
# the return value supplied.
|
9
|
+
#
|
10
|
+
# @param [Integer] retval the return value you want the error code for
|
11
|
+
# @raise [ArgumentError] if something other than a Integer is supplied
|
12
|
+
# @return [Array<WindowsError::ErrorCode>] all Win32 ErrorCodes that matched
|
13
|
+
def self.find_by_retval(retval)
|
14
|
+
raise ArgumentError, "Invalid Return Code!" unless retval.kind_of? Integer
|
15
|
+
error_codes = []
|
16
|
+
self.constants.each do |constant_name|
|
17
|
+
error_code = self.const_get(constant_name)
|
18
|
+
if error_code == retval
|
19
|
+
error_codes << error_code
|
20
|
+
end
|
21
|
+
end
|
22
|
+
error_codes
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# CONSTANTS
|
27
|
+
#
|
28
|
+
|
29
|
+
# (0x00000000) The client request is successful.
|
30
|
+
STATUS_SUCCESS = WindowsError::ErrorCode.new('STATUS_SUCCESS', 0x00000000, 'The client request is successful.')
|
31
|
+
|
32
|
+
# (0x00010002) An invalid SMB client request is received by the server.
|
33
|
+
STATUS_INVALID_SMB = WindowsError::ErrorCode.new('STATUS_INVALID_SMB', 0x00010002, 'An invalid SMB client request is received by the server.')
|
34
|
+
|
35
|
+
# (0x00050002) The client request received by the server contains an invalid TID value.
|
36
|
+
STATUS_SMB_BAD_TID = WindowsError::ErrorCode.new('STATUS_SMB_BAD_TID', 0x00050002, 'The client request received by the server contains an invalid TID value.')
|
37
|
+
|
38
|
+
# (0x00160002) The client request received by the server contains an unknown SMB command code.
|
39
|
+
STATUS_SMB_BAD_COMMAND = WindowsError::ErrorCode.new('STATUS_SMB_BAD_COMMAND', 0x00160002, 'The client request received by the server contains an unknown SMB command code.')
|
40
|
+
|
41
|
+
# (0x005B0002) The client request to the server contains an invalid UID value.
|
42
|
+
STATUS_SMB_BAD_UID = WindowsError::ErrorCode.new('STATUS_SMB_BAD_UID', 0x005B0002, 'The client request to the server contains an invalid UID value.')
|
43
|
+
|
44
|
+
# (0x00FB0002) The client request received by the server is for a non-standard SMB operation (for example, an SMB_COM_READ_MPX request on a non-disk share). The client SHOULD send another request with a different SMB command to perform this operation.
|
45
|
+
STATUS_SMB_USE_STANDARD = WindowsError::ErrorCode.new('STATUS_SMB_USE_STANDARD', 0x00FB0002, 'The client request received by the server is for a non-standard SMB operation (for example, an SMB_COM_READ_MPX request on a non-disk share). The client SHOULD send another request with a different SMB command to perform this operation.')
|
46
|
+
|
47
|
+
# (0x80000005) The data was too large to fit into the specified buffer.
|
48
|
+
STATUS_BUFFER_OVERFLOW = WindowsError::ErrorCode.new('STATUS_BUFFER_OVERFLOW', 0x80000005, 'The data was too large to fit into the specified buffer.')
|
49
|
+
|
50
|
+
# (0x80000006) No more files were found that match the file specification.
|
51
|
+
STATUS_NO_MORE_FILES = WindowsError::ErrorCode.new('STATUS_NO_MORE_FILES', 0x80000006, 'No more files were found that match the file specification.')
|
52
|
+
|
53
|
+
# (0x8000002D) The create operation stopped after reaching a symbolic link.
|
54
|
+
STATUS_STOPPED_ON_SYMLINK = WindowsError::ErrorCode.new('STATUS_STOPPED_ON_SYMLINK', 0x8000002D, 'The create operation stopped after reaching a symbolic link.')
|
55
|
+
|
56
|
+
# (0xC0000002) The requested operation is not implemented.
|
57
|
+
STATUS_NOT_IMPLEMENTED = WindowsError::ErrorCode.new('STATUS_NOT_IMPLEMENTED', 0xC0000002, 'The requested operation is not implemented.')
|
58
|
+
|
59
|
+
# (0xC000000D) The parameter specified in the request is not valid.
|
60
|
+
STATUS_INVALID_PARAMETER = WindowsError::ErrorCode.new('STATUS_INVALID_PARAMETER', 0xC000000D, 'The parameter specified in the request is not valid.')
|
61
|
+
|
62
|
+
# (0xC000000E) A device that does not exist was specified.
|
63
|
+
STATUS_NO_SUCH_DEVICE = WindowsError::ErrorCode.new('STATUS_NO_SUCH_DEVICE', 0xC000000E, 'A device that does not exist was specified.')
|
64
|
+
|
65
|
+
# (0xC0000010) The specified request is not a valid operation for the target device.
|
66
|
+
STATUS_INVALID_DEVICE_REQUEST = WindowsError::ErrorCode.new('STATUS_INVALID_DEVICE_REQUEST', 0xC0000010, 'The specified request is not a valid operation for the target device.')
|
67
|
+
|
68
|
+
# (0xC0000016) If extended security has been negotiated, then this error code can be returned in the SMB_COM_SESSION_SETUP_ANDX response from the server to indicate that additional authentication information is to be exchanged. See section 2.2.4.6 for details.
|
69
|
+
STATUS_MORE_PROCESSING_REQUIRED = WindowsError::ErrorCode.new('STATUS_MORE_PROCESSING_REQUIRED', 0xC0000016, 'If extended security has been negotiated, then this error code can be returned in the SMB_COM_SESSION_SETUP_ANDX response from the server to indicate that additional authentication information is to be exchanged. See section 2.2.4.6 for details.')
|
70
|
+
|
71
|
+
# (0xC0000022) The client did not have the required permission needed for the operation.
|
72
|
+
STATUS_ACCESS_DENIED = WindowsError::ErrorCode.new('STATUS_ACCESS_DENIED', 0xC0000022, 'The client did not have the required permission needed for the operation.')
|
73
|
+
|
74
|
+
# (0xC0000023) The buffer is too small to contain the entry. No information has been written to the buffer.
|
75
|
+
STATUS_BUFFER_TOO_SMALL = WindowsError::ErrorCode.new('STATUS_BUFFER_TOO_SMALL', 0xC0000023, 'The buffer is too small to contain the entry. No information has been written to the buffer.')
|
76
|
+
|
77
|
+
# (0xC0000034) The object name is not found.
|
78
|
+
STATUS_OBJECT_NAME_NOT_FOUND = WindowsError::ErrorCode.new('STATUS_OBJECT_NAME_NOT_FOUND', 0xC0000034, 'The object name is not found.')
|
79
|
+
|
80
|
+
# (0xC0000035) The object name already exists.
|
81
|
+
STATUS_OBJECT_NAME_COLLISION = WindowsError::ErrorCode.new('STATUS_OBJECT_NAME_COLLISION', 0xC0000035, 'The object name already exists.')
|
82
|
+
|
83
|
+
# (0xC000003A) The path to the directory specified was not found. This error is also returned on a create request if the operation requires the creation of more than one new directory level for the path specified.
|
84
|
+
STATUS_OBJECT_PATH_NOT_FOUND = WindowsError::ErrorCode.new('STATUS_OBJECT_PATH_NOT_FOUND', 0xC000003A, 'The path to the directory specified was not found. This error is also returned on a create request if the operation requires the creation of more than one new directory level for the path specified.')
|
85
|
+
|
86
|
+
# (0xC00000A5) A specified impersonation level is invalid. This error is also used to indicate that a required impersonation level was not provided.
|
87
|
+
STATUS_BAD_IMPERSONATION_LEVEL = WindowsError::ErrorCode.new('STATUS_BAD_IMPERSONATION_LEVEL', 0xC00000A5, 'A specified impersonation level is invalid. This error is also used to indicate that a required impersonation level was not provided.')
|
88
|
+
|
89
|
+
# (0xC00000B5) The specified I/O operation was not completed before the time-out period expired.
|
90
|
+
STATUS_IO_TIMEOUT = WindowsError::ErrorCode.new('STATUS_IO_TIMEOUT', 0xC00000B5, 'The specified I/O operation was not completed before the time-out period expired.')
|
91
|
+
|
92
|
+
# (0xC00000BA) The file that was specified as a target is a directory and the caller specified that it could be anything but a directory.
|
93
|
+
STATUS_FILE_IS_A_DIRECTORY = WindowsError::ErrorCode.new('STATUS_FILE_IS_A_DIRECTORY', 0xC00000BA, 'The file that was specified as a target is a directory and the caller specified that it could be anything but a directory.')
|
94
|
+
|
95
|
+
# (0xC00000BB) The client request is not supported.
|
96
|
+
STATUS_NOT_SUPPORTED = WindowsError::ErrorCode.new('STATUS_NOT_SUPPORTED', 0xC00000BB, 'The client request is not supported.')
|
97
|
+
|
98
|
+
# (0xC00000C9) The network name specified by the client has been deleted on the server. This error is returned if the client specifies an incorrect TID or the share on the server represented by the TID was deleted.
|
99
|
+
STATUS_NETWORK_NAME_DELETED = WindowsError::ErrorCode.new('STATUS_NETWORK_NAME_DELETED', 0xC00000C9, 'The network name specified by the client has been deleted on the server. This error is returned if the client specifies an incorrect TID or the share on the server represented by the TID was deleted.')
|
100
|
+
|
101
|
+
# (0xC0000203) The user session specified by the client has been deleted on the server. This error is returned by the server if the client sends an incorrect UID.
|
102
|
+
STATUS_USER_SESSION_DELETED = WindowsError::ErrorCode.new('STATUS_USER_SESSION_DELETED', 0xC0000203, 'The user session specified by the client has been deleted on the server. This error is returned by the server if the client sends an incorrect UID.')
|
103
|
+
|
104
|
+
# (0xC000035C) The client's session has expired; therefore, the client MUST re-authenticate to continue accessing remote resources.
|
105
|
+
STATUS_NETWORK_SESSION_EXPIRED = WindowsError::ErrorCode.new('STATUS_NETWORK_SESSION_EXPIRED', 0xC000035C, 'The client\'s session has expired; therefore, the client MUST re-authenticate to continue accessing remote resources.')
|
106
|
+
|
107
|
+
# (0xC000205A) The client has requested too many UID values from the server or the client already has an SMB session setup with this UID value.
|
108
|
+
STATUS_SMB_TOO_MANY_UIDS = WindowsError::ErrorCode.new('STATUS_SMB_TOO_MANY_UIDS', 0xC000205A, 'The client has requested too many UID values from the server or the client already has an SMB session setup with this UID value.')
|
109
|
+
end
|
110
|
+
end
|
data/lib/ruby_smb/version.rb
CHANGED
data/lib/ruby_smb.rb
CHANGED
@@ -12,6 +12,7 @@ require 'windows_error/nt_status'
|
|
12
12
|
# [[MS-SMB2] Server Message Block (SMB) Protocol Versions 2 and 3](https://msdn.microsoft.com/en-us/library/cc246482.aspx)
|
13
13
|
module RubySMB
|
14
14
|
require 'ruby_smb/error'
|
15
|
+
require 'ruby_smb/create_actions'
|
15
16
|
require 'ruby_smb/dispositions'
|
16
17
|
require 'ruby_smb/impersonation_levels'
|
17
18
|
require 'ruby_smb/gss'
|
@@ -28,4 +29,5 @@ module RubySMB
|
|
28
29
|
require 'ruby_smb/compression'
|
29
30
|
require 'ruby_smb/server'
|
30
31
|
require 'ruby_smb/dialect'
|
32
|
+
require 'ruby_smb/smb_error'
|
31
33
|
end
|
data/ruby_smb.gemspec
CHANGED
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec|
|
|
34
34
|
spec.add_development_dependency 'yard'
|
35
35
|
|
36
36
|
spec.add_runtime_dependency 'rubyntlm'
|
37
|
-
spec.add_runtime_dependency 'windows_error'
|
37
|
+
spec.add_runtime_dependency 'windows_error', '>= 0.1.3'
|
38
38
|
spec.add_runtime_dependency 'bindata'
|
39
39
|
spec.add_runtime_dependency 'openssl-ccm'
|
40
40
|
spec.add_runtime_dependency 'openssl-cmac'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::EncryptingFileSystem::EfsRpcEncryptFileSrvRequest do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :file_name }
|
5
|
+
|
6
|
+
it 'is little endian' do
|
7
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#file_name' do
|
11
|
+
it 'is a NdrConfVarWideStringz' do
|
12
|
+
expect(packet.file_name).to be_a RubySMB::Dcerpc::Ndr::NdrConfVarWideStringz
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#initialize_instance' do
|
17
|
+
it 'sets #opnum to EFS_RPC_ENCRYPT_FILE_SRV constant' do
|
18
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::EncryptingFileSystem::EFS_RPC_ENCRYPT_FILE_SRV)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'reads its own binary representation and outputs the same packet' do
|
23
|
+
packet = described_class.new(
|
24
|
+
file_name: 'file_name'
|
25
|
+
)
|
26
|
+
binary = packet.to_binary_s
|
27
|
+
expect(described_class.read(binary)).to eq(packet)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
data/spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_response_spec.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::EncryptingFileSystem::EfsRpcEncryptFileSrvResponse do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :error_status }
|
5
|
+
|
6
|
+
it 'is little endian' do
|
7
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#error_status' do
|
11
|
+
it 'is a NdrUint32' do
|
12
|
+
expect(packet.error_status).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#initialize_instance' do
|
17
|
+
it 'sets #opnum to EFS_RPC_ENCRYPT_FILE_SRV constant' do
|
18
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::EncryptingFileSystem::EFS_RPC_ENCRYPT_FILE_SRV)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'reads its own binary representation and outputs the same packet' do
|
23
|
+
packet = described_class.new(
|
24
|
+
error_status: 0
|
25
|
+
)
|
26
|
+
binary = packet.to_binary_s
|
27
|
+
expect(described_class.read(binary)).to eq(packet)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::EncryptingFileSystem::EfsRpcOpenFileRawRequest do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :file_name }
|
5
|
+
it { is_expected.to respond_to :flags }
|
6
|
+
|
7
|
+
it 'is little endian' do
|
8
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#file_name' do
|
12
|
+
it 'is a NdrConfVarWideStringz' do
|
13
|
+
expect(packet.file_name).to be_a RubySMB::Dcerpc::Ndr::NdrConfVarWideStringz
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#flags' do
|
18
|
+
it 'is a NdrUint32' do
|
19
|
+
expect(packet.flags).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#initialize_instance' do
|
24
|
+
it 'sets #opnum to EFS_RPC_OPEN_FILE_RAW constant' do
|
25
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::EncryptingFileSystem::EFS_RPC_OPEN_FILE_RAW)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'reads its own binary representation and outputs the same packet' do
|
30
|
+
packet = described_class.new(
|
31
|
+
file_name: 'file_name',
|
32
|
+
flags: 0
|
33
|
+
)
|
34
|
+
binary = packet.to_binary_s
|
35
|
+
expect(described_class.read(binary)).to eq(packet)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::EncryptingFileSystem::EfsRpcOpenFileRawResponse do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :h_context }
|
5
|
+
it { is_expected.to respond_to :error_status }
|
6
|
+
|
7
|
+
it 'is little endian' do
|
8
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#h_context' do
|
12
|
+
it 'is a NdrContextHandle' do
|
13
|
+
expect(packet.h_context).to be_a RubySMB::Dcerpc::Ndr::NdrContextHandle
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#error_status' do
|
18
|
+
it 'is a NdrUint32' do
|
19
|
+
expect(packet.error_status).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#initialize_instance' do
|
24
|
+
it 'sets #opnum to EFS_RPC_OPEN_FILE_RAW constant' do
|
25
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::EncryptingFileSystem::EFS_RPC_OPEN_FILE_RAW)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'reads its own binary representation and outputs the same packet' do
|
30
|
+
packet = described_class.new(
|
31
|
+
h_context: RubySMB::Dcerpc::Ndr::NdrContextHandle.new,
|
32
|
+
error_status: 0
|
33
|
+
)
|
34
|
+
binary = packet.to_binary_s
|
35
|
+
expect(described_class.read(binary)).to eq(packet)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::PrintSystem::DriverContainer do
|
2
|
+
subject(:struct) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :level }
|
5
|
+
it { is_expected.to respond_to :tag }
|
6
|
+
it { is_expected.to respond_to :driver_info }
|
7
|
+
|
8
|
+
it 'is little endian' do
|
9
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#level' do
|
13
|
+
it 'is a NdrUint32' do
|
14
|
+
expect(struct.level).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#tag' do
|
19
|
+
it 'is a NdrUint32' do
|
20
|
+
expect(struct.tag).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'reads its own binary representation and outputs the same struct' do
|
25
|
+
struct = described_class.new(
|
26
|
+
level: 2,
|
27
|
+
tag: 0,
|
28
|
+
driver_info: RubySMB::Dcerpc::PrintSystem::DriverInfo2.new(
|
29
|
+
c_version: 0,
|
30
|
+
p_name: 'p_name',
|
31
|
+
p_environment: 'p_environment',
|
32
|
+
p_driver_path: 'p_driver_path',
|
33
|
+
p_data_file: 'p_data_file',
|
34
|
+
p_config_file: 'p_config_file'
|
35
|
+
)
|
36
|
+
)
|
37
|
+
binary = struct.to_binary_s
|
38
|
+
expect(described_class.read(binary)).to eq(struct)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|