ruby_smb 2.0.2 → 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/examples/anonymous_auth.rb +3 -3
  5. data/examples/append_file.rb +10 -8
  6. data/examples/authenticate.rb +9 -5
  7. data/examples/delete_file.rb +8 -6
  8. data/examples/enum_registry_key.rb +5 -4
  9. data/examples/enum_registry_values.rb +5 -4
  10. data/examples/list_directory.rb +8 -6
  11. data/examples/negotiate_with_netbios_service.rb +9 -5
  12. data/examples/net_share_enum_all.rb +6 -4
  13. data/examples/pipes.rb +11 -12
  14. data/examples/query_service_status.rb +64 -0
  15. data/examples/read_file.rb +8 -6
  16. data/examples/read_registry_key_value.rb +6 -5
  17. data/examples/rename_file.rb +9 -7
  18. data/examples/tree_connect.rb +7 -5
  19. data/examples/write_file.rb +9 -7
  20. data/lib/ruby_smb/client.rb +81 -48
  21. data/lib/ruby_smb/client/authentication.rb +5 -10
  22. data/lib/ruby_smb/client/echo.rb +2 -4
  23. data/lib/ruby_smb/client/negotiation.rb +3 -4
  24. data/lib/ruby_smb/client/tree_connect.rb +2 -4
  25. data/lib/ruby_smb/client/utils.rb +16 -10
  26. data/lib/ruby_smb/client/winreg.rb +1 -1
  27. data/lib/ruby_smb/dcerpc.rb +4 -0
  28. data/lib/ruby_smb/dcerpc/error.rb +3 -0
  29. data/lib/ruby_smb/dcerpc/ndr.rb +306 -44
  30. data/lib/ruby_smb/dcerpc/netlogon.rb +101 -0
  31. data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb +37 -0
  32. data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response.rb +26 -0
  33. data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request.rb +37 -0
  34. data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response.rb +23 -0
  35. data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request.rb +32 -0
  36. data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response.rb +24 -0
  37. data/lib/ruby_smb/dcerpc/request.rb +19 -0
  38. data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
  39. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +9 -6
  40. data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
  41. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
  42. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
  43. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
  44. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
  45. data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
  46. data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
  47. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
  48. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
  49. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
  50. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
  51. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
  52. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
  53. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
  54. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
  55. data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
  56. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
  57. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
  58. data/lib/ruby_smb/dcerpc/winreg.rb +98 -17
  59. data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
  60. data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
  61. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +1 -1
  62. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +1 -1
  63. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +1 -1
  64. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +4 -4
  65. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
  66. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +7 -6
  67. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +10 -10
  68. data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
  69. data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
  70. data/lib/ruby_smb/dispatcher/base.rb +1 -1
  71. data/lib/ruby_smb/dispatcher/socket.rb +1 -1
  72. data/lib/ruby_smb/error.rb +21 -5
  73. data/lib/ruby_smb/field/stringz16.rb +17 -1
  74. data/lib/ruby_smb/generic_packet.rb +11 -1
  75. data/lib/ruby_smb/nbss/session_header.rb +4 -4
  76. data/lib/ruby_smb/smb1/file.rb +10 -25
  77. data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +0 -1
  78. data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +0 -1
  79. data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +1 -2
  80. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +1 -13
  81. data/lib/ruby_smb/smb1/pipe.rb +8 -6
  82. data/lib/ruby_smb/smb1/tree.rb +13 -9
  83. data/lib/ruby_smb/smb2/file.rb +33 -33
  84. data/lib/ruby_smb/smb2/pipe.rb +9 -6
  85. data/lib/ruby_smb/smb2/tree.rb +21 -11
  86. data/lib/ruby_smb/version.rb +1 -1
  87. data/spec/lib/ruby_smb/client_spec.rb +174 -68
  88. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1396 -77
  89. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request_spec.rb +69 -0
  90. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response_spec.rb +53 -0
  91. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request_spec.rb +69 -0
  92. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response_spec.rb +37 -0
  93. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request_spec.rb +45 -0
  94. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response_spec.rb +37 -0
  95. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
  96. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +49 -12
  97. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
  98. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
  99. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
  100. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
  101. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
  102. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
  103. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
  104. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
  105. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
  106. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
  107. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
  108. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
  109. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
  110. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
  111. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
  112. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
  113. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
  114. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
  115. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
  116. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
  117. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +0 -4
  118. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +2 -2
  119. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +2 -2
  120. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +9 -4
  121. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
  122. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +17 -17
  123. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +11 -23
  124. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
  125. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
  126. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +227 -41
  127. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +10 -10
  128. data/spec/lib/ruby_smb/error_spec.rb +34 -5
  129. data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
  130. data/spec/lib/ruby_smb/generic_packet_spec.rb +7 -0
  131. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
  132. data/spec/lib/ruby_smb/smb1/file_spec.rb +2 -4
  133. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +0 -1
  134. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +0 -1
  135. data/spec/lib/ruby_smb/smb1/packet/trans2/open2_response_spec.rb +0 -5
  136. data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +0 -6
  137. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +30 -5
  138. data/spec/lib/ruby_smb/smb1/tree_spec.rb +22 -0
  139. data/spec/lib/ruby_smb/smb2/file_spec.rb +61 -9
  140. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +9 -5
  141. data/spec/lib/ruby_smb/smb2/tree_spec.rb +58 -1
  142. metadata +107 -18
  143. metadata.gz.sig +0 -0
@@ -49,13 +49,20 @@ module RubySMB
49
49
  raise RubySMB::Error::InvalidPacket.new(
50
50
  expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
51
51
  expected_cmd: RubySMB::SMB1::Packet::TreeDisconnectResponse::COMMAND,
52
- received_proto: response.smb_header.protocol,
53
- received_cmd: response.smb_header.command
52
+ packet: response
54
53
  )
55
54
  end
56
55
  response.status_code
57
56
  end
58
57
 
58
+ def open_pipe(opts)
59
+ # Make sure we don't modify the caller's hash options
60
+ opts = opts.dup
61
+ opts[:filename] = opts[:filename].dup
62
+ opts[:filename].prepend('\\') unless opts[:filename].start_with?('\\')
63
+ open_file(opts)
64
+ end
65
+
59
66
  # Open a file on the remote share.
60
67
  #
61
68
  # @example
@@ -135,15 +142,14 @@ module RubySMB
135
142
  raise RubySMB::Error::InvalidPacket.new(
136
143
  expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
137
144
  expected_cmd: RubySMB::SMB1::Packet::NtCreateAndxResponse::COMMAND,
138
- received_proto: response.smb_header.protocol,
139
- received_cmd: response.smb_header.command
145
+ packet: response
140
146
  )
141
147
  end
142
148
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
143
149
  raise RubySMB::Error::UnexpectedStatusCode, response.status_code
144
150
  end
145
151
 
146
- case response.parameter_block.resource_type
152
+ case response.parameter_block.resource_type
147
153
  when RubySMB::SMB1::ResourceType::BYTE_MODE_PIPE, RubySMB::SMB1::ResourceType::MESSAGE_MODE_PIPE
148
154
  RubySMB::SMB1::Pipe.new(name: filename, tree: self, response: response)
149
155
  when RubySMB::SMB1::ResourceType::DISK
@@ -195,8 +201,7 @@ module RubySMB
195
201
  raise RubySMB::Error::InvalidPacket.new(
196
202
  expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
197
203
  expected_cmd: RubySMB::SMB1::Packet::Trans2::FindFirst2Response::COMMAND,
198
- received_proto: response.smb_header.protocol,
199
- received_cmd: response.smb_header.command
204
+ packet: response
200
205
  )
201
206
  end
202
207
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
@@ -230,8 +235,7 @@ module RubySMB
230
235
  raise RubySMB::Error::InvalidPacket.new(
231
236
  expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
232
237
  expected_cmd: RubySMB::SMB1::Packet::Trans2::FindNext2Response::COMMAND,
233
- received_proto: response.smb_header.protocol,
234
- received_cmd: response.smb_header.command
238
+ packet: response
235
239
  )
236
240
  end
237
241
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
@@ -95,8 +95,7 @@ module RubySMB
95
95
  raise RubySMB::Error::InvalidPacket.new(
96
96
  expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
97
97
  expected_cmd: RubySMB::SMB2::Packet::CloseResponse::COMMAND,
98
- received_proto: response.smb2_header.protocol,
99
- received_cmd: response.smb2_header.command
98
+ packet: response
100
99
  )
101
100
  end
102
101
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
@@ -115,21 +114,22 @@ module RubySMB
115
114
  # @raise [RubySMB::Error::InvalidPacket] if the response is not a ReadResponse packet
116
115
  # @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
117
116
  def read(bytes: size, offset: 0)
118
- atomic_read_size = if bytes > tree.client.server_max_read_size
119
- tree.client.server_max_read_size
120
- else
121
- bytes
122
- end
117
+ max_read = tree.client.server_max_read_size
118
+ max_read = 65536 unless tree.client.server_supports_multi_credit
119
+ atomic_read_size = [bytes, max_read].min
120
+ credit_charge = 0
121
+ if tree.client.server_supports_multi_credit
122
+ credit_charge = (atomic_read_size - 1) / 65536 + 1
123
+ end
123
124
 
124
- read_request = read_packet(read_length: atomic_read_size, offset: offset)
125
+ read_request = read_packet(read_length: atomic_read_size, offset: offset, credit_charge: credit_charge)
125
126
  raw_response = tree.client.send_recv(read_request, encrypt: @tree_connect_encrypt_data)
126
127
  response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
127
128
  unless response.valid?
128
129
  raise RubySMB::Error::InvalidPacket.new(
129
130
  expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
130
131
  expected_cmd: RubySMB::SMB2::Packet::ReadResponse::COMMAND,
131
- received_proto: response.smb2_header.protocol,
132
- received_cmd: response.smb2_header.command
132
+ packet: response
133
133
  )
134
134
  end
135
135
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
@@ -142,17 +142,16 @@ module RubySMB
142
142
 
143
143
  while remaining_bytes > 0
144
144
  offset += atomic_read_size
145
- atomic_read_size = remaining_bytes if remaining_bytes < tree.client.server_max_read_size
145
+ atomic_read_size = remaining_bytes if remaining_bytes < max_read
146
146
 
147
- read_request = read_packet(read_length: atomic_read_size, offset: offset)
147
+ read_request = read_packet(read_length: atomic_read_size, offset: offset, credit_charge: credit_charge)
148
148
  raw_response = tree.client.send_recv(read_request, encrypt: @tree_connect_encrypt_data)
149
149
  response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
150
150
  unless response.valid?
151
151
  raise RubySMB::Error::InvalidPacket.new(
152
152
  expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
153
153
  expected_cmd: RubySMB::SMB2::Packet::ReadResponse::COMMAND,
154
- received_proto: response.smb2_header.protocol,
155
- received_cmd: response.smb2_header.command
154
+ packet: response
156
155
  )
157
156
  end
158
157
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
@@ -169,11 +168,13 @@ module RubySMB
169
168
  #
170
169
  # @param bytes [Integer] the number of bytes to read
171
170
  # @param offset [Integer] the byte offset in the file to start reading from
171
+ # @param credit_charge [Integer] the number of credits that this request consumes
172
172
  # @return [RubySMB::SMB2::Packet::ReadRequest] the data read from the file
173
- def read_packet(read_length: 0, offset: 0)
173
+ def read_packet(read_length: 0, offset: 0, credit_charge: 1)
174
174
  read_request = set_header_fields(RubySMB::SMB2::Packet::ReadRequest.new)
175
175
  read_request.read_length = read_length
176
176
  read_request.offset = offset
177
+ read_request.smb2_header.credit_charge = credit_charge
177
178
  read_request
178
179
  end
179
180
 
@@ -185,8 +186,7 @@ module RubySMB
185
186
  raise RubySMB::Error::InvalidPacket.new(
186
187
  expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
187
188
  expected_cmd: RubySMB::SMB2::Packet::ReadResponse::COMMAND,
188
- received_proto: response.smb2_header.protocol,
189
- received_cmd: response.smb2_header.command
189
+ packet: response
190
190
  )
191
191
  end
192
192
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
@@ -206,8 +206,7 @@ module RubySMB
206
206
  raise RubySMB::Error::InvalidPacket.new(
207
207
  expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
208
208
  expected_cmd: RubySMB::SMB2::Packet::SetInfoResponse::COMMAND,
209
- received_proto: response.smb2_header.protocol,
210
- received_cmd: response.smb2_header.command
209
+ packet: response
211
210
  )
212
211
  end
213
212
  response.smb2_header.nt_status.to_nt_status
@@ -240,29 +239,30 @@ module RubySMB
240
239
  # @return [WindowsError::ErrorCode] the NTStatus code returned from the operation
241
240
  # @raise [RubySMB::Error::InvalidPacket] if the response is not a WriteResponse packet
242
241
  def write(data:'', offset: 0)
242
+ max_write = tree.client.server_max_write_size
243
+ max_write = 65536 unless tree.client.server_supports_multi_credit
243
244
  buffer = data.dup
244
245
  bytes = data.length
245
- atomic_write_size = if bytes > tree.client.server_max_write_size
246
- tree.client.server_max_write_size
247
- else
248
- bytes
249
- end
246
+ atomic_write_size = [bytes, max_write].min
247
+ credit_charge = 0
248
+ if tree.client.server_supports_multi_credit
249
+ credit_charge = (atomic_write_size - 1) / 65536 + 1
250
+ end
250
251
 
251
252
  while buffer.length > 0 do
252
- write_request = write_packet(data: buffer.slice!(0,atomic_write_size), offset: offset)
253
+ write_request = write_packet(data: buffer.slice!(0, atomic_write_size), offset: offset, credit_charge: credit_charge)
253
254
  raw_response = tree.client.send_recv(write_request, encrypt: @tree_connect_encrypt_data)
254
255
  response = RubySMB::SMB2::Packet::WriteResponse.read(raw_response)
255
256
  unless response.valid?
256
257
  raise RubySMB::Error::InvalidPacket.new(
257
258
  expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
258
259
  expected_cmd: RubySMB::SMB2::Packet::WriteResponse::COMMAND,
259
- received_proto: response.smb2_header.protocol,
260
- received_cmd: response.smb2_header.command
260
+ packet: response
261
261
  )
262
262
  end
263
263
  status = response.smb2_header.nt_status.to_nt_status
264
264
 
265
- offset+= atomic_write_size
265
+ offset += atomic_write_size
266
266
  return status unless status == WindowsError::NTStatus::STATUS_SUCCESS
267
267
  end
268
268
 
@@ -273,11 +273,13 @@ module RubySMB
273
273
  #
274
274
  # @param data [String] the data to write to the file
275
275
  # @param offset [Integer] the offset in the file to start writing from
276
+ # @param credit_charge [Integer] the number of credits that this request consumes
276
277
  # @return []RubySMB::SMB2::Packet::WriteRequest] the request packet
277
- def write_packet(data:'', offset: 0)
278
+ def write_packet(data:'', offset: 0, credit_charge: 1)
278
279
  write_request = set_header_fields(RubySMB::SMB2::Packet::WriteRequest.new)
279
280
  write_request.write_offset = offset
280
281
  write_request.buffer = data
282
+ write_request.smb2_header.credit_charge = credit_charge
281
283
  write_request
282
284
  end
283
285
 
@@ -289,8 +291,7 @@ module RubySMB
289
291
  raise RubySMB::Error::InvalidPacket.new(
290
292
  expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
291
293
  expected_cmd: RubySMB::SMB2::Packet::WriteResponse::COMMAND,
292
- received_proto: response.smb2_header.protocol,
293
- received_cmd: response.smb2_header.command
294
+ packet: response
294
295
  )
295
296
  end
296
297
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
@@ -311,8 +312,7 @@ module RubySMB
311
312
  raise RubySMB::Error::InvalidPacket.new(
312
313
  expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
313
314
  expected_cmd: RubySMB::SMB2::Packet::SetInfoResponse::COMMAND,
314
- received_proto: response.smb2_header.protocol,
315
- received_cmd: response.smb2_header.command
315
+ packet: response
316
316
  )
317
317
  end
318
318
  response.smb2_header.nt_status.to_nt_status
@@ -13,9 +13,13 @@ module RubySMB
13
13
  def initialize(tree:, response:, name:)
14
14
  raise ArgumentError, 'No Name Provided' if name.nil?
15
15
  case name
16
- when 'srvsvc'
16
+ when 'netlogon', '\\netlogon'
17
+ extend RubySMB::Dcerpc::Netlogon
18
+ when 'srvsvc', '\\srvsvc'
17
19
  extend RubySMB::Dcerpc::Srvsvc
18
- when 'winreg'
20
+ when 'svcctl', '\\svcctl'
21
+ extend RubySMB::Dcerpc::Svcctl
22
+ when 'winreg', '\\winreg'
19
23
  extend RubySMB::Dcerpc::Winreg
20
24
  end
21
25
  super(tree: tree, response: response, name: name)
@@ -40,8 +44,7 @@ module RubySMB
40
44
  raise RubySMB::Error::InvalidPacket.new(
41
45
  expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
42
46
  expected_cmd: RubySMB::SMB2::Packet::IoctlResponse::COMMAND,
43
- received_proto: response.smb2_header.protocol,
44
- received_cmd: response.smb2_header.command
47
+ packet: response
45
48
  )
46
49
  end
47
50
 
@@ -89,6 +92,7 @@ module RubySMB
89
92
  request = set_header_fields(RubySMB::SMB2::Packet::IoctlRequest.new(options))
90
93
  request.ctl_code = 0x0011C017
91
94
  request.flags.is_fsctl = 0x00000001
95
+ # TODO: handle fragmentation when the request size > MAX_XMIT_FRAG
92
96
  request.buffer = action.to_binary_s
93
97
 
94
98
  ioctl_raw_response = @tree.client.send_recv(request)
@@ -97,8 +101,7 @@ module RubySMB
97
101
  raise RubySMB::Error::InvalidPacket.new(
98
102
  expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
99
103
  expected_cmd: RubySMB::SMB2::Packet::IoctlRequest::COMMAND,
100
- received_proto: ioctl_response.smb2_header.protocol,
101
- received_cmd: ioctl_response.smb2_header.command
104
+ packet: ioctl_response
102
105
  )
103
106
  end
104
107
  unless [WindowsError::NTStatus::STATUS_SUCCESS,
@@ -50,13 +50,20 @@ module RubySMB
50
50
  raise RubySMB::Error::InvalidPacket.new(
51
51
  expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
52
52
  expected_cmd: RubySMB::SMB2::Packet::TreeDisconnectResponse::COMMAND,
53
- received_proto: response.smb2_header.protocol,
54
- received_cmd: response.smb2_header.command
53
+ packet: response
55
54
  )
56
55
  end
57
56
  response.status_code
58
57
  end
59
58
 
59
+ def open_pipe(opts)
60
+ # Make sure we don't modify the caller's hash options
61
+ opts = opts.dup
62
+ opts[:filename] = opts[:filename].dup
63
+ opts[:filename] = opts[:filename][1..-1] if opts[:filename].start_with? '\\'
64
+ open_file(opts)
65
+ end
66
+
60
67
  def open_file(filename:, attributes: nil, options: nil, disposition: RubySMB::Dispositions::FILE_OPEN,
61
68
  impersonation: RubySMB::ImpersonationLevels::SEC_IMPERSONATE, read: true, write: false, delete: false)
62
69
 
@@ -108,8 +115,7 @@ module RubySMB
108
115
  raise RubySMB::Error::InvalidPacket.new(
109
116
  expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
110
117
  expected_cmd: RubySMB::SMB2::Packet::CreateResponse::COMMAND,
111
- received_proto: response.smb2_header.protocol,
112
- received_cmd: response.smb2_header.command
118
+ packet: response
113
119
  )
114
120
  end
115
121
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
@@ -147,12 +153,19 @@ module RubySMB
147
153
  directory_request.file_information_class = type::CLASS_LEVEL
148
154
  directory_request.file_id = file_id
149
155
  directory_request.name = pattern
150
- directory_request.output_length = 65_535
156
+
157
+ max_read = client.server_max_read_size
158
+ max_read = 65536 unless client.server_supports_multi_credit
159
+ credit_charge = 0
160
+ if client.server_supports_multi_credit
161
+ credit_charge = (max_read - 1) / 65536 + 1
162
+ end
163
+ directory_request.output_length = max_read
164
+ directory_request.smb2_header.credit_charge = credit_charge
151
165
 
152
166
  directory_request = set_header_fields(directory_request)
153
167
 
154
168
  files = []
155
-
156
169
  loop do
157
170
  response = client.send_recv(directory_request, encrypt: @tree_connect_encrypt_data)
158
171
  directory_response = RubySMB::SMB2::Packet::QueryDirectoryResponse.read(response)
@@ -160,8 +173,7 @@ module RubySMB
160
173
  raise RubySMB::Error::InvalidPacket.new(
161
174
  expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
162
175
  expected_cmd: RubySMB::SMB2::Packet::QueryDirectoryResponse::COMMAND,
163
- received_proto: directory_response.smb2_header.protocol,
164
- received_cmd: directory_response.smb2_header.command
176
+ packet: directory_response
165
177
  )
166
178
  end
167
179
 
@@ -205,8 +217,7 @@ module RubySMB
205
217
  raise RubySMB::Error::InvalidPacket.new(
206
218
  expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
207
219
  expected_cmd: RubySMB::SMB2::Packet::CreateResponse::COMMAND,
208
- received_proto: response.smb2_header.protocol,
209
- received_cmd: response.smb2_header.command
220
+ packet: response
210
221
  )
211
222
  end
212
223
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
@@ -256,7 +267,6 @@ module RubySMB
256
267
  # @return [RubySMB::SMB2::Packet] the modified packet.
257
268
  def set_header_fields(request)
258
269
  request.smb2_header.tree_id = id
259
- request.smb2_header.credit_charge = 1
260
270
  request.smb2_header.credits = 256
261
271
  request
262
272
  end
@@ -1,3 +1,3 @@
1
1
  module RubySMB
2
- VERSION = '2.0.2'.freeze
2
+ VERSION = '2.0.7'.freeze
3
3
  end
@@ -65,6 +65,8 @@ RSpec.describe RubySMB::Client do
65
65
  it { is_expected.to respond_to :verify_signature }
66
66
  it { is_expected.to respond_to :auth_user }
67
67
  it { is_expected.to respond_to :last_file_id }
68
+ it { is_expected.to respond_to :pid }
69
+ it { is_expected.to respond_to :server_supports_multi_credit }
68
70
 
69
71
  describe '#initialize' do
70
72
  it 'should raise an ArgumentError without a valid dispatcher' do
@@ -141,6 +143,18 @@ RSpec.describe RubySMB::Client do
141
143
  it 'sets the max_buffer_size to MAX_BUFFER_SIZE' do
142
144
  expect(client.max_buffer_size).to eq RubySMB::Client::MAX_BUFFER_SIZE
143
145
  end
146
+
147
+ it 'sets the server_supports_multi_credit to false' do
148
+ expect(client.server_supports_multi_credit).to be false
149
+ end
150
+
151
+ it 'sets the pid to a random value' do
152
+ 100.times do
153
+ previous_pid = client.pid
154
+ client = described_class.new(dispatcher, username: username, password: password)
155
+ expect(client.pid).to_not eq(previous_pid)
156
+ end
157
+ end
144
158
  end
145
159
 
146
160
  describe '#echo' do
@@ -184,11 +198,13 @@ RSpec.describe RubySMB::Client do
184
198
  describe '#send_recv' do
185
199
  let(:smb1_request) { RubySMB::SMB1::Packet::TreeConnectRequest.new }
186
200
  let(:smb2_request) { RubySMB::SMB2::Packet::TreeConnectRequest.new }
201
+ let(:smb2_header) { RubySMB::SMB2::SMB2Header.new }
187
202
 
188
203
  before(:each) do
189
204
  allow(client).to receive(:is_status_pending?).and_return(false)
190
205
  allow(dispatcher).to receive(:send_packet).and_return(nil)
191
206
  allow(dispatcher).to receive(:recv_packet).and_return('A')
207
+ allow(RubySMB::SMB2::SMB2Header).to receive(:read).and_return(smb2_header)
192
208
  end
193
209
 
194
210
  context 'when signing' do
@@ -199,9 +215,10 @@ RSpec.describe RubySMB::Client do
199
215
 
200
216
  context 'with an SMB2 packet' do
201
217
  it 'does not sign a SessionSetupRequest packet' do
218
+ allow(smb2_client).to receive(:is_status_pending?).and_return(false)
202
219
  expect(smb2_client).to_not receive(:smb2_sign)
203
220
  expect(smb2_client).to_not receive(:smb3_sign)
204
- client.send_recv(RubySMB::SMB2::Packet::SessionSetupRequest.new)
221
+ smb2_client.send_recv(RubySMB::SMB2::Packet::SessionSetupRequest.new)
205
222
  end
206
223
 
207
224
  it 'calls #smb2_sign if it is an SMB2 client' do
@@ -229,6 +246,29 @@ RSpec.describe RubySMB::Client do
229
246
  expect(smb1_client).to_not receive(:is_status_pending?)
230
247
  smb1_client.send_recv(smb1_request)
231
248
  end
249
+
250
+ it 'set the #uid SMB header when #user_id is defined' do
251
+ smb1_client.user_id = 333
252
+ smb1_client.send_recv(smb1_request)
253
+ expect(smb1_request.smb_header.uid).to eq(333)
254
+ end
255
+
256
+ it 'does not set the #uid SMB header when #user_id is not defined' do
257
+ smb1_client.send_recv(smb1_request)
258
+ expect(smb1_request.smb_header.uid).to eq(0)
259
+ end
260
+
261
+ it 'set the #pid SMB header when #pid is defined' do
262
+ smb1_client.pid = 333
263
+ smb1_client.send_recv(smb1_request)
264
+ expect(smb1_request.smb_header.pid_low).to eq(333)
265
+ end
266
+
267
+ it 'does not set the #pid SMB header when #pid is not defined' do
268
+ smb1_client.pid = nil
269
+ smb1_client.send_recv(smb1_request)
270
+ expect(smb1_request.smb_header.pid_low).to eq(0)
271
+ end
232
272
  end
233
273
 
234
274
  context 'with SMB2' do
@@ -251,10 +291,8 @@ RSpec.describe RubySMB::Client do
251
291
  context 'with a SessionSetupRequest' do
252
292
  it 'does not encrypt/decrypt' do
253
293
  request = RubySMB::SMB2::Packet::SessionSetupRequest.new
254
- expect(smb3_client).to_not receive(:send_encrypt).with(request)
255
- expect(smb3_client).to_not receive(:recv_encrypt)
256
- expect(dispatcher).to receive(:send_packet).with(request)
257
- expect(dispatcher).to receive(:recv_packet)
294
+ expect(smb3_client).to receive(:send_packet).with(request, encrypt: false)
295
+ expect(smb3_client).to receive(:recv_packet).with(encrypt: false)
258
296
  smb3_client.send_recv(request)
259
297
  end
260
298
  end
@@ -262,17 +300,15 @@ RSpec.describe RubySMB::Client do
262
300
  context 'with a NegotiateRequest' do
263
301
  it 'does not encrypt/decrypt' do
264
302
  request = RubySMB::SMB2::Packet::NegotiateRequest.new
265
- expect(smb3_client).to_not receive(:send_encrypt).with(request)
266
- expect(smb3_client).to_not receive(:recv_encrypt)
267
- expect(dispatcher).to receive(:send_packet).with(request)
268
- expect(dispatcher).to receive(:recv_packet)
303
+ expect(smb3_client).to receive(:send_packet).with(request, encrypt: false)
304
+ expect(smb3_client).to receive(:recv_packet).with(encrypt: false)
269
305
  smb3_client.send_recv(request)
270
306
  end
271
307
  end
272
308
 
273
309
  it 'encrypts and decrypts' do
274
- expect(smb3_client).to receive(:send_encrypt).with(smb2_request)
275
- expect(smb3_client).to receive(:recv_encrypt)
310
+ expect(smb3_client).to receive(:send_packet).with(smb2_request, encrypt: true)
311
+ expect(smb3_client).to receive(:recv_packet).with(encrypt: true)
276
312
  smb3_client.send_recv(smb2_request)
277
313
  end
278
314
 
@@ -280,12 +316,44 @@ RSpec.describe RubySMB::Client do
280
316
  it 'waits 1 second and reads/decrypts again' do
281
317
  allow(smb3_client).to receive(:is_status_pending?).and_return(true, false)
282
318
  expect(smb3_client).to receive(:sleep).with(1)
283
- expect(smb3_client).to receive(:send_encrypt).with(smb2_request)
284
- expect(smb3_client).to receive(:recv_encrypt).twice
319
+ expect(smb3_client).to receive(:send_packet).with(smb2_request, encrypt: true)
320
+ expect(smb3_client).to receive(:recv_packet).with(encrypt: true).twice
285
321
  smb3_client.send_recv(smb2_request)
286
322
  end
287
323
  end
288
324
  end
325
+
326
+ it 'increments the sequence counter if signing is required and the session key exist' do
327
+ allow(smb2_client).to receive(:is_status_pending?).and_return(false)
328
+ smb2_client.signing_required = true
329
+ smb2_client.session_key = 'key'
330
+ smb2_client.sequence_counter = 0
331
+ smb2_client.send_recv(smb2_request)
332
+ expect(smb2_client.sequence_counter).to eq(1)
333
+ end
334
+
335
+ it 'updates #smb2_message_id with SMB2 header #credit_charge if the server supports multi credits' do
336
+ allow(smb2_client).to receive(:is_status_pending?).and_return(false)
337
+ smb2_client.smb2_message_id = 0
338
+ smb2_client.server_supports_multi_credit = true
339
+ smb2_header.credit_charge = 5
340
+ smb2_client.send_recv(smb2_request)
341
+ expect(smb2_client.smb2_message_id).to eq(5)
342
+ end
343
+
344
+ it 'does not update #msb2_message_id with SMB2 header #credit_charge if the server does not support multi credits' do
345
+ allow(smb2_client).to receive(:is_status_pending?).and_return(false)
346
+ smb2_client.smb2_message_id = 0
347
+ smb2_client.server_supports_multi_credit = false
348
+ smb2_header.credit_charge = 5
349
+ smb2_client.send_recv(smb2_request)
350
+ expect(smb2_client.smb2_message_id).to eq(1)
351
+ end
352
+
353
+ it 'ignores errors thrown when parsing the SMB2 header' do
354
+ allow(RubySMB::SMB2::SMB2Header).to receive(:read).and_raise(IOError)
355
+ expect { smb2_client.send_recv(smb2_request) }.to_not raise_error
356
+ end
289
357
  end
290
358
 
291
359
  describe '#is_status_pending?' do
@@ -297,17 +365,17 @@ RSpec.describe RubySMB::Client do
297
365
  }
298
366
 
299
367
  it 'returns true when the response has a STATUS_PENDING status code and the async_command flag set' do
300
- expect(client.is_status_pending?(response.to_binary_s)).to be true
368
+ expect(client.is_status_pending?(response.smb2_header)).to be true
301
369
  end
302
370
 
303
371
  it 'returns false when the response has a STATUS_PENDING status code and the async_command flag not set' do
304
372
  response.smb2_header.flags.async_command = 0
305
- expect(client.is_status_pending?(response.to_binary_s)).to be false
373
+ expect(client.is_status_pending?(response.smb2_header)).to be false
306
374
  end
307
375
 
308
376
  it 'returns false when the response has no STATUS_PENDING status code but the async_command flag set' do
309
377
  response.smb2_header.nt_status= WindowsError::NTStatus::STATUS_SUCCESS.value
310
- expect(client.is_status_pending?(response.to_binary_s)).to be false
378
+ expect(client.is_status_pending?(response.smb2_header)).to be false
311
379
  end
312
380
  end
313
381
 
@@ -344,35 +412,47 @@ RSpec.describe RubySMB::Client do
344
412
  end
345
413
  end
346
414
 
347
- describe '#send_encrypt' do
415
+ describe '#send_packet' do
348
416
  let(:packet) { RubySMB::SMB2::Packet::SessionSetupRequest.new }
349
417
  before :example do
350
418
  allow(dispatcher).to receive(:send_packet)
351
419
  client.dialect = '0x0300'
352
420
  end
353
421
 
354
- it 'creates a Transform request' do
355
- expect(client).to receive(:smb3_encrypt).with(packet.to_binary_s)
356
- client.send_encrypt(packet)
422
+ it 'does not encrypt the packet' do
423
+ expect(client).to_not receive(:smb3_encrypt)
424
+ client.send_packet(packet)
357
425
  end
358
426
 
359
- it 'raises an EncryptionError exception if an error occurs while encrypting' do
360
- allow(client).to receive(:smb3_encrypt).and_raise(RubySMB::Error::RubySMBError.new('Error'))
361
- expect { client.send_encrypt(packet) }.to raise_error(
362
- RubySMB::Error::EncryptionError,
363
- "Error while encrypting #{packet.class.name} packet (SMB 0x0300): Error"
364
- )
427
+ it 'sends the packet through the dispatcher' do
428
+ client.send_packet(packet)
429
+ expect(dispatcher).to have_received(:send_packet).with(packet)
365
430
  end
366
431
 
367
- it 'sends the encrypted packet' do
368
- encrypted_packet = double('Encrypted packet')
369
- allow(client).to receive(:smb3_encrypt).and_return(encrypted_packet)
370
- client.send_encrypt(packet)
371
- expect(dispatcher).to have_received(:send_packet).with(encrypted_packet)
432
+ context 'with encryption' do
433
+ it 'creates a Transform request' do
434
+ expect(client).to receive(:smb3_encrypt).with(packet.to_binary_s)
435
+ client.send_packet(packet, encrypt: true)
436
+ end
437
+
438
+ it 'raises an EncryptionError exception if an error occurs while encrypting' do
439
+ allow(client).to receive(:smb3_encrypt).and_raise(RubySMB::Error::RubySMBError.new('Error'))
440
+ expect { client.send_packet(packet, encrypt: true) }.to raise_error(
441
+ RubySMB::Error::EncryptionError,
442
+ "Error while encrypting #{packet.class.name} packet (SMB 0x0300): Error"
443
+ )
444
+ end
445
+
446
+ it 'sends the encrypted packet' do
447
+ encrypted_packet = double('Encrypted packet')
448
+ allow(client).to receive(:smb3_encrypt).and_return(encrypted_packet)
449
+ client.send_packet(packet, encrypt: true)
450
+ expect(dispatcher).to have_received(:send_packet).with(encrypted_packet)
451
+ end
372
452
  end
373
453
  end
374
454
 
375
- describe '#recv_encrypt' do
455
+ describe '#recv_packet' do
376
456
  let(:packet) { RubySMB::SMB2::Packet::SessionSetupRequest.new }
377
457
  before :example do
378
458
  allow(dispatcher).to receive(:recv_packet).and_return(packet.to_binary_s)
@@ -381,42 +461,49 @@ RSpec.describe RubySMB::Client do
381
461
  end
382
462
 
383
463
  it 'reads the response packet' do
384
- client.recv_encrypt
464
+ client.recv_packet
385
465
  expect(dispatcher).to have_received(:recv_packet)
386
466
  end
387
467
 
388
- it 'raises an EncryptionError exception if an error occurs while receiving the response' do
468
+ it 'raises an CommunicationError exception if an error occurs while receiving the response' do
389
469
  allow(dispatcher).to receive(:recv_packet).and_raise(RubySMB::Error::CommunicationError)
390
- expect { client.recv_encrypt }.to raise_error(
391
- RubySMB::Error::EncryptionError,
392
- 'Communication error with the remote host: RubySMB::Error::CommunicationError. '\
393
- 'The server supports encryption but was not able to handle the encrypted request.'
394
- )
470
+ expect { client.recv_packet }.to raise_error(RubySMB::Error::CommunicationError)
395
471
  end
396
472
 
397
- it 'parses the response as a Transform response packet' do
398
- expect(RubySMB::SMB2::Packet::TransformHeader).to receive(:read).with(packet.to_binary_s)
399
- client.recv_encrypt
400
- end
473
+ context 'with encryption' do
474
+ it 'raises an EncryptionError exception if an error occurs while receiving the response' do
475
+ allow(dispatcher).to receive(:recv_packet).and_raise(RubySMB::Error::CommunicationError)
476
+ expect { client.recv_packet(encrypt: true) }.to raise_error(
477
+ RubySMB::Error::EncryptionError,
478
+ 'Communication error with the remote host: RubySMB::Error::CommunicationError. '\
479
+ 'The server supports encryption but was not able to handle the encrypted request.'
480
+ )
481
+ end
401
482
 
402
- it 'raises an InvalidPacket exception if an error occurs while parsing the response' do
403
- allow(RubySMB::SMB2::Packet::TransformHeader).to receive(:read).and_raise(IOError)
404
- expect { client.recv_encrypt }.to raise_error(RubySMB::Error::InvalidPacket, 'Not a SMB2 TransformHeader packet')
405
- end
483
+ it 'parses the response as a Transform response packet' do
484
+ expect(RubySMB::SMB2::Packet::TransformHeader).to receive(:read).with(packet.to_binary_s)
485
+ client.recv_packet(encrypt: true)
486
+ end
406
487
 
407
- it 'decrypts the Transform response packet' do
408
- transform = double('Transform header packet')
409
- allow(RubySMB::SMB2::Packet::TransformHeader).to receive(:read).and_return(transform)
410
- client.recv_encrypt
411
- expect(client).to have_received(:smb3_decrypt).with(transform)
412
- end
488
+ it 'raises an InvalidPacket exception if an error occurs while parsing the response' do
489
+ allow(RubySMB::SMB2::Packet::TransformHeader).to receive(:read).and_raise(IOError)
490
+ expect { client.recv_packet(encrypt: true) }.to raise_error(RubySMB::Error::InvalidPacket, 'Not a SMB2 TransformHeader packet')
491
+ end
413
492
 
414
- it 'raises an EncryptionError exception if an error occurs while decrypting' do
415
- allow(client).to receive(:smb3_decrypt).and_raise(RubySMB::Error::RubySMBError)
416
- expect { client.recv_encrypt }.to raise_error(
417
- RubySMB::Error::EncryptionError,
418
- 'Error while decrypting RubySMB::SMB2::Packet::TransformHeader packet (SMB 0x0300}): RubySMB::Error::RubySMBError'
419
- )
493
+ it 'decrypts the Transform response packet' do
494
+ transform = double('Transform header packet')
495
+ allow(RubySMB::SMB2::Packet::TransformHeader).to receive(:read).and_return(transform)
496
+ client.recv_packet(encrypt: true)
497
+ expect(client).to have_received(:smb3_decrypt).with(transform)
498
+ end
499
+
500
+ it 'raises an EncryptionError exception if an error occurs while decrypting' do
501
+ allow(client).to receive(:smb3_decrypt).and_raise(RubySMB::Error::RubySMBError)
502
+ expect { client.recv_packet(encrypt: true) }.to raise_error(
503
+ RubySMB::Error::EncryptionError,
504
+ 'Error while decrypting RubySMB::SMB2::Packet::TransformHeader packet (SMB 0x0300}): RubySMB::Error::RubySMBError'
505
+ )
506
+ end
420
507
  end
421
508
  end
422
509
 
@@ -667,7 +754,7 @@ RSpec.describe RubySMB::Client do
667
754
  expect(session_packet.session_header.session_packet_type).to eq RubySMB::Nbss::SESSION_REQUEST
668
755
  expect(session_packet.called_name).to eq called_name
669
756
  expect(session_packet.calling_name).to eq calling_name
670
- expect(session_packet.session_header.packet_length).to eq(
757
+ expect(session_packet.session_header.stream_protocol_length).to eq(
671
758
  session_packet.called_name.to_binary_s.size + session_packet.calling_name.to_binary_s.size
672
759
  )
673
760
  end
@@ -1036,6 +1123,19 @@ RSpec.describe RubySMB::Client do
1036
1123
  it 'returns the string \'SMB2\'' do
1037
1124
  expect(client.parse_negotiate_response(smb2_response)).to eq ('SMB2')
1038
1125
  end
1126
+
1127
+ it 'sets #server_supports_multi_credit to true when the response has #large_mtu capability set' do
1128
+ smb2_response.capabilities.large_mtu = 1
1129
+ client.parse_negotiate_response(smb2_response)
1130
+ expect(client.server_supports_multi_credit).to be true
1131
+ end
1132
+
1133
+ it 'sets #server_supports_multi_credit to false when the dialect is 0x0202' do
1134
+ smb2_response.dialect_revision = 0x0202
1135
+ smb2_response.capabilities.large_mtu = 1 # just to make sure it won't affect the result
1136
+ client.parse_negotiate_response(smb2_response)
1137
+ expect(client.server_supports_multi_credit).to be false
1138
+ end
1039
1139
  end
1040
1140
 
1041
1141
  context 'when SMB3 was negotiated' do
@@ -1060,6 +1160,12 @@ RSpec.describe RubySMB::Client do
1060
1160
  expect(client.parse_negotiate_response(smb3_response)).to eq ('SMB3')
1061
1161
  end
1062
1162
 
1163
+ it 'sets #server_supports_multi_credit to true when the response has #large_mtu capability set' do
1164
+ smb3_response.capabilities.large_mtu = 1
1165
+ client.parse_negotiate_response(smb3_response)
1166
+ expect(client.server_supports_multi_credit).to be true
1167
+ end
1168
+
1063
1169
  context 'when the server supports encryption' do
1064
1170
  before :example do
1065
1171
  smb3_response.capabilities.encryption = 1
@@ -2253,7 +2359,7 @@ RSpec.describe RubySMB::Client do
2253
2359
  let(:named_pipe){ double("Named Pipe") }
2254
2360
 
2255
2361
  before :example do
2256
- allow(tree).to receive(:open_file).and_return(named_pipe)
2362
+ allow(tree).to receive(:open_pipe).and_return(named_pipe)
2257
2363
  allow(named_pipe).to receive(:net_share_enum_all)
2258
2364
  end
2259
2365
 
@@ -2268,8 +2374,8 @@ RSpec.describe RubySMB::Client do
2268
2374
  smb1_client.net_share_enum_all(sock.peeraddr)
2269
2375
  end
2270
2376
 
2271
- it 'it calls the Tree #open_file method to open "srvsvc" named pipe' do
2272
- expect(tree).to receive(:open_file).with(filename: "srvsvc", write: true, read: true).and_return(named_pipe)
2377
+ it 'it calls the Tree #open_pipe method to open "srvsvc" named pipe' do
2378
+ expect(tree).to receive(:open_pipe).with(filename: "srvsvc", write: true, read: true).and_return(named_pipe)
2273
2379
  smb1_client.net_share_enum_all(sock.peeraddr)
2274
2380
  end
2275
2381
 
@@ -2291,8 +2397,8 @@ RSpec.describe RubySMB::Client do
2291
2397
  smb2_client.net_share_enum_all(sock.peeraddr)
2292
2398
  end
2293
2399
 
2294
- it 'it calls the Tree #open_file method to open "srvsvc" named pipe' do
2295
- expect(tree).to receive(:open_file).with(filename: "srvsvc", write: true, read: true).and_return(named_pipe)
2400
+ it 'it calls the Tree #open_pipe method to open "srvsvc" named pipe' do
2401
+ expect(tree).to receive(:open_pipe).with(filename: "srvsvc", write: true, read: true).and_return(named_pipe)
2296
2402
  smb2_client.net_share_enum_all(sock.peeraddr)
2297
2403
  end
2298
2404
 
@@ -2373,7 +2479,7 @@ RSpec.describe RubySMB::Client do
2373
2479
  before :example do
2374
2480
  allow(ipc_tree).to receive_messages(
2375
2481
  :share => share,
2376
- :open_file => named_pipe
2482
+ :open_pipe => named_pipe
2377
2483
  )
2378
2484
  allow(client).to receive(:tree_connect).and_return(ipc_tree)
2379
2485
  end
@@ -2395,9 +2501,9 @@ RSpec.describe RubySMB::Client do
2395
2501
  expect(client).to have_received(:tree_connect).with(share)
2396
2502
  end
2397
2503
 
2398
- it 'open \'winreg\' file on the IPC$ Tree' do
2504
+ it 'open \'winreg\' pipe on the IPC$ Tree' do
2399
2505
  client.connect_to_winreg(host)
2400
- expect(ipc_tree).to have_received(:open_file).with(filename: "winreg", write: true, read: true)
2506
+ expect(ipc_tree).to have_received(:open_pipe).with(filename: "winreg", write: true, read: true)
2401
2507
  end
2402
2508
 
2403
2509
  it 'returns the expected opened named pipe' do