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
@@ -4,6 +4,8 @@ module RubySMB
4
4
  # This class represents an SMB1 TreeConnect Request Packet as defined in
5
5
  # [2.2.4.7.1 Client Request Extensions](https://msdn.microsoft.com/en-us/library/cc246330.aspx)
6
6
  class TreeConnectRequest < RubySMB::GenericPacket
7
+ COMMAND = RubySMB::SMB1::Commands::SMB_COM_TREE_CONNECT
8
+
7
9
  # A SMB1 Parameter Block as defined by the {TreeConnectRequest}
8
10
  class ParameterBlock < RubySMB::SMB1::ParameterBlock
9
11
  and_x_block :andx_block
@@ -22,10 +24,6 @@ module RubySMB
22
24
  parameter_block :parameter_block
23
25
  data_block :data_block
24
26
 
25
- def initialize_instance
26
- super
27
- smb_header.command = RubySMB::SMB1::Commands::SMB_COM_TREE_CONNECT
28
- end
29
27
  end
30
28
  end
31
29
  end
@@ -4,6 +4,8 @@ module RubySMB
4
4
  # A SMB1 TreeConnect Response Packet as defined in
5
5
  # [2.2.4.7.2 Server Response Extensions](https://msdn.microsoft.com/en-us/library/cc246331.aspx)
6
6
  class TreeConnectResponse < RubySMB::GenericPacket
7
+ COMMAND = RubySMB::SMB1::Commands::SMB_COM_TREE_CONNECT
8
+
7
9
  # A SMB1 Parameter Block as defined by the {SessionSetupResponse}
8
10
  class ParameterBlock < RubySMB::SMB1::ParameterBlock
9
11
  and_x_block :andx_block
@@ -24,7 +26,6 @@ module RubySMB
24
26
 
25
27
  def initialize_instance
26
28
  super
27
- smb_header.command = RubySMB::SMB1::Commands::SMB_COM_TREE_CONNECT
28
29
  smb_header.flags.reply = 1
29
30
  end
30
31
 
@@ -34,12 +35,17 @@ module RubySMB
34
35
  #
35
36
  # @return [RubySMB::SMB1::BitField::DirectoryAccessMask] if a directory was connected to
36
37
  # @return [RubySMB::SMB1::BitField::FileAccessMask] if anything else was connected to
38
+ # @raise [RubySMB::Error::InvalidBitField] if ACCESS_MASK bit field is not valid
37
39
  def access_rights
38
40
  if is_directory?
39
41
  parameter_block.access_rights
40
42
  else
41
43
  mask = parameter_block.access_rights.to_binary_s
42
- RubySMB::SMB1::BitField::FileAccessMask.read(mask)
44
+ begin
45
+ RubySMB::SMB1::BitField::FileAccessMask.read(mask)
46
+ rescue IOError
47
+ raise RubySMB::Error::InvalidBitField, 'Invalid ACCESS_MASK for the Maximal Share Access Rights'
48
+ end
43
49
  end
44
50
  end
45
51
 
@@ -54,7 +60,11 @@ module RubySMB
54
60
  parameter_block.guest_access_rights
55
61
  else
56
62
  mask = parameter_block.guest_access_rights.to_binary_s
57
- RubySMB::SMB1::BitField::FileAccessMask.read(mask)
63
+ begin
64
+ RubySMB::SMB1::BitField::FileAccessMask.read(mask)
65
+ rescue IOError
66
+ raise RubySMB::Error::InvalidBitField, 'Invalid ACCESS_MASK for the Guest Share Access Rights'
67
+ end
58
68
  end
59
69
  end
60
70
 
@@ -4,6 +4,8 @@ module RubySMB
4
4
  # This class represents an SMB1 TreeDisonnect Request Packet as defined in
5
5
  # [2.2.4.51.1 Request](https://msdn.microsoft.com/en-us/library/ee441622.aspx)
6
6
  class TreeDisconnectRequest < RubySMB::GenericPacket
7
+ COMMAND = RubySMB::SMB1::Commands::SMB_COM_TREE_DISCONNECT
8
+
7
9
  # The Parameter Block for this packet is empty save the Word Count
8
10
  # The {RubySMB::SMB1::ParameterBlock} specific to this packet type.
9
11
  class ParameterBlock < RubySMB::SMB1::ParameterBlock
@@ -17,10 +19,6 @@ module RubySMB
17
19
  parameter_block :parameter_block
18
20
  data_block :data_block
19
21
 
20
- def initialize_instance
21
- super
22
- smb_header.command = RubySMB::SMB1::Commands::SMB_COM_TREE_DISCONNECT
23
- end
24
22
  end
25
23
  end
26
24
  end
@@ -4,6 +4,8 @@ module RubySMB
4
4
  # This class represents an SMB1 TreeDisonnect Response Packet as defined in
5
5
  # [2.2.4.51.2 Response](https://msdn.microsoft.com/en-us/library/ee441823.aspx)
6
6
  class TreeDisconnectResponse < RubySMB::GenericPacket
7
+ COMMAND = RubySMB::SMB1::Commands::SMB_COM_TREE_DISCONNECT
8
+
7
9
  # The Parameter Block for this packet is empty save the Word Count
8
10
  # The {RubySMB::SMB1::ParameterBlock} specific to this packet type.
9
11
  class ParameterBlock < RubySMB::SMB1::ParameterBlock
@@ -19,7 +21,6 @@ module RubySMB
19
21
 
20
22
  def initialize_instance
21
23
  super
22
- smb_header.command = RubySMB::SMB1::Commands::SMB_COM_TREE_DISCONNECT
23
24
  smb_header.flags.reply = 1
24
25
  end
25
26
  end
@@ -5,6 +5,8 @@ module RubySMB
5
5
  # [2.2.4.43.1 Request](https://msdn.microsoft.com/en-us/library/ee441954.aspx)
6
6
  # [2.2.4.3.1 Client Request Extensions](https://msdn.microsoft.com/en-us/library/ff469893.aspx)
7
7
  class WriteAndxRequest < RubySMB::GenericPacket
8
+ COMMAND = RubySMB::SMB1::Commands::SMB_COM_WRITE_ANDX
9
+
8
10
  # A SMB1 Parameter Block as defined by the {WriteAndxRequest}
9
11
  class ParameterBlock < RubySMB::SMB1::ParameterBlock
10
12
  endian :little
@@ -49,11 +51,6 @@ module RubySMB
49
51
  parameter_block :parameter_block
50
52
  data_block :data_block
51
53
 
52
- def initialize_instance
53
- super
54
- smb_header.command = RubySMB::SMB1::Commands::SMB_COM_WRITE_ANDX
55
- end
56
-
57
54
  # Specifies whether the offset is a 32-bit (default) or 64-bit value. When `is_64_bit`
58
55
  # is true, a 64-bit offset will be used and the OffsetHigh field will be added to the structure.
59
56
  #
@@ -5,6 +5,8 @@ module RubySMB
5
5
  # [2.2.4.43.2 Response](https://msdn.microsoft.com/en-us/library/ee441673.aspx)
6
6
  # [2.2.4.3.2 Server Response Extensions](https://msdn.microsoft.com/en-us/library/ff469858.aspx)
7
7
  class WriteAndxResponse < RubySMB::GenericPacket
8
+ COMMAND = RubySMB::SMB1::Commands::SMB_COM_WRITE_ANDX
9
+
8
10
  # A SMB1 Parameter Block as defined by the {WriteAndxResponse}
9
11
  class ParameterBlock < RubySMB::SMB1::ParameterBlock
10
12
  endian :little
@@ -26,7 +28,6 @@ module RubySMB
26
28
 
27
29
  def initialize_instance
28
30
  super
29
- smb_header.command = RubySMB::SMB1::Commands::SMB_COM_WRITE_ANDX
30
31
  smb_header.flags.reply = 1
31
32
  end
32
33
  end
@@ -26,14 +26,19 @@ module RubySMB
26
26
  packet = @tree.set_header_fields(packet)
27
27
  raw_response = @tree.client.send_recv(packet)
28
28
  response = RubySMB::SMB1::Packet::Trans::PeekNmpipeResponse.read(raw_response)
29
+ unless response.valid?
30
+ raise RubySMB::Error::InvalidPacket.new(
31
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
32
+ expected_cmd: RubySMB::SMB1::Packet::Trans::PeekNmpipeRequest::COMMAND,
33
+ received_proto: response.smb_header.protocol,
34
+ received_cmd: response.smb_header.command
35
+ )
36
+ end
29
37
 
30
38
  unless response.status_code == WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW or response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
31
39
  raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
32
40
  end
33
41
 
34
- unless response.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_TRANSACTION
35
- raise RubySMB::Error::InvalidPacket, 'Not a TransResponse packet'
36
- end
37
42
  response
38
43
  end
39
44
 
@@ -39,11 +39,20 @@ module RubySMB
39
39
  # Disconnects this Tree from the current session
40
40
  #
41
41
  # @return [WindowsError::ErrorCode] the NTStatus sent back by the server.
42
+ # @raise [RubySMB::Error::InvalidPacket] if the response is not a TreeDisconnectResponse packet
42
43
  def disconnect!
43
44
  request = RubySMB::SMB1::Packet::TreeDisconnectRequest.new
44
45
  request = set_header_fields(request)
45
46
  raw_response = client.send_recv(request)
46
47
  response = RubySMB::SMB1::Packet::TreeDisconnectResponse.read(raw_response)
48
+ unless response.valid?
49
+ raise RubySMB::Error::InvalidPacket.new(
50
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
51
+ expected_cmd: RubySMB::SMB1::Packet::TreeDisconnectResponse::COMMAND,
52
+ received_proto: response.smb_header.protocol,
53
+ received_cmd: response.smb_header.command
54
+ )
55
+ end
47
56
  response.status_code
48
57
  end
49
58
 
@@ -113,8 +122,13 @@ module RubySMB
113
122
 
114
123
  raw_response = @client.send_recv(nt_create_andx_request)
115
124
  response = RubySMB::SMB1::Packet::NtCreateAndxResponse.read(raw_response)
116
- unless response.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_NT_CREATE_ANDX
117
- raise RubySMB::Error::InvalidPacket, 'Not a NtCreateAndxResponse packet'
125
+ unless response.valid?
126
+ raise RubySMB::Error::InvalidPacket.new(
127
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
128
+ expected_cmd: RubySMB::SMB1::Packet::NtCreateAndxResponse::COMMAND,
129
+ received_proto: response.smb_header.protocol,
130
+ received_cmd: response.smb_header.command
131
+ )
118
132
  end
119
133
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
120
134
  raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
@@ -140,6 +154,8 @@ module RubySMB
140
154
  # @param pattern [String] search pattern
141
155
  # @param type [Class] file information class
142
156
  # @return [Array] array of directory structures
157
+ # @raise [RubySMB::Error::InvalidPacket] if the response is not a Trans2 packet
158
+ # @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
143
159
  def list(directory: '\\', pattern: '*', unicode: true,
144
160
  type: RubySMB::SMB1::Packet::Trans2::FindInformationLevel::FindFileFullDirectoryInfo)
145
161
  find_first_request = RubySMB::SMB1::Packet::Trans2::FindFirst2Request.new
@@ -166,6 +182,17 @@ module RubySMB
166
182
 
167
183
  raw_response = client.send_recv(find_first_request)
168
184
  response = RubySMB::SMB1::Packet::Trans2::FindFirst2Response.read(raw_response)
185
+ unless response.valid?
186
+ raise RubySMB::Error::InvalidPacket.new(
187
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
188
+ expected_cmd: RubySMB::SMB1::Packet::Trans2::FindFirst2Response::COMMAND,
189
+ received_proto: response.smb_header.protocol,
190
+ received_cmd: response.smb_header.command
191
+ )
192
+ end
193
+ unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
194
+ raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
195
+ end
169
196
 
170
197
  results = response.results(type, unicode: unicode)
171
198
 
@@ -190,6 +217,17 @@ module RubySMB
190
217
 
191
218
  raw_response = client.send_recv(find_next_request)
192
219
  response = RubySMB::SMB1::Packet::Trans2::FindNext2Response.read(raw_response)
220
+ unless response.valid?
221
+ raise RubySMB::Error::InvalidPacket.new(
222
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
223
+ expected_cmd: RubySMB::SMB1::Packet::Trans2::FindNext2Response::COMMAND,
224
+ received_proto: response.smb_header.protocol,
225
+ received_cmd: response.smb_header.command
226
+ )
227
+ end
228
+ unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
229
+ raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
230
+ end
193
231
 
194
232
  results += response.results(type, unicode: unicode)
195
233
 
@@ -55,8 +55,13 @@ module RubySMB
55
55
  request.buffer = action.to_binary_s
56
56
  ioctl_raw_response = @tree.client.send_recv(request)
57
57
  ioctl_response = RubySMB::SMB2::Packet::IoctlResponse.read(ioctl_raw_response)
58
- unless ioctl_response.smb2_header.command == RubySMB::SMB2::Commands::IOCTL
59
- raise RubySMB::Error::InvalidPacket, 'Not a IoctlResponse packet'
58
+ unless ioctl_response.valid?
59
+ raise RubySMB::Error::InvalidPacket.new(
60
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
61
+ expected_cmd: RubySMB::SMB2::Packet::IoctlRequest::COMMAND,
62
+ received_proto: ioctl_response.smb2_header.protocol,
63
+ received_cmd: ioctl_response.smb2_header.command
64
+ )
60
65
  end
61
66
  unless ioctl_response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
62
67
  raise RubySMB::Error::UnexpectedStatusCode, ioctl_response.status_code.name
@@ -79,11 +79,24 @@ module RubySMB
79
79
  # Closes the handle to the remote file.
80
80
  #
81
81
  # @return [WindowsError::ErrorCode] the NTStatus code returned by the operation
82
+ # @raise [RubySMB::Error::InvalidPacket] if the response is not a CloseResponse packet
83
+ # @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
82
84
  def close
83
85
  close_request = set_header_fields(RubySMB::SMB2::Packet::CloseRequest.new)
84
86
  raw_response = tree.client.send_recv(close_request)
85
87
  response = RubySMB::SMB2::Packet::CloseResponse.read(raw_response)
86
- response.smb2_header.nt_status.to_nt_status
88
+ unless response.valid?
89
+ raise RubySMB::Error::InvalidPacket.new(
90
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
91
+ expected_cmd: RubySMB::SMB2::Packet::CloseResponse::COMMAND,
92
+ received_proto: response.smb2_header.protocol,
93
+ received_cmd: response.smb2_header.command
94
+ )
95
+ end
96
+ unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
97
+ raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
98
+ end
99
+ response.status_code
87
100
  end
88
101
 
89
102
  # Read from the file, a specific number of bytes
@@ -93,6 +106,8 @@ module RubySMB
93
106
  # @param bytes [Integer] the number of bytes to read
94
107
  # @param offset [Integer] the byte offset in the file to start reading from
95
108
  # @return [String] the data read from the file
109
+ # @raise [RubySMB::Error::InvalidPacket] if the response is not a ReadResponse packet
110
+ # @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
96
111
  def read(bytes: size, offset: 0)
97
112
  atomic_read_size = if bytes > tree.client.server_max_read_size
98
113
  tree.client.server_max_read_size
@@ -103,6 +118,17 @@ module RubySMB
103
118
  read_request = read_packet(read_length: atomic_read_size, offset: offset)
104
119
  raw_response = tree.client.send_recv(read_request)
105
120
  response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
121
+ unless response.valid?
122
+ raise RubySMB::Error::InvalidPacket.new(
123
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
124
+ expected_cmd: RubySMB::SMB2::Packet::ReadResponse::COMMAND,
125
+ received_proto: response.smb2_header.protocol,
126
+ received_cmd: response.smb2_header.command
127
+ )
128
+ end
129
+ unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
130
+ raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
131
+ end
106
132
 
107
133
  data = response.buffer.to_binary_s
108
134
 
@@ -115,6 +141,17 @@ module RubySMB
115
141
  read_request = read_packet(read_length: atomic_read_size, offset: offset)
116
142
  raw_response = tree.client.send_recv(read_request)
117
143
  response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
144
+ unless response.valid?
145
+ raise RubySMB::Error::InvalidPacket.new(
146
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
147
+ expected_cmd: RubySMB::SMB2::Packet::ReadResponse::COMMAND,
148
+ received_proto: response.smb2_header.protocol,
149
+ received_cmd: response.smb2_header.command
150
+ )
151
+ end
152
+ unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
153
+ raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
154
+ end
118
155
 
119
156
  data << response.buffer.to_binary_s
120
157
  remaining_bytes -= atomic_read_size
@@ -138,10 +175,26 @@ module RubySMB
138
175
  read_request = read_packet(read_length: read_length, offset: offset)
139
176
  raw_response = tree.client.send_recv(read_request)
140
177
  response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
178
+ unless response.valid?
179
+ raise RubySMB::Error::InvalidPacket.new(
180
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
181
+ expected_cmd: RubySMB::SMB2::Packet::ReadResponse::COMMAND,
182
+ received_proto: response.smb2_header.protocol,
183
+ received_cmd: response.smb2_header.command
184
+ )
185
+ end
141
186
  if response.status_code == WindowsError::NTStatus::STATUS_PENDING
142
187
  sleep 1
143
188
  raw_response = tree.client.dispatcher.recv_packet
144
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
145
198
  elsif response.status_code != WindowsError::NTStatus::STATUS_SUCCESS
146
199
  raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
147
200
  end
@@ -151,9 +204,18 @@ module RubySMB
151
204
  # Delete a file on close
152
205
  #
153
206
  # @return [WindowsError::ErrorCode] the NTStatus Response code
207
+ # @raise [RubySMB::Error::InvalidPacket] if the response is not a SetInfoResponse packet
154
208
  def delete
155
209
  raw_response = tree.client.send_recv(delete_packet)
156
210
  response = RubySMB::SMB2::Packet::SetInfoResponse.read(raw_response)
211
+ unless response.valid?
212
+ raise RubySMB::Error::InvalidPacket.new(
213
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
214
+ expected_cmd: RubySMB::SMB2::Packet::SetInfoResponse::COMMAND,
215
+ received_proto: response.smb2_header.protocol,
216
+ received_cmd: response.smb2_header.command
217
+ )
218
+ end
157
219
  response.smb2_header.nt_status.to_nt_status
158
220
  end
159
221
 
@@ -182,6 +244,7 @@ module RubySMB
182
244
  # @param data [String] the data to write to the file
183
245
  # @param offset [Integer] the offset in the file to start writing from
184
246
  # @return [WindowsError::ErrorCode] the NTStatus code returned from the operation
247
+ # @raise [RubySMB::Error::InvalidPacket] if the response is not a WriteResponse packet
185
248
  def write(data:'', offset: 0)
186
249
  buffer = data.dup
187
250
  bytes = data.length
@@ -195,6 +258,14 @@ module RubySMB
195
258
  write_request = write_packet(data: buffer.slice!(0,atomic_write_size), offset: offset)
196
259
  raw_response = tree.client.send_recv(write_request)
197
260
  response = RubySMB::SMB2::Packet::WriteResponse.read(raw_response)
261
+ unless response.valid?
262
+ raise RubySMB::Error::InvalidPacket.new(
263
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
264
+ expected_cmd: RubySMB::SMB2::Packet::WriteResponse::COMMAND,
265
+ received_proto: response.smb2_header.protocol,
266
+ received_cmd: response.smb2_header.command
267
+ )
268
+ end
198
269
  status = response.smb2_header.nt_status.to_nt_status
199
270
 
200
271
  offset+= atomic_write_size
@@ -220,10 +291,26 @@ module RubySMB
220
291
  pkt = write_packet(data: data, offset: offset)
221
292
  raw_response = tree.client.send_recv(pkt)
222
293
  response = RubySMB::SMB2::Packet::WriteResponse.read(raw_response)
294
+ unless response.valid?
295
+ raise RubySMB::Error::InvalidPacket.new(
296
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
297
+ expected_cmd: RubySMB::SMB2::Packet::WriteResponse::COMMAND,
298
+ received_proto: response.smb2_header.protocol,
299
+ received_cmd: response.smb2_header.command
300
+ )
301
+ end
223
302
  if response.status_code == WindowsError::NTStatus::STATUS_PENDING
224
303
  sleep 1
225
304
  raw_response = tree.client.dispatcher.recv_packet
226
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
227
314
  elsif response.status_code != WindowsError::NTStatus::STATUS_SUCCESS
228
315
  raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
229
316
  end
@@ -234,9 +321,18 @@ module RubySMB
234
321
  #
235
322
  # @param new_file_name [String] the new name
236
323
  # @return [WindowsError::ErrorCode] the NTStatus Response code
324
+ # @raise [RubySMB::Error::InvalidPacket] if the response is not a SetInfoResponse packet
237
325
  def rename(new_file_name)
238
326
  raw_response = tree.client.send_recv(rename_packet(new_file_name))
239
327
  response = RubySMB::SMB2::Packet::SetInfoResponse.read(raw_response)
328
+ unless response.valid?
329
+ raise RubySMB::Error::InvalidPacket.new(
330
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
331
+ expected_cmd: RubySMB::SMB2::Packet::SetInfoResponse::COMMAND,
332
+ received_proto: response.smb2_header.protocol,
333
+ received_cmd: response.smb2_header.command
334
+ )
335
+ end
240
336
  response.smb2_header.nt_status.to_nt_status
241
337
  end
242
338
 
@@ -4,6 +4,8 @@ module RubySMB
4
4
  # An SMB2 Close Request Packet as defined in
5
5
  # [2.2.15 SMB2 CLOSE Request](https://msdn.microsoft.com/en-us/library/cc246523.aspx)
6
6
  class CloseRequest < RubySMB::GenericPacket
7
+ COMMAND = RubySMB::SMB2::Commands::CLOSE
8
+
7
9
  endian :little
8
10
 
9
11
  smb2_header :smb2_header
@@ -12,10 +14,6 @@ module RubySMB
12
14
  uint32 :reserved, label: 'Reserved Space'
13
15
  smb2_fileid :file_id, label: 'File ID'
14
16
 
15
- def initialize_instance
16
- super
17
- smb2_header.command = RubySMB::SMB2::Commands::CLOSE
18
- end
19
17
  end
20
18
  end
21
19
  end