rapid7/ruby_smb

View on GitHub
lib/ruby_smb/smb1/packet/tree_connect_response.rb

Summary

Maintainability
A
35 mins
Test Coverage
module RubySMB
  module SMB1
    module Packet
      # A SMB1 TreeConnect Response Packet as defined in
      # [2.2.4.7.2 Server Response Extensions](https://msdn.microsoft.com/en-us/library/cc246331.aspx)
      class TreeConnectResponse < RubySMB::GenericPacket
        COMMAND = RubySMB::SMB1::Commands::SMB_COM_TREE_CONNECT

        # A SMB1 Parameter Block as defined by the {SessionSetupResponse}
        class ParameterBlock < RubySMB::SMB1::ParameterBlock
          and_x_block                :andx_block
          optional_support           :optional_support
          directory_access_mask      :access_rights,       label: 'Maximal Share Access Rights', onlyif: -> { word_count >= 5 }
          directory_access_mask      :guest_access_rights, label: 'Guest Share Access Rights',   onlyif: -> { word_count == 7 }
        end

        # Represents the specific layout of the DataBlock for a {SessionSetupResponse} Packet.
        class DataBlock < RubySMB::SMB1::DataBlock
          stringz   :service,             label: 'Service Type'
          stringz   :native_file_system,  label: 'Native File System'
        end

        smb_header        :smb_header
        parameter_block   :parameter_block
        data_block        :data_block

        def initialize_instance
          super
          smb_header.flags.reply = 1
        end

        # Returns the ACCESS_MASK for the Maximal Share Access Rights. The packet
        # defaults this to a {RubySMB::SMB1::BitField::DirectoryAccessMask}. If it is anything other than
        # a directory that has been connected to, it will re-cast it as a {}RubySMB::SMB1::BitField::FileAccessMask}
        #
        # @return [RubySMB::SMB1::BitField::DirectoryAccessMask] if a directory was connected to
        # @return [RubySMB::SMB1::BitField::FileAccessMask] if anything else was connected to
        # @raise [RubySMB::Error::InvalidBitField] if ACCESS_MASK bit field is not valid
        def access_rights
          if is_directory?
            parameter_block.access_rights
          else
            mask = parameter_block.access_rights.to_binary_s
            begin
              RubySMB::SMB1::BitField::FileAccessMask.read(mask)
            rescue IOError
              raise RubySMB::Error::InvalidBitField, 'Invalid ACCESS_MASK for the Maximal Share Access Rights'
            end
          end
        end

        # Returns the ACCESS_MASK for the Guest Share Access Rights. The packet
        # defaults this to a {RubySMB::SMB1::BitField::DirectoryAccessMask}. If it is anything other than
        # a directory that has been connected to, it will re-cast it as a {RubySMB::SMB1::BitField::FileAccessMask}
        #
        # @return [RubySMB::SMB1::BitField::DirectoryAccessMask] if a directory was connected to
        # @return [RubySMB::SMB1::BitField::FileAccessMask] if anything else was connected to
        def guest_access_rights
          if is_directory?
            parameter_block.guest_access_rights
          else
            mask = parameter_block.guest_access_rights.to_binary_s
            begin
              RubySMB::SMB1::BitField::FileAccessMask.read(mask)
            rescue IOError
              raise RubySMB::Error::InvalidBitField, 'Invalid ACCESS_MASK for the Guest Share Access Rights'
            end
          end
        end

        # Checks whether the response is for a Directory
        # This alters the type of access mask that is used.
        #
        # @return [TrueClass] if service is 'A:'
        # @return [FalseClass] if service is NOT 'A:'
        def is_directory?
          data_block.service == 'A:'
        end
      end
    end
  end
end