def _GetLVMVolumeIdentifiers(self, scan_node, options): """Determines the LVM volume identifiers. Args: scan_node (SourceScanNode): scan node. options (VolumeScannerOptions): volume scanner options. Returns: list[str]: LVM volume identifiers. Raises: ScannerError: if the scan node is invalid or the scanner does not know how to proceed. UserAbort: if the user requested to abort. """ if not scan_node or not scan_node.path_spec: raise errors.ScannerError('Invalid scan node.') volume_system = lvm_volume_system.LVMVolumeSystem() volume_system.Open(scan_node.path_spec) volume_identifiers = self._source_scanner.GetVolumeIdentifiers( volume_system) if not volume_identifiers: return [] if options.volumes: if options.volumes == ['all']: volumes = range(1, volume_system.number_of_volumes + 1) else: volumes = options.volumes try: selected_volumes = self._NormalizedVolumeIdentifiers( volume_system, volumes, prefix='lvm') if not set(selected_volumes).difference(volume_identifiers): return selected_volumes except errors.ScannerError as exception: if self._mediator: self._mediator.PrintWarning('{0!s}'.format(exception)) if len(volume_identifiers) > 1: if not self._mediator: raise errors.ScannerError( 'Unable to proceed. LVM volumes found but no mediator to ' 'determine how they should be used.') try: volume_identifiers = self._mediator.GetLVMVolumeIdentifiers( volume_system, volume_identifiers) except KeyboardInterrupt: raise errors.UserAbort('File system scan aborted.') return self._NormalizedVolumeIdentifiers( volume_system, volume_identifiers, prefix='lvm')
def _GetLVMVolumeIdentifiers(self, scan_node): """Determines the LVM volume identifiers. Args: scan_node (dfvfs.SourceScanNode): scan node. Returns: list[str]: LVM volume identifiers. Raises: SourceScannerError: if the scan node is invalid or more than 1 volume was found but no volumes were specified. UserAbort: if the user requested to abort. """ if not scan_node or not scan_node.path_spec: raise errors.SourceScannerError('Invalid scan node.') volume_system = lvm_volume_system.LVMVolumeSystem() volume_system.Open(scan_node.path_spec) volume_identifiers = self._source_scanner.GetVolumeIdentifiers( volume_system) if not volume_identifiers: return [] # TODO: refactor self._volumes to use scan options. if self._volumes: if self._volumes == 'all': volumes = volume_system.volume_identifiers else: volumes = self._mediator.ParseVolumeIdentifiersString( self._volumes, prefix='lvm') selected_volume_identifiers = self._NormalizedVolumeIdentifiers( volume_system, volumes, prefix='lvm') if not set(selected_volume_identifiers).difference( volume_identifiers): return selected_volume_identifiers if len(volume_identifiers) > 1: if self._unattended_mode: raise errors.SourceScannerError( 'More than 1 volume found but no volumes specified.') try: volume_identifiers = self._mediator.GetLVMVolumeIdentifiers( volume_system, volume_identifiers) except KeyboardInterrupt: raise errors.UserAbort('File system scan aborted.') return self._NormalizedVolumeIdentifiers(volume_system, volume_identifiers, prefix='lvm')
def testPrintLVMVolumeIdentifiersOverview(self): """Tests the _PrintLVMVolumeIdentifiersOverview function.""" test_file_path = self._GetTestFilePath(['lvm.raw']) self._SkipIfPathNotExists(test_file_path) test_os_path_spec = path_spec_factory.Factory.NewPathSpec( dfvfs_definitions.TYPE_INDICATOR_OS, location=test_file_path) test_raw_path_spec = path_spec_factory.Factory.NewPathSpec( dfvfs_definitions.TYPE_INDICATOR_RAW, parent=test_os_path_spec) test_lvm_path_spec = path_spec_factory.Factory.NewPathSpec( dfvfs_definitions.TYPE_INDICATOR_LVM, location='/', parent=test_raw_path_spec) volume_system = lvm_volume_system.LVMVolumeSystem() volume_system.Open(test_lvm_path_spec) file_object = io.BytesIO() test_output_writer = tools.FileObjectOutputWriter(file_object) test_mediator = storage_media_tool.StorageMediaToolMediator( output_writer=test_output_writer) test_mediator._PrintLVMVolumeIdentifiersOverview( volume_system, ['lvm1', 'lvm2']) file_object.seek(0, os.SEEK_SET) output_data = file_object.read() expected_output_data = [ b'The following Logical Volume Manager (LVM) volumes were found:', b'', b'Identifier', b'lvm1', b'lvm2', b'', b''] if not win32console: # Using join here since Python 3 does not support format of bytes. expected_output_data[2] = b''.join([ b'\x1b[1m', expected_output_data[2], b'\x1b[0m']) self.assertEqual(output_data.split(b'\n'), expected_output_data)
def testIterateVolumes(self): """Test the iterate volumes functionality.""" volume_system = lvm_volume_system.LVMVolumeSystem() volume_system.Open(self._lvm_path_spec) self.assertEqual(volume_system.number_of_volumes, 2) volume = volume_system.GetVolumeByIndex(1) self.assertIsNotNone(volume) self.assertEqual(volume.number_of_extents, 1) self.assertEqual(volume.number_of_attributes, 1) self.assertEqual(volume.identifier, u'lvm2') expected_value = u'bJxmc8-JEMZ-jXT9-oVeY-40AY-ROro-mCO8Zz' volume_attribute = volume.GetAttribute(u'identifier') self.assertIsNotNone(volume_attribute) self.assertEqual(volume_attribute.value, expected_value) volume = volume_system.GetVolumeByIndex(7) self.assertIsNone(volume)
def testIterateVolumes(self): """Test the iterate volumes functionality.""" volume_system = lvm_volume_system.LVMVolumeSystem() volume_system.Open(self._lvm_path_spec) self.assertEqual(volume_system.number_of_volumes, 2) volume = volume_system.GetVolumeByIndex(0) self.assertIsNotNone(volume) self.assertEqual(volume.number_of_extents, 1) self.assertEqual(volume.number_of_attributes, 1) self.assertEqual(volume.identifier, 'lvm1') expected_value = 'RI0pgm-rdy4-XxcL-5eoK-Easc-fgPq-CWaEJb' volume_attribute = volume.GetAttribute('identifier') self.assertIsNotNone(volume_attribute) self.assertEqual(volume_attribute.value, expected_value) volume = volume_system.GetVolumeByIndex(99) self.assertIsNone(volume)
def testIterateVolumes(self): """Test the iterate volumes functionality.""" volume_system = lvm_volume_system.LVMVolumeSystem() volume_system.Open(self._lvm_path_spec) self.assertEqual(volume_system.number_of_volumes, 1) volume = volume_system.GetVolumeByIndex(0) self.assertIsNotNone(volume) self.assertEqual(volume.number_of_extents, 1) self.assertEqual(volume.number_of_attributes, 1) self.assertEqual(volume.identifier, 'lvm1') expected_value = '0MUZZr-7jgO-iFwW-sSG3-Rb8W-w5td-qAOF8e' volume_attribute = volume.GetAttribute('identifier') self.assertIsNotNone(volume_attribute) self.assertEqual(volume_attribute.value, expected_value) volume = volume_system.GetVolumeByIndex(99) self.assertIsNone(volume)
def testGetLVMVolumeIdentifiers(self): """Tests the GetLVMVolumeIdentifiers function.""" test_path = self._GetTestFilePath(['lvm.raw']) self._SkipIfPathNotExists(test_path) test_os_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_OS, location=test_path) test_raw_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_RAW, parent=test_os_path_spec) test_lvm_container_path_spec = path_spec_factory.Factory.NewPathSpec( definitions.TYPE_INDICATOR_LVM, location='/', parent=test_raw_path_spec) volume_system = lvm_volume_system.LVMVolumeSystem() volume_system.Open(test_lvm_container_path_spec) # Test selection of single volume. input_file_object = io.BytesIO(b'1\n') test_input_reader = command_line.FileObjectInputReader( input_file_object) output_file_object = io.BytesIO() test_output_writer = command_line.FileObjectOutputWriter( output_file_object) test_mediator = command_line.CLIVolumeScannerMediator( input_reader=test_input_reader, output_writer=test_output_writer) volume_identifiers = test_mediator.GetLVMVolumeIdentifiers( volume_system, ['lvm1']) self.assertEqual(volume_identifiers, ['lvm1']) # Test selection of single volume. input_file_object = io.BytesIO(b'lvm1\n') test_input_reader = command_line.FileObjectInputReader( input_file_object) output_file_object = io.BytesIO() test_output_writer = command_line.FileObjectOutputWriter( output_file_object) test_mediator = command_line.CLIVolumeScannerMediator( input_reader=test_input_reader, output_writer=test_output_writer) volume_identifiers = test_mediator.GetLVMVolumeIdentifiers( volume_system, ['lvm1']) self.assertEqual(volume_identifiers, ['lvm1']) # Test selection of single volume with invalid input on first attempt. input_file_object = io.BytesIO(b'bogus\nlvm1\n') test_input_reader = command_line.FileObjectInputReader( input_file_object) output_file_object = io.BytesIO() test_output_writer = command_line.FileObjectOutputWriter( output_file_object) test_mediator = command_line.CLIVolumeScannerMediator( input_reader=test_input_reader, output_writer=test_output_writer) volume_identifiers = test_mediator.GetLVMVolumeIdentifiers( volume_system, ['lvm1']) self.assertEqual(volume_identifiers, ['lvm1']) # Test selection of all volumes. input_file_object = io.BytesIO(b'all\n') test_input_reader = command_line.FileObjectInputReader( input_file_object) output_file_object = io.BytesIO() test_output_writer = command_line.FileObjectOutputWriter( output_file_object) test_mediator = command_line.CLIVolumeScannerMediator( input_reader=test_input_reader, output_writer=test_output_writer) volume_identifiers = test_mediator.GetLVMVolumeIdentifiers( volume_system, ['lvm1', 'lvm2']) self.assertEqual(volume_identifiers, ['lvm1', 'lvm2']) # Test selection of no volumes. input_file_object = io.BytesIO(b'\n') test_input_reader = command_line.FileObjectInputReader( input_file_object) output_file_object = io.BytesIO() test_output_writer = command_line.FileObjectOutputWriter( output_file_object) test_mediator = command_line.CLIVolumeScannerMediator( input_reader=test_input_reader, output_writer=test_output_writer) volume_identifiers = test_mediator.GetLVMVolumeIdentifiers( volume_system, ['lvm1']) self.assertEqual(volume_identifiers, [])
def _ProcessPartition(self, path_spec): """Generate RawDiskPartition from a PathSpec. Args: path_spec (dfvfs.PathSpec): dfVFS path spec. Returns: A new RawDiskPartition evidence item and a list of strings containing partition information to add to the status report. """ status_report = [] fs_path_spec = path_spec fs_location = None partition_location = None volume_index = None partition_index = None partition_offset = None partition_size = None lv_uuid = None # File system location / identifier is_lvm = False fs_location = getattr(path_spec, 'location', None) while path_spec.HasParent(): type_indicator = path_spec.type_indicator if type_indicator == dfvfs_definitions.TYPE_INDICATOR_APFS_CONTAINER: # APFS volume index volume_index = getattr(path_spec, 'volume_index', None) if type_indicator in ( dfvfs_definitions.TYPE_INDICATOR_GPT, dfvfs_definitions.TYPE_INDICATOR_LVM, dfvfs_definitions.TYPE_INDICATOR_TSK_PARTITION): if fs_location in ('\\', '/'): # Partition location / identifier fs_location = getattr(path_spec, 'location', None) partition_location = getattr(path_spec, 'location', None) # Partition index partition_index = getattr(path_spec, 'part_index', None) if type_indicator == dfvfs_definitions.TYPE_INDICATOR_TSK_PARTITION: volume_system = tsk_volume_system.TSKVolumeSystem() elif type_indicator == dfvfs_definitions.TYPE_INDICATOR_LVM: is_lvm = True volume_system = lvm_volume_system.LVMVolumeSystem() else: volume_system = gpt_volume_system.GPTVolumeSystem() try: volume_system.Open(path_spec) volume_identifier = partition_location.replace('/', '') volume = volume_system.GetVolumeByIdentifier( volume_identifier) if is_lvm: # LVM Logical Volume UUID lv_uuid = volume.GetAttribute('identifier') if lv_uuid: lv_uuid = lv_uuid.value partition_offset = volume.extents[0].offset partition_size = volume.extents[0].size except dfvfs_errors.VolumeSystemError as e: raise TurbiniaException( 'Could not process partition: {0!s}'.format(e)) break path_spec = path_spec.parent status_report.append(fmt.heading5('{0!s}:'.format(fs_location))) status_report.append( fmt.bullet('Filesystem: {0!s}'.format( fs_path_spec.type_indicator))) if volume_index is not None: status_report.append( fmt.bullet('Volume index: {0!s}'.format(volume_index))) if partition_index is not None: status_report.append( fmt.bullet('Partition index: {0!s}'.format(partition_index))) status_report.append( fmt.bullet('Partition offset: {0!s}'.format(partition_offset))) status_report.append( fmt.bullet('Partition size: {0!s}'.format(partition_size))) if volume_index is None and partition_index is None: status_report.append( fmt.bullet('Source evidence is a volume image')) # Not setting path_spec here as it will need to be generated for each task partition_evidence = DiskPartition(partition_location=fs_location, partition_offset=partition_offset, partition_size=partition_size, lv_uuid=lv_uuid) return partition_evidence, status_report
def _ScanVolumeSystemRoot(self, scan_context, scan_node, options, base_path_specs): """Scans a volume system root scan node for volume and file systems. Args: scan_context (SourceScannerContext): source scanner context. scan_node (SourceScanNode): volume system root scan node. options (VolumeScannerOptions): volume scanner options. base_path_specs (list[PathSpec]): file system base path specifications. Raises: dfvfs.ScannerError: if the scan node is invalid, the scan node type is not supported or if a sub scan node cannot be retrieved. """ if not scan_node or not scan_node.path_spec: raise dfvfs_errors.ScannerError('Invalid scan node.') if scan_node.type_indicator == ( dfvfs_definitions.TYPE_INDICATOR_APFS_CONTAINER): volume_system = apfs_volume_system.APFSVolumeSystem() volume_system.Open(scan_node.path_spec) volume_identifiers = self._GetVolumeIdentifiers( volume_system, options) elif scan_node.type_indicator == dfvfs_definitions.TYPE_INDICATOR_GPT: volume_identifiers = self._GetPartitionIdentifiers( scan_node, options) elif scan_node.type_indicator == dfvfs_definitions.TYPE_INDICATOR_LVM: volume_system = lvm_volume_system.LVMVolumeSystem() volume_system.Open(scan_node.path_spec) volume_identifiers = self._GetVolumeIdentifiers( volume_system, options) elif scan_node.type_indicator == dfvfs_definitions.TYPE_INDICATOR_VSHADOW: volume_system = vshadow_volume_system.VShadowVolumeSystem() volume_system.Open(scan_node.path_spec) volume_identifiers = self._GetVolumeSnapshotIdentifiers( volume_system, options) # Process VSS stores (snapshots) starting with the most recent one. volume_identifiers.reverse() # TODO: difference with dfVFS for current VSS volume support. if not options.snapshots_only and self._mediator and volume_identifiers: snapshots_only = not self._mediator.PromptUserForVSSCurrentVolume( ) options.snapshots_only = snapshots_only self._snapshots_only = snapshots_only else: raise dfvfs_errors.ScannerError( 'Unsupported volume system type: {0:s}.'.format( scan_node.type_indicator)) for volume_identifier in volume_identifiers: location = '/{0:s}'.format(volume_identifier) sub_scan_node = scan_node.GetSubNodeByLocation(location) if not sub_scan_node: raise dfvfs_errors.ScannerError( 'Scan node missing for volume identifier: {0:s}.'.format( volume_identifier)) self._ScanVolume(scan_context, sub_scan_node, options, base_path_specs)