def testGetCoreStorageStateEnabled(self): self.mox.StubOutWithMock(util, 'GetPlistFromExec') pl = plistlib.readPlistFromString(CORE_STORAGE_PLIST_LIST_ENABLED) pl2 = plistlib.readPlistFromString(CORE_STORAGE_PLIST_LVF_INFO_ENABLED) util.GetPlistFromExec(mox.In(DISKUTIL)).AndReturn(pl) util.GetPlistFromExec(mox.In(DISKUTIL)).AndReturn(pl2) self.mox.ReplayAll() self.assertEquals(corestorage.GetState(), corestorage.State.enabled) self.mox.VerifyAll()
def GetStateAndVolumeIds(): """Determine the state of core storage and the volume IDs (if any). In the case that core storage is enabled, it is required that every present volume is encrypted, to return "encrypted" status (i.e. the entire drive is encrypted, for all present drives). Otherwise only "enabled" status is returned. Returns: tuple: (State, [list; str encrypted UUIDs], [list; str unencrypted UUIDs]) Raises: Error: there was a problem getting the corestorage list, or family info. """ try: cs_plist = util.GetPlistFromExec( (DISKUTIL, 'corestorage', 'list', '-plist')) except util.ExecError: logging.exception( 'GetStateAndVolumeIds() failed to get corestorage list.') raise Error state = State.none volume_ids = [] encrypted_volume_ids = [] groups = cs_plist.get('CoreStorageLogicalVolumeGroups', []) if groups: state = State.enabled for group in groups: for family in group.get('CoreStorageLogicalVolumeFamilies', []): family_id = family['CoreStorageUUID'] if not util.UuidIsValid(family_id): continue try: info_plist = util.GetPlistFromExec( (DISKUTIL, 'corestorage', 'info', '-plist', family_id)) except util.ExecError: logging.exception( 'GetStateAndVolumeIds() failed to get corestorage family info: %s', family_id) raise Error enc = info_plist.get( 'CoreStorageLogicalVolumeFamilyEncryptionType', '') for volume in family['CoreStorageLogicalVolumes']: volume_id = volume['CoreStorageUUID'] if enc == 'AES-XTS': encrypted_volume_ids.append(volume_id) else: volume_ids.append(volume_id) if encrypted_volume_ids and not volume_ids: state = State.encrypted return state, encrypted_volume_ids, volume_ids
def testGetCoreStorageStateFailed(self): self.mox.StubOutWithMock(util, 'GetPlistFromExec') pl = plistlib.readPlistFromString(CORE_STORAGE_PLIST_LIST_ENABLED) pl2 = plistlib.readPlistFromString(CORE_STORAGE_PLIST_LVF_INFO_ENABLED) pl3 = plistlib.readPlistFromString(CORE_STORAGE_PLIST_LV_INFO) pl3['CoreStorageLogicalVolumeConversionState'] = 'Failed' util.GetPlistFromExec(mox.In(DISKUTIL)).AndReturn(pl) util.GetPlistFromExec(mox.In(DISKUTIL)).AndReturn(pl2) util.GetPlistFromExec(mox.In(DISKUTIL)).AndReturn(pl3) self.mox.ReplayAll() self.assertEquals(corestorage.GetState(), corestorage.State.FAILED) self.mox.VerifyAll()
def testGetRecoveryPartition(self): self.mox.StubOutWithMock(util, 'GetPlistFromExec') pl = plistlib.readPlistFromString(DISKUTIL_LIST_PLIST) util.GetPlistFromExec(mox.In(DISKUTIL)).AndReturn(pl) self.mox.ReplayAll() self.assertEquals(corestorage.GetRecoveryPartition(), '/dev/disk0s3') self.mox.VerifyAll()
def testGetRecoveryPartitionWhenDiskutilFail(self): self.mox.StubOutWithMock(util, 'GetPlistFromExec') util.GetPlistFromExec(mox.In(DISKUTIL)).AndRaise( corestorage.util.ExecError) self.mox.ReplayAll() self.assertEquals(corestorage.GetRecoveryPartition(), None) self.mox.VerifyAll()
def testGetCoreStorageStateNone(self): self.mox.StubOutWithMock(util, 'GetPlistFromExec') pl = plistlib.readPlistFromString(CORE_STORAGE_PLIST_LIST_EMPTY) util.GetPlistFromExec(mox.In(DISKUTIL)).AndReturn(pl) self.mox.ReplayAll() self.assertEquals(corestorage.GetState(), corestorage.State.NONE) self.mox.VerifyAll()
def UpdateEscrowPassphrase(password): """Change the FileVault2 recovery key. Under CoreStorage, the current recovery key could be used as the password to fdesetup, but this does not work with APFS. Since the user password works in both cases and we already require it for sudo, we simply default to that. Args: password: the user password. Returns: The new recovery key. """ command = ('sudo', '-k', '-S', FDESETUP_PATH, 'changerecovery', '-personal', '-outputplist', '-inputplist') stdin = plistlib.writePlistToString({'Password': password}) if os.getuid() != 0: stdin = '%s\n%s' % (password, stdin) try: result_plist = util.GetPlistFromExec(command, stdin=stdin) except util.ExecError as e: logging.error(e.stderr) raise Error(e.message) recovery_key = result_plist.get('RecoveryKey') return recovery_key
def GetVolumeSize(uuid, readable=True): """Return the size of the volume with the given UUID. Args: uuid: str, ID of the volume in question readable: Optional boolean, default true: return a human-readable string when true, otherwise int number of bytes. Returns: str or int, see "readable" arg. Raises: Error: there was a problem getting volume info. ValueError: The UUID is formatted incorrectly. """ if not util.UuidIsValid(uuid): raise ValueError('Invalid UUID: ' + uuid) try: plist = util.GetPlistFromExec( (DISKUTIL, 'corestorage', 'info', '-plist', uuid)) except util.ExecError: logging.exception('GetVolumeSize() failed to get volume info: %s', uuid) raise Error num_bytes = plist['CoreStorageLogicalVolumeSize'] if readable: return '%.2f GiB' % (num_bytes / (1 << 30)) else: return num_bytes
def GetFilesystemType(): try: plist = util.GetPlistFromExec((DISKUTIL, 'info', '-plist', '/')) except util.ExecError: logging.error('FilesystemType lookup failed. Defaulting to hfs') return 'hfs' fstype = plist.get('FilesystemType', None) return fstype
def GetPrimaryVolumeUUID(self): """Returns string UUID of the boot volume (/), or None if error.""" cmd = [DISKUTIL, 'info', '-plist', '/'] try: plist = util.GetPlistFromExec(cmd) except util.ExecError: return None return plist.get('VolumeUUID')
def IsBootVolumeEncrypted(): """Returns True if the boot volume (/) is encrypted, False otherwise.""" try: csinfo_plist = util.GetPlistFromExec( (DISKUTIL, 'cs', 'info', '-plist', '/')) except util.ExecError: return False # Non-zero return means / volume isn't a CoreStorage volume. lvf_uuid = csinfo_plist.get('MemberOfCoreStorageLogicalVolumeFamily') if lvf_uuid: try: lvf_info_plist = util.GetPlistFromExec( (DISKUTIL, 'cs', 'info', '-plist', lvf_uuid)) except util.ExecError: return False # Couldn't get info on Logical Volume Family UUID. return lvf_info_plist.get( 'CoreStorageLogicalVolumeFamilyEncryptionType') == 'AES-XTS' return False
def testGetPlistFromExec(self): self.mox.StubOutWithMock(util, 'Exec') self.mox.StubOutWithMock(util.plistlib, 'readPlistFromString') util.Exec('cmd', stdin='stdin').AndReturn((0, 'stdout', 'stderr')) util.plistlib.readPlistFromString('stdout').AndReturn('plist') self.mox.ReplayAll() self.assertEqual('plist', util.GetPlistFromExec('cmd', stdin='stdin')) self.mox.VerifyAll()
def EnableEncryption(self): """Enable full disk encryption. Returns: A 2-tuple containing the encrypted volume's UUID, and the recovery token. """ try: result_plist = util.GetPlistFromExec(self._GetCommand(), stdin=self._GetStdin()) except util.ExecError as e: self._HandleFailure(e) return self._HandleResult(result_plist)
def UpdateEscrowPassphrase(password, passphrase): """Change recovery passphrase.""" command = ('sudo', '-k', '-S', FDESETUP_PATH, 'changerecovery', '-personal', '-outputplist', '-inputplist') stdin = plistlib.writePlistToString({'Password': passphrase}) if os.getuid() != 0: stdin = '%s\n%s' % (password, stdin) try: result_plist = util.GetPlistFromExec(command, stdin=stdin) except util.ExecError as e: logging.error(e.stderr) raise Error(e.message) recovery_key = result_plist.get('RecoveryKey') return recovery_key
def _GetAPFSVolumesAndContainers(self, uuid=None, disk=None): """Returns a tuple of volumes and containers from apfs list -plist. Args: uuid: str, optional, APFSVolume uuid. If no uuid is provided, this function returns a diskutil apfs list plist.. disk: str, optional, name of the disk to look at. Returns: A dict of diskutil cs info/list -plist output. Raises: Error: The given uuid was invalid or there was a diskutil error. """ if uuid: if not util.UuidIsValid(uuid): raise storage.Error if disk or not self._containers: cmd = [DISKUTIL, 'apfs', 'list', '-plist'] if disk: cmd.append(disk) try: plist = util.GetPlistFromExec(cmd) except util.ExecError: return ([], []) containers = plist.get('Containers', []) if containers: volumes = containers[0].get('Volumes', []) else: volumes = [] if not disk: # save the full list for future lookups self._containers = containers self._volumes = volumes else: containers = self._containers volumes = self._volumes if uuid: uuid_volumes = [] for volume in volumes: if volume.get('APFSVolumeUUID') == uuid: uuid_volumes.append(volume) return (uuid_volumes, containers) else: return (volumes, containers)
def GetRecoveryPartition(): """Determine the location of the recovery partition. Returns: str, like "/dev/disk0s3" where the recovery partition is, OR None, if no recovery partition exists or cannot be detected. """ try: disklist_plist = util.GetPlistFromExec((DISKUTIL, 'list', '-plist')) except util.ExecError: logging.exception( 'GetRecoveryPartition() failed to get partition list.') return alldisks = disklist_plist.get('AllDisksAndPartitions', []) for disk in alldisks: partitions = disk.get('Partitions', []) for partition in partitions: if partition.get('VolumeName') == 'Recovery HD': return '/dev/%s' % partition['DeviceIdentifier']
def GetCoreStoragePlist(uuid=None): """Returns a dict of diskutil cs info plist for a given str CoreStorage uuid. Args: uuid: str, optional, CoreStorage uuid. If no uuid is provided, this function returns a diskutil cs list plist.. Returns: A dict of diskutil cs info/list -plist output. Raises: Error: The given uuid was invalid or there was a diskutil error. """ if uuid: if not util.UuidIsValid(uuid): raise Error cmd = [DISKUTIL, 'corestorage', 'info', '-plist', uuid] else: cmd = [DISKUTIL, 'corestorage', 'list', '-plist'] try: return util.GetPlistFromExec(cmd) except util.ExecError: raise Error
"""Base class for all errors raised by options.""" def ApplyEncryption(fvclient, username, password): """Turn encryption on.""" # Supply entropy to the system before csfde uses /dev/random. try: entropy = util.RetrieveEntropy() util.SupplyEntropy(entropy) except util.EntropyError, e: raise Error('Entropy operations failed: %s' % str(e)) root_disk = util.GetRootDisk() try: csfde_plist = util.GetPlistFromExec( (CSFDE_PATH, root_disk, username, '-'), stdin=password) except util.ExecError, e: if e.returncode == CSFDE_RETURN_AUTH_FAIL: raise InputError( 'Authentication problem with local account. Drive NOT encrypted.' ) elif e.returncode != 0: logging.error('csfde failed with stderr:\n%s', e.stderr) raise Error('Problem running csfde (exit status = %d)' % e.returncode) else: logging.exception('Problem running csfde.') raise Error('Problem running csfde', e) fvclient.SetOwner(username) return GetEncryptionResults(csfde_plist)
def testGetPlistFromExec(self, exec_mock, read_plist_mock): self.assertEqual('plist', util.GetPlistFromExec('cmd', stdin='stdin')) exec_mock.assert_called_once_with('cmd', stdin='stdin') read_plist_mock.assert_called_once_with('stdout')