ruby_smb 1.1.0 → 2.0.0
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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -4
- data/.travis.yml +3 -5
- data/Gemfile +6 -2
- data/examples/negotiate.rb +51 -8
- data/examples/read_file_encryption.rb +56 -0
- data/lib/ruby_smb.rb +4 -0
- data/lib/ruby_smb/client.rb +172 -16
- data/lib/ruby_smb/client/authentication.rb +27 -8
- data/lib/ruby_smb/client/encryption.rb +62 -0
- data/lib/ruby_smb/client/negotiation.rb +133 -12
- data/lib/ruby_smb/client/signing.rb +19 -0
- data/lib/ruby_smb/client/tree_connect.rb +4 -4
- data/lib/ruby_smb/client/utils.rb +8 -7
- data/lib/ruby_smb/crypto.rb +30 -0
- data/lib/ruby_smb/dispatcher/socket.rb +2 -2
- data/lib/ruby_smb/error.rb +28 -1
- data/lib/ruby_smb/smb1/commands.rb +1 -1
- data/lib/ruby_smb/smb1/file.rb +4 -4
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -2
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -2
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +1 -1
- data/lib/ruby_smb/smb1/pipe.rb +2 -2
- data/lib/ruby_smb/smb1/tree.rb +3 -3
- data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
- data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
- data/lib/ruby_smb/smb2/file.rb +25 -43
- data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
- data/lib/ruby_smb/smb2/packet.rb +2 -0
- data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -14
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +49 -3
- data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +92 -6
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -26
- data/lib/ruby_smb/smb2/pipe.rb +3 -16
- data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
- data/lib/ruby_smb/smb2/tree.rb +23 -17
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +3 -1
- data/spec/lib/ruby_smb/client_spec.rb +1256 -57
- data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
- data/spec/lib/ruby_smb/error_spec.rb +59 -0
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
- data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
- data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
- data/spec/lib/ruby_smb/smb2/file_spec.rb +86 -62
- data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
- data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
- data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
- data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
- data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -30
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +0 -40
- data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +53 -8
- metadata +124 -75
- metadata.gz.sig +0 -0
@@ -48,7 +48,7 @@ module RubySMB
|
|
48
48
|
end
|
49
49
|
|
50
50
|
rescue IOError, Errno::ECONNABORTED, Errno::ECONNRESET => e
|
51
|
-
raise RubySMB::Error::CommunicationError, "An error
|
51
|
+
raise RubySMB::Error::CommunicationError, "An error occurred writing to the Socket: #{e.message}"
|
52
52
|
end
|
53
53
|
nil
|
54
54
|
end
|
@@ -84,7 +84,7 @@ module RubySMB
|
|
84
84
|
end
|
85
85
|
data
|
86
86
|
rescue Errno::EINVAL, Errno::ECONNABORTED, Errno::ECONNRESET, TypeError, NoMethodError => e
|
87
|
-
raise RubySMB::Error::CommunicationError, "An error
|
87
|
+
raise RubySMB::Error::CommunicationError, "An error occurred reading from the Socket #{e.message}"
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
data/lib/ruby_smb/error.rb
CHANGED
@@ -53,7 +53,28 @@ module RubySMB
|
|
53
53
|
end
|
54
54
|
|
55
55
|
# Raised when a response packet has a NTStatus code that was unexpected.
|
56
|
-
class UnexpectedStatusCode < RubySMBError
|
56
|
+
class UnexpectedStatusCode < RubySMBError
|
57
|
+
attr_reader :status_code
|
58
|
+
|
59
|
+
def initialize(status_code)
|
60
|
+
case status_code
|
61
|
+
when WindowsError::ErrorCode
|
62
|
+
@status_code = status_code
|
63
|
+
when Integer
|
64
|
+
@status_code = WindowsError::NTStatus.find_by_retval(status_code).first
|
65
|
+
if @status_code.nil?
|
66
|
+
@status_code = WindowsError::ErrorCode.new("0x#{status_code.to_s(16)}", status_code, "Unknown 0x#{status_code.to_s(16)}")
|
67
|
+
end
|
68
|
+
else
|
69
|
+
raise ArgumentError, "Status code must be a WindowsError::ErrorCode or an Integer, got #{status_code.class}"
|
70
|
+
end
|
71
|
+
super
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_s
|
75
|
+
"The server responded with an unexpected status code: #{status_code.name}"
|
76
|
+
end
|
77
|
+
end
|
57
78
|
|
58
79
|
# Raised when an error occurs with the underlying socket.
|
59
80
|
class CommunicationError < RubySMBError; end
|
@@ -65,5 +86,11 @@ module RubySMB
|
|
65
86
|
# Raised when trying to parse raw binary into a BitField and the data
|
66
87
|
# is invalid.
|
67
88
|
class InvalidBitField < RubySMBError; end
|
89
|
+
|
90
|
+
# Raised when an encryption operation fails
|
91
|
+
class EncryptionError < RubySMBError; end
|
92
|
+
|
93
|
+
# Raised when an signing operation fails
|
94
|
+
class SigningError < RubySMBError; end
|
68
95
|
end
|
69
96
|
end
|
@@ -10,7 +10,7 @@ module RubySMB
|
|
10
10
|
SMB_COM_TRANSACTION2_SECONDARY = 0x33
|
11
11
|
SMB_COM_TREE_DISCONNECT = 0x71
|
12
12
|
SMB_COM_NEGOTIATE = 0x72
|
13
|
-
|
13
|
+
SMB_COM_SESSION_SETUP_ANDX = 0x73
|
14
14
|
SMB_COM_LOGOFF = 0x74
|
15
15
|
SMB_COM_TREE_CONNECT = 0x75
|
16
16
|
SMB_COM_NT_TRANSACT = 0xA0
|
data/lib/ruby_smb/smb1/file.rb
CHANGED
@@ -91,7 +91,7 @@ module RubySMB
|
|
91
91
|
)
|
92
92
|
end
|
93
93
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
94
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
94
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
95
95
|
end
|
96
96
|
response.status_code
|
97
97
|
end
|
@@ -127,7 +127,7 @@ module RubySMB
|
|
127
127
|
)
|
128
128
|
end
|
129
129
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
130
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
130
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
131
131
|
end
|
132
132
|
|
133
133
|
if response.is_a?(RubySMB::SMB1::Packet::ReadAndxResponse)
|
@@ -176,7 +176,7 @@ module RubySMB
|
|
176
176
|
)
|
177
177
|
end
|
178
178
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
179
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
179
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
180
180
|
end
|
181
181
|
|
182
182
|
response.data_block.data.to_binary_s
|
@@ -244,7 +244,7 @@ module RubySMB
|
|
244
244
|
)
|
245
245
|
end
|
246
246
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
247
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
247
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
248
248
|
end
|
249
249
|
bytes_written = response.parameter_block.count_low + (response.parameter_block.count_high << 16)
|
250
250
|
total_bytes_written += bytes_written
|
@@ -4,7 +4,7 @@ module RubySMB
|
|
4
4
|
# A SMB1 SMB_COM_SESSION_SETUP_ANDX Request Packet, without NTLMSSP as defined in
|
5
5
|
# [2.2.4.53.1 Request](https://msdn.microsoft.com/en-us/library/ee441849.aspx)
|
6
6
|
class SessionSetupLegacyRequest < RubySMB::GenericPacket
|
7
|
-
COMMAND = RubySMB::SMB1::Commands::
|
7
|
+
COMMAND = RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
8
8
|
|
9
9
|
# A SMB1 Parameter Block as defined by the {SessionSetupRequest}
|
10
10
|
class ParameterBlock < RubySMB::SMB1::ParameterBlock
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module RubySMB
|
2
2
|
module SMB1
|
3
3
|
module Packet
|
4
|
-
# A SMB1
|
4
|
+
# A SMB1 SMB_COM_SESSION_SETUP_ANDX Legacy Response Packet as defined in
|
5
5
|
# [2.2.4.53.2 Response](https://msdn.microsoft.com/en-us/library/ee442143.aspx)
|
6
6
|
class SessionSetupLegacyResponse < RubySMB::GenericPacket
|
7
|
-
COMMAND = RubySMB::SMB1::Commands::
|
7
|
+
COMMAND = RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
8
8
|
|
9
9
|
# A SMB1 Parameter Block as defined by the {SessionSetupResponse}
|
10
10
|
class ParameterBlock < RubySMB::SMB1::ParameterBlock
|
@@ -4,7 +4,7 @@ module RubySMB
|
|
4
4
|
# A SMB1 SMB_COM_SESSION_SETUP_ANDX Request Packet as defined in
|
5
5
|
# [2.2.4.6.1](https://msdn.microsoft.com/en-us/library/cc246328.aspx)
|
6
6
|
class SessionSetupRequest < RubySMB::GenericPacket
|
7
|
-
COMMAND = RubySMB::SMB1::Commands::
|
7
|
+
COMMAND = RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
8
8
|
|
9
9
|
# A SMB1 Parameter Block as defined by the {SessionSetupRequest}
|
10
10
|
class ParameterBlock < RubySMB::SMB1::ParameterBlock
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module RubySMB
|
2
2
|
module SMB1
|
3
3
|
module Packet
|
4
|
-
# A SMB1
|
4
|
+
# A SMB1 SMB_COM_SESSION_SETUP_ANDX Response Packet as defined in
|
5
5
|
# [2.2.4.6.2](https://msdn.microsoft.com/en-us/library/cc246329.aspx)
|
6
6
|
class SessionSetupResponse < RubySMB::GenericPacket
|
7
|
-
COMMAND = RubySMB::SMB1::Commands::
|
7
|
+
COMMAND = RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
8
8
|
|
9
9
|
# A SMB1 Parameter Block as defined by the {SessionSetupResponse}
|
10
10
|
class ParameterBlock < RubySMB::SMB1::ParameterBlock
|
data/lib/ruby_smb/smb1/pipe.rb
CHANGED
@@ -47,7 +47,7 @@ module RubySMB
|
|
47
47
|
end
|
48
48
|
|
49
49
|
unless response.status_code == WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW or response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
50
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
50
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
51
51
|
end
|
52
52
|
|
53
53
|
response
|
@@ -106,7 +106,7 @@ module RubySMB
|
|
106
106
|
end
|
107
107
|
unless [WindowsError::NTStatus::STATUS_SUCCESS,
|
108
108
|
WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW].include?(trans_nmpipe_response.status_code)
|
109
|
-
raise RubySMB::Error::UnexpectedStatusCode, trans_nmpipe_response.status_code
|
109
|
+
raise RubySMB::Error::UnexpectedStatusCode, trans_nmpipe_response.status_code
|
110
110
|
end
|
111
111
|
|
112
112
|
raw_data = trans_nmpipe_response.data_block.trans_data.read_data.to_binary_s
|
data/lib/ruby_smb/smb1/tree.rb
CHANGED
@@ -131,7 +131,7 @@ module RubySMB
|
|
131
131
|
)
|
132
132
|
end
|
133
133
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
134
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
134
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
135
135
|
end
|
136
136
|
|
137
137
|
case response.parameter_block.resource_type
|
@@ -191,7 +191,7 @@ module RubySMB
|
|
191
191
|
)
|
192
192
|
end
|
193
193
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
194
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
194
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
195
195
|
end
|
196
196
|
|
197
197
|
results = response.results(type, unicode: unicode)
|
@@ -226,7 +226,7 @@ module RubySMB
|
|
226
226
|
)
|
227
227
|
end
|
228
228
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
229
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
229
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
230
230
|
end
|
231
231
|
|
232
232
|
results += response.results(type, unicode: unicode)
|
@@ -4,7 +4,8 @@ module RubySMB
|
|
4
4
|
# The SessionsFlags bit-field for a {RubySMB::SMB2::Packet::SessionSetupResponse}
|
5
5
|
class SessionFlags < BinData::Record
|
6
6
|
endian :little
|
7
|
-
|
7
|
+
bit5 :reserved3, label: 'Reserved', initial_value: 0
|
8
|
+
bit1 :encrypt_data, label: 'Encrypt Data', initial_value: 0
|
8
9
|
bit1 :null, label: 'ASYNC Command', initial_value: 0
|
9
10
|
bit1 :guest, label: 'Is Guest?', initial_value: 0
|
10
11
|
resume_byte_alignment
|
@@ -8,7 +8,7 @@ module RubySMB
|
|
8
8
|
bit2 :reserved1, label: 'Reserved Space'
|
9
9
|
bit1 :vdo_caching, label: 'VDO Caching'
|
10
10
|
bit1 :auto_caching, label: 'Auto Caching'
|
11
|
-
bit2 :reserved2
|
11
|
+
bit2 :reserved2, label: 'Reserved Space'
|
12
12
|
bit1 :dfs_root, label: 'DFS Root'
|
13
13
|
bit1 :dfs, label: 'DFS'
|
14
14
|
# byte boundary
|
@@ -20,9 +20,11 @@ module RubySMB
|
|
20
20
|
bit1 :namespace_caching, label: 'Namespace Caching'
|
21
21
|
bit1 :shared_delete, label: 'Force Shared Delete'
|
22
22
|
bit1 :restrict_exclusive_opens, label: 'Restrict Exclusive Opens'
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
# byte boundary
|
24
|
+
bit5 :reserved3, label: 'Reserved Space'
|
25
|
+
bit1 :identity_remoting, label: 'Identity Remoting'
|
26
|
+
bit2 :reserved4, label: 'Reserved Space'
|
27
|
+
bit8 :reserved5, label: 'Reserved Space'
|
26
28
|
|
27
29
|
def caching_type
|
28
30
|
if vdo_caching == 1 && auto_caching.zero?
|
data/lib/ruby_smb/smb2/file.rb
CHANGED
@@ -52,7 +52,12 @@ module RubySMB
|
|
52
52
|
# @return [RubySMB::SMB2::Tree]
|
53
53
|
attr_accessor :tree
|
54
54
|
|
55
|
-
|
55
|
+
# Whether or not encryption is required (SMB 3.x)
|
56
|
+
# @!attribute [rw] encryption_required
|
57
|
+
# @return [Boolean]
|
58
|
+
attr_accessor :encryption_required
|
59
|
+
|
60
|
+
def initialize(tree:, response:, name:, encrypt: false)
|
56
61
|
raise ArgumentError, 'No Tree Provided' if tree.nil?
|
57
62
|
raise ArgumentError, 'No Response Provided' if response.nil?
|
58
63
|
|
@@ -66,6 +71,7 @@ module RubySMB
|
|
66
71
|
@last_write = response.last_write.to_datetime
|
67
72
|
@size = response.end_of_file
|
68
73
|
@size_on_disk = response.allocation_size
|
74
|
+
@encryption_required = encrypt
|
69
75
|
end
|
70
76
|
|
71
77
|
# Appends the supplied data to the end of the file.
|
@@ -83,7 +89,7 @@ module RubySMB
|
|
83
89
|
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
|
84
90
|
def close
|
85
91
|
close_request = set_header_fields(RubySMB::SMB2::Packet::CloseRequest.new)
|
86
|
-
raw_response = tree.client.send_recv(close_request)
|
92
|
+
raw_response = tree.client.send_recv(close_request, encrypt: @encryption_required)
|
87
93
|
response = RubySMB::SMB2::Packet::CloseResponse.read(raw_response)
|
88
94
|
unless response.valid?
|
89
95
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -94,7 +100,7 @@ module RubySMB
|
|
94
100
|
)
|
95
101
|
end
|
96
102
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
97
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
103
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
98
104
|
end
|
99
105
|
response.status_code
|
100
106
|
end
|
@@ -116,7 +122,7 @@ module RubySMB
|
|
116
122
|
end
|
117
123
|
|
118
124
|
read_request = read_packet(read_length: atomic_read_size, offset: offset)
|
119
|
-
raw_response = tree.client.send_recv(read_request)
|
125
|
+
raw_response = tree.client.send_recv(read_request, encrypt: @encryption_required)
|
120
126
|
response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
|
121
127
|
unless response.valid?
|
122
128
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -127,7 +133,7 @@ module RubySMB
|
|
127
133
|
)
|
128
134
|
end
|
129
135
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
130
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
136
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
131
137
|
end
|
132
138
|
|
133
139
|
data = response.buffer.to_binary_s
|
@@ -139,7 +145,7 @@ module RubySMB
|
|
139
145
|
atomic_read_size = remaining_bytes if remaining_bytes < tree.client.server_max_read_size
|
140
146
|
|
141
147
|
read_request = read_packet(read_length: atomic_read_size, offset: offset)
|
142
|
-
raw_response = tree.client.send_recv(read_request)
|
148
|
+
raw_response = tree.client.send_recv(read_request, encrypt: @encryption_required)
|
143
149
|
response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
|
144
150
|
unless response.valid?
|
145
151
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -150,7 +156,7 @@ module RubySMB
|
|
150
156
|
)
|
151
157
|
end
|
152
158
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
153
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
159
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
154
160
|
end
|
155
161
|
|
156
162
|
data << response.buffer.to_binary_s
|
@@ -170,10 +176,10 @@ module RubySMB
|
|
170
176
|
read_request.offset = offset
|
171
177
|
read_request
|
172
178
|
end
|
173
|
-
|
179
|
+
|
174
180
|
def send_recv_read(read_length: 0, offset: 0)
|
175
181
|
read_request = read_packet(read_length: read_length, offset: offset)
|
176
|
-
raw_response = tree.client.send_recv(read_request)
|
182
|
+
raw_response = tree.client.send_recv(read_request, encrypt: @encryption_required)
|
177
183
|
response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
|
178
184
|
unless response.valid?
|
179
185
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -183,20 +189,8 @@ module RubySMB
|
|
183
189
|
received_cmd: response.smb2_header.command
|
184
190
|
)
|
185
191
|
end
|
186
|
-
|
187
|
-
|
188
|
-
raw_response = tree.client.dispatcher.recv_packet
|
189
|
-
response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
|
190
|
-
unless response.valid?
|
191
|
-
raise RubySMB::Error::InvalidPacket.new(
|
192
|
-
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
193
|
-
expected_cmd: RubySMB::SMB2::Packet::ReadResponse::COMMAND,
|
194
|
-
received_proto: response.smb2_header.protocol,
|
195
|
-
received_cmd: response.smb2_header.command
|
196
|
-
)
|
197
|
-
end
|
198
|
-
elsif response.status_code != WindowsError::NTStatus::STATUS_SUCCESS
|
199
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
|
192
|
+
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
193
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
200
194
|
end
|
201
195
|
response.buffer.to_binary_s
|
202
196
|
end
|
@@ -206,7 +200,7 @@ module RubySMB
|
|
206
200
|
# @return [WindowsError::ErrorCode] the NTStatus Response code
|
207
201
|
# @raise [RubySMB::Error::InvalidPacket] if the response is not a SetInfoResponse packet
|
208
202
|
def delete
|
209
|
-
raw_response = tree.client.send_recv(delete_packet)
|
203
|
+
raw_response = tree.client.send_recv(delete_packet, encrypt: @encryption_required)
|
210
204
|
response = RubySMB::SMB2::Packet::SetInfoResponse.read(raw_response)
|
211
205
|
unless response.valid?
|
212
206
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -256,7 +250,7 @@ module RubySMB
|
|
256
250
|
|
257
251
|
while buffer.length > 0 do
|
258
252
|
write_request = write_packet(data: buffer.slice!(0,atomic_write_size), offset: offset)
|
259
|
-
raw_response = tree.client.send_recv(write_request)
|
253
|
+
raw_response = tree.client.send_recv(write_request, encrypt: @encryption_required)
|
260
254
|
response = RubySMB::SMB2::Packet::WriteResponse.read(raw_response)
|
261
255
|
unless response.valid?
|
262
256
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -286,10 +280,10 @@ module RubySMB
|
|
286
280
|
write_request.buffer = data
|
287
281
|
write_request
|
288
282
|
end
|
289
|
-
|
283
|
+
|
290
284
|
def send_recv_write(data:'', offset: 0)
|
291
285
|
pkt = write_packet(data: data, offset: offset)
|
292
|
-
raw_response = tree.client.send_recv(pkt)
|
286
|
+
raw_response = tree.client.send_recv(pkt, encrypt: @encryption_required)
|
293
287
|
response = RubySMB::SMB2::Packet::WriteResponse.read(raw_response)
|
294
288
|
unless response.valid?
|
295
289
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -299,31 +293,19 @@ module RubySMB
|
|
299
293
|
received_cmd: response.smb2_header.command
|
300
294
|
)
|
301
295
|
end
|
302
|
-
|
303
|
-
|
304
|
-
raw_response = tree.client.dispatcher.recv_packet
|
305
|
-
response = RubySMB::SMB2::Packet::WriteResponse.read(raw_response)
|
306
|
-
unless response.valid?
|
307
|
-
raise RubySMB::Error::InvalidPacket.new(
|
308
|
-
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
309
|
-
expected_cmd: RubySMB::SMB2::Packet::WriteResponse::COMMAND,
|
310
|
-
received_proto: response.smb2_header.protocol,
|
311
|
-
received_cmd: response.smb2_header.command
|
312
|
-
)
|
313
|
-
end
|
314
|
-
elsif response.status_code != WindowsError::NTStatus::STATUS_SUCCESS
|
315
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
|
296
|
+
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
297
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
316
298
|
end
|
317
299
|
response.write_count
|
318
300
|
end
|
319
|
-
|
301
|
+
|
320
302
|
# Rename a file
|
321
303
|
#
|
322
304
|
# @param new_file_name [String] the new name
|
323
305
|
# @return [WindowsError::ErrorCode] the NTStatus Response code
|
324
306
|
# @raise [RubySMB::Error::InvalidPacket] if the response is not a SetInfoResponse packet
|
325
307
|
def rename(new_file_name)
|
326
|
-
raw_response = tree.client.send_recv(rename_packet(new_file_name))
|
308
|
+
raw_response = tree.client.send_recv(rename_packet(new_file_name), encrypt: @encryption_required)
|
327
309
|
response = RubySMB::SMB2::Packet::SetInfoResponse.read(raw_response)
|
328
310
|
unless response.valid?
|
329
311
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module SMB2
|
3
|
+
|
4
|
+
# An SMB2 PREAUTH_INTEGRITY_CAPABILITIES context struct as defined in
|
5
|
+
# [2.2.3.1.1 SMB2_PREAUTH_INTEGRITY_CAPABILITIES](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5a07bd66-4734-4af8-abcf-5a44ff7ee0e5)
|
6
|
+
class PreauthIntegrityCapabilities < BinData::Record
|
7
|
+
SHA_512 = 0x0001
|
8
|
+
HASH_ALGORITM_MAP = {
|
9
|
+
SHA_512 => 'SHA512'
|
10
|
+
}
|
11
|
+
|
12
|
+
endian :little
|
13
|
+
|
14
|
+
uint16 :hash_algorithm_count, label: 'Hash Algorithm Count', initial_value: -> { hash_algorithms.size }
|
15
|
+
uint16 :salt_length, label: 'Salt Length', initial_value: -> { salt.num_bytes }
|
16
|
+
array :hash_algorithms, label: 'Hash Algorithms', type: :uint16, initial_length: -> { hash_algorithm_count }
|
17
|
+
string :salt, label: 'Salt', read_length: -> { salt_length }
|
18
|
+
end
|
19
|
+
|
20
|
+
# An SMB2 ENCRYPTION_CAPABILITIES context struct as defined in
|
21
|
+
# [2.2.3.1.2 SMB2_ENCRYPTION_CAPABILITIES](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/16693be7-2b27-4d3b-804b-f605bde5bcdd)
|
22
|
+
class EncryptionCapabilities < BinData::Record
|
23
|
+
AES_128_CCM = 0x0001
|
24
|
+
AES_128_GCM = 0x0002
|
25
|
+
ENCRYPTION_ALGORITHM_MAP = {
|
26
|
+
AES_128_CCM => 'AES-128-CCM',
|
27
|
+
AES_128_GCM => 'AES-128-GCM'
|
28
|
+
}
|
29
|
+
|
30
|
+
endian :little
|
31
|
+
|
32
|
+
uint16 :cipher_count, label: 'Cipher Count', initial_value: -> { ciphers.size }
|
33
|
+
array :ciphers, label: 'Ciphers', type: :uint16, initial_length: -> { cipher_count }
|
34
|
+
end
|
35
|
+
|
36
|
+
# An SMB2 COMPRESSION_CAPABILITIES context struct as defined in
|
37
|
+
# [2.2.3.1.3 SMB2_COMPRESSION_CAPABILITIES](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/78e0c942-ab41-472b-b117-4a95ebe88271)
|
38
|
+
class CompressionCapabilities < BinData::Record
|
39
|
+
# Flags
|
40
|
+
# Chained compression is not supported.
|
41
|
+
SMB2_COMPRESSION_CAPABILITIES_FLAG_NONE = 0x00000000
|
42
|
+
# Chained compression is supported on this connection.
|
43
|
+
SMB2_COMPRESSION_CAPABILITIES_FLAG_CHAINED = 0x00000001
|
44
|
+
|
45
|
+
# Compression Algorithms
|
46
|
+
NONE = 0x0000
|
47
|
+
LZNT1 = 0x0001
|
48
|
+
LZ77 = 0x0002
|
49
|
+
LZ77_Huffman = 0x0003
|
50
|
+
Pattern_V1 = 0x0004
|
51
|
+
COMPRESSION_ALGORITHM_MAP = {
|
52
|
+
NONE => 'NONE',
|
53
|
+
LZNT1 => 'LZNT1',
|
54
|
+
LZ77 => 'LZ77',
|
55
|
+
LZ77_Huffman => 'LZ77_Huffman',
|
56
|
+
Pattern_V1 => 'Pattern_V1'
|
57
|
+
}
|
58
|
+
|
59
|
+
endian :little
|
60
|
+
|
61
|
+
uint16 :compression_algorithm_count, label: 'Compression Algorithm Count', initial_value: -> { compression_algorithms.size }
|
62
|
+
uint16 :padding, label: 'Padding', initial_value: 0
|
63
|
+
uint32 :flags, label: 'Flags'
|
64
|
+
array :compression_algorithms, label: 'Compression Algorithms', type: :uint16, initial_length: -> { compression_algorithm_count }
|
65
|
+
end
|
66
|
+
|
67
|
+
# An SMB2 NETNAME_NEGOTIATE_CONTEXT_ID context struct as defined in
|
68
|
+
# [2.2.3.1.4 SMB2_NETNAME_NEGOTIATE_CONTEXT_ID](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/ca6726bd-b9cf-43d9-b0bc-d127d3c993b3)
|
69
|
+
class NetnameNegotiateContextId < BinData::Record
|
70
|
+
endian :little
|
71
|
+
|
72
|
+
stringz16 :net_name, label: 'Net Name'
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# An SMB2 NEGOTIATE_CONTEXT struct as defined in
|
77
|
+
# [2.2.3.1 SMB2 NEGOTIATE_CONTEXT Request Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/15332256-522e-4a53-8cd7-0bd17678a2f7)
|
78
|
+
class NegotiateContext < BinData::Record
|
79
|
+
# The NegotiateContext Data field contains a list of preauthentication integrity hash functions as well as an optional salt value, as specified in section 2.2.3.1.1.
|
80
|
+
SMB2_PREAUTH_INTEGRITY_CAPABILITIES = 0x0001
|
81
|
+
# The NegotiateContext Data field contains a list of encryption algorithms, as specified in section 2.2.3.1.2.
|
82
|
+
SMB2_ENCRYPTION_CAPABILITIES = 0x0002
|
83
|
+
# The NegotiateContext Data field contains a list of compression algorithms, as specified in section 2.2.3.1.3.
|
84
|
+
SMB2_COMPRESSION_CAPABILITIES = 0x0003
|
85
|
+
# The NegotiateContext Data field contains the server name to which the client connects.
|
86
|
+
SMB2_NETNAME_NEGOTIATE_CONTEXT_ID = 0x0005
|
87
|
+
|
88
|
+
endian :little
|
89
|
+
|
90
|
+
string :pad, label: 'Padding', length: -> { pad_length }
|
91
|
+
uint16 :context_type, label: 'Context Type'
|
92
|
+
uint16 :data_length, label: 'Data Length', initial_value: -> { data.num_bytes }
|
93
|
+
uint32 :reserved, label: 'Reserved', initial_value: 0
|
94
|
+
choice :data, label: 'Data', selection: -> { context_type } do
|
95
|
+
preauth_integrity_capabilities SMB2_PREAUTH_INTEGRITY_CAPABILITIES, label: 'Preauthentication Integrity Capabilities'
|
96
|
+
encryption_capabilities SMB2_ENCRYPTION_CAPABILITIES, label: 'Encryption Capabilities'
|
97
|
+
compression_capabilities SMB2_COMPRESSION_CAPABILITIES, label: 'Compression Capabilities'
|
98
|
+
netname_negotiate_context_id SMB2_NETNAME_NEGOTIATE_CONTEXT_ID, label: 'Netname Negotiate Context ID'
|
99
|
+
end
|
100
|
+
|
101
|
+
def pad_length
|
102
|
+
offset = pad.abs_offset % 8
|
103
|
+
(8 - offset) % 8
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|