Module: RubySMB::SMB1::Packet::Trans2::Win9xFraming

Included in:
FindFirst2Response
Defined in:
lib/ruby_smb/smb1/packet/trans2/win9x_framing.rb

Overview

Shared workaround for pre-NT / LAN Manager-era servers (observed on Windows 9x / ME) that pack trans2_parameters directly after byte_count with no 4-byte-alignment pad, and trans2_data with whatever padding they feel like — always smaller than the NT-style alignment BinData unconditionally assumes via DataBlock#pad1_length and DataBlock#pad2_length. When that happens both sections land in the wrong place and eos, sid, last_name_offset, and every entry in the data buffer come back garbled.

Fixing this in BinData itself (by having pad1/pad2 consult parameter_block.parameter_offset / data_offset) is the natural design, but cross-field lookups during field-read callbacks corrupt BinData's registered-class resolution cache, causing unrelated Trans2 responses to round-trip their parameter_block / data_block through the base classes instead of the concrete subclasses. So instead we surface the raw response bytes at the call site and let the response slice both sections from the offsets the server reported in its parameter_block.

Mix into any RubySMB::SMB1::Packet::Trans2 response whose caller holds on to the raw response bytes. The response itself must have the standard Response::ParameterBlock shape (parameter_offset / parameter_count / data_offset / data_count) and a data_block with trans2_parameters and trans2_data.buffer fields — every concrete Trans2 response does.

Same slicing pattern as Rap::NetShareEnum#parse_net_share_enum_response uses for the sibling Trans (not Trans2) response type.

Instance Method Summary collapse

Instance Method Details

#win9x_trans2_overrides(raw_response) ⇒ Array(BinData::Record, String), Array(nil, nil)

Returns [effective_trans2_parameters, effective_trans2_data_bytes] when the server's layout differs from BinData's, or [nil, nil] when BinData already read the full buffer (standard NT-era servers).

When a non-nil pair is returned, callers should prefer the override values over the BinData-parsed ones:

params_ovr, data_ovr = response.win9x_trans2_overrides(raw) params = params_ovr || response.data_block.trans2_parameters data = data_ovr || response.data_block.trans2_data.buffer.to_binary_s

Parameters:

  • raw_response (String)

    the raw bytes the response was read from.

Returns:

  • (Array(BinData::Record, String), Array(nil, nil))


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/ruby_smb/smb1/packet/trans2/win9x_framing.rb', line 47

def win9x_trans2_overrides(raw_response)
  declared_data = parameter_block.data_count.to_i
  parsed_data   = data_block.trans2_data.buffer.to_binary_s.bytesize
  return [nil, nil] if declared_data.zero? || parsed_data == declared_data

  param_offset = parameter_block.parameter_offset.to_i
  param_count  = parameter_block.parameter_count.to_i
  data_offset  = parameter_block.data_offset.to_i
  return [nil, nil] if raw_response.bytesize < data_offset + declared_data
  return [nil, nil] if raw_response.bytesize < param_offset + param_count

  params_bytes = raw_response.byteslice(param_offset, param_count)
  params_class = data_block.trans2_parameters.class
  params       = params_class.read(params_bytes)
  data_bytes   = raw_response.byteslice(data_offset, declared_data)
  [params, data_bytes]
end