module RubySMB module Dcerpc # The Response PDU as defined in # [The response PDU](http://pubs.opengroup.org/onlinepubs/9629399/chap12.htm#tagcjh_17_06_04_10) class Response < BinData::Record PTYPE = PTypes::RESPONSE endian :little # PDU Header pdu_header :pdu_header, label: 'PDU header common fields' uint32 :alloc_hint, label: 'Allocation hint', initial_value: -> { stub.do_num_bytes } uint16 :p_cont_id, label: 'Presentation context identification' uint8 :cancel_count, label: 'Cancel count' uint8 :reserved # PDU Body string :stub, label: 'Stub', read_length: -> { stub_length } string :auth_pad, onlyif: -> { has_auth_verifier? }, length: -> { calculate_padding_size } # Auth Verifier sec_trailer :sec_trailer, onlyif: -> { has_auth_verifier? } string :auth_value, label: 'Authentication verifier', onlyif: -> { has_auth_verifier? }, read_length: -> { pdu_header.auth_length } # Per the spec (MS_RPCE 2.2.2.11): start of the trailer should be a multiple of 16 bytes offset from the start of the stub def calculate_padding_size (16 - (stub.num_bytes % 16)) % 16 end def initialize_instance super pdu_header.ptype = PTYPE end def has_auth_verifier? self.pdu_header.auth_length > 0 end def stub_length stub_length = pdu_header.frag_length - stub.rel_offset if has_auth_verifier? # Note that the resulting stub length includes auth_pad. We will be # able to separate the auth_pad from the stub once the sec_trailer # structure is read. stub_length -= (sec_trailer.num_bytes + pdu_header.auth_length) end stub_length end def read(io) super if has_auth_verifier? && sec_trailer.auth_pad_length > 0 # At this point, auth_pad is at the end of the stub. We need to move # it to the correct field. It is now possible since we know its # length from the sec_trailer auth_pad_length field. pad = stub[-(sec_trailer.auth_pad_length)..-1] stub.assign(stub[0...-(sec_trailer.auth_pad_length)]) auth_pad.assign(pad) end end end end end