Beispiel #1
0
    def _GetLink(self):
        """Retrieves the link.

    Returns:
      str: path of the linked file.
    """
        if self._link is None:
            self._link = u''

            if not self.IsLink():
                return self._link

            tsk_file = self.GetTSKFile()

            # Note that because pytsk3.File does not explicitly defines info
            # we need to check if the attribute exists and has a value other
            # than None.
            if getattr(tsk_file, u'info', None) is None:
                return self._link

            # If pytsk3.FS_Info.open() was used file.info has an attribute meta
            # (pytsk3.TSK_FS_META) that contains the link.
            if getattr(tsk_file.info, u'meta', None) is None:
                return self._link

            # Note that the SleuthKit does not expose NTFS
            # IO_REPARSE_TAG_MOUNT_POINT or IO_REPARSE_TAG_SYMLINK as a link.
            link = getattr(tsk_file.info.meta, u'link', None)

            if link is None:
                return self._link

            try:
                # pytsk3 returns an UTF-8 encoded byte string without a leading
                # path segment separator.
                link = u'{0:s}{1:s}'.format(self._file_system.PATH_SEPARATOR,
                                            link.decode(u'utf8'))
            except UnicodeError:
                raise errors.BackEndError(
                    u'pytsk3 returned a non UTF-8 formatted link.')

            self._link = link

        return self._link
Beispiel #2
0
    def _ScanEncryptedVolumeNode(self, scan_context, scan_node):
        """Scans an encrypted volume node for supported formats.

    Args:
      scan_context (SourceScannerContext): source scanner context.
      scan_node (SourceScanNode): source scan node.

    Raises:
      BackEndError: if the scan node cannot be unlocked.
      ValueError: if the scan context or scan node is invalid.
    """
        if scan_node.type_indicator == definitions.TYPE_INDICATOR_APFS_CONTAINER:
            # TODO: consider changes this when upstream changes have been made.
            # Currently pyfsapfs does not support reading from a volume as a device.
            # Also see: https://github.com/log2timeline/dfvfs/issues/332
            container_file_entry = resolver.Resolver.OpenFileEntry(
                scan_node.path_spec, resolver_context=self._resolver_context)
            fsapfs_volume = container_file_entry.GetAPFSVolume()

            # TODO: unlocking the volume multiple times is inefficient cache volume
            # object in scan node and use is_locked = fsapfs_volume.is_locked()
            try:
                is_locked = not apfs_helper.APFSUnlockVolume(
                    fsapfs_volume, scan_node.path_spec,
                    resolver.Resolver.key_chain)
            except IOError as exception:
                raise errors.BackEndError(
                    'Unable to unlock APFS volume with error: {0!s}'.format(
                        exception))

        else:
            file_object = resolver.Resolver.OpenFileObject(
                scan_node.path_spec, resolver_context=self._resolver_context)
            is_locked = not file_object or file_object.is_locked

        if is_locked:
            scan_context.LockScanNode(scan_node.path_spec)

            # For BitLocker To Go add a scan node for the unencrypted part of
            # the volume.
            if scan_node.type_indicator == definitions.TYPE_INDICATOR_BDE:
                path_spec = self.ScanForFileSystem(scan_node.path_spec.parent)
                if path_spec:
                    scan_context.AddScanNode(path_spec, scan_node.parent_node)
    def __init__(self,
                 resolver_context,
                 file_system,
                 path_spec,
                 is_root=False,
                 is_virtual=False,
                 tsk_vs_part=None):
        """Initializes a file entry.

    Args:
      resolver_context (Context): resolver context.
      file_system (FileSystem): file system.
      path_spec (PathSpec): path specification.
      is_root (Optional[bool]): True if the file entry is the root file entry
          of the corresponding file system.
      is_virtual (Optional[bool]): True if the file entry is a virtual file
          entry emulated by the corresponding file system.
      tsk_vs_part (Optional[pytsk3.TSK_VS_PART_INFO]): TSK volume system part.

    Raises:
      BackEndError: when the TSK volume system part is missing in a non-virtual
          file entry.
    """
        tsk_volume = file_system.GetTSKVolume()
        if not is_virtual and tsk_vs_part is None:
            tsk_vs_part, _ = tsk_partition.GetTSKVsPartByPathSpec(
                tsk_volume, path_spec)
        if not is_virtual and tsk_vs_part is None:
            raise errors.BackEndError(
                'Missing TSK volume system part in non-virtual file entry.')

        super(TSKPartitionFileEntry, self).__init__(resolver_context,
                                                    file_system,
                                                    path_spec,
                                                    is_root=is_root,
                                                    is_virtual=is_virtual)
        self._name = None
        self._tsk_volume = tsk_volume
        self._tsk_vs_part = tsk_vs_part

        if is_virtual:
            self.entry_type = definitions.FILE_ENTRY_TYPE_DIRECTORY
        else:
            self.entry_type = definitions.FILE_ENTRY_TYPE_FILE
Beispiel #4
0
    def _GetStat(self):
        """Retrieves the stat object.

    Returns:
      The stat object (instance of vfs.VFSStat).

    Raises:
      BackEndError: when the regf key is missing.
    """
        if not self._regf_key:
            raise errors.BackEndError(u'Missing regf key.')

        stat_object = vfs_stat.VFSStat()

        # File data stat information.
        if self._regf_value:
            stat_object.size = self._regf_value.get_data_size()

        # Date and time stat information.
        if self._regf_value:
            timestamp = None
        else:
            timestamp = date_time.PosixTimestamp.FromFiletime(
                self._regf_key.get_last_written_time_as_integer())

        if timestamp is not None:
            stat_object.mtime = timestamp

        # Ownership and permissions stat information.
        # TODO: add support for security key.

        # File entry type stat information.
        if self._regf_value:
            stat_object.type = stat_object.TYPE_FILE
        else:
            stat_object.type = stat_object.TYPE_DIRECTORY

        # TODO: add support for a link:
        # stat_object.type = stat_object.TYPE_LINK

        # Other stat information.
        stat_object.is_allocated = True

        return stat_object
    def _GetStat(self):
        """Retrieves the stat object.

    Returns:
      The stat object (instance of vfs.VFSStat).

    Raises:
      BackEndError: when the vshadow store is missing in a non-virtual
                    file entry.
    """
        vshadow_store = self.GetVShadowStore()
        if not self._is_virtual and vshadow_store is None:
            raise errors.BackEndError(
                u'Missing vshadow store in non-virtual file entry.')

        stat_object = vfs_stat.VFSStat()

        # File data stat information.
        if vshadow_store is not None:
            stat_object.size = vshadow_store.volume_size

        # Date and time stat information.
        if vshadow_store is not None:
            timestamp = vshadow_store.get_creation_time_as_integer()
            date_time_values = dfdatetime_filetime.Filetime(
                timestamp=timestamp)

            stat_time, stat_time_nano = date_time_values.CopyToStatTimeTuple()
            if stat_time is not None:
                stat_object.crtime = stat_time
                stat_object.crtime_nano = stat_time_nano

        # Ownership and permissions stat information.

        # File entry type stat information.

        # The root file entry is virtual and should have type directory.
        if self._is_virtual:
            stat_object.type = stat_object.TYPE_DIRECTORY
        else:
            stat_object.type = stat_object.TYPE_FILE

        return stat_object
    def HasExternalData(self):
        """Determines if the file entry has external stored data.

    Returns:
      A boolean to indicate the file entry has external data.

    Raises:
      BackEndError: when the vshadow store is missing in a non-virtual
                    file entry.
    """
        vshadow_store = self.GetVShadowStore()
        if not self._is_virtual and vshadow_store is None:
            raise errors.BackEndError(
                u'Missing vshadow store in non-virtual file entry.')

        if vshadow_store is None:
            return False

        return not vshadow_store.has_in_volume_data()
Beispiel #7
0
    def _GetLink(self):
        """Retrieves the link.

    Returns:
      str: link.

    Raises:
      BackEndError: when the TAR info is missing in a non-virtual file entry.
    """
        if self._link is None:
            tar_info = self.GetTARInfo()
            if not self._is_virtual and not tar_info:
                raise errors.BackEndError(
                    u'Missing TAR info in non-virtual file entry.')

            if tar_info:
                self._link = tar_info.linkname

        return self._link
Beispiel #8
0
    def _EntriesGenerator(self):
        """Retrieves directory entries.

    Since a directory can contain a vast number of entries using
    a generator is more memory efficient.

    Yields:
      A path specification (instance of path.OSPathSpec).

    Raises:
      AccessError: if the access to list the directory was denied.
      BackEndError: if the directory could not be listed.
    """
        location = getattr(self.path_spec, u'location', None)
        if location is None:
            return

        # Windows will raise WindowsError, which can be caught by OSError,
        # if the process has not access to list the directory. The os.access()
        # function cannot be used since it will return true even when os.listdir()
        # fails.
        try:
            for directory_entry in os.listdir(location):
                directory_entry_location = self._file_system.JoinPath(
                    [location, directory_entry])
                yield os_path_spec.OSPathSpec(
                    location=directory_entry_location)

        except OSError as exception:
            if exception.errno == errno.EACCES:
                exception_string = str(exception)
                if not isinstance(exception_string, py2to3.UNICODE_TYPE):
                    exception_string = py2to3.UNICODE_TYPE(exception_string,
                                                           errors=u'replace')

                raise errors.AccessError(
                    u'Access to directory denied with error: {0:s}'.format(
                        exception_string))
            else:
                raise errors.BackEndError(
                    u'Unable to list directory: {0:s} with error: {1:s}'.
                    format(location, exception))
Beispiel #9
0
    def __init__(self,
                 resolver_context,
                 file_system,
                 path_spec,
                 is_root=False,
                 is_virtual=False,
                 zip_info=None):
        """Initializes a file entry.

    Args:
      resolver_context (Context): resolver context.
      file_system (FileSystem): file system.
      path_spec (PathSpec): path specification.
      is_root (Optional[bool]): True if the file entry is the root file entry
          of the corresponding file system.
      is_virtual (Optional[bool]): True if the file entry is a virtual file
          entry emulated by the corresponding file system.
      zip_info (Optional[zipfile.ZipInfo]): ZIP information.

    Raises:
      BackEndError: when the zip info is missing in a non-virtual file entry.
    """
        if not is_virtual and zip_info is None:
            zip_info = file_system.GetZipInfoByPathSpec(path_spec)
        if not is_virtual and zip_info is None:
            raise errors.BackEndError(
                'Missing zip info in non-virtual file entry.')

        super(ZipFileEntry, self).__init__(resolver_context,
                                           file_system,
                                           path_spec,
                                           is_root=is_root,
                                           is_virtual=is_virtual)
        self._creator_system = getattr(zip_info, 'create_system', 0)
        self._external_attributes = getattr(zip_info, 'external_attr', 0)
        self._zip_info = zip_info

        if (is_virtual or self._external_attributes
                & self._MSDOS_FILE_ATTRIBUTES_IS_DIRECTORY):
            self.entry_type = definitions.FILE_ENTRY_TYPE_DIRECTORY
        else:
            self.entry_type = definitions.FILE_ENTRY_TYPE_FILE
Beispiel #10
0
    def __init__(self,
                 resolver_context,
                 file_system,
                 path_spec,
                 is_root=False,
                 is_virtual=False,
                 vslvm_logical_volume=None):
        """Initializes a file entry.

    Args:
      resolver_context (Context): resolver context.
      file_system (FileSystem): file system.
      path_spec (PathSpec): path specification.
      is_root (Optional[bool]): True if the file entry is the root file entry
          of the corresponding file system.
      is_virtual (Optional[bool]): True if the file entry is a virtual file
      vslvm_logical_volume (Optional[pyvslvm.logical_volume]): a LVM logical
          volume.

    Raises:
      BackEndError: when LVM logical volume is missing for a non-virtual file
          entry.
    """
        if not is_virtual and vslvm_logical_volume is None:
            vslvm_logical_volume = file_system.GetLVMLogicalVolumeByPathSpec(
                path_spec)
        if not is_virtual and vslvm_logical_volume is None:
            raise errors.BackEndError(
                'Missing vslvm logical volume in non-virtual file entry.')

        super(LVMFileEntry, self).__init__(resolver_context,
                                           file_system,
                                           path_spec,
                                           is_root=is_root,
                                           is_virtual=is_virtual)
        self._name = None
        self._vslvm_logical_volume = vslvm_logical_volume

        if self._is_virtual:
            self.entry_type = definitions.FILE_ENTRY_TYPE_DIRECTORY
        else:
            self.entry_type = definitions.FILE_ENTRY_TYPE_FILE
Beispiel #11
0
    def Decode(self, encoded_data):
        """Decode the encoded data.

    Args:
      encoded_data (byte): encoded data.

    Returns:
      tuple(bytes,bytes): decoded data and remaining encoded data.

    Raises:
      BackEndError: if the base32 stream cannot be decoded.
    """
        try:
            decoded_data = base64.b32decode(encoded_data, casefold=False)
        except (TypeError, binascii.Error) as exception:
            raise errors.BackEndError(
                u'Unable to decode base32 stream with error: {0!s}.'.format(
                    exception))

        return decoded_data, b''
Beispiel #12
0
    def __init__(self,
                 resolver_context,
                 file_system,
                 path_spec,
                 fsntfs_file_entry=None,
                 is_root=False,
                 is_virtual=False):
        """Initializes the file entry object.

    Args:
      resolver_context (Context): resolver context.
      file_system (FileSystem): file system.
      path_spec (PathSpec): path specification.
      fsntfs_file_entry (Optional[pyfsntfs.file_entry]): NTFS file entry.
      is_root (Optional[bool]): True if the file entry is the root file entry
          of the corresponding file system.
      is_virtual (Optional[bool]): True if the file entry is a virtual file
          entry emulated by the corresponding file system.

    Raises:
      BackEndError: if the pyfsntfs file entry is missing.
    """
        if not fsntfs_file_entry:
            fsntfs_file_entry = file_system.GetNTFSFileEntryByPathSpec(
                path_spec)
        if not fsntfs_file_entry:
            raise errors.BackEndError('Missing pyfsntfs file entry.')

        super(NTFSFileEntry, self).__init__(resolver_context,
                                            file_system,
                                            path_spec,
                                            is_root=is_root,
                                            is_virtual=is_virtual)
        self._fsntfs_file_entry = fsntfs_file_entry

        if self._IsLink(fsntfs_file_entry.file_attribute_flags):
            self.entry_type = definitions.FILE_ENTRY_TYPE_LINK
        elif fsntfs_file_entry.has_directory_entries_index():
            self.entry_type = definitions.FILE_ENTRY_TYPE_DIRECTORY
        else:
            self.entry_type = definitions.FILE_ENTRY_TYPE_FILE
Beispiel #13
0
  def GetFileEntryByPathSpec(self, path_spec):
    """Retrieves a file entry for a path specification.

    Args:
      path_spec (PathSpec): path specification.

    Returns:
      NTFSFileEntry: file entry or None.

    Raises:
      BackEndError: if the file entry cannot be opened.
    """
    # Opening a file by MFT entry is faster than opening a file by location.
    # However we need the index of the corresponding $FILE_NAME MFT attribute.
    fsntfs_file_entry = None
    location = getattr(path_spec, u'location', None)
    mft_attribute = getattr(path_spec, u'mft_attribute', None)
    mft_entry = getattr(path_spec, u'mft_entry', None)

    if (location == self.LOCATION_ROOT or
        mft_entry == self.MFT_ENTRY_ROOT_DIRECTORY):
      fsntfs_file_entry = self._fsntfs_volume.get_root_directory()
      return dfvfs.vfs.ntfs_file_entry.NTFSFileEntry(
          self._resolver_context, self, path_spec,
          fsntfs_file_entry=fsntfs_file_entry, is_root=True)

    try:
      if mft_attribute is not None and mft_entry is not None:
        fsntfs_file_entry = self._fsntfs_volume.get_file_entry(mft_entry)
      elif location is not None:
        fsntfs_file_entry = self._fsntfs_volume.get_file_entry_by_path(location)

    except IOError as exception:
      raise errors.BackEndError(exception)

    if fsntfs_file_entry is None:
      return

    return dfvfs.vfs.ntfs_file_entry.NTFSFileEntry(
        self._resolver_context, self, path_spec,
        fsntfs_file_entry=fsntfs_file_entry)
Beispiel #14
0
  def Decode(self, encoded_data):
    """Decode the encoded data.

    Args:
      encoded_data: a byte string containing the encoded data.

    Returns:
      A tuple containing a byte string of the decoded data and
      the remaining encoded data.

    Raises:
      BackEndError: if the base32 stream cannot be decoded.
    """
    try:
      decoded_data = base64.b32decode(encoded_data, casefold=False)
    except TypeError as exception:
      raise errors.BackEndError(
          u'Unable to decode base32 stream with error: {0:s}.'.format(
              exception))

    return decoded_data, b''
    def GetNumberOfRows(self):
        """Retrieves the number of rows in the table.

    Returns:
      An integer containing the number of rows.

    Raises:
      BackEndError: when the SQLite blob file-like object is missing.
    """
        file_object = self.GetFileObject()
        if not file_object:
            raise errors.BackEndError(
                u'Unable to retrieve SQLite blob file-like object.')

        try:
            # TODO: move this function out of SQLiteBlobFile.
            self._number_of_entries = file_object.GetNumberOfRows()
        finally:
            file_object.close()

        return self._number_of_entries
Beispiel #16
0
  def GetFileEntryByPathSpec(self, path_spec):
    """Retrieves a file entry for a path specification.

    Args:
      path_spec (PathSpec): path specification.

    Returns:
      APFSFileEntry: file entry or None if not available.

    Raises:
      BackEndError: if the file entry cannot be opened.
    """
    # Opening a file by identifier is faster than opening a file by location.
    fsapfs_file_entry = None
    location = getattr(path_spec, 'location', None)
    identifier = getattr(path_spec, 'identifier', None)

    if (location == self.LOCATION_ROOT or
        identifier == self.ROOT_DIRECTORY_IDENTIFIER):
      fsapfs_file_entry = self._fsapfs_volume.get_root_directory()
      return apfs_file_entry.APFSFileEntry(
          self._resolver_context, self, path_spec,
          fsapfs_file_entry=fsapfs_file_entry, is_root=True)

    try:
      if identifier is not None:
        fsapfs_file_entry = self._fsapfs_volume.get_file_entry_by_identifier(
            identifier)
      elif location is not None:
        fsapfs_file_entry = self._fsapfs_volume.get_file_entry_by_path(location)

    except IOError as exception:
      raise errors.BackEndError(exception)

    if fsapfs_file_entry is None:
      return None

    return apfs_file_entry.APFSFileEntry(
        self._resolver_context, self, path_spec,
        fsapfs_file_entry=fsapfs_file_entry)
Beispiel #17
0
    def _GetDataStreams(self):
        """Retrieves the data streams.

    Returns:
      list[NTFSDataStream]: data streams.

    Raises:
      BackEndError: if the pyfsntfs file entry is missing.
    """
        if self._data_streams is None:
            fsntfs_file_entry = self.GetNTFSFileEntry()
            if not fsntfs_file_entry:
                raise errors.BackEndError(u'Missing pyfsntfs file entry.')

            self._data_streams = []
            if fsntfs_file_entry.has_default_data_stream():
                self._data_streams.append(NTFSDataStream(None))

            for fsntfs_data_stream in fsntfs_file_entry.alternate_data_streams:
                self._data_streams.append(NTFSDataStream(fsntfs_data_stream))

        return self._data_streams
Beispiel #18
0
    def __init__(self,
                 resolver_context,
                 file_system,
                 path_spec,
                 is_root=False,
                 is_virtual=False):
        """Initializes a file entry.

    Args:
      resolver_context (Context): resolver context.
      file_system (FileSystem): file system.
      path_spec (PathSpec): path specification.
      is_root (Optional[bool]): True if the file entry is the root file entry
          of the corresponding file system.
      is_virtual (Optional[bool]): True if the file entry is a virtual file
          entry emulated by the corresponding file system.

    Raises:
      BackEndError: when the vshadow store is missing in a non-virtual
          file entry.
    """
        vshadow_store = file_system.GetVShadowStoreByPathSpec(path_spec)
        if not is_virtual and vshadow_store is None:
            raise errors.BackEndError(
                'Missing vshadow store in non-virtual file entry.')

        super(VShadowFileEntry, self).__init__(resolver_context,
                                               file_system,
                                               path_spec,
                                               is_root=is_root,
                                               is_virtual=is_virtual)
        self._name = None
        self._vshadow_store = vshadow_store

        if self._is_virtual:
            self.entry_type = definitions.FILE_ENTRY_TYPE_DIRECTORY
        else:
            self.entry_type = definitions.FILE_ENTRY_TYPE_FILE
Beispiel #19
0
    def _GetStat(self):
        """Retrieves the stat object.

    Returns:
      The stat object (instance of vfs.VFSStat).

    Raises:
      BackEndError: when the gzip file is missing.
    """
        gzip_file = self.GetFileObject()
        if not gzip_file:
            raise errors.BackEndError(
                u'Unable to open gzip file: {0:s}.'.format(
                    self.path_spec.comparable))

        try:
            stat_object = vfs_stat.VFSStat()

            # File data stat information.
            stat_object.size = gzip_file.uncompressed_data_size

            # Date and time stat information.
            stat_object.mtime = gzip_file.modification_time

            # Ownership and permissions stat information.

            # File entry type stat information.
            stat_object.type = stat_object.TYPE_FILE

            # Other stat information.
            # gzip_file.comment
            # gzip_file.operating_system
            # gzip_file.original_filename

        finally:
            gzip_file.close()

        return stat_object
Beispiel #20
0
    def _GetStat(self):
        """Retrieves the stat object.

    Returns:
      VFSStat: stat object.

    Raises:
      BackEndError: when the SQLite blob file-like object is missing.
    """
        stat_object = super(SQLiteBlobFileEntry, self)._GetStat()

        if not self._is_virtual:
            file_object = self.GetFileObject()
            if not file_object:
                raise errors.BackEndError(
                    'Unable to retrieve SQLite blob file-like object.')

            try:
                stat_object.size = file_object.get_size()
            finally:
                file_object.close()

        return stat_object
Beispiel #21
0
  def Decompress(self, compressed_data):
    """Decompresses the compressed data.

    Args:
      compressed_data (bytes): compressed data.

    Returns:
      tuple(bytes, bytes): uncompressed data and remaining compressed data.

    Raises:
      BackEndError: if the BZIP2 compressed stream cannot be decompressed.
    """
    try:
      uncompressed_data = self._bz2_decompressor.decompress(compressed_data)
      remaining_compressed_data = getattr(
          self._bz2_decompressor, 'unused_data', b'')

    except (EOFError, IOError) as exception:
      raise errors.BackEndError((
          'Unable to decompress BZIP2 compressed stream with error: '
          '{0!s}.').format(exception))

    return uncompressed_data, remaining_compressed_data
  def Decompress(self, compressed_data):
    """Decompresses the compressed data.

    Args:
      compressed_data (bytes): compressed data.

    Returns:
      tuple(bytes,bytes): uncompressed data and remaining compressed data.

    Raises:
      BackEndError: if the zlib compressed stream cannot be decompressed.
    """
    try:
      uncompressed_data = self._zlib_decompressor.decompress(compressed_data)
      remaining_compressed_data = getattr(
          self._zlib_decompressor, u'unused_data', b'')

    except zlib.error as exception:
      raise errors.BackEndError((
          u'Unable to decompress zlib compressed stream with error: '
          u'{0!s}.').format(exception))

    return uncompressed_data, remaining_compressed_data
Beispiel #23
0
    def _GetAttributes(self):
        """Retrieves the attributes.

    Returns:
      list[NTFSAttribute]: attributes.

    Raises:
      BackEndError: if the pyfsntfs file entry is missing.
    """
        if self._attributes is None:
            fsntfs_file_entry = self.GetNTFSFileEntry()
            if not fsntfs_file_entry:
                raise errors.BackEndError(u'Missing pyfsntfs file entry.')

            self._attributes = []
            for fsntfs_attribute in fsntfs_file_entry.attributes:
                attribute_class = self._ATTRIBUTE_TYPE_CLASS_MAPPINGS.get(
                    fsntfs_attribute.attribute_type, NTFSAttribute)

                attribute_object = attribute_class(fsntfs_attribute)
                self._attributes.append(attribute_object)

        return self._attributes
Beispiel #24
0
    def __init__(self,
                 resolver_context,
                 file_system,
                 path_spec,
                 fsapfs_file_entry=None,
                 is_root=False,
                 is_virtual=False):
        """Initializes a file entry.

    Args:
      resolver_context (Context): resolver context.
      file_system (FileSystem): file system.
      path_spec (PathSpec): path specification.
      fsapfs_file_entry (Optional[pyfsapfs.file_entry]): APFS file entry.
      is_root (Optional[bool]): True if the file entry is the root file entry
          of the corresponding file system.
      is_virtual (Optional[bool]): True if the file entry is a virtual file
          entry emulated by the corresponding file system.

    Raises:
      BackEndError: if the pyfsapfs file entry is missing.
    """
        if not fsapfs_file_entry:
            fsapfs_file_entry = file_system.GetAPFSFileEntryByPathSpec(
                path_spec)
        if not fsapfs_file_entry:
            raise errors.BackEndError('Missing pyfsapfs file entry.')

        super(APFSFileEntry, self).__init__(resolver_context,
                                            file_system,
                                            path_spec,
                                            is_root=is_root,
                                            is_virtual=is_virtual)
        self._fsapfs_file_entry = fsapfs_file_entry

        self.entry_type = self._ENTRY_TYPES.get(
            fsapfs_file_entry.file_mode & 0xf000, None)
Beispiel #25
0
    def Decode(self, encoded_data):
        """Decode the encoded data.

    Args:
      encoded_data (byte): encoded data.

    Returns:
      tuple(bytes,bytes): decoded data and remaining encoded data.

    Raises:
      BackEndError: if the base64 stream cannot be decoded.
    """
        try:
            # TODO: replace by libuna implementation or equivalent. The behavior of
            # base64.b64decode() does not raise TypeError for certain invalid base64
            # data e.g. b'\x01\x02\x03\x04\x05\x06\x07\x08' these are silently
            # ignored.
            decoded_data = base64.b64decode(encoded_data)
        except (TypeError, binascii.Error) as exception:
            raise errors.BackEndError(
                u'Unable to decode base64 stream with error: {0!s}.'.format(
                    exception))

        return decoded_data, b''
Beispiel #26
0
    def _ScanNode(self, scan_context, scan_node, auto_recurse=True):
        """Scans for supported formats using a scan node.

    Args:
      scan_context (SourceScannerContext): source scanner context.
      scan_node (SourceScanNode): source scan node.
      auto_recurse (Optional[bool]): True if the scan should automatically
          recurse as far as possible.

    Raises:
      BackEndError: if the source cannot be scanned.
      ValueError: if the scan context or scan node is invalid.
    """
        if not scan_context:
            raise ValueError('Invalid scan context.')

        if not scan_node:
            raise ValueError('Invalid scan node.')

        scan_path_spec = scan_node.path_spec

        if not scan_node.IsSystemLevel():
            system_level_file_entry = None

        else:
            system_level_file_entry = resolver.Resolver.OpenFileEntry(
                scan_node.path_spec, resolver_context=self._resolver_context)

            if system_level_file_entry is None:
                raise errors.BackEndError('Unable to open file entry.')

            if system_level_file_entry.IsDirectory():
                scan_context.SetSourceType(definitions.SOURCE_TYPE_DIRECTORY)
                return

            source_path_spec = self.ScanForStorageMediaImage(
                scan_node.path_spec)
            if source_path_spec:
                scan_node.scanned = True
                scan_node = scan_context.AddScanNode(source_path_spec,
                                                     scan_node)

                if system_level_file_entry.IsDevice():
                    scan_context.SetSourceType(
                        definitions.SOURCE_TYPE_STORAGE_MEDIA_DEVICE)
                else:
                    scan_context.SetSourceType(
                        definitions.SOURCE_TYPE_STORAGE_MEDIA_IMAGE)

                if not auto_recurse:
                    return

            # In case we did not find a storage media image type we keep looking
            # since not all RAW storage media image naming schemas are known and
            # its type can only detected by its content.

        source_path_spec = None
        while True:
            # No need to scan a file systems scan node for volume systems.
            if scan_node.type_indicator in definitions.FILE_SYSTEM_TYPE_INDICATORS:
                break

            # No need to scan a locked scan node e.g. an encrypted volume.
            if scan_context.IsLockedScanNode(scan_node.path_spec):
                break

            source_path_spec = self.ScanForVolumeSystem(scan_node.path_spec)
            # Nothing found in the volume system scan.
            if not source_path_spec:
                break

            if not scan_context.HasScanNode(source_path_spec):
                scan_node.scanned = True
                scan_node = scan_context.AddScanNode(source_path_spec,
                                                     scan_node)

                if system_level_file_entry and system_level_file_entry.IsDevice(
                ):
                    scan_context.SetSourceType(
                        definitions.SOURCE_TYPE_STORAGE_MEDIA_DEVICE)
                else:
                    scan_context.SetSourceType(
                        definitions.SOURCE_TYPE_STORAGE_MEDIA_IMAGE)

            if scan_node.type_indicator in definitions.VOLUME_SYSTEM_TYPE_INDICATORS:
                # For VSS add a scan node for the current volume.
                if scan_node.type_indicator == definitions.TYPE_INDICATOR_VSHADOW:
                    path_spec = self.ScanForFileSystem(
                        scan_node.path_spec.parent)
                    if path_spec:
                        scan_context.AddScanNode(path_spec,
                                                 scan_node.parent_node)

                # Determine the path specifications of the sub file entries.
                file_entry = resolver.Resolver.OpenFileEntry(
                    scan_node.path_spec,
                    resolver_context=self._resolver_context)

                for sub_file_entry in file_entry.sub_file_entries:
                    sub_scan_node = scan_context.AddScanNode(
                        sub_file_entry.path_spec, scan_node)

                    # Since scanning for file systems in VSS snapshot volumes can
                    # be expensive we only do this when explicitly asked for.
                    if scan_node.type_indicator != definitions.TYPE_INDICATOR_VSHADOW:
                        if auto_recurse or not scan_context.updated:
                            self._ScanNode(scan_context,
                                           sub_scan_node,
                                           auto_recurse=auto_recurse)

                # We already have already scanned for the file systems in _ScanNode().
                return

            elif scan_node.type_indicator in (
                    definitions.ENCRYPTED_VOLUME_TYPE_INDICATORS):
                file_object = resolver.Resolver.OpenFileObject(
                    scan_node.path_spec,
                    resolver_context=self._resolver_context)
                is_locked = not file_object or file_object.is_locked
                file_object.close()

                if is_locked:
                    scan_context.LockScanNode(scan_node.path_spec)

                    # For BitLocker To Go add a scan node for the unencrypted part
                    # of the volume.
                    if scan_node.type_indicator == definitions.TYPE_INDICATOR_BDE:
                        path_spec = self.ScanForFileSystem(
                            scan_node.path_spec.parent)
                        if path_spec:
                            scan_context.AddScanNode(path_spec,
                                                     scan_node.parent_node)

            if not auto_recurse and scan_context.updated:
                return

            # Nothing new found.
            if not scan_context.updated:
                break

        # In case we did not find a volume system type we keep looking
        # since we could be dealing with a storage media image that contains
        # a single volume.

        # No need to scan the root of a volume system for a file system.
        if (scan_node.path_spec.type_indicator
                in (definitions.VOLUME_SYSTEM_TYPE_INDICATORS)
                and getattr(scan_node.path_spec, 'location', None) == '/'):
            pass

        # No need to scan a locked scan node e.g. an encrypted volume.
        elif scan_context.IsLockedScanNode(scan_node.path_spec):
            pass

        # Since scanning for file systems in VSS snapshot volumes can
        # be expensive we only do this when explicitly asked for.
        elif (scan_node.type_indicator == definitions.TYPE_INDICATOR_VSHADOW
              and auto_recurse and scan_node.path_spec != scan_path_spec):
            pass

        elif scan_node.type_indicator not in (
                definitions.FILE_SYSTEM_TYPE_INDICATORS):
            source_path_spec = self.ScanForFileSystem(scan_node.path_spec)
            if not source_path_spec:
                # Since RAW storage media image can only be determined by naming schema
                # we could have single file that is not a RAW storage media image yet
                # matches the naming schema.
                if scan_node.path_spec.type_indicator == definitions.TYPE_INDICATOR_RAW:
                    scan_node = scan_context.RemoveScanNode(
                        scan_node.path_spec)

                    # Make sure to override the previously assigned source type.
                    scan_context.source_type = definitions.SOURCE_TYPE_FILE
                else:
                    scan_context.SetSourceType(definitions.SOURCE_TYPE_FILE)

            elif not scan_context.HasScanNode(source_path_spec):
                scan_node.scanned = True
                scan_node = scan_context.AddScanNode(source_path_spec,
                                                     scan_node)

                if system_level_file_entry and system_level_file_entry.IsDevice(
                ):
                    scan_context.SetSourceType(
                        definitions.SOURCE_TYPE_STORAGE_MEDIA_DEVICE)
                else:
                    scan_context.SetSourceType(
                        definitions.SOURCE_TYPE_STORAGE_MEDIA_IMAGE)

        # If all scans failed mark the scan node as scanned so we do not scan it
        # again.
        if not scan_node.scanned:
            scan_node.scanned = True

        return
Beispiel #27
0
    def _EntriesGenerator(self):
        """Retrieves directory entries.

    Since a directory can contain a vast number of entries using
    a generator is more memory efficient.

    Yields:
      TSKPathSpec: path specification.

    Raises:
      BackEndError: if pytsk3 cannot open the directory.
    """
        # Opening a file by inode number is faster than opening a file
        # by location.
        inode = getattr(self.path_spec, u'inode', None)
        location = getattr(self.path_spec, u'location', None)

        fs_info = self._file_system.GetFsInfo()
        tsk_directory = None

        try:
            if inode is not None:
                tsk_directory = fs_info.open_dir(inode=inode)
            elif location is not None:
                tsk_directory = fs_info.open_dir(path=location)

        except IOError as exception:
            raise errors.BackEndError(
                u'Unable to open directory with error: {0:s}'.format(
                    exception))

        if not tsk_directory:
            return

        for tsk_directory_entry in tsk_directory:
            # Note that because pytsk3.Directory does not explicitly defines info
            # we need to check if the attribute exists and has a value other
            # than None.
            if getattr(tsk_directory_entry, u'info', None) is None:
                continue

            # Note that because pytsk3.TSK_FS_FILE does not explicitly defines fs_info
            # we need to check if the attribute exists and has a value other
            # than None.
            if getattr(tsk_directory_entry.info, u'fs_info', None) is None:
                continue

            # Note that because pytsk3.TSK_FS_FILE does not explicitly defines meta
            # we need to check if the attribute exists and has a value other
            # than None.
            if getattr(tsk_directory_entry.info, u'meta', None) is None:
                # Most directory entries will have an "inode" but not all, e.g.
                # previously deleted files. Currently directory entries without
                # a pytsk3.TSK_FS_META object are ignored.
                continue

            # Note that because pytsk3.TSK_FS_META does not explicitly defines addr
            # we need to check if the attribute exists.
            if not hasattr(tsk_directory_entry.info.meta, u'addr'):
                continue

            directory_entry_inode = tsk_directory_entry.info.meta.addr
            directory_entry = None

            # Ignore references to self.
            if directory_entry_inode == inode:
                continue

            # On non-NTFS file systems ignore inode 0.
            if directory_entry_inode == 0 and not self._file_system.IsNTFS():
                continue

            # Note that because pytsk3.TSK_FS_FILE does not explicitly defines name
            # we need to check if the attribute exists and has a value other
            # than None.
            if getattr(tsk_directory_entry.info, u'name', None) is not None:
                # Ignore file entries marked as "unallocated".
                flags = getattr(tsk_directory_entry.info.name, u'flags', 0)
                if int(flags) & pytsk3.TSK_FS_NAME_FLAG_UNALLOC:
                    continue

                directory_entry = getattr(tsk_directory_entry.info.name,
                                          u'name', u'')

                try:
                    # pytsk3 returns an UTF-8 encoded byte string.
                    directory_entry = directory_entry.decode(u'utf8')
                except UnicodeError:
                    # Continue here since we cannot represent the directory entry.
                    continue

                if directory_entry:
                    # Ignore references to self or parent.
                    if directory_entry in [u'.', u'..']:
                        continue

                    if location == self._file_system.PATH_SEPARATOR:
                        directory_entry = self._file_system.JoinPath(
                            [directory_entry])
                    else:
                        directory_entry = self._file_system.JoinPath(
                            [location, directory_entry])

            yield tsk_path_spec.TSKPathSpec(inode=directory_entry_inode,
                                            location=directory_entry,
                                            parent=self.path_spec.parent)
Beispiel #28
0
    def _GetStat(self):
        """Retrieves the stat object.

    Returns:
      VFSStat: stat object.

    Raises:
      BackEndError: if the TSK File .info or .info.meta attribute is missing.
    """
        tsk_file = self.GetTSKFile()
        if not tsk_file or not tsk_file.info or not tsk_file.info.meta:
            raise errors.BackEndError(u'Missing TSK File .info or .info.meta.')

        stat_object = vfs_stat.VFSStat()

        # File data stat information.
        stat_object.size = getattr(tsk_file.info.meta, u'size', None)

        # Date and time stat information.
        stat_time, stat_time_nano = self._TSKFileTimeCopyToStatTimeTuple(
            tsk_file, u'atime')
        if stat_time is not None:
            stat_object.atime = stat_time
            stat_object.atime_nano = stat_time_nano

        stat_time, stat_time_nano = self._TSKFileTimeCopyToStatTimeTuple(
            tsk_file, u'bkup')
        if stat_time is not None:
            stat_object.bkup = stat_time
            stat_object.bkup_nano = stat_time_nano

        stat_time, stat_time_nano = self._TSKFileTimeCopyToStatTimeTuple(
            tsk_file, u'ctime')
        if stat_time is not None:
            stat_object.ctime = stat_time
            stat_object.ctime_nano = stat_time_nano

        stat_time, stat_time_nano = self._TSKFileTimeCopyToStatTimeTuple(
            tsk_file, u'crtime')
        if stat_time is not None:
            stat_object.crtime = stat_time
            stat_object.crtime_nano = stat_time_nano

        stat_time, stat_time_nano = self._TSKFileTimeCopyToStatTimeTuple(
            tsk_file, u'dtime')
        if stat_time is not None:
            stat_object.dtime = stat_time
            stat_object.dtime_nano = stat_time_nano

        stat_time, stat_time_nano = self._TSKFileTimeCopyToStatTimeTuple(
            tsk_file, u'mtime')
        if stat_time is not None:
            stat_object.mtime = stat_time
            stat_object.mtime_nano = stat_time_nano

        # Ownership and permissions stat information.
        mode = getattr(tsk_file.info.meta, u'mode', None)
        if mode is not None:
            # We need to cast mode to an int since it is of type
            # pytsk3.TSK_FS_META_MODE_ENUM.
            stat_object.mode = int(mode)

        stat_object.uid = getattr(tsk_file.info.meta, u'uid', None)
        stat_object.gid = getattr(tsk_file.info.meta, u'gid', None)

        # File entry type stat information.
        # The type is an instance of pytsk3.TSK_FS_META_TYPE_ENUM.
        tsk_fs_meta_type = getattr(tsk_file.info.meta, u'type',
                                   pytsk3.TSK_FS_META_TYPE_UNDEF)

        if tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_REG:
            stat_object.type = stat_object.TYPE_FILE
        elif tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_DIR:
            stat_object.type = stat_object.TYPE_DIRECTORY
        elif tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_LNK:
            stat_object.type = stat_object.TYPE_LINK
        elif (tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_CHR
              or tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_BLK):
            stat_object.type = stat_object.TYPE_DEVICE
        elif tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_FIFO:
            stat_object.type = stat_object.TYPE_PIPE
        elif tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_SOCK:
            stat_object.type = stat_object.TYPE_SOCKET
        # TODO: implement support for:
        # pytsk3.TSK_FS_META_TYPE_UNDEF
        # pytsk3.TSK_FS_META_TYPE_SHAD
        # pytsk3.TSK_FS_META_TYPE_WHT
        # pytsk3.TSK_FS_META_TYPE_VIRT

        # Other stat information.
        stat_object.ino = getattr(tsk_file.info.meta, u'addr', None)
        # stat_object.dev = stat_info.st_dev
        # stat_object.nlink = getattr(tsk_file.info.meta, u'nlink', None)
        # stat_object.fs_type = u'Unknown'

        flags = getattr(tsk_file.info.meta, u'flags', 0)

        # The flags are an instance of pytsk3.TSK_FS_META_FLAG_ENUM.
        if int(flags) & pytsk3.TSK_FS_META_FLAG_ALLOC:
            stat_object.is_allocated = True
        else:
            stat_object.is_allocated = False

        return stat_object
Beispiel #29
0
    def _GetStat(self):
        """Retrieves the stat object.

    Returns:
      VFSStat: stat object.

    Raises:
      BackEndError: if the pyfsntfs file entry is missing.
    """
        fsntfs_file_entry = self.GetNTFSFileEntry()
        if not fsntfs_file_entry:
            raise errors.BackEndError(u'Missing pyfsntfs file entry.')

        stat_object = vfs_stat.VFSStat()

        # File data stat information.
        if fsntfs_file_entry.has_default_data_stream():
            stat_object.size = fsntfs_file_entry.get_size()

        # Date and time stat information.
        timestamp = fsntfs_file_entry.get_access_time_as_integer()
        date_time_values = dfdatetime_filetime.Filetime(timestamp=timestamp)

        stat_time, stat_time_nano = date_time_values.CopyToStatTimeTuple()
        if stat_time is not None:
            stat_object.atime = stat_time
            stat_object.atime_nano = stat_time_nano

        timestamp = fsntfs_file_entry.get_creation_time_as_integer()
        date_time_values = dfdatetime_filetime.Filetime(timestamp=timestamp)

        stat_time, stat_time_nano = date_time_values.CopyToStatTimeTuple()
        if stat_time is not None:
            stat_object.crtime = stat_time
            stat_object.crtime_nano = stat_time_nano

        timestamp = fsntfs_file_entry.get_modification_time_as_integer()
        date_time_values = dfdatetime_filetime.Filetime(timestamp=timestamp)

        stat_time, stat_time_nano = date_time_values.CopyToStatTimeTuple()
        if stat_time is not None:
            stat_object.mtime = stat_time
            stat_object.mtime_nano = stat_time_nano

        timestamp = fsntfs_file_entry.get_entry_modification_time_as_integer()
        date_time_values = dfdatetime_filetime.Filetime(timestamp=timestamp)

        stat_time, stat_time_nano = date_time_values.CopyToStatTimeTuple()
        if stat_time is not None:
            stat_object.ctime = stat_time
            stat_object.ctime_nano = stat_time_nano

        # Ownership and permissions stat information.
        # TODO: stat_object.mode
        # TODO: stat_object.uid
        # TODO: stat_object.gid

        # File entry type stat information.
        if self._IsLink(fsntfs_file_entry.file_attribute_flags):
            stat_object.type = stat_object.TYPE_LINK
        elif fsntfs_file_entry.has_directory_entries_index():
            stat_object.type = stat_object.TYPE_DIRECTORY
        else:
            stat_object.type = stat_object.TYPE_FILE

        # Other stat information.
        stat_object.ino = (fsntfs_file_entry.file_reference
                           & _FILE_REFERENCE_MFT_ENTRY_BITMASK)
        stat_object.fs_type = u'NTFS'

        stat_object.is_allocated = fsntfs_file_entry.is_allocated()

        return stat_object
Beispiel #30
0
  def _GetStat(self):
    """Retrieves the stat object (instance of vfs.VFSStat).

    Raises:
      BackEndError: If an OSError comes up it is caught and an
                    BackEndError error is raised instead.
    Returns:
      Stat object (instance of VFSStat) or None if no location is set.
    """
    location = getattr(self.path_spec, u'location', None)
    if location is None:
      return

    stat_object = vfs_stat.VFSStat()

    is_windows_device = False
    stat_info = None

    # Windows does not support running os.stat on device files so we use
    # libsmdev to do an initial check.
    if platform.system() == u'Windows':
      try:
        is_windows_device = pysmdev.check_device(location)
      except IOError:
        pass

    if is_windows_device:
      stat_object.type = stat_object.TYPE_DEVICE

    else:
      # We are only catching OSError. However on the Windows platform
      # a WindowsError can be raised as well. We are not catching that since
      # that error does not exist on non-Windows platforms.
      try:
        stat_info = os.stat(location)
      except OSError as exception:
        raise errors.BackEndError(
            u'Unable to retrieve stat object with error: {0:s}'.format(
                exception))

      # File data stat information.
      stat_object.size = stat_info.st_size

      # Date and time stat information.
      stat_object.atime = stat_info.st_atime
      stat_object.ctime = stat_info.st_ctime
      stat_object.mtime = stat_info.st_mtime

      # Ownership and permissions stat information.
      stat_object.mode = stat.S_IMODE(stat_info.st_mode)
      stat_object.uid = stat_info.st_uid
      stat_object.gid = stat_info.st_gid

      # If location contains a trailing segment separator and points to
      # a symbolic link to a directory stat info will not indicate
      # the file entry as a symbolic link. The following check ensures
      # that the LINK type is correctly detected.
      is_link = os.path.islink(location)

      # File entry type stat information.

      # The stat info member st_mode can have multiple types e.g.
      # LINK and DIRECTORY in case of a symbolic link to a directory
      # dfVFS currently only supports one type so we need to check
      # for LINK first.
      if stat.S_ISLNK(stat_info.st_mode) or is_link:
        stat_object.type = stat_object.TYPE_LINK
      elif stat.S_ISREG(stat_info.st_mode):
        stat_object.type = stat_object.TYPE_FILE
      elif stat.S_ISDIR(stat_info.st_mode):
        stat_object.type = stat_object.TYPE_DIRECTORY
      elif (stat.S_ISCHR(stat_info.st_mode) or
            stat.S_ISBLK(stat_info.st_mode)):
        stat_object.type = stat_object.TYPE_DEVICE
      elif stat.S_ISFIFO(stat_info.st_mode):
        stat_object.type = stat_object.TYPE_PIPE
      elif stat.S_ISSOCK(stat_info.st_mode):
        stat_object.type = stat_object.TYPE_SOCKET

      # Other stat information.
      stat_object.ino = stat_info.st_ino
      # stat_info.st_dev
      # stat_info.st_nlink

    return stat_object