ruby_smb 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
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