ruby_smb 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +1 -4
  4. data/.travis.yml +3 -5
  5. data/Gemfile +6 -2
  6. data/examples/negotiate.rb +51 -8
  7. data/examples/read_file_encryption.rb +56 -0
  8. data/lib/ruby_smb.rb +4 -0
  9. data/lib/ruby_smb/client.rb +172 -16
  10. data/lib/ruby_smb/client/authentication.rb +27 -8
  11. data/lib/ruby_smb/client/encryption.rb +62 -0
  12. data/lib/ruby_smb/client/negotiation.rb +133 -12
  13. data/lib/ruby_smb/client/signing.rb +19 -0
  14. data/lib/ruby_smb/client/tree_connect.rb +4 -4
  15. data/lib/ruby_smb/client/utils.rb +8 -7
  16. data/lib/ruby_smb/crypto.rb +30 -0
  17. data/lib/ruby_smb/dispatcher/socket.rb +2 -2
  18. data/lib/ruby_smb/error.rb +28 -1
  19. data/lib/ruby_smb/smb1/commands.rb +1 -1
  20. data/lib/ruby_smb/smb1/file.rb +4 -4
  21. data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +1 -1
  22. data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -2
  23. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
  24. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -2
  25. data/lib/ruby_smb/smb1/packet/write_andx_request.rb +1 -1
  26. data/lib/ruby_smb/smb1/pipe.rb +2 -2
  27. data/lib/ruby_smb/smb1/tree.rb +3 -3
  28. data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
  29. data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
  30. data/lib/ruby_smb/smb2/file.rb +25 -43
  31. data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
  32. data/lib/ruby_smb/smb2/packet.rb +2 -0
  33. data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
  34. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -14
  35. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +49 -3
  36. data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
  37. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +92 -6
  38. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -26
  39. data/lib/ruby_smb/smb2/pipe.rb +3 -16
  40. data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
  41. data/lib/ruby_smb/smb2/tree.rb +23 -17
  42. data/lib/ruby_smb/version.rb +1 -1
  43. data/ruby_smb.gemspec +3 -1
  44. data/spec/lib/ruby_smb/client_spec.rb +1256 -57
  45. data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
  46. data/spec/lib/ruby_smb/error_spec.rb +59 -0
  47. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
  48. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
  49. data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
  50. data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
  51. data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
  52. data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
  53. data/spec/lib/ruby_smb/smb2/file_spec.rb +86 -62
  54. data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
  55. data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
  56. data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
  57. data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
  58. data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
  59. data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
  60. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -30
  61. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +0 -40
  62. data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
  63. data/spec/lib/ruby_smb/smb2/tree_spec.rb +53 -8
  64. metadata +124 -75
  65. 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 occured writing to the Socket: #{e.message}"
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 occured reading from the Socket #{e.message}"
87
+ raise RubySMB::Error::CommunicationError, "An error occurred reading from the Socket #{e.message}"
88
88
  end
89
89
  end
90
90
  end
@@ -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; end
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
- SMB_COM_SESSION_SETUP = 0x73
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
@@ -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.name
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.name
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.name
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.name
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::SMB_COM_SESSION_SETUP
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 SMB_COM_SESSION_SETUP Legacy Response Packet as defined in
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::SMB_COM_SESSION_SETUP
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::SMB_COM_SESSION_SETUP
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 SMB_COM_SESSION_SETUP Response Packet as defined in
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::SMB_COM_SESSION_SETUP
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
@@ -43,7 +43,7 @@ module RubySMB
43
43
 
44
44
  # Represents the specific layout of the DataBlock for a {WriteAndxRequest} Packet.
45
45
  class DataBlock < RubySMB::SMB1::DataBlock
46
- uint8 :pad, label: 'Pad'
46
+ string :pad, label: 'Pad', length: 1
47
47
  string :data, label: 'Data'
48
48
  end
49
49
 
@@ -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.name
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.name
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
@@ -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.name
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.name
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.name
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
- bit6 :reserved3, label: 'Reserved', initial_value: 0
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
- bit8 :reserved3, label: 'Reserved Space'
25
- bit8 :reserved4, label: 'Reserved Space'
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?
@@ -52,7 +52,12 @@ module RubySMB
52
52
  # @return [RubySMB::SMB2::Tree]
53
53
  attr_accessor :tree
54
54
 
55
- def initialize(tree:, response:, name:)
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.name
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.name
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.name
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
- if response.status_code == WindowsError::NTStatus::STATUS_PENDING
187
- sleep 1
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
- if response.status_code == WindowsError::NTStatus::STATUS_PENDING
303
- sleep 1
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