예제 #1
0
    def detect_volumes(self, vstype=None, method=None, force=False):
        """Iterator for detecting volumes within this volume system.

        :param str vstype: The volume system type to use. If None, uses :attr:`vstype`
        :param str method: The detection method to use. If None, uses :attr:`detection`
        :param bool force: Specify if you wnat to force running the detection if has_Detected is True.
        """
        if self.has_detected and not force:
            logger.warning("Detection already ran.")
            return

        if vstype is None:
            vstype = self.vstype
        if method is None:
            method = self.volume_detector

        if method == 'auto':
            method = VolumeSystem._determine_auto_detection_method()

        if method in ALL_VOLUME_SYSTEM_DETECTORS:
            yield from ALL_VOLUME_SYSTEM_DETECTORS[method].detect(self, vstype)
        else:
            logger.error("No viable detection method found")
            raise ArgumentError("No viable detection method found")

        self.has_detected = True
예제 #2
0
    def mount(self, volume):
        """Mounts a BDE container. Uses key material provided by the :attr:`keys` attribute. The key material should be
        provided in the same format as to :cmd:`bdemount`, used as follows:

        k:full volume encryption and tweak key
        p:passphrase
        r:recovery password
        s:file to startup key (.bek)

        :return: the Volume contained in the BDE container
        :raises ArgumentError: if the keys argument is invalid
        :raises SubsystemError: when the underlying command fails
        """

        volume._paths['bde'] = tempfile.mkdtemp(prefix='image_mounter_bde_')

        try:
            if volume.key:
                t, v = volume.key.split(':', 1)
                key = ['-' + t, v]
            else:
                logger.warning("No key material provided for %s", volume)
                key = []
        except ValueError:
            logger.exception(
                "Invalid key material provided (%s) for %s. Expecting [arg]:[value]",
                volume.key, volume)
            raise ArgumentError()

        # noinspection PyBroadException
        try:
            cmd = [
                "bdemount",
                volume.get_raw_path(), volume._paths['bde'], '-o',
                str(volume.offset)
            ]
            cmd.extend(key)
            _util.check_call_(cmd)
        except Exception as e:
            del volume._paths['bde']
            logger.exception("Failed mounting BDE volume %s.", volume)
            raise SubsystemError(e)

        container = volume.volumes._make_single_subvolume(flag='alloc',
                                                          offset=0,
                                                          size=volume.size)
        container.info['fsdescription'] = 'BDE Volume'

        return container
예제 #3
0
    def detect_volumes(self, vstype=None, method=None, force=False):
        """Iterator for detecting volumes within this volume system.

        :param str vstype: The volume system type to use. If None, uses :attr:`vstype`
        :param str method: The detection method to use. If None, uses :attr:`detection`
        :param bool force: Specify if you wnat to force running the detection if has_Detected is True.
        """
        if self.has_detected and not force:
            logger.warning("Detection already ran.")
            return

        if vstype is None:
            vstype = self.vstype
        if method is None:
            method = self.volume_detector

        if method == 'auto':
            method = VolumeSystem._determine_auto_detection_method()

        if vstype == 'lvm':
            for v in self._detect_lvm_volumes(
                    self.parent.info.get('volume_group')):
                yield v
        elif vstype == 'vss':
            for v in self._detect_vss_volumes(self.parent._paths['vss']):
                yield v
        elif method == 'single':  # dummy method for Disk
            for v in self._detect_single_volume():
                yield v
        elif method == 'mmls':
            for v in self._detect_mmls_volumes(vstype):
                yield v
        elif method == 'parted':
            for v in self._detect_parted_volumes(vstype):
                yield v
        elif method == 'pytsk3':
            for v in self._detect_pytsk3_volumes(vstype):
                yield v
        else:
            logger.error("No viable detection method found")
            raise ArgumentError("No viable detection method found")

        self.has_detected = True
예제 #4
0
    def mount(self):
        """Mounts the base image on a temporary location using the mount method stored in :attr:`method`. If mounting
        was successful, :attr:`mountpoint` is set to the temporary mountpoint.

        If :attr:`read_write` is enabled, a temporary read-write cache is also created and stored in :attr:`rwpath`.

        :return: whether the mounting was successful
        :rtype: bool
        """

        if self.parser.casename:
            self.mountpoint = tempfile.mkdtemp(prefix='image_mounter_',
                                               suffix='_' +
                                               self.parser.casename)
        else:
            self.mountpoint = tempfile.mkdtemp(prefix='image_mounter_')

        if self.read_write:
            self.rwpath = tempfile.mkstemp(prefix="image_mounter_rw_cache_")[1]

        disk_type = self.get_disk_type()
        methods = self._get_mount_methods(disk_type)

        cmds = []
        for method in methods:
            if method == 'avfs':  # avfs does not participate in the fallback stuff, unfortunately
                self._mount_avfs()
                self.disk_mounter = method
                self.was_mounted = True
                self.is_mounted = True
                return

            elif method == 'dummy':
                os.rmdir(self.mountpoint)
                self.mountpoint = ""
                logger.debug("Raw path to dummy is {}".format(
                    self.get_raw_path()))
                self.disk_mounter = method
                self.was_mounted = True
                self.is_mounted = True
                return

            elif method == 'xmount':
                cmds.append([
                    'xmount', '--in', 'ewf' if disk_type == 'encase' else 'dd'
                ])
                if self.read_write:
                    cmds[-1].extend(['--rw', self.rwpath])
                cmds[-1].extend(
                    self.paths)  # specify all paths, xmount needs this :(
                cmds[-1].append(self.mountpoint)

            elif method == 'affuse':
                cmds.extend([[
                    'affuse', '-o', 'allow_other', self.paths[0],
                    self.mountpoint
                ], ['affuse', self.paths[0], self.mountpoint]])

            elif method == 'ewfmount':
                cmds.extend([[
                    'ewfmount', '-X', 'allow_other', self.paths[0],
                    self.mountpoint
                ], ['ewfmount', self.paths[0], self.mountpoint]])

            elif method == 'vmware-mount':
                cmds.append([
                    'vmware-mount', '-r', '-f', self.paths[0], self.mountpoint
                ])

            elif method == 'nbd':
                _util.check_output_(['modprobe', 'nbd',
                                     'max_part=63'])  # Load nbd driver
                try:
                    self._paths['nbd'] = _util.get_free_nbd_device(
                    )  # Get free nbd device
                except NoNetworkBlockAvailableError:
                    logger.warning("No free network block device found.",
                                   exc_info=True)
                    raise
                cmds.extend([[
                    'qemu-nbd', '--read-only', '-c', self._paths['nbd'],
                    self.paths[0]
                ]])

            else:
                raise ArgumentError("Unknown mount method {0}".format(
                    self.disk_mounter))

        for cmd in cmds:
            # noinspection PyBroadException
            try:
                _util.check_call_(cmd, stdout=subprocess.PIPE)
                # mounting does not seem to be instant, add a timer here
                time.sleep(.1)
            except Exception:
                logger.warning(
                    'Could not mount {0}, trying other method'.format(
                        self.paths[0]),
                    exc_info=True)
                continue
            else:
                raw_path = self.get_raw_path()
                logger.debug("Raw path to disk is {}".format(raw_path))
                self.disk_mounter = cmd[0]

                if raw_path is None:
                    raise MountpointEmptyError()
                self.was_mounted = True
                self.is_mounted = True
                return

        logger.error('Unable to mount {0}'.format(self.paths[0]))
        os.rmdir(self.mountpoint)
        self.mountpoint = ""
        raise MountError()
예제 #5
0
    def mount(self, volume):
        """Command that is an alternative to the :func:`mount` command that opens a LUKS container. The opened volume is
        added to the subvolume set of this volume. Requires the user to enter the key manually.

        TODO: add support for :attr:`keys`

        :return: the Volume contained in the LUKS container, or None on failure.
        :raises NoLoopbackAvailableError: when no free loopback could be found
        :raises IncorrectFilesystemError: when this is not a LUKS volume
        :raises SubsystemError: when the underlying command fails
        """

        # Open a loopback device
        volume._find_loopback()

        # Check if this is a LUKS device
        # noinspection PyBroadException
        try:
            _util.check_call_(["cryptsetup", "isLuks", volume.loopback],
                              stderr=subprocess.STDOUT)
            # ret = 0 if isLuks
        except Exception:
            logger.warning("Not a LUKS volume")
            # clean the loopback device, we want this method to be clean as possible
            # noinspection PyBroadException
            try:
                volume._free_loopback()
            except Exception:
                pass
            raise IncorrectFilesystemError()

        try:
            extra_args = []
            key = None
            if volume.key:
                t, v = volume.key.split(':', 1)
                if t == 'p':  # passphrase
                    key = v
                elif t == 'f':  # key-file
                    extra_args = ['--key-file', v]
                elif t == 'm':  # master-key-file
                    extra_args = ['--master-key-file', v]
            else:
                logger.warning("No key material provided for %s", volume)
        except ValueError:
            logger.exception(
                "Invalid key material provided (%s) for %s. Expecting [arg]:[value]",
                volume.key, volume)
            volume._free_loopback()
            raise ArgumentError()

        # Open the LUKS container
        volume._paths['luks'] = 'image_mounter_luks_' + str(
            random.randint(10000, 99999))

        # noinspection PyBroadException
        try:
            cmd = [
                "cryptsetup", "luksOpen", volume.loopback,
                volume._paths['luks']
            ]
            cmd.extend(extra_args)
            if not volume.disk.read_write:
                cmd.insert(1, '-r')

            if key is not None:
                logger.debug('$ {0}'.format(' '.join(cmd)))
                # for py 3.2+, we could have used input=, but that doesn't exist in py2.7.
                p = subprocess.Popen(cmd,
                                     stdin=subprocess.PIPE,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE)
                p.communicate(key.encode("utf-8"))
                p.wait()
                retcode = p.poll()
                if retcode:
                    raise KeyInvalidError()
            else:
                _util.check_call_(cmd)
        except ImageMounterError:
            del volume._paths['luks']
            volume._free_loopback()
            raise
        except Exception as e:
            del volume._paths['luks']
            volume._free_loopback()
            raise SubsystemError(e)

        size = None
        # noinspection PyBroadException
        try:
            result = _util.check_output_(
                ["cryptsetup", "status", volume._paths['luks']])
            for l in result.splitlines():
                if "size:" in l and "key" not in l:
                    size = int(
                        l.replace("size:", "").replace(
                            "sectors", "").strip()) * volume.disk.block_size
        except Exception:
            pass

        container = volume.volumes._make_single_subvolume(flag='alloc',
                                                          offset=0,
                                                          size=size)
        container.info['fsdescription'] = 'LUKS Volume'

        return container