ruby_smb 1.0.3 → 1.0.4

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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/ruby_smb/client.rb +26 -4
  5. data/lib/ruby_smb/client/authentication.rb +43 -25
  6. data/lib/ruby_smb/client/echo.rb +20 -2
  7. data/lib/ruby_smb/client/negotiation.rb +27 -12
  8. data/lib/ruby_smb/client/tree_connect.rb +20 -14
  9. data/lib/ruby_smb/error.rb +40 -1
  10. data/lib/ruby_smb/generic_packet.rb +33 -4
  11. data/lib/ruby_smb/smb1/dcerpc.rb +7 -2
  12. data/lib/ruby_smb/smb1/file.rb +60 -11
  13. data/lib/ruby_smb/smb1/packet/close_request.rb +2 -5
  14. data/lib/ruby_smb/smb1/packet/close_response.rb +2 -1
  15. data/lib/ruby_smb/smb1/packet/echo_request.rb +2 -4
  16. data/lib/ruby_smb/smb1/packet/echo_response.rb +2 -1
  17. data/lib/ruby_smb/smb1/packet/empty_packet.rb +7 -0
  18. data/lib/ruby_smb/smb1/packet/logoff_request.rb +2 -4
  19. data/lib/ruby_smb/smb1/packet/logoff_response.rb +2 -1
  20. data/lib/ruby_smb/smb1/packet/negotiate_request.rb +2 -5
  21. data/lib/ruby_smb/smb1/packet/negotiate_response.rb +3 -7
  22. data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +4 -4
  23. data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +2 -4
  24. data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +2 -1
  25. data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +2 -1
  26. data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +2 -1
  27. data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +2 -4
  28. data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +2 -1
  29. data/lib/ruby_smb/smb1/packet/read_andx_request.rb +2 -5
  30. data/lib/ruby_smb/smb1/packet/read_andx_response.rb +2 -1
  31. data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -1
  32. data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -1
  33. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +2 -5
  34. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -1
  35. data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_request.rb +0 -1
  36. data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_response.rb +3 -2
  37. data/lib/ruby_smb/smb1/packet/trans/request.rb +2 -5
  38. data/lib/ruby_smb/smb1/packet/trans/response.rb +2 -1
  39. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +1 -1
  40. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +1 -1
  41. data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +2 -1
  42. data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +8 -2
  43. data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +2 -1
  44. data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +8 -2
  45. data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +2 -1
  46. data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +2 -1
  47. data/lib/ruby_smb/smb1/packet/trans2/request.rb +2 -4
  48. data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +2 -4
  49. data/lib/ruby_smb/smb1/packet/trans2/response.rb +2 -1
  50. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +2 -1
  51. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +2 -1
  52. data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +2 -4
  53. data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +13 -3
  54. data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
  55. data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -1
  56. data/lib/ruby_smb/smb1/packet/write_andx_request.rb +2 -5
  57. data/lib/ruby_smb/smb1/packet/write_andx_response.rb +2 -1
  58. data/lib/ruby_smb/smb1/pipe.rb +8 -3
  59. data/lib/ruby_smb/smb1/tree.rb +40 -2
  60. data/lib/ruby_smb/smb2/dcerpc.rb +7 -2
  61. data/lib/ruby_smb/smb2/file.rb +97 -1
  62. data/lib/ruby_smb/smb2/packet/close_request.rb +2 -4
  63. data/lib/ruby_smb/smb2/packet/close_response.rb +2 -1
  64. data/lib/ruby_smb/smb2/packet/create_request.rb +2 -4
  65. data/lib/ruby_smb/smb2/packet/create_response.rb +2 -1
  66. data/lib/ruby_smb/smb2/packet/echo_request.rb +2 -4
  67. data/lib/ruby_smb/smb2/packet/echo_response.rb +2 -1
  68. data/lib/ruby_smb/smb2/packet/error_packet.rb +7 -0
  69. data/lib/ruby_smb/smb2/packet/ioctl_request.rb +2 -5
  70. data/lib/ruby_smb/smb2/packet/ioctl_response.rb +2 -1
  71. data/lib/ruby_smb/smb2/packet/logoff_request.rb +2 -4
  72. data/lib/ruby_smb/smb2/packet/logoff_response.rb +2 -1
  73. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +2 -5
  74. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +2 -1
  75. data/lib/ruby_smb/smb2/packet/query_directory_request.rb +2 -4
  76. data/lib/ruby_smb/smb2/packet/query_directory_response.rb +8 -2
  77. data/lib/ruby_smb/smb2/packet/read_request.rb +2 -4
  78. data/lib/ruby_smb/smb2/packet/read_response.rb +2 -1
  79. data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
  80. data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -1
  81. data/lib/ruby_smb/smb2/packet/set_info_request.rb +2 -4
  82. data/lib/ruby_smb/smb2/packet/set_info_response.rb +2 -1
  83. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +2 -5
  84. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -2
  85. data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +2 -4
  86. data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +2 -1
  87. data/lib/ruby_smb/smb2/packet/write_request.rb +2 -4
  88. data/lib/ruby_smb/smb2/packet/write_response.rb +2 -1
  89. data/lib/ruby_smb/smb2/pipe.rb +9 -9
  90. data/lib/ruby_smb/smb2/tree.rb +44 -6
  91. data/lib/ruby_smb/version.rb +1 -1
  92. data/spec/lib/ruby_smb/client_spec.rb +123 -11
  93. data/spec/lib/ruby_smb/generic_packet_spec.rb +52 -4
  94. data/spec/lib/ruby_smb/smb1/file_spec.rb +182 -1
  95. data/spec/lib/ruby_smb/smb1/packet/{error_packet_spec.rb → empty_packet_spec.rb} +21 -0
  96. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +11 -2
  97. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +11 -2
  98. data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +40 -0
  99. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +63 -2
  100. data/spec/lib/ruby_smb/smb1/tree_spec.rb +44 -7
  101. data/spec/lib/ruby_smb/smb2/file_spec.rb +295 -2
  102. data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +51 -0
  103. data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +8 -0
  104. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +8 -0
  105. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +69 -3
  106. data/spec/lib/ruby_smb/smb2/tree_spec.rb +214 -0
  107. metadata +6 -4
  108. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2c631886979a7433c911311d4a86e396714d492c
4
- data.tar.gz: 2239c4167668f032308e16d047b40e0f4c1587cb
3
+ metadata.gz: 7d5e35bee112d4186cdb919a1041dbd54c72739d
4
+ data.tar.gz: 002b2dcada90c5617d15d472f5d06c5f1474619d
5
5
  SHA512:
6
- metadata.gz: 1fcc1eacddf7c95375b966772d580357ba321d31c157d277e4c4306e448696f0f1f1aa210f06b127db7f2ffad83b5086f30608e8cbeb0ad370339dd3e1630731
7
- data.tar.gz: 9cb22ee1ce93621365fba1f3bb67f0855a92331e28fc388b42d10e7b32716e587bfb29dda783d8c5bf617b388735f02abdc805a84b438aa1bdad70317f93d4f5
6
+ metadata.gz: 8516db67fb88bb248314f69eefef87f8021fcc409fa637e43a1b97474665d28e8d24fe470283d895c65374479d13d372d9eed346814eebd6bf144b63805b8bf2
7
+ data.tar.gz: 21632505b70f1af84724a613eb2344fda82e7c60f63255eb92569bef752fd0dcdf1e0fcb58f7f3cf21200b79fdfc3e592fde3643a42b0b5002db963d5f54e3ba
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -297,15 +297,32 @@ module RubySMB
297
297
  # Sends a LOGOFF command to the remote server to terminate the session
298
298
  #
299
299
  # @return [WindowsError::ErrorCode] the NTStatus of the response
300
+ # @raise [RubySMB::Error::InvalidPacket] if the response packet is not a LogoffResponse packet
300
301
  def logoff!
301
302
  if smb2
302
303
  request = RubySMB::SMB2::Packet::LogoffRequest.new
303
304
  raw_response = send_recv(request)
304
305
  response = RubySMB::SMB2::Packet::LogoffResponse.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::LogoffResponse::COMMAND,
310
+ received_proto: response.smb2_header.protocol,
311
+ received_cmd: response.smb2_header.command
312
+ )
313
+ end
305
314
  else
306
315
  request = RubySMB::SMB1::Packet::LogoffRequest.new
307
316
  raw_response = send_recv(request)
308
317
  response = RubySMB::SMB1::Packet::LogoffResponse.read(raw_response)
318
+ unless response.valid?
319
+ raise RubySMB::Error::InvalidPacket.new(
320
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
321
+ expected_cmd: RubySMB::SMB1::Packet::LogoffResponse::COMMAND,
322
+ received_proto: response.smb_header.protocol,
323
+ received_cmd: response.smb_header.command
324
+ )
325
+ end
309
326
  end
310
327
  wipe_state!
311
328
  response.status_code
@@ -380,14 +397,19 @@ module RubySMB
380
397
  # @param name [String] the NetBIOS name to request
381
398
  # @return [TrueClass] if session request is granted
382
399
  # @raise [RubySMB::Error::NetBiosSessionService] if session request is refused
400
+ # @raise [RubySMB::Error::InvalidPacket] if the response packet is not a NBSS packet
383
401
  def session_request(name = '*SMBSERVER')
384
402
  session_request = session_request_packet(name)
385
403
  dispatcher.send_packet(session_request, nbss_header: false)
386
404
  raw_response = dispatcher.recv_packet(full_response: true)
387
- session_header = RubySMB::Nbss::SessionHeader.read(raw_response)
388
- if session_header.session_packet_type == RubySMB::Nbss::NEGATIVE_SESSION_RESPONSE
389
- negative_session_response = RubySMB::Nbss::NegativeSessionResponse.read(raw_response)
390
- raise RubySMB::Error::NetBiosSessionService, "Session Request failed: #{negative_session_response.error_msg}"
405
+ begin
406
+ session_header = RubySMB::Nbss::SessionHeader.read(raw_response)
407
+ if session_header.session_packet_type == RubySMB::Nbss::NEGATIVE_SESSION_RESPONSE
408
+ negative_session_response = RubySMB::Nbss::NegativeSessionResponse.read(raw_response)
409
+ raise RubySMB::Error::NetBiosSessionService, "Session Request failed: #{negative_session_response.error_msg}"
410
+ end
411
+ rescue IOError
412
+ raise RubySMB::Error::InvalidPacket, 'Not a NBSS packet'
391
413
  end
392
414
 
393
415
  return true
@@ -54,14 +54,15 @@ module RubySMB
54
54
  end
55
55
 
56
56
  def smb1_anonymous_auth_response(raw_response)
57
- begin
58
- packet = RubySMB::SMB1::Packet::SessionSetupLegacyResponse.read(raw_response)
59
- rescue
60
- packet = RubySMB::SMB1::Packet::EmptyPacket.read(raw_response)
61
- end
62
-
63
- unless packet.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
64
- raise RubySMB::Error::InvalidPacket, "Command was #{packet.smb_header.command} and not #{RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP}"
57
+ packet = RubySMB::SMB1::Packet::SessionSetupLegacyResponse.read(raw_response)
58
+
59
+ unless packet.valid?
60
+ raise RubySMB::Error::InvalidPacket.new(
61
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
62
+ expected_cmd: RubySMB::SMB1::Packet::SessionSetupLegacyResponse::COMMAND,
63
+ received_proto: packet.smb_header.protocol,
64
+ received_cmd: packet.smb_header.command
65
+ )
65
66
  end
66
67
  packet
67
68
  end
@@ -147,14 +148,15 @@ module RubySMB
147
148
 
148
149
  # Takes the raw binary string and returns a {RubySMB::SMB1::Packet::SessionSetupResponse}
149
150
  def smb1_ntlmssp_final_packet(raw_response)
150
- begin
151
- packet = RubySMB::SMB1::Packet::SessionSetupResponse.read(raw_response)
152
- rescue
153
- packet = RubySMB::SMB1::Packet::EmptyPacket.read(raw_response)
154
- end
151
+ packet = RubySMB::SMB1::Packet::SessionSetupResponse.read(raw_response)
155
152
 
156
- unless packet.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
157
- raise RubySMB::Error::InvalidPacket, "Command was #{packet.smb_header.command} and not #{RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP}"
153
+ unless packet.valid?
154
+ raise RubySMB::Error::InvalidPacket.new(
155
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
156
+ expected_cmd: RubySMB::SMB1::Packet::SessionSetupResponse::COMMAND,
157
+ received_proto: packet.smb_header.protocol,
158
+ received_cmd: packet.smb_header.command
159
+ )
158
160
  end
159
161
  packet
160
162
  end
@@ -162,15 +164,20 @@ module RubySMB
162
164
  # Takes the raw binary string and returns a {RubySMB::SMB1::Packet::SessionSetupResponse}
163
165
  def smb1_ntlmssp_challenge_packet(raw_response)
164
166
  packet = RubySMB::SMB1::Packet::SessionSetupResponse.read(raw_response)
165
- status_code = packet.status_code
167
+ unless packet.valid?
168
+ raise RubySMB::Error::InvalidPacket.new(
169
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
170
+ expected_cmd: RubySMB::SMB1::Packet::SessionSetupResponse::COMMAND,
171
+ received_proto: packet.smb_header.protocol,
172
+ received_cmd: packet.smb_header.command
173
+ )
174
+ end
166
175
 
176
+ status_code = packet.status_code
167
177
  unless status_code.name == 'STATUS_MORE_PROCESSING_REQUIRED'
168
178
  raise RubySMB::Error::UnexpectedStatusCode, status_code.to_s
169
179
  end
170
180
 
171
- unless packet.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
172
- raise RubySMB::Error::InvalidPacket, "Command was #{packet.smb_header.command} and not #{RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP}"
173
- end
174
181
  packet
175
182
  end
176
183
 
@@ -212,23 +219,34 @@ module RubySMB
212
219
  # Takes the raw binary string and returns a {RubySMB::SMB2::Packet::SessionSetupResponse}
213
220
  def smb2_ntlmssp_final_packet(raw_response)
214
221
  packet = RubySMB::SMB2::Packet::SessionSetupResponse.read(raw_response)
215
- unless packet.smb2_header.command == RubySMB::SMB2::Commands::SESSION_SETUP
216
- raise RubySMB::Error::InvalidPacket, "Command was #{packet.smb2_header.command} and not #{RubySMB::SMB2::Commands::SESSION_SETUP}"
222
+ unless packet.valid?
223
+ raise RubySMB::Error::InvalidPacket.new(
224
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
225
+ expected_cmd: RubySMB::SMB2::Packet::SessionSetupResponse::COMMAND,
226
+ received_proto: packet.smb2_header.protocol,
227
+ received_cmd: packet.smb2_header.command
228
+ )
217
229
  end
230
+
218
231
  packet
219
232
  end
220
233
 
221
234
  # Takes the raw binary string and returns a {RubySMB::SMB2::Packet::SessionSetupResponse}
222
235
  def smb2_ntlmssp_challenge_packet(raw_response)
223
236
  packet = RubySMB::SMB2::Packet::SessionSetupResponse.read(raw_response)
237
+ unless packet.valid?
238
+ raise RubySMB::Error::InvalidPacket.new(
239
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
240
+ expected_cmd: RubySMB::SMB2::Packet::SessionSetupResponse::COMMAND,
241
+ received_proto: packet.smb2_header.protocol,
242
+ received_cmd: packet.smb2_header.command
243
+ )
244
+ end
245
+
224
246
  status_code = packet.status_code
225
247
  unless status_code.name == 'STATUS_MORE_PROCESSING_REQUIRED'
226
248
  raise RubySMB::Error::UnexpectedStatusCode, status_code.to_s
227
249
  end
228
-
229
- unless packet.smb2_header.command == RubySMB::SMB2::Commands::SESSION_SETUP
230
- raise RubySMB::Error::InvalidPacket, "Command was #{packet.smb2_header.command} and not #{RubySMB::SMB2::Commands::SESSION_SETUP}"
231
- end
232
250
  packet
233
251
  end
234
252
 
@@ -16,7 +16,16 @@ module RubySMB
16
16
  (count - 1).times do
17
17
  raw_response = dispatcher.recv_packet
18
18
  end
19
- RubySMB::SMB1::Packet::EchoResponse.read(raw_response)
19
+ response = RubySMB::SMB1::Packet::EchoResponse.read(raw_response)
20
+ unless response.valid?
21
+ raise RubySMB::Error::InvalidPacket.new(
22
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
23
+ expected_cmd: RubySMB::SMB1::Packet::EchoResponse::COMMAND,
24
+ received_proto: response.smb_header.protocol,
25
+ received_cmd: response.smb_header.command
26
+ )
27
+ end
28
+ response
20
29
  end
21
30
 
22
31
  # Sends an ECHO request packet and returns the
@@ -26,7 +35,16 @@ module RubySMB
26
35
  def smb2_echo
27
36
  request = RubySMB::SMB2::Packet::EchoRequest.new
28
37
  raw_response = send_recv(request)
29
- RubySMB::SMB2::Packet::EchoResponse.read(raw_response)
38
+ response = RubySMB::SMB2::Packet::EchoResponse.read(raw_response)
39
+ unless response.valid?
40
+ raise RubySMB::Error::InvalidPacket.new(
41
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
42
+ expected_cmd: RubySMB::SMB2::Packet::EchoResponse::COMMAND,
43
+ received_proto: response.smb2_header.protocol,
44
+ received_cmd: response.smb2_header.command
45
+ )
46
+ end
47
+ response
30
48
  end
31
49
  end
32
50
  end
@@ -47,23 +47,38 @@ module RubySMB
47
47
  def negotiate_response(raw_data)
48
48
  response = nil
49
49
  if smb1
50
- begin
51
- packet = RubySMB::SMB1::Packet::NegotiateResponseExtended.read raw_data
52
- rescue StandardError => e
53
- raise RubySMB::Error::InvalidPacket, "Not a Valid SMB1 Negoitate Response #{e.message}"
54
- end
50
+ packet = RubySMB::SMB1::Packet::NegotiateResponseExtended.read raw_data
55
51
  response = packet if packet.valid?
56
52
  end
57
53
  if smb2 && response.nil?
58
- begin
59
- packet = RubySMB::SMB2::Packet::NegotiateResponse.read raw_data
60
- rescue StandardError => e
61
- raise RubySMB::Error::InvalidPacket, "Not a Valid SMB2 Negoitate Response #{e.message}"
62
- end
63
- response = packet
54
+ packet = RubySMB::SMB2::Packet::NegotiateResponse.read raw_data
55
+ response = packet if packet.valid?
64
56
  end
65
57
  if response.nil?
66
- raise RubySMB::Error::InvalidPacket, 'No Valid Negotiate Response found'
58
+ if packet.packet_smb_version == 'SMB1'
59
+ extended_security = if packet.is_a? RubySMB::SMB1::Packet::NegotiateResponseExtended
60
+ packet.parameter_block.capabilities.extended_security
61
+ else
62
+ "n/a"
63
+ end
64
+ raise RubySMB::Error::InvalidPacket.new(
65
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
66
+ expected_cmd: RubySMB::SMB1::Packet::NegotiateResponseExtended::COMMAND,
67
+ expected_custom: "extended_security=1",
68
+ received_proto: packet.smb_header.protocol,
69
+ received_cmd: packet.smb_header.command,
70
+ received_custom: "extended_security=#{extended_security}"
71
+ )
72
+ elsif packet.packet_smb_version == 'SMB2'
73
+ raise RubySMB::Error::InvalidPacket.new(
74
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
75
+ expected_cmd: RubySMB::SMB2::Packet::NegotiateResponse::COMMAND,
76
+ received_proto: packet.smb2_header.protocol,
77
+ received_cmd: packet.smb2_header.command
78
+ )
79
+ else
80
+ raise RubySMB::Error::InvalidPacket, 'Unknown SMB protocol version'
81
+ end
67
82
  end
68
83
  response
69
84
  end
@@ -17,11 +17,7 @@ module RubySMB
17
17
  request.smb_header.tid = 65_535
18
18
  request.data_block.path = share
19
19
  raw_response = send_recv(request)
20
- begin
21
- response = RubySMB::SMB1::Packet::TreeConnectResponse.read(raw_response)
22
- rescue EOFError
23
- response = RubySMB::SMB1::Packet::EmptyPacket.read(raw_response)
24
- end
20
+ response = RubySMB::SMB1::Packet::TreeConnectResponse.read(raw_response)
25
21
  smb1_tree_from_response(share, response)
26
22
  end
27
23
 
@@ -30,9 +26,16 @@ module RubySMB
30
26
  # @param share [String] the share path to connect to
31
27
  # @param response [RubySMB::SMB1::Packet::TreeConnectResponse] the response packet to parse into our Tree
32
28
  # @return [RubySMB::SMB1::Tree]
29
+ # @raise [RubySMB::Error::InvalidPacket] if the response command is not a TreeConnectResponse packet
30
+ # @raise [RubySMB::Error::UnexpectedStatusCode] if the response status code is not STATUS_SUCCESS
33
31
  def smb1_tree_from_response(share, response)
34
- unless response.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_TREE_CONNECT
35
- raise RubySMB::Error::InvalidPacket, 'Not a TreeConnectResponse'
32
+ unless response.valid?
33
+ raise RubySMB::Error::InvalidPacket.new(
34
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
35
+ expected_cmd: RubySMB::SMB1::Packet::TreeConnectResponse::COMMAND,
36
+ received_proto: response.smb_header.protocol,
37
+ received_cmd: response.smb_header.command
38
+ )
36
39
  end
37
40
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
38
41
  raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
@@ -54,11 +57,7 @@ module RubySMB
54
57
  request.smb2_header.tree_id = 65_535
55
58
  request.encode_path(share)
56
59
  raw_response = send_recv(request)
57
- begin
58
- response = RubySMB::SMB2::Packet::TreeConnectResponse.read(raw_response)
59
- rescue EOFError
60
- response = RubySMB::SMB2::Packet::ErrorPacket.read(raw_response)
61
- end
60
+ response = RubySMB::SMB2::Packet::TreeConnectResponse.read(raw_response)
62
61
  smb2_tree_from_response(share, response)
63
62
  end
64
63
 
@@ -67,9 +66,16 @@ module RubySMB
67
66
  # @param share [String] the share path to connect to
68
67
  # @param response [RubySMB::SMB2::Packet::TreeConnectResponse] the response packet to parse into our Tree
69
68
  # @return [RubySMB::SMB2::Tree]
69
+ # @raise [RubySMB::Error::InvalidPacket] if the response command is not a TreeConnectResponse packet
70
+ # @raise [RubySMB::Error::UnexpectedStatusCode] if the response status code is not STATUS_SUCCESS
70
71
  def smb2_tree_from_response(share, response)
71
- unless response.smb2_header.command == RubySMB::SMB2::Commands::TREE_CONNECT
72
- raise RubySMB::Error::InvalidPacket, 'Not a TreeConnectResponse'
72
+ unless response.valid?
73
+ raise RubySMB::Error::InvalidPacket.new(
74
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
75
+ expected_cmd: RubySMB::SMB2::Packet::TreeConnectResponse::COMMAND,
76
+ received_proto: response.smb2_header.protocol,
77
+ received_cmd: response.smb2_header.command
78
+ )
73
79
  end
74
80
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
75
81
  raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
@@ -15,7 +15,42 @@ module RubySMB
15
15
 
16
16
  # Raised when trying to parse raw binary into a Packet and the data
17
17
  # is invalid.
18
- class InvalidPacket < RubySMBError; end
18
+ class InvalidPacket < RubySMBError
19
+ def initialize(args = nil)
20
+ if args.nil?
21
+ super
22
+ elsif args.is_a? String
23
+ super(args)
24
+ elsif args.is_a? Hash
25
+ expected_proto = args[:expected_proto] ? translate_protocol(args[:expected_proto]) : "???"
26
+ expected_cmd = args[:expected_cmd] || "???"
27
+ received_proto = args[:received_proto] ? translate_protocol(args[:received_proto]) : "???"
28
+ received_cmd = args[:received_cmd] || "???"
29
+ super(
30
+ "Expecting #{expected_proto} protocol "\
31
+ "with command=#{expected_cmd}"\
32
+ "#{(" (" + args[:expected_custom] + ")") if args[:expected_custom]}, "\
33
+ "got #{received_proto} protocol "\
34
+ "with command=#{received_cmd}"\
35
+ "#{(" (" + args[:received_custom] + ")") if args[:received_custom]}"
36
+ )
37
+ else
38
+ raise ArgumentError, "InvalidPacket expects a String or a Hash, got a #{args.class}"
39
+ end
40
+ end
41
+
42
+ def translate_protocol(proto)
43
+ case proto
44
+ when RubySMB::SMB1::SMB_PROTOCOL_ID
45
+ 'SMB1'
46
+ when RubySMB::SMB2::SMB2_PROTOCOL_ID
47
+ 'SMB2'
48
+ else
49
+ raise ArgumentError, 'Unknown SMB protocol'
50
+ end
51
+ end
52
+ private :translate_protocol
53
+ end
19
54
 
20
55
  # Raised when a response packet has a NTStatus code that was unexpected.
21
56
  class UnexpectedStatusCode < RubySMBError; end
@@ -26,5 +61,9 @@ module RubySMB
26
61
  # Raised when Protocol Negotiation fails, possibly due to an
27
62
  # unsupported protocol.
28
63
  class NegotiationFailure < RubySMBError; end
64
+
65
+ # Raised when trying to parse raw binary into a BitField and the data
66
+ # is invalid.
67
+ class InvalidBitField < RubySMBError; end
29
68
  end
30
69
  end
@@ -45,14 +45,16 @@ module RubySMB
45
45
  rescue IOError => e
46
46
  case self.to_s
47
47
  when /EmptyPacket|ErrorPacket/
48
- raise e
48
+ raise RubySMB::Error::InvalidPacket, 'Not a valid SMB packet'
49
49
  when /SMB1/
50
- RubySMB::SMB1::Packet::EmptyPacket.read(val)
50
+ packet = RubySMB::SMB1::Packet::EmptyPacket.read(val)
51
51
  when /SMB2/
52
- RubySMB::SMB2::Packet::ErrorPacket.read(val)
52
+ packet = RubySMB::SMB2::Packet::ErrorPacket.read(val)
53
53
  else
54
- raise e
54
+ raise RubySMB::Error::InvalidPacket, 'Not a valid SMB packet'
55
55
  end
56
+ packet.original_command = self::COMMAND
57
+ packet
56
58
  end
57
59
  end
58
60
 
@@ -72,6 +74,33 @@ module RubySMB
72
74
  status_code
73
75
  end
74
76
 
77
+ # Validates the packet protocol ID and the SMB command
78
+ #
79
+ # @return [TrueClass, FalseClass] true if the packet is valid, false otherwise
80
+ def valid?
81
+ case packet_smb_version
82
+ when 'SMB1'
83
+ return smb_header.protocol == RubySMB::SMB1::SMB_PROTOCOL_ID &&
84
+ smb_header.command == self.class::COMMAND
85
+ when 'SMB2'
86
+ return smb2_header.protocol == RubySMB::SMB2::SMB2_PROTOCOL_ID &&
87
+ smb2_header.command == self.class::COMMAND
88
+ end
89
+ end
90
+
91
+ def initialize_instance
92
+ super
93
+
94
+ unless [RubySMB::SMB1::Packet::EmptyPacket, RubySMB::SMB2::Packet::ErrorPacket].any? {|klass| self.is_a? klass}
95
+ case packet_smb_version
96
+ when 'SMB1'
97
+ smb_header.command = self.class::COMMAND
98
+ when 'SMB2'
99
+ smb2_header.command = self.class::COMMAND
100
+ end
101
+ end
102
+ end
103
+
75
104
  # Returns an array of hashes representing the
76
105
  # fields for this record.
77
106
  #
@@ -43,8 +43,13 @@ module RubySMB
43
43
 
44
44
  trans_nmpipe_raw_response = @tree.client.send_recv(request)
45
45
  trans_nmpipe_response = RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse.read(trans_nmpipe_raw_response)
46
- unless trans_nmpipe_response.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_TRANSACTION
47
- raise RubySMB::Error::InvalidPacket, 'Not a Trans packet'
46
+ unless trans_nmpipe_response.valid?
47
+ raise RubySMB::Error::InvalidPacket.new(
48
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
49
+ expected_cmd: RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse::COMMAND,
50
+ received_proto: trans_nmpipe_response.smb_header.protocol,
51
+ received_cmd: trans_nmpipe_response.smb_header.command
52
+ )
48
53
  end
49
54
  unless trans_nmpipe_response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
50
55
  raise RubySMB::Error::UnexpectedStatusCode, trans_nmpipe_response.status_code.name