ruby_smb 3.0.6 → 3.1.2
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/file_server.rb +8 -1
- data/examples/virtual_file_server.rb +143 -0
- data/lib/ruby_smb/client/encryption.rb +16 -4
- data/lib/ruby_smb/client/negotiation.rb +10 -8
- data/lib/ruby_smb/fscc/file_information/file_access_information.rb +15 -0
- data/lib/ruby_smb/fscc/file_information/file_alignment_information.rb +45 -0
- data/lib/ruby_smb/fscc/file_information/file_all_information.rb +23 -0
- data/lib/ruby_smb/fscc/file_information/file_basic_information.rb +20 -0
- data/lib/ruby_smb/fscc/file_information/file_both_directory_information.rb +3 -3
- data/lib/ruby_smb/fscc/file_information/file_directory_information.rb +3 -3
- data/lib/ruby_smb/fscc/file_information/file_ea_information.rb +1 -0
- data/lib/ruby_smb/fscc/file_information/file_full_directory_information.rb +3 -3
- data/lib/ruby_smb/fscc/file_information/file_id_both_directory_information.rb +3 -3
- data/lib/ruby_smb/fscc/file_information/file_id_full_directory_information.rb +3 -3
- data/lib/ruby_smb/fscc/file_information/file_internal_information.rb +15 -0
- data/lib/ruby_smb/fscc/file_information/file_mode_information.rb +29 -0
- data/lib/ruby_smb/fscc/file_information/file_name_information.rb +16 -0
- data/lib/ruby_smb/fscc/file_information/file_names_information.rb +1 -1
- data/lib/ruby_smb/fscc/file_information/file_normalized_name_information.rb +16 -0
- data/lib/ruby_smb/fscc/file_information/file_position_information.rb +15 -0
- data/lib/ruby_smb/fscc/file_information/file_rename_information.rb +1 -1
- data/lib/ruby_smb/fscc/file_information/file_standard_information.rb +20 -0
- data/lib/ruby_smb/fscc/file_information/file_stream_information.rb +3 -0
- data/lib/ruby_smb/fscc/file_information.rb +43 -6
- data/lib/ruby_smb/fscc/file_system_information/file_fs_attribute_information.rb +1 -0
- data/lib/ruby_smb/fscc/file_system_information/file_fs_volume_information.rb +1 -0
- data/lib/ruby_smb/fscc/file_system_information.rb +4 -0
- data/lib/ruby_smb/gss/provider/ntlm.rb +20 -3
- data/lib/ruby_smb/gss/provider.rb +10 -1
- data/lib/ruby_smb/server/server_client/encryption.rb +66 -0
- data/lib/ruby_smb/server/server_client/negotiation.rb +14 -3
- data/lib/ruby_smb/server/server_client/session_setup.rb +21 -4
- data/lib/ruby_smb/server/server_client/share_io.rb +17 -0
- data/lib/ruby_smb/server/server_client/tree_connect.rb +40 -3
- data/lib/ruby_smb/server/server_client.rb +156 -38
- data/lib/ruby_smb/server/session.rb +5 -1
- data/lib/ruby_smb/server/share/provider/disk/file_system.rb +28 -0
- data/lib/ruby_smb/server/share/provider/disk/processor/close.rb +46 -0
- data/lib/ruby_smb/server/share/provider/disk/processor/create.rb +143 -0
- data/lib/ruby_smb/server/share/provider/disk/processor/query.rb +359 -0
- data/lib/ruby_smb/server/share/provider/disk/processor/read.rb +70 -0
- data/lib/ruby_smb/server/share/provider/disk/processor.rb +223 -0
- data/lib/ruby_smb/server/share/provider/disk.rb +12 -418
- data/lib/ruby_smb/server/share/provider/pipe.rb +2 -2
- data/lib/ruby_smb/server/share/provider/processor.rb +16 -0
- data/lib/ruby_smb/server/share/provider/virtual_disk/virtual_file.rb +85 -0
- data/lib/ruby_smb/server/share/provider/virtual_disk/virtual_pathname.rb +196 -0
- data/lib/ruby_smb/server/share/provider/virtual_disk/virtual_stat.rb +175 -0
- data/lib/ruby_smb/server/share/provider/virtual_disk.rb +116 -0
- data/lib/ruby_smb/server/share/provider.rb +1 -0
- data/lib/ruby_smb/server.rb +13 -3
- data/lib/ruby_smb/signing.rb +18 -4
- data/lib/ruby_smb/smb1/commands.rb +1 -0
- data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +11 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/read_andx_response.rb +5 -4
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +12 -4
- data/lib/ruby_smb/smb1/packet/trans2/data_block.rb +9 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +52 -51
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +37 -37
- data/lib/ruby_smb/smb1/packet/trans2/find_information_level/find_file_both_directory_info.rb +48 -0
- data/lib/ruby_smb/smb1/packet/trans2/find_information_level.rb +28 -15
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +51 -51
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +36 -36
- data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +40 -39
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +40 -40
- data/lib/ruby_smb/smb1/packet/trans2/query_file_information_request.rb +60 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_file_information_response.rb +59 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level/query_fs_attribute_info.rb +31 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level.rb +40 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request.rb +46 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_response.rb +59 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_information_level/query_file_basic_info.rb +23 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_information_level/query_file_standard_info.rb +22 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_information_level.rb +62 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_path_information_request.rb +65 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_path_information_response.rb +59 -0
- data/lib/ruby_smb/smb1/packet/trans2/request.rb +24 -8
- data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +4 -4
- data/lib/ruby_smb/smb1/packet/trans2/response.rb +29 -20
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +42 -42
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +23 -23
- data/lib/ruby_smb/smb1/packet/trans2/subcommands.rb +23 -5
- data/lib/ruby_smb/smb1/packet/trans2.rb +4 -0
- data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +4 -1
- data/lib/ruby_smb/smb2/negotiate_context.rb +10 -1
- data/lib/ruby_smb/smb2/packet/transform_header.rb +7 -7
- data/lib/ruby_smb/smb2/tree.rb +1 -0
- data/lib/ruby_smb/smb2.rb +1 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +31 -8
- data/spec/lib/ruby_smb/fscc/file_information/file_access_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_alignment_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_all_information_spec.rb +61 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_basic_information_spec.rb +41 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_both_directory_information_spec.rb +59 -10
- data/spec/lib/ruby_smb/fscc/file_information/file_directory_information_spec.rb +30 -12
- data/spec/lib/ruby_smb/fscc/file_information/file_ea_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_full_directory_information_spec.rb +30 -12
- data/spec/lib/ruby_smb/fscc/file_information/file_id_both_directory_information_spec.rb +63 -10
- data/spec/lib/ruby_smb/fscc/file_information/file_id_full_directory_information_spec.rb +30 -12
- data/spec/lib/ruby_smb/fscc/file_information/file_internal_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_mode_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_name_information_spec.rb +44 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_names_information_spec.rb +30 -12
- data/spec/lib/ruby_smb/fscc/file_information/file_network_open_information_spec.rb +51 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_normalized_name_information_spec.rb +44 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_position_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_rename_information_spec.rb +1 -1
- data/spec/lib/ruby_smb/fscc/file_information/file_standard_information_spec.rb +41 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_stream_information_spec.rb +51 -0
- data/spec/lib/ruby_smb/fscc/file_information_spec.rb +14 -0
- data/spec/lib/ruby_smb/fscc/file_system_information/file_fs_attribute_information_spec.rb +46 -0
- data/spec/lib/ruby_smb/fscc/file_system_information/file_fs_volume_information_spec.rb +51 -0
- data/spec/lib/ruby_smb/fscc/file_system_information_spec.rb +14 -0
- data/spec/lib/ruby_smb/server/server_client_spec.rb +15 -0
- data/spec/lib/ruby_smb/server/share/provider/virtual_disk/virtual_pathname_spec.rb +581 -0
- data/spec/lib/ruby_smb/server/share/provider/virtual_disk/virtual_stat_spec.rb +207 -0
- data/spec/lib/ruby_smb/server/share/provider/virtual_disk_spec.rb +122 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +36 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +35 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/query_file_information_request_spec.rb +74 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/query_file_information_response_spec.rb +96 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request_spec.rb +62 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/query_fs_information_response_spec.rb +88 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/query_path_information_request_spec.rb +79 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/query_path_information_response_spec.rb +96 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/response_spec.rb +3 -3
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_request_spec.rb +3 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +7 -2
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +3 -3
- data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +2 -2
- data.tar.gz.sig +0 -0
- metadata +88 -2
- metadata.gz.sig +0 -0
@@ -4,7 +4,10 @@ module RubySMB
|
|
4
4
|
# The FileStreamInformation
|
5
5
|
# [2.4.43 FileStreamInformation](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/f8762be6-3ab9-411e-a7d6-5cc68f70c78d)
|
6
6
|
class FileStreamInformation < BinData::Record
|
7
|
+
CLASS_LEVEL = Fscc::FileInformation::FILE_STREAM_INFORMATION
|
8
|
+
|
7
9
|
endian :little
|
10
|
+
|
8
11
|
uint32 :next_entry_offset, label: 'Next Entry Offset'
|
9
12
|
uint32 :stream_name_length, label: 'Stream Name Length', initial_value: -> { stream_name.do_num_bytes }
|
10
13
|
int64 :stream_size, label: 'Stream Size'
|
@@ -17,10 +17,26 @@ module RubySMB
|
|
17
17
|
# contents of a directory.
|
18
18
|
FILE_BOTH_DIRECTORY_INFORMATION = 0x03
|
19
19
|
|
20
|
+
# Information class used to query or set file information.
|
21
|
+
FILE_BASIC_INFORMATION = 0x04
|
22
|
+
|
23
|
+
# Information class is used to query file information.
|
24
|
+
FILE_STANDARD_INFORMATION = 0x05
|
25
|
+
|
26
|
+
# Information class used to query for the file system's 64-bit file ID.
|
27
|
+
FILE_INTERNAL_INFORMATION = 0x06
|
28
|
+
|
20
29
|
# Information class used to query for the size of the extended attributes
|
21
30
|
# (EA) for a file.
|
22
31
|
FILE_EA_INFORMATION = 0x07
|
23
32
|
|
33
|
+
# Information class used to query the access rights of a file that were
|
34
|
+
# granted when the file was opened.
|
35
|
+
FILE_ACCESS_INFORMATION = 0x08
|
36
|
+
|
37
|
+
# Information class is used locally to query the name of a file.
|
38
|
+
FILE_NAME_INFORMATION = 0x09
|
39
|
+
|
24
40
|
# Information class used to rename a file.
|
25
41
|
FILE_RENAME_INFORMATION = 0x0A
|
26
42
|
|
@@ -31,6 +47,17 @@ module RubySMB
|
|
31
47
|
# Information class used to mark a file for deletion.
|
32
48
|
FILE_DISPOSITION_INFORMATION = 0x0D
|
33
49
|
|
50
|
+
# Information class used to query or set the position of the file pointer
|
51
|
+
# within a file.
|
52
|
+
FILE_POSITION_INFORMATION = 0x0E
|
53
|
+
|
54
|
+
# Information class used to query or set the mode of the file.
|
55
|
+
FILE_MODE_INFORMATION = 0x10
|
56
|
+
|
57
|
+
# Information class used to query the buffer alignment required by the
|
58
|
+
# underlying device.
|
59
|
+
FILE_ALIGNMENT_INFORMATION = 0x11
|
60
|
+
|
34
61
|
# Information class used to enumerate the data streams of a file or a
|
35
62
|
# directory.
|
36
63
|
FILE_STREAM_INFORMATION = 0x16
|
@@ -57,6 +84,10 @@ module RubySMB
|
|
57
84
|
FILE_NORMALIZED_NAME_INFORMATION = 0x30
|
58
85
|
|
59
86
|
|
87
|
+
# Information class is used to query a collection of file information
|
88
|
+
# structures.
|
89
|
+
FILE_ALL_INFORMATION = 0x12
|
90
|
+
|
60
91
|
# These Information Classes can be used by SMB1 using the pass-through
|
61
92
|
# Information Levels when available on the server (CAP_INFOLEVEL_PASSTHRU
|
62
93
|
# capability flag in an SMB_COM_NEGOTIATE server response). The constant
|
@@ -65,12 +96,8 @@ module RubySMB
|
|
65
96
|
# [2.2.2.3.5 Pass-through Information Level Codes](https://msdn.microsoft.com/en-us/library/ff470158.aspx)
|
66
97
|
SMB_INFO_PASSTHROUGH = 0x03e8
|
67
98
|
|
68
|
-
|
69
|
-
|
70
|
-
class FileNameInformation < BinData::Record
|
71
|
-
endian :little
|
72
|
-
uint32 :file_name_length, label: 'File Name Length', initial_value: -> { file_name.do_num_bytes }
|
73
|
-
string16 :file_name, label: 'File Name', read_length: -> { file_name_length }
|
99
|
+
def self.name(value)
|
100
|
+
constants.select { |c| c.upcase == c }.find { |c| const_get(c) == value }
|
74
101
|
end
|
75
102
|
|
76
103
|
require 'ruby_smb/fscc/file_information/file_directory_information'
|
@@ -79,11 +106,21 @@ module RubySMB
|
|
79
106
|
require 'ruby_smb/fscc/file_information/file_id_full_directory_information'
|
80
107
|
require 'ruby_smb/fscc/file_information/file_both_directory_information'
|
81
108
|
require 'ruby_smb/fscc/file_information/file_id_both_directory_information'
|
109
|
+
require 'ruby_smb/fscc/file_information/file_name_information'
|
82
110
|
require 'ruby_smb/fscc/file_information/file_names_information'
|
111
|
+
require 'ruby_smb/fscc/file_information/file_normalized_name_information'
|
83
112
|
require 'ruby_smb/fscc/file_information/file_rename_information'
|
84
113
|
require 'ruby_smb/fscc/file_information/file_network_open_information'
|
85
114
|
require 'ruby_smb/fscc/file_information/file_ea_information'
|
86
115
|
require 'ruby_smb/fscc/file_information/file_stream_information'
|
116
|
+
require 'ruby_smb/fscc/file_information/file_basic_information'
|
117
|
+
require 'ruby_smb/fscc/file_information/file_standard_information'
|
118
|
+
require 'ruby_smb/fscc/file_information/file_internal_information'
|
119
|
+
require 'ruby_smb/fscc/file_information/file_access_information'
|
120
|
+
require 'ruby_smb/fscc/file_information/file_position_information'
|
121
|
+
require 'ruby_smb/fscc/file_information/file_mode_information'
|
122
|
+
require 'ruby_smb/fscc/file_information/file_alignment_information'
|
123
|
+
require 'ruby_smb/fscc/file_information/file_all_information'
|
87
124
|
end
|
88
125
|
end
|
89
126
|
end
|
@@ -7,6 +7,7 @@ module RubySMB
|
|
7
7
|
CLASS_LEVEL = FileSystemInformation::FILE_FS_ATTRIBUTE_INFORMATION
|
8
8
|
|
9
9
|
endian :little
|
10
|
+
|
10
11
|
struct :file_system_attributes, label: 'File System Attributes' do
|
11
12
|
bit1 :file_supports_reparse_points, label: 'FS Supports Reparse Points'
|
12
13
|
bit1 :file_supports_sparse_files, label: 'FS Supports Sparse Files'
|
@@ -7,6 +7,7 @@ module RubySMB
|
|
7
7
|
CLASS_LEVEL = FileSystemInformation::FILE_FS_VOLUME_INFORMATION
|
8
8
|
|
9
9
|
endian :little
|
10
|
+
|
10
11
|
file_time :volume_creation_time, label: 'Volume Creation Time'
|
11
12
|
uint32 :volume_serial_number, label: 'Volume Serial Number'
|
12
13
|
uint32 :volume_label_length, label: 'Volume Label Length', initial_value: -> { volume_label.do_num_bytes }
|
@@ -15,6 +15,10 @@ module RubySMB
|
|
15
15
|
FILE_FS_VOLUME_FLAGS_INFORMATION = 10
|
16
16
|
FILE_FS_SECTOR_SIZE_INFORMATION = 11
|
17
17
|
|
18
|
+
def self.name(value)
|
19
|
+
constants.select { |c| c.upcase == c }.find { |c| const_get(c) == value }
|
20
|
+
end
|
21
|
+
|
18
22
|
require 'ruby_smb/fscc/file_system_information/file_fs_attribute_information'
|
19
23
|
require 'ruby_smb/fscc/file_system_information/file_fs_volume_information'
|
20
24
|
end
|
@@ -78,6 +78,10 @@ module RubySMB
|
|
78
78
|
msg.flag |= NTLM::NEGOTIATE_FLAGS.fetch(flag)
|
79
79
|
end
|
80
80
|
|
81
|
+
if type1_msg.flag & NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY] == NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY]
|
82
|
+
msg.flag |= NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY]
|
83
|
+
end
|
84
|
+
|
81
85
|
@server_challenge = @provider.generate_server_challenge
|
82
86
|
msg.challenge = @server_challenge.unpack1('Q<') # 64-bit unsigned, little endian (uint64_t)
|
83
87
|
target_info = Net::NTLM::TargetInfo.new('')
|
@@ -109,6 +113,7 @@ module RubySMB
|
|
109
113
|
def process_ntlm_type3(type3_msg)
|
110
114
|
if type3_msg.user == '' && type3_msg.domain == ''
|
111
115
|
if @provider.allow_anonymous
|
116
|
+
@session_key = "\x00".b * 16 # see MS-NLMP section 3.4
|
112
117
|
return WindowsError::NTStatus::STATUS_SUCCESS
|
113
118
|
end
|
114
119
|
|
@@ -122,6 +127,12 @@ module RubySMB
|
|
122
127
|
domain: type3_msg.domain
|
123
128
|
)
|
124
129
|
if account.nil?
|
130
|
+
if @provider.allow_guests
|
131
|
+
logger.info("NTLM authentication request succeeded for #{dbg_string} (guest)")
|
132
|
+
@session_key = "\x00".b * 16 # see MS-NLMP section 3.4
|
133
|
+
return WindowsError::NTStatus::STATUS_SUCCESS
|
134
|
+
end
|
135
|
+
|
125
136
|
logger.info("NTLM authentication request failed for #{dbg_string} (no account)")
|
126
137
|
return WindowsError::NTStatus::STATUS_LOGON_FAILURE
|
127
138
|
end
|
@@ -229,25 +240,31 @@ module RubySMB
|
|
229
240
|
domain: type3_msg.domain
|
230
241
|
)
|
231
242
|
if account.nil?
|
232
|
-
if
|
243
|
+
if type3_msg.user == ''
|
244
|
+
is_guest = false
|
233
245
|
identity = IDENTITY_ANONYMOUS
|
246
|
+
else
|
247
|
+
is_guest = true
|
248
|
+
identity = Account.new(type3_msg.user.encode(''.encoding), '', type3_msg.domain.encode(''.encoding)).to_s
|
234
249
|
end
|
235
250
|
else
|
251
|
+
is_guest = false
|
236
252
|
identity = account.to_s
|
237
253
|
end
|
238
254
|
end
|
239
255
|
|
240
|
-
Result.new(buffer, nt_status, identity)
|
256
|
+
Result.new(buffer, nt_status, identity, is_guest)
|
241
257
|
end
|
242
258
|
end
|
243
259
|
|
244
260
|
# @param [Boolean] allow_anonymous whether or not to allow anonymous authentication attempts
|
245
261
|
# @param [String] default_domain the default domain to use for authentication, unless specified 'WORKGROUP' will
|
246
262
|
# be used
|
247
|
-
def initialize(allow_anonymous: false, default_domain: 'WORKGROUP')
|
263
|
+
def initialize(allow_anonymous: false, allow_guests: false, default_domain: 'WORKGROUP')
|
248
264
|
raise ArgumentError, 'Must specify a default domain' unless default_domain
|
249
265
|
|
250
266
|
@allow_anonymous = allow_anonymous
|
267
|
+
@allow_guests = allow_guests
|
251
268
|
@default_domain = default_domain
|
252
269
|
@accounts = []
|
253
270
|
@generate_server_challenge = -> { SecureRandom.bytes(8) }
|
@@ -7,7 +7,11 @@ module RubySMB
|
|
7
7
|
# A special constant implying that the authenticated user is anonymous.
|
8
8
|
IDENTITY_ANONYMOUS = :anonymous
|
9
9
|
# The result of a processed GSS request.
|
10
|
-
Result = Struct.new(:buffer, :nt_status, :identity)
|
10
|
+
Result = Struct.new(:buffer, :nt_status, :identity, :is_guest) do
|
11
|
+
def is_anonymous
|
12
|
+
identity == Gss::Provider::IDENTITY_ANONYMOUS
|
13
|
+
end
|
14
|
+
end
|
11
15
|
|
12
16
|
#
|
13
17
|
# The base class for a GSS authentication provider. This class defines a common interface and is not usable as a
|
@@ -26,6 +30,11 @@ module RubySMB
|
|
26
30
|
# Whether or not anonymous authentication attempts should be permitted.
|
27
31
|
#
|
28
32
|
attr_accessor :allow_anonymous
|
33
|
+
|
34
|
+
#
|
35
|
+
# Whether or not unknown users should be allowed to authenticate as guests.
|
36
|
+
#
|
37
|
+
attr_accessor :allow_guests
|
29
38
|
end
|
30
39
|
end
|
31
40
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module RubySMB
|
2
|
+
class Server
|
3
|
+
class ServerClient
|
4
|
+
# Contains the methods for handling encryption / decryption
|
5
|
+
module Encryption
|
6
|
+
def smb3_encrypt(data, session)
|
7
|
+
encryption_algorithm = SMB2::EncryptionCapabilities::ENCRYPTION_ALGORITHM_MAP[@cipher_id]
|
8
|
+
raise RubySMB::Error::EncryptionError.new('The encryption algorithm has not been set') if encryption_algorithm.nil?
|
9
|
+
|
10
|
+
key_bit_len = OpenSSL::Cipher.new(encryption_algorithm).key_len * 8
|
11
|
+
|
12
|
+
case @dialect
|
13
|
+
when '0x0300', '0x0302'
|
14
|
+
server_encryption_key = RubySMB::Crypto::KDF.counter_mode(
|
15
|
+
session.key,
|
16
|
+
"SMB2AESCCM\x00",
|
17
|
+
"ServerOut\x00",
|
18
|
+
length: key_bit_len
|
19
|
+
)
|
20
|
+
when '0x0311'
|
21
|
+
server_encryption_key = RubySMB::Crypto::KDF.counter_mode(
|
22
|
+
session.key,
|
23
|
+
"SMBS2CCipherKey\x00",
|
24
|
+
@preauth_integrity_hash_value,
|
25
|
+
length: key_bit_len
|
26
|
+
)
|
27
|
+
else
|
28
|
+
raise RubySMB::Error::EncryptionError.new('Dialect is incompatible with SMBv3 decryption')
|
29
|
+
end
|
30
|
+
|
31
|
+
th = RubySMB::SMB2::Packet::TransformHeader.new(flags: 1, session_id: session.id)
|
32
|
+
th.encrypt(data, server_encryption_key, algorithm: encryption_algorithm)
|
33
|
+
th
|
34
|
+
end
|
35
|
+
|
36
|
+
def smb3_decrypt(encrypted_request, session)
|
37
|
+
encryption_algorithm = SMB2::EncryptionCapabilities::ENCRYPTION_ALGORITHM_MAP[@cipher_id]
|
38
|
+
raise RubySMB::Error::EncryptionError.new('The encryption algorithm has not been set') if encryption_algorithm.nil?
|
39
|
+
|
40
|
+
key_bit_len = OpenSSL::Cipher.new(encryption_algorithm).key_len * 8
|
41
|
+
|
42
|
+
case @dialect
|
43
|
+
when '0x0300', '0x0302'
|
44
|
+
client_encryption_key = RubySMB::Crypto::KDF.counter_mode(
|
45
|
+
session.key,
|
46
|
+
"SMB2AESCCM\x00",
|
47
|
+
"ServerIn \x00",
|
48
|
+
length: key_bit_len
|
49
|
+
)
|
50
|
+
when '0x0311'
|
51
|
+
client_encryption_key = RubySMB::Crypto::KDF.counter_mode(
|
52
|
+
session.key,
|
53
|
+
"SMBC2SCipherKey\x00",
|
54
|
+
@preauth_integrity_hash_value,
|
55
|
+
length: key_bit_len
|
56
|
+
)
|
57
|
+
else
|
58
|
+
raise RubySMB::Error::EncryptionError.new('Dialect is incompatible with SMBv3 encryption')
|
59
|
+
end
|
60
|
+
|
61
|
+
encrypted_request.decrypt(client_encryption_key, algorithm: encryption_algorithm)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -119,14 +119,25 @@ module RubySMB
|
|
119
119
|
)
|
120
120
|
|
121
121
|
nc = request.find_negotiate_context(SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES)
|
122
|
-
|
123
|
-
|
122
|
+
ciphers = nc&.data&.ciphers
|
123
|
+
if ciphers
|
124
|
+
cipher = ciphers.find { |cipher| SMB2::EncryptionCapabilities::ENCRYPTION_ALGORITHM_MAP.include?(cipher) }
|
125
|
+
@cipher_id = cipher unless cipher.nil?
|
126
|
+
end
|
127
|
+
|
124
128
|
contexts << SMB2::NegotiateContext.new(
|
125
129
|
context_type: SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES,
|
126
130
|
data: {
|
127
|
-
ciphers: [
|
131
|
+
ciphers: [ @cipher_id ]
|
128
132
|
}
|
129
133
|
)
|
134
|
+
elsif dialect == '0x0300' || dialect == '0x0302'
|
135
|
+
if request.capabilities.encryption == 1
|
136
|
+
response.capabilities.encryption = 1
|
137
|
+
@cipher_id = SMB2::EncryptionCapabilities::AES_128_CCM
|
138
|
+
else
|
139
|
+
response.capabilities = 0
|
140
|
+
end
|
130
141
|
end
|
131
142
|
|
132
143
|
# the order in which the response is built is important to ensure it is valid
|
@@ -2,7 +2,7 @@ module RubySMB
|
|
2
2
|
class Server
|
3
3
|
class ServerClient
|
4
4
|
module SessionSetup
|
5
|
-
def
|
5
|
+
def do_session_setup_andx_smb1(request, session)
|
6
6
|
session_id = request.smb_header.uid
|
7
7
|
if session_id == 0
|
8
8
|
session_id = rand(1..0x10000)
|
@@ -41,6 +41,17 @@ module RubySMB
|
|
41
41
|
response
|
42
42
|
end
|
43
43
|
|
44
|
+
alias :do_session_setup_smb1 :do_session_setup_andx_smb1
|
45
|
+
|
46
|
+
def do_logoff_andx_smb1(request, session)
|
47
|
+
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/00fc0299-496c-4330-9089-67358994f272
|
48
|
+
@session_table.delete(request.smb_header.uid)
|
49
|
+
session.logoff!
|
50
|
+
|
51
|
+
response = SMB1::Packet::LogoffResponse.new
|
52
|
+
response
|
53
|
+
end
|
54
|
+
|
44
55
|
def do_session_setup_smb2(request, session)
|
45
56
|
session_id = request.smb2_header.session_id
|
46
57
|
if session_id == 0
|
@@ -67,11 +78,16 @@ module RubySMB
|
|
67
78
|
|
68
79
|
update_preauth_hash(request) if @dialect == '0x0311'
|
69
80
|
if gss_result.nt_status == WindowsError::NTStatus::STATUS_SUCCESS
|
70
|
-
response.smb2_header.credits = 32
|
71
81
|
session.state = :valid
|
72
82
|
session.user_id = gss_result.identity
|
83
|
+
session.is_guest = !!gss_result.is_guest
|
73
84
|
session.key = @gss_authenticator.session_key
|
74
|
-
session.signing_required = request.security_mode.signing_required == 1
|
85
|
+
session.signing_required = request.security_mode.signing_required == 1 || (!session.is_guest && !session.is_anonymous)
|
86
|
+
|
87
|
+
response.smb2_header.credits = 32
|
88
|
+
@cipher_id = 0 if session.is_anonymous || session.is_guest # disable encryption for anonymous users and guest users which have a null session key
|
89
|
+
response.session_flags.encrypt_data = 1 unless @cipher_id == 0
|
90
|
+
response.session_flags.guest = session.is_guest
|
75
91
|
elsif gss_result.nt_status == WindowsError::NTStatus::STATUS_MORE_PROCESSING_REQUIRED && @dialect == '0x0311'
|
76
92
|
update_preauth_hash(response)
|
77
93
|
end
|
@@ -80,7 +96,8 @@ module RubySMB
|
|
80
96
|
end
|
81
97
|
|
82
98
|
def do_logoff_smb2(request, session)
|
83
|
-
|
99
|
+
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/a6fbc502-75a5-42ef-a88c-c67b44817850
|
100
|
+
@session_table.delete(session.id)
|
84
101
|
session.logoff!
|
85
102
|
|
86
103
|
response = SMB2::Packet::LogoffResponse.new
|
@@ -2,6 +2,23 @@ module RubySMB
|
|
2
2
|
class Server
|
3
3
|
class ServerClient
|
4
4
|
module ShareIO
|
5
|
+
def proxy_share_io_smb1(request, session)
|
6
|
+
share_processor = session.tree_connect_table[request.smb_header.tid]
|
7
|
+
if share_processor.nil?
|
8
|
+
response = SMB1::Packet::EmptyPacket.new
|
9
|
+
response.smb_header.nt_status = WindowsError::NTStatus::STATUS_NETWORK_NAME_DELETED
|
10
|
+
return response
|
11
|
+
end
|
12
|
+
|
13
|
+
logger.debug("Received #{SMB1::Commands.name(request.smb_header.command)} request for share: #{share_processor.provider.name}")
|
14
|
+
share_processor.send(__callee__, request)
|
15
|
+
end
|
16
|
+
|
17
|
+
alias :do_close_smb1 :proxy_share_io_smb1
|
18
|
+
alias :do_nt_create_andx_smb1 :proxy_share_io_smb1
|
19
|
+
alias :do_read_andx_smb1 :proxy_share_io_smb1
|
20
|
+
alias :do_transactions2_smb1 :proxy_share_io_smb1
|
21
|
+
|
5
22
|
def proxy_share_io_smb2(request, session)
|
6
23
|
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/9a639360-87be-4d49-a1dd-4c6be0c020bd
|
7
24
|
share_processor = session.tree_connect_table[request.smb2_header.tree_id]
|
@@ -3,6 +3,43 @@ module RubySMB
|
|
3
3
|
class ServerClient
|
4
4
|
MAX_TREE_CONNECTIONS = 1000
|
5
5
|
module TreeConnect
|
6
|
+
def do_tree_connect_smb1(request, session)
|
7
|
+
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/b062f3e3-1b65-4a9a-854a-0ee432499d8f
|
8
|
+
response = RubySMB::SMB1::Packet::TreeConnectResponse.new
|
9
|
+
|
10
|
+
share_name = request.data_block.path.encode('UTF-8').split('\\', 4).last
|
11
|
+
share_provider = @server.shares.transform_keys(&:downcase)[share_name.downcase]
|
12
|
+
if share_provider.nil?
|
13
|
+
logger.warn("Received TREE_CONNECT request for non-existent share: #{share_name}")
|
14
|
+
response.smb_header.nt_status = WindowsError::NTStatus::STATUS_OBJECT_PATH_NOT_FOUND
|
15
|
+
return response
|
16
|
+
end
|
17
|
+
logger.debug("Received TREE_CONNECT request for share: #{share_name}")
|
18
|
+
|
19
|
+
tree_id = rand(1..0xfffe)
|
20
|
+
tree_id = rand(1..0xfffe) while session.tree_connect_table.include?(tree_id)
|
21
|
+
|
22
|
+
response.smb_header.tid = tree_id
|
23
|
+
session.tree_connect_table[tree_id] = share_processor = share_provider.new_processor(self, session)
|
24
|
+
response.parameter_block.access_rights = share_processor.maximal_access
|
25
|
+
|
26
|
+
response
|
27
|
+
end
|
28
|
+
|
29
|
+
def do_tree_disconnect_smb1(request, session)
|
30
|
+
share_processor = session.tree_connect_table.delete(request.smb_header.tid)
|
31
|
+
if share_processor.nil?
|
32
|
+
response = RubySMB::SMB1::Packet::EmptyPacket.new
|
33
|
+
response.smb_header.nt_status = WindowsError::NTStatus::STATUS_NETWORK_NAME_DELETED
|
34
|
+
return response
|
35
|
+
end
|
36
|
+
|
37
|
+
logger.debug("Received TREE_DISCONNECT request for share: #{share_processor.provider.name}")
|
38
|
+
share_processor.disconnect!
|
39
|
+
response = RubySMB::SMB1::Packet::TreeDisconnectResponse.new
|
40
|
+
response
|
41
|
+
end
|
42
|
+
|
6
43
|
def do_tree_connect_smb2(request, session)
|
7
44
|
response = RubySMB::SMB2::Packet::TreeConnectResponse.new
|
8
45
|
response.smb2_header.credits = 1
|
@@ -13,7 +50,7 @@ module RubySMB
|
|
13
50
|
end
|
14
51
|
|
15
52
|
share_name = request.path.encode('UTF-8').split('\\', 4).last
|
16
|
-
share_provider = @server.shares[share_name]
|
53
|
+
share_provider = @server.shares.transform_keys(&:downcase)[share_name.downcase]
|
17
54
|
|
18
55
|
if share_provider.nil?
|
19
56
|
logger.warn("Received TREE_CONNECT request for non-existent share: #{share_name}")
|
@@ -31,8 +68,8 @@ module RubySMB
|
|
31
68
|
RubySMB::SMB2::Packet::TreeConnectResponse::SMB2_SHARE_TYPE_PRINT
|
32
69
|
end
|
33
70
|
|
34
|
-
tree_id = rand(
|
35
|
-
tree_id = rand(
|
71
|
+
tree_id = rand(1..0xfffffffe)
|
72
|
+
tree_id = rand(1..0xfffffffe) while session.tree_connect_table.include?(tree_id)
|
36
73
|
|
37
74
|
response.smb2_header.tree_id = tree_id
|
38
75
|
session.tree_connect_table[tree_id] = share_processor = share_provider.new_processor(self, session)
|