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
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
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
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()
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