diff options
Diffstat (limited to 'src/Core')
39 files changed, 5300 insertions, 0 deletions
diff --git a/src/Core/Core.h b/src/Core/Core.h new file mode 100644 index 00000000..37bbb986 --- /dev/null +++ b/src/Core/Core.h @@ -0,0 +1,20 @@ +/* + Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_Core +#define TC_HEADER_Core_Core + +#include "CoreBase.h" + +namespace TrueCrypt +{ + extern auto_ptr <CoreBase> Core; + extern auto_ptr <CoreBase> CoreDirect; +} + +#endif // TC_HEADER_Core_Core diff --git a/src/Core/Core.make b/src/Core/Core.make new file mode 100644 index 00000000..c4a5ccf2 --- /dev/null +++ b/src/Core/Core.make @@ -0,0 +1,27 @@ +# +# Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. +# +# Governed by the TrueCrypt License 3.0 the full text of which is contained in +# the file License.txt included in TrueCrypt binary and source code distribution +# packages. +# + +OBJS := +OBJS += CoreBase.o +OBJS += CoreException.o +OBJS += FatFormatter.o +OBJS += HostDevice.o +OBJS += MountOptions.o +OBJS += RandomNumberGenerator.o +OBJS += VolumeCreator.o +OBJS += Unix/CoreService.o +OBJS += Unix/CoreServiceRequest.o +OBJS += Unix/CoreServiceResponse.o +OBJS += Unix/CoreUnix.o +OBJS += Unix/$(PLATFORM)/Core$(PLATFORM).o +OBJS += Unix/$(PLATFORM)/Core$(PLATFORM).o +ifeq "$(PLATFORM)" "MacOSX" +OBJS += Unix/FreeBSD/CoreFreeBSD.o +endif + +include $(BUILD_INC)/Makefile.inc diff --git a/src/Core/CoreBase.cpp b/src/Core/CoreBase.cpp new file mode 100644 index 00000000..b615b7ff --- /dev/null +++ b/src/Core/CoreBase.cpp @@ -0,0 +1,279 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include <set> + +#include "CoreBase.h" +#include "RandomNumberGenerator.h" +#include "Volume/Volume.h" + +namespace TrueCrypt +{ + CoreBase::CoreBase () + : DeviceChangeInProgress (false) + { + } + + CoreBase::~CoreBase () + { + } + + void CoreBase::ChangePassword (shared_ptr <Volume> openVolume, shared_ptr <VolumePassword> newPassword, shared_ptr <KeyfileList> newKeyfiles, shared_ptr <Pkcs5Kdf> newPkcs5Kdf) const + { + if ((!newPassword || newPassword->Size() < 1) && (!newKeyfiles || newKeyfiles->empty())) + throw PasswordEmpty (SRC_POS); + + if (!newPkcs5Kdf) + newPkcs5Kdf = openVolume->GetPkcs5Kdf(); + + if ((openVolume->GetHeader()->GetFlags() & TC_HEADER_FLAG_ENCRYPTED_SYSTEM) != 0 + && openVolume->GetType() == VolumeType::Hidden + && openVolume->GetPath().IsDevice()) + { + throw EncryptedSystemRequired (SRC_POS); + } + + RandomNumberGenerator::SetHash (newPkcs5Kdf->GetHash()); + + SecureBuffer newSalt (openVolume->GetSaltSize()); + SecureBuffer newHeaderKey (VolumeHeader::GetLargestSerializedKeySize()); + + shared_ptr <VolumePassword> password (Keyfile::ApplyListToPassword (newKeyfiles, newPassword)); + + bool backupHeader = false; + while (true) + { + for (int i = 1; i <= SecureWipePassCount; i++) + { + if (i == SecureWipePassCount) + RandomNumberGenerator::GetData (newSalt); + else + RandomNumberGenerator::GetDataFast (newSalt); + + newPkcs5Kdf->DeriveKey (newHeaderKey, *password, newSalt); + + openVolume->ReEncryptHeader (backupHeader, newSalt, newHeaderKey, newPkcs5Kdf); + openVolume->GetFile()->Flush(); + } + + if (!openVolume->GetLayout()->HasBackupHeader() || backupHeader) + break; + + backupHeader = true; + } + } + + void CoreBase::ChangePassword (shared_ptr <VolumePath> volumePath, bool preserveTimestamps, shared_ptr <VolumePassword> password, shared_ptr <KeyfileList> keyfiles, shared_ptr <VolumePassword> newPassword, shared_ptr <KeyfileList> newKeyfiles, shared_ptr <Pkcs5Kdf> newPkcs5Kdf) const + { + shared_ptr <Volume> volume = OpenVolume (volumePath, preserveTimestamps, password, keyfiles); + ChangePassword (volume, newPassword, newKeyfiles, newPkcs5Kdf); + } + + void CoreBase::CoalesceSlotNumberAndMountPoint (MountOptions &options) const + { + if (options.SlotNumber < GetFirstSlotNumber()) + { + if (options.MountPoint && !options.MountPoint->IsEmpty()) + options.SlotNumber = MountPointToSlotNumber (*options.MountPoint); + else + options.SlotNumber = GetFirstFreeSlotNumber(); + } + + if (!IsSlotNumberAvailable (options.SlotNumber)) +#ifdef TC_WINDOWS + throw DriveLetterUnavailable (SRC_POS); +#else + throw VolumeSlotUnavailable (SRC_POS); +#endif + if (!options.NoFilesystem && (!options.MountPoint || options.MountPoint->IsEmpty())) + options.MountPoint.reset (new DirectoryPath (SlotNumberToMountPoint (options.SlotNumber))); + } + + void CoreBase::CreateKeyfile (const FilePath &keyfilePath) const + { + SecureBuffer keyfileBuffer (VolumePassword::MaxSize); + RandomNumberGenerator::GetData (keyfileBuffer); + + File keyfile; + keyfile.Open (keyfilePath, File::CreateWrite); + keyfile.Write (keyfileBuffer); + } + + VolumeSlotNumber CoreBase::GetFirstFreeSlotNumber (VolumeSlotNumber startFrom) const + { + if (startFrom < GetFirstSlotNumber()) + startFrom = GetFirstSlotNumber(); + + set <VolumeSlotNumber> usedSlotNumbers; + + foreach_ref (const VolumeInfo &volume, GetMountedVolumes()) + usedSlotNumbers.insert (volume.SlotNumber); + + for (VolumeSlotNumber slotNumber = startFrom; slotNumber <= GetLastSlotNumber(); ++slotNumber) + { + if (usedSlotNumbers.find (slotNumber) == usedSlotNumbers.end() + && IsMountPointAvailable (SlotNumberToMountPoint (slotNumber))) + return slotNumber; + } +#ifdef TC_WINDOWS + throw DriveLetterUnavailable (SRC_POS); +#else + throw VolumeSlotUnavailable (SRC_POS); +#endif + } + + uint64 CoreBase::GetMaxHiddenVolumeSize (shared_ptr <Volume> outerVolume) const + { + uint32 sectorSize = outerVolume->GetSectorSize(); + + SecureBuffer bootSectorBuffer (sectorSize); + outerVolume->ReadSectors (bootSectorBuffer, 0); + + int fatType; + byte *bootSector = bootSectorBuffer.Ptr(); + + if (memcmp (bootSector + 54, "FAT12", 5) == 0) + fatType = 12; + else if (memcmp (bootSector + 54, "FAT16", 5) == 0) + fatType = 16; + else if (memcmp (bootSector + 82, "FAT32", 5) == 0) + fatType = 32; + else + throw ParameterIncorrect (SRC_POS); + + uint32 clusterSize = bootSector[13] * sectorSize; + uint32 reservedSectorCount = Endian::Little (*(uint16 *) (bootSector + 14)); + uint32 fatCount = bootSector[16]; + + uint64 fatSectorCount; + if (fatType == 32) + fatSectorCount = Endian::Little (*(uint32 *) (bootSector + 36)); + else + fatSectorCount = Endian::Little (*(uint16 *) (bootSector + 22)); + uint64 fatSize = fatSectorCount * sectorSize; + + uint64 fatStartOffset = reservedSectorCount * sectorSize; + uint64 dataAreaOffset = reservedSectorCount * sectorSize + fatSize * fatCount; + + if (fatType < 32) + dataAreaOffset += Endian::Little (*(uint16 *) (bootSector + 17)) * 32; + + SecureBuffer sector (sectorSize); + + // Find last used cluster + for (uint64 readOffset = fatStartOffset + fatSize - sectorSize; + readOffset >= fatStartOffset; + readOffset -= sectorSize) + { + outerVolume->ReadSectors (sector, readOffset); + + for (int offset = sectorSize - 4; offset >= 0; offset -= 4) + { + if (*(uint32 *) (sector.Ptr() + offset)) + { + uint64 clusterNumber = readOffset - fatStartOffset + offset; + + if (fatType == 12) + clusterNumber = (clusterNumber * 8) / 12; + else if (fatType == 16) + clusterNumber /= 2; + else if (fatType == 32) + clusterNumber /= 4; + + uint64 maxSize = outerVolume->GetSize() - dataAreaOffset; + + // Some FAT entries may span over sector boundaries + if (maxSize >= clusterSize) + maxSize -= clusterSize; + + uint64 clusterOffset = clusterNumber * clusterSize; + if (maxSize < clusterOffset) + return 0; + + return maxSize - clusterOffset; + } + } + } + + return 0; + } + + shared_ptr <VolumeInfo> CoreBase::GetMountedVolume (const VolumePath &volumePath) const + { + VolumeInfoList volumes = GetMountedVolumes (volumePath); + if (volumes.empty()) + return shared_ptr <VolumeInfo> (); + else + return volumes.front(); + } + + shared_ptr <VolumeInfo> CoreBase::GetMountedVolume (VolumeSlotNumber slot) const + { + foreach (shared_ptr <VolumeInfo> volume, GetMountedVolumes()) + { + if (volume->SlotNumber == slot) + return volume; + } + + return shared_ptr <VolumeInfo> (); + } + + bool CoreBase::IsSlotNumberAvailable (VolumeSlotNumber slotNumber) const + { + if (!IsMountPointAvailable (SlotNumberToMountPoint (slotNumber))) + return false; + + foreach_ref (const VolumeInfo &volume, GetMountedVolumes()) + { + if (volume.SlotNumber == slotNumber) + return false; + } + + return true; + } + + bool CoreBase::IsVolumeMounted (const VolumePath &volumePath) const + { + return GetMountedVolume (volumePath); + } + + shared_ptr <Volume> CoreBase::OpenVolume (shared_ptr <VolumePath> volumePath, bool preserveTimestamps, shared_ptr <VolumePassword> password, shared_ptr <KeyfileList> keyfiles, VolumeProtection::Enum protection, shared_ptr <VolumePassword> protectionPassword, shared_ptr <KeyfileList> protectionKeyfiles, bool sharedAccessAllowed, VolumeType::Enum volumeType, bool useBackupHeaders, bool partitionInSystemEncryptionScope) const + { + make_shared_auto (Volume, volume); + volume->Open (*volumePath, preserveTimestamps, password, keyfiles, protection, protectionPassword, protectionKeyfiles, sharedAccessAllowed, volumeType, useBackupHeaders, partitionInSystemEncryptionScope); + return volume; + } + + void CoreBase::RandomizeEncryptionAlgorithmKey (shared_ptr <EncryptionAlgorithm> encryptionAlgorithm) const + { + SecureBuffer eaKey (encryptionAlgorithm->GetKeySize()); + RandomNumberGenerator::GetData (eaKey); + encryptionAlgorithm->SetKey (eaKey); + + SecureBuffer modeKey (encryptionAlgorithm->GetMode()->GetKeySize()); + RandomNumberGenerator::GetData (modeKey); + encryptionAlgorithm->GetMode()->SetKey (modeKey); + } + + void CoreBase::ReEncryptVolumeHeaderWithNewSalt (const BufferPtr &newHeaderBuffer, shared_ptr <VolumeHeader> header, shared_ptr <VolumePassword> password, shared_ptr <KeyfileList> keyfiles) const + { + shared_ptr <Pkcs5Kdf> pkcs5Kdf = header->GetPkcs5Kdf(); + + RandomNumberGenerator::SetHash (pkcs5Kdf->GetHash()); + + SecureBuffer newSalt (header->GetSaltSize()); + SecureBuffer newHeaderKey (VolumeHeader::GetLargestSerializedKeySize()); + + shared_ptr <VolumePassword> passwordKey (Keyfile::ApplyListToPassword (keyfiles, password)); + + RandomNumberGenerator::GetData (newSalt); + pkcs5Kdf->DeriveKey (newHeaderKey, *passwordKey, newSalt); + + header->EncryptNew (newHeaderBuffer, newSalt, newHeaderKey, pkcs5Kdf); + } +} diff --git a/src/Core/CoreBase.h b/src/Core/CoreBase.h new file mode 100644 index 00000000..d99420ab --- /dev/null +++ b/src/Core/CoreBase.h @@ -0,0 +1,99 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_CoreBase +#define TC_HEADER_Core_CoreBase + +#include "Platform/Platform.h" +#include "Platform/Functor.h" +#include "Platform/User.h" +#include "Common/Crypto.h" +#include "Volume/Keyfile.h" +#include "Volume/VolumeInfo.h" +#include "Volume/Volume.h" +#include "Volume/VolumePassword.h" +#include "CoreException.h" +#include "HostDevice.h" +#include "MountOptions.h" + +namespace TrueCrypt +{ + class CoreBase + { + public: + virtual ~CoreBase (); + + virtual void ChangePassword (shared_ptr <Volume> openVolume, shared_ptr <VolumePassword> newPassword, shared_ptr <KeyfileList> newKeyfiles, shared_ptr <Pkcs5Kdf> newPkcs5Kdf = shared_ptr <Pkcs5Kdf> ()) const; + virtual void ChangePassword (shared_ptr <VolumePath> volumePath, bool preserveTimestamps, shared_ptr <VolumePassword> password, shared_ptr <KeyfileList> keyfiles, shared_ptr <VolumePassword> newPassword, shared_ptr <KeyfileList> newKeyfiles, shared_ptr <Pkcs5Kdf> newPkcs5Kdf = shared_ptr <Pkcs5Kdf> ()) const; + virtual void CheckFilesystem (shared_ptr <VolumeInfo> mountedVolume, bool repair = false) const = 0; + virtual void CoalesceSlotNumberAndMountPoint (MountOptions &options) const; + virtual void CreateKeyfile (const FilePath &keyfilePath) const; + virtual void DismountFilesystem (const DirectoryPath &mountPoint, bool force) const = 0; + virtual shared_ptr <VolumeInfo> DismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles = false, bool syncVolumeInfo = false) = 0; + virtual bool FilesystemSupportsLargeFiles (const FilePath &filePath) const = 0; + virtual DirectoryPath GetDeviceMountPoint (const DevicePath &devicePath) const = 0; + virtual uint32 GetDeviceSectorSize (const DevicePath &devicePath) const = 0; + virtual uint64 GetDeviceSize (const DevicePath &devicePath) const = 0; + virtual VolumeSlotNumber GetFirstFreeSlotNumber (VolumeSlotNumber startFrom = 0) const; + virtual VolumeSlotNumber GetFirstSlotNumber () const { return 1; } + virtual VolumeSlotNumber GetLastSlotNumber () const { return 64; } + virtual HostDeviceList GetHostDevices (bool pathListOnly = false) const = 0; + virtual FilePath GetApplicationExecutablePath () const { return ApplicationExecutablePath; } + virtual uint64 GetMaxHiddenVolumeSize (shared_ptr <Volume> outerVolume) const; + virtual int GetOSMajorVersion () const = 0; + virtual int GetOSMinorVersion () const = 0; + virtual shared_ptr <VolumeInfo> GetMountedVolume (const VolumePath &volumePath) const; + virtual shared_ptr <VolumeInfo> GetMountedVolume (VolumeSlotNumber slot) const; + virtual VolumeInfoList GetMountedVolumes (const VolumePath &volumePath = VolumePath()) const = 0; + virtual bool HasAdminPrivileges () const = 0; + virtual void Init () { } + virtual bool IsDeviceChangeInProgress () const { return DeviceChangeInProgress; } + virtual bool IsDevicePresent (const DevicePath &device) const = 0; + virtual bool IsInPortableMode () const = 0; + virtual bool IsMountPointAvailable (const DirectoryPath &mountPoint) const = 0; + virtual bool IsOSVersion (int major, int minor) const = 0; + virtual bool IsOSVersionLower (int major, int minor) const = 0; + virtual bool IsPasswordCacheEmpty () const = 0; + virtual bool IsSlotNumberAvailable (VolumeSlotNumber slotNumber) const; + virtual bool IsSlotNumberValid (VolumeSlotNumber slotNumber) const { return slotNumber >= GetFirstSlotNumber() && slotNumber <= GetLastSlotNumber(); } + virtual bool IsVolumeMounted (const VolumePath &volumePath) const; + virtual VolumeSlotNumber MountPointToSlotNumber (const DirectoryPath &mountPoint) const = 0; + virtual shared_ptr <VolumeInfo> MountVolume (MountOptions &options) = 0; + virtual shared_ptr <Volume> OpenVolume (shared_ptr <VolumePath> volumePath, bool preserveTimestamps, shared_ptr <VolumePassword> password, shared_ptr <KeyfileList> keyfiles, VolumeProtection::Enum protection = VolumeProtection::None, shared_ptr <VolumePassword> protectionPassword = shared_ptr <VolumePassword> (), shared_ptr <KeyfileList> protectionKeyfiles = shared_ptr <KeyfileList> (), bool sharedAccessAllowed = false, VolumeType::Enum volumeType = VolumeType::Unknown, bool useBackupHeaders = false, bool partitionInSystemEncryptionScope = false) const; + virtual void RandomizeEncryptionAlgorithmKey (shared_ptr <EncryptionAlgorithm> encryptionAlgorithm) const; + virtual void ReEncryptVolumeHeaderWithNewSalt (const BufferPtr &newHeaderBuffer, shared_ptr <VolumeHeader> header, shared_ptr <VolumePassword> password, shared_ptr <KeyfileList> keyfiles) const; + virtual void SetAdminPasswordCallback (shared_ptr <GetStringFunctor> functor) { } + virtual void SetApplicationExecutablePath (const FilePath &path) { ApplicationExecutablePath = path; } + virtual void SetFileOwner (const FilesystemPath &path, const UserId &owner) const = 0; + virtual DirectoryPath SlotNumberToMountPoint (VolumeSlotNumber slotNumber) const = 0; + virtual void WipePasswordCache () const = 0; + + Event VolumeDismountedEvent; + Event VolumeMountedEvent; + Event WarningEvent; + + protected: + CoreBase (); + + static const int SecureWipePassCount = PRAND_DISK_WIPE_PASSES; + bool DeviceChangeInProgress; + FilePath ApplicationExecutablePath; + + private: + CoreBase (const CoreBase &); + CoreBase &operator= (const CoreBase &); + }; + + struct VolumeEventArgs : EventArgs + { + VolumeEventArgs (shared_ptr <VolumeInfo> volume) : mVolume (volume) { } + shared_ptr <VolumeInfo> mVolume; + }; +} + +#endif // TC_HEADER_Core_CoreBase diff --git a/src/Core/CoreException.cpp b/src/Core/CoreException.cpp new file mode 100644 index 00000000..da939a8d --- /dev/null +++ b/src/Core/CoreException.cpp @@ -0,0 +1,29 @@ +/* + Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include "CoreException.h" +#include "Platform/SerializerFactory.h" + +namespace TrueCrypt +{ + void ElevationFailed::Deserialize (shared_ptr <Stream> stream) + { + ExecutedProcessFailed::Deserialize (stream); + } + + void ElevationFailed::Serialize (shared_ptr <Stream> stream) const + { + ExecutedProcessFailed::Serialize (stream); + } + +#define TC_EXCEPTION(TYPE) TC_SERIALIZER_FACTORY_ADD(TYPE) +#undef TC_EXCEPTION_NODECL +#define TC_EXCEPTION_NODECL(TYPE) TC_SERIALIZER_FACTORY_ADD(TYPE) + + TC_SERIALIZER_FACTORY_ADD_EXCEPTION_SET (CoreException); +} diff --git a/src/Core/CoreException.h b/src/Core/CoreException.h new file mode 100644 index 00000000..40ffbcea --- /dev/null +++ b/src/Core/CoreException.h @@ -0,0 +1,52 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_CoreException +#define TC_HEADER_Core_CoreException + +#include "Platform/Platform.h" + +namespace TrueCrypt +{ + struct ElevationFailed : public ExecutedProcessFailed + { + ElevationFailed () { } + ElevationFailed (const string &message, const string &command, int exitCode, const string &errorOutput) + : ExecutedProcessFailed (message, command, exitCode, errorOutput) { } + TC_SERIALIZABLE_EXCEPTION (ElevationFailed); + }; + + TC_EXCEPTION_DECL (RootDeviceUnavailable, SystemException); + +#define TC_EXCEPTION(NAME) TC_EXCEPTION_DECL(NAME,Exception) + +#undef TC_EXCEPTION_SET +#define TC_EXCEPTION_SET \ + TC_EXCEPTION_NODECL (ElevationFailed); \ + TC_EXCEPTION_NODECL (RootDeviceUnavailable); \ + TC_EXCEPTION (DriveLetterUnavailable); \ + TC_EXCEPTION (DriverError); \ + TC_EXCEPTION (EncryptedSystemRequired); \ + TC_EXCEPTION (HigherFuseVersionRequired); \ + TC_EXCEPTION (KernelCryptoServiceTestFailed); \ + TC_EXCEPTION (LoopDeviceSetupFailed); \ + TC_EXCEPTION (MountPointRequired); \ + TC_EXCEPTION (MountPointUnavailable); \ + TC_EXCEPTION (NoDriveLetterAvailable); \ + TC_EXCEPTION (TemporaryDirectoryFailure); \ + TC_EXCEPTION (UnsupportedSectorSizeHiddenVolumeProtection); \ + TC_EXCEPTION (UnsupportedSectorSizeNoKernelCrypto); \ + TC_EXCEPTION (VolumeAlreadyMounted); \ + TC_EXCEPTION (VolumeSlotUnavailable); + + TC_EXCEPTION_SET; + +#undef TC_EXCEPTION +} + +#endif // TC_HEADER_Core_CoreException diff --git a/src/Core/FatFormatter.cpp b/src/Core/FatFormatter.cpp new file mode 100644 index 00000000..ba69df61 --- /dev/null +++ b/src/Core/FatFormatter.cpp @@ -0,0 +1,384 @@ +/* + Legal Notice: Some portions of the source code contained in this file were + derived from the source code of Encryption for the Masses 2.02a, which is + Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License + Agreement for Encryption for the Masses'. Modifications and additions to + the original source code (contained in this file) and all other portions + of this file are Copyright (c) 2003-2010 TrueCrypt Developers Association + and are governed by the TrueCrypt License 3.0 the full text of which is + contained in the file License.txt included in TrueCrypt binary and source + code distribution packages. */ + +#include "Common/Tcdefs.h" +#include "Platform/Platform.h" +#include "Volume/VolumeHeader.h" +#include "FatFormatter.h" +#include "RandomNumberGenerator.h" + +namespace TrueCrypt +{ + struct fatparams + { + char volume_name[11]; + uint32 num_sectors; /* total number of sectors */ + uint32 cluster_count; /* number of clusters */ + uint32 size_root_dir; /* size of the root directory in bytes */ + uint32 size_fat; /* size of FAT */ + uint32 fats; + uint32 media; + uint32 cluster_size; + uint32 fat_length; + uint16 dir_entries; + uint16 sector_size; + uint32 hidden; + uint16 reserved; + uint16 sectors; + uint32 total_sect; + + uint16 heads; + uint16 secs_track; + + }; + + static void GetFatParams (fatparams * ft) + { + uint64 volumeSize = (uint64) ft->num_sectors * ft->sector_size; + unsigned int fatsecs; + + if(ft->cluster_size == 0) // 'Default' cluster size + { + uint32 clusterSize; + + // Determine optimal cluster size to minimize FAT size (mounting delay), maximize number of files, keep 4 KB alignment, etc. + if (volumeSize >= 2 * BYTES_PER_TB) + clusterSize = 256 * BYTES_PER_KB; + else if (volumeSize >= 512 * BYTES_PER_GB) + clusterSize = 128 * BYTES_PER_KB; + else if (volumeSize >= 128 * BYTES_PER_GB) + clusterSize = 64 * BYTES_PER_KB; + else if (volumeSize >= 64 * BYTES_PER_GB) + clusterSize = 32 * BYTES_PER_KB; + else if (volumeSize >= 32 * BYTES_PER_GB) + clusterSize = 16 * BYTES_PER_KB; + else if (volumeSize >= 16 * BYTES_PER_GB) + clusterSize = 8 * BYTES_PER_KB; + else if (volumeSize >= 512 * BYTES_PER_MB) + clusterSize = 4 * BYTES_PER_KB; + else if (volumeSize >= 256 * BYTES_PER_MB) + clusterSize = 2 * BYTES_PER_KB; + else if (volumeSize >= 1 * BYTES_PER_MB) + clusterSize = 1 * BYTES_PER_KB; + else + clusterSize = 512; + + ft->cluster_size = clusterSize / ft->sector_size; + + if (ft->cluster_size == 0) + ft->cluster_size = 1; + + if (ft->cluster_size * ft->sector_size > TC_MAX_FAT_CLUSTER_SIZE) + ft->cluster_size = TC_MAX_FAT_CLUSTER_SIZE / ft->sector_size; + + if (ft->cluster_size > 128) + ft->cluster_size = 128; + } + + if (volumeSize <= TC_MAX_FAT_CLUSTER_SIZE * 4) + ft->cluster_size = 1; + + // Geometry always set to SECTORS/1/1 + ft->secs_track = 1; + ft->heads = 1; + + ft->dir_entries = 512; + ft->fats = 2; + ft->media = 0xf8; + ft->hidden = 0; + + ft->size_root_dir = ft->dir_entries * 32; + + // FAT12 + ft->size_fat = 12; + ft->reserved = 2; + fatsecs = ft->num_sectors - (ft->size_root_dir + ft->sector_size - 1) / ft->sector_size - ft->reserved; + ft->cluster_count = (int) (((int64) fatsecs * ft->sector_size) / (ft->cluster_size * ft->sector_size)); + ft->fat_length = (((ft->cluster_count * 3 + 1) >> 1) + ft->sector_size - 1) / ft->sector_size; + + if (ft->cluster_count >= 4085) // FAT16 + { + ft->size_fat = 16; + ft->reserved = 2; + fatsecs = ft->num_sectors - (ft->size_root_dir + ft->sector_size - 1) / ft->sector_size - ft->reserved; + ft->cluster_count = (int) (((int64) fatsecs * ft->sector_size) / (ft->cluster_size * ft->sector_size)); + ft->fat_length = (ft->cluster_count * 2 + ft->sector_size - 1) / ft->sector_size; + } + + if(ft->cluster_count >= 65525) // FAT32 + { + ft->size_fat = 32; + ft->reserved = 32 - 1; + + do + { + ft->reserved++; + + fatsecs = ft->num_sectors - ft->reserved; + ft->size_root_dir = ft->cluster_size * ft->sector_size; + ft->cluster_count = (int) (((int64) fatsecs * ft->sector_size) / (ft->cluster_size * ft->sector_size)); + ft->fat_length = (ft->cluster_count * 4 + ft->sector_size - 1) / ft->sector_size; + + // Align data area on TC_MAX_VOLUME_SECTOR_SIZE + + } while (ft->sector_size == TC_SECTOR_SIZE_LEGACY + && (ft->reserved * ft->sector_size + ft->fat_length * ft->fats * ft->sector_size) % TC_MAX_VOLUME_SECTOR_SIZE != 0); + } + + ft->cluster_count -= ft->fat_length * ft->fats / ft->cluster_size; + + if (ft->num_sectors >= 65536 || ft->size_fat == 32) + { + ft->sectors = 0; + ft->total_sect = ft->num_sectors; + } + else + { + ft->sectors = (uint16) ft->num_sectors; + ft->total_sect = 0; + } + } + + static void PutBoot (fatparams * ft, byte *boot, uint32 volumeId) + { + int cnt = 0; + + boot[cnt++] = 0xeb; /* boot jump */ + boot[cnt++] = 0x3c; + boot[cnt++] = 0x90; + memcpy (boot + cnt, "MSDOS5.0", 8); /* system id */ + cnt += 8; + *(int16 *)(boot + cnt) = Endian::Little (ft->sector_size); /* bytes per sector */ + cnt += 2; + boot[cnt++] = (int8) ft->cluster_size; /* sectors per cluster */ + *(int16 *)(boot + cnt) = Endian::Little (ft->reserved); /* reserved sectors */ + cnt += 2; + boot[cnt++] = (int8) ft->fats; /* 2 fats */ + + if(ft->size_fat == 32) + { + boot[cnt++] = 0x00; + boot[cnt++] = 0x00; + } + else + { + *(int16 *)(boot + cnt) = Endian::Little (ft->dir_entries); /* 512 root entries */ + cnt += 2; + } + + *(int16 *)(boot + cnt) = Endian::Little (ft->sectors); /* # sectors */ + cnt += 2; + boot[cnt++] = (int8) ft->media; /* media byte */ + + if(ft->size_fat == 32) + { + boot[cnt++] = 0x00; + boot[cnt++] = 0x00; + } + else + { + *(uint16 *)(boot + cnt) = Endian::Little ((uint16) ft->fat_length); /* fat size */ + cnt += 2; + } + + *(int16 *)(boot + cnt) = Endian::Little (ft->secs_track); /* # sectors per track */ + cnt += 2; + *(int16 *)(boot + cnt) = Endian::Little (ft->heads); /* # heads */ + cnt += 2; + *(int32 *)(boot + cnt) = Endian::Little (ft->hidden); /* # hidden sectors */ + cnt += 4; + *(int32 *)(boot + cnt) = Endian::Little (ft->total_sect); /* # huge sectors */ + cnt += 4; + + if(ft->size_fat == 32) + { + *(int32 *)(boot + cnt) = Endian::Little (ft->fat_length); cnt += 4; /* fat size 32 */ + boot[cnt++] = 0x00; /* ExtFlags */ + boot[cnt++] = 0x00; + boot[cnt++] = 0x00; /* FSVer */ + boot[cnt++] = 0x00; + boot[cnt++] = 0x02; /* RootClus */ + boot[cnt++] = 0x00; + boot[cnt++] = 0x00; + boot[cnt++] = 0x00; + boot[cnt++] = 0x01; /* FSInfo */ + boot[cnt++] = 0x00; + boot[cnt++] = 0x06; /* BkBootSec */ + boot[cnt++] = 0x00; + memset(boot+cnt, 0, 12); cnt+=12; /* Reserved */ + } + + boot[cnt++] = 0x00; /* drive number */ // FIXED 80 > 00 + boot[cnt++] = 0x00; /* reserved */ + boot[cnt++] = 0x29; /* boot sig */ + + *(int32 *)(boot + cnt) = volumeId; + cnt += 4; + + memcpy (boot + cnt, ft->volume_name, 11); /* vol title */ + cnt += 11; + + switch(ft->size_fat) /* filesystem type */ + { + case 12: memcpy (boot + cnt, "FAT12 ", 8); break; + case 16: memcpy (boot + cnt, "FAT16 ", 8); break; + case 32: memcpy (boot + cnt, "FAT32 ", 8); break; + } + cnt += 8; + + memset (boot + cnt, 0, ft->size_fat==32 ? 420:448); /* boot code */ + cnt += ft->size_fat==32 ? 420:448; + boot[cnt++] = 0x55; + boot[cnt++] = 0xaa; /* boot sig */ + } + + + /* FAT32 FSInfo */ + static void PutFSInfo (byte *sector, fatparams *ft) + { + memset (sector, 0, ft->sector_size); + sector[3] = 0x41; /* LeadSig */ + sector[2] = 0x61; + sector[1] = 0x52; + sector[0] = 0x52; + sector[484+3] = 0x61; /* StrucSig */ + sector[484+2] = 0x41; + sector[484+1] = 0x72; + sector[484+0] = 0x72; + + // Free cluster count + *(uint32 *)(sector + 488) = Endian::Little (ft->cluster_count - ft->size_root_dir / ft->sector_size / ft->cluster_size); + + // Next free cluster + *(uint32 *)(sector + 492) = Endian::Little ((uint32) 2); + + sector[508+3] = 0xaa; /* TrailSig */ + sector[508+2] = 0x55; + sector[508+1] = 0x00; + sector[508+0] = 0x00; + } + + void FatFormatter::Format (WriteSectorCallback &writeSector, uint64 deviceSize, uint32 clusterSize, uint32 sectorSize) + { + fatparams fatParams; + +#if TC_MAX_VOLUME_SECTOR_SIZE > 0xFFFF +#error TC_MAX_VOLUME_SECTOR_SIZE > 0xFFFF +#endif + fatParams.sector_size = (uint16) sectorSize; + + if (deviceSize / fatParams.sector_size > 0xffffFFFF) + throw ParameterIncorrect (SRC_POS); + + fatParams.num_sectors = (uint32) (deviceSize / fatParams.sector_size); + fatParams.cluster_size = clusterSize / fatParams.sector_size; + memcpy (fatParams.volume_name, "NO NAME ", 11); + GetFatParams (&fatParams); + fatparams *ft = &fatParams; + + SecureBuffer sector (ft->sector_size); + uint32 sectorNumber = 0; + + /* Write the data area */ + + sector.Zero(); + + uint32 volumeId; + RandomNumberGenerator::GetDataFast (BufferPtr ((byte *) &volumeId, sizeof (volumeId))); + + PutBoot (ft, (byte *) sector, volumeId); + writeSector (sector); ++sectorNumber; + + /* fat32 boot area */ + if (ft->size_fat == 32) + { + /* fsinfo */ + PutFSInfo((byte *) sector, ft); + writeSector (sector); ++sectorNumber; + + /* reserved */ + while (sectorNumber < 6) + { + sector.Zero(); + sector[508+3] = 0xaa; /* TrailSig */ + sector[508+2] = 0x55; + writeSector (sector); ++sectorNumber; + } + + /* bootsector backup */ + sector.Zero(); + PutBoot (ft, (byte *) sector, volumeId); + writeSector (sector); ++sectorNumber; + + PutFSInfo((byte *) sector, ft); + writeSector (sector); ++sectorNumber; + } + + /* reserved */ + while (sectorNumber < (uint32)ft->reserved) + { + sector.Zero(); + writeSector (sector); ++sectorNumber; + } + + /* write fat */ + for (uint32 x = 1; x <= ft->fats; x++) + { + for (uint32 n = 0; n < ft->fat_length; n++) + { + sector.Zero(); + + if (n == 0) + { + byte fat_sig[12]; + if (ft->size_fat == 32) + { + fat_sig[0] = (byte) ft->media; + fat_sig[1] = fat_sig[2] = 0xff; + fat_sig[3] = 0x0f; + fat_sig[4] = fat_sig[5] = fat_sig[6] = 0xff; + fat_sig[7] = 0x0f; + fat_sig[8] = fat_sig[9] = fat_sig[10] = 0xff; + fat_sig[11] = 0x0f; + memcpy (sector, fat_sig, 12); + } + else if (ft->size_fat == 16) + { + fat_sig[0] = (byte) ft->media; + fat_sig[1] = 0xff; + fat_sig[2] = 0xff; + fat_sig[3] = 0xff; + memcpy (sector, fat_sig, 4); + } + else if (ft->size_fat == 12) + { + fat_sig[0] = (byte) ft->media; + fat_sig[1] = 0xff; + fat_sig[2] = 0xff; + fat_sig[3] = 0x00; + memcpy (sector, fat_sig, 4); + } + } + + if (!writeSector (sector)) + return; + } + } + + /* write rootdir */ + for (uint32 x = 0; x < ft->size_root_dir / ft->sector_size; x++) + { + sector.Zero(); + if (!writeSector (sector)) + return; + } + } +} diff --git a/src/Core/FatFormatter.h b/src/Core/FatFormatter.h new file mode 100644 index 00000000..47702190 --- /dev/null +++ b/src/Core/FatFormatter.h @@ -0,0 +1,29 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_FatFormatter +#define TC_HEADER_Core_FatFormatter + +#include "Platform/Platform.h" + +namespace TrueCrypt +{ + class FatFormatter + { + public: + struct WriteSectorCallback + { + virtual ~WriteSectorCallback () { } + virtual bool operator() (const BufferPtr §or) = 0; + }; + + static void Format (WriteSectorCallback &writeSector, uint64 deviceSize, uint32 clusterSize, uint32 sectorSize); + }; +} + +#endif // TC_HEADER_Core_FatFormatter diff --git a/src/Core/HostDevice.cpp b/src/Core/HostDevice.cpp new file mode 100644 index 00000000..0147d568 --- /dev/null +++ b/src/Core/HostDevice.cpp @@ -0,0 +1,47 @@ +/* + Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include "HostDevice.h" +#include "Platform/SerializerFactory.h" + +namespace TrueCrypt +{ + void HostDevice::Deserialize (shared_ptr <Stream> stream) + { + Serializer sr (stream); + MountPoint = sr.DeserializeWString ("MountPoint"); + sr.Deserialize ("Name", Name); + Path = sr.DeserializeWString ("Path"); + sr.Deserialize ("Removable", Removable); + sr.Deserialize ("Size", Size); + sr.Deserialize ("SystemNumber", SystemNumber); + + uint32 partitionCount; + sr.Deserialize ("Partitions", partitionCount); + for (uint32 i = 0; i < partitionCount; i++) + Partitions.push_back (Serializable::DeserializeNew <HostDevice> (stream)); + } + + void HostDevice::Serialize (shared_ptr <Stream> stream) const + { + Serializable::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("MountPoint", wstring (MountPoint)); + sr.Serialize ("Name", Name); + sr.Serialize ("Path", wstring (Path)); + sr.Serialize ("Removable", Removable); + sr.Serialize ("Size", Size); + sr.Serialize ("SystemNumber", SystemNumber); + + sr.Serialize ("Partitions", (uint32) Partitions.size()); + foreach_ref (const HostDevice &partition, Partitions) + partition.Serialize (stream); + } + + TC_SERIALIZER_FACTORY_ADD_CLASS (HostDevice); +} diff --git a/src/Core/HostDevice.h b/src/Core/HostDevice.h new file mode 100644 index 00000000..227dc241 --- /dev/null +++ b/src/Core/HostDevice.h @@ -0,0 +1,45 @@ +/* + Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_HostDevice +#define TC_HEADER_Core_HostDevice + +#include "Platform/Platform.h" +#include "Platform/Serializable.h" + +namespace TrueCrypt +{ + struct HostDevice; + typedef list < shared_ptr <HostDevice> > HostDeviceList; + + struct HostDevice : public Serializable + { + HostDevice () + : Removable (false), + Size (0) + { + } + + virtual ~HostDevice () + { + } + + TC_SERIALIZABLE (HostDevice); + + DirectoryPath MountPoint; + wstring Name; + DevicePath Path; + bool Removable; + uint64 Size; + uint32 SystemNumber; + + HostDeviceList Partitions; + }; +} + +#endif // TC_HEADER_Core_HostDevice diff --git a/src/Core/MountOptions.cpp b/src/Core/MountOptions.cpp new file mode 100644 index 00000000..04187311 --- /dev/null +++ b/src/Core/MountOptions.cpp @@ -0,0 +1,129 @@ +/* + Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include "MountOptions.h" +#include "Platform/MemoryStream.h" +#include "Platform/SerializerFactory.h" + +namespace TrueCrypt +{ + void MountOptions::CopyFrom (const MountOptions &other) + { +#define TC_CLONE(NAME) NAME = other.NAME +#define TC_CLONE_SHARED(TYPE,NAME) NAME = other.NAME ? make_shared <TYPE> (*other.NAME) : shared_ptr <TYPE> () + + TC_CLONE (CachePassword); + TC_CLONE (FilesystemOptions); + TC_CLONE (FilesystemType); + TC_CLONE_SHARED (KeyfileList, Keyfiles); + TC_CLONE_SHARED (DirectoryPath, MountPoint); + TC_CLONE (NoFilesystem); + TC_CLONE (NoHardwareCrypto); + TC_CLONE (NoKernelCrypto); + TC_CLONE_SHARED (VolumePassword, Password); + TC_CLONE_SHARED (VolumePath, Path); + TC_CLONE (PartitionInSystemEncryptionScope); + TC_CLONE (PreserveTimestamps); + TC_CLONE (Protection); + TC_CLONE_SHARED (VolumePassword, ProtectionPassword); + TC_CLONE_SHARED (KeyfileList, ProtectionKeyfiles); + TC_CLONE (Removable); + TC_CLONE (SharedAccessAllowed); + TC_CLONE (SlotNumber); + TC_CLONE (UseBackupHeaders); + } + + void MountOptions::Deserialize (shared_ptr <Stream> stream) + { + Serializer sr (stream); + + sr.Deserialize ("CachePassword", CachePassword); + sr.Deserialize ("FilesystemOptions", FilesystemOptions); + sr.Deserialize ("FilesystemType", FilesystemType); + + Keyfiles = Keyfile::DeserializeList (stream, "Keyfiles"); + + if (!sr.DeserializeBool ("MountPointNull")) + MountPoint.reset (new DirectoryPath (sr.DeserializeWString ("MountPoint"))); + else + MountPoint.reset(); + + sr.Deserialize ("NoFilesystem", NoFilesystem); + sr.Deserialize ("NoHardwareCrypto", NoHardwareCrypto); + sr.Deserialize ("NoKernelCrypto", NoKernelCrypto); + + if (!sr.DeserializeBool ("PasswordNull")) + Password = Serializable::DeserializeNew <VolumePassword> (stream); + else + Password.reset(); + + if (!sr.DeserializeBool ("PathNull")) + Path.reset (new VolumePath (sr.DeserializeWString ("Path"))); + else + Path.reset(); + + sr.Deserialize ("PartitionInSystemEncryptionScope", PartitionInSystemEncryptionScope); + sr.Deserialize ("PreserveTimestamps", PreserveTimestamps); + + Protection = static_cast <VolumeProtection::Enum> (sr.DeserializeInt32 ("Protection")); + + if (!sr.DeserializeBool ("ProtectionPasswordNull")) + ProtectionPassword = Serializable::DeserializeNew <VolumePassword> (stream); + else + ProtectionPassword.reset(); + + ProtectionKeyfiles = Keyfile::DeserializeList (stream, "ProtectionKeyfiles"); + sr.Deserialize ("Removable", Removable); + sr.Deserialize ("SharedAccessAllowed", SharedAccessAllowed); + sr.Deserialize ("SlotNumber", SlotNumber); + sr.Deserialize ("UseBackupHeaders", UseBackupHeaders); + } + + void MountOptions::Serialize (shared_ptr <Stream> stream) const + { + Serializable::Serialize (stream); + Serializer sr (stream); + + sr.Serialize ("CachePassword", CachePassword); + sr.Serialize ("FilesystemOptions", FilesystemOptions); + sr.Serialize ("FilesystemType", FilesystemType); + Keyfile::SerializeList (stream, "Keyfiles", Keyfiles); + + sr.Serialize ("MountPointNull", MountPoint == nullptr); + if (MountPoint) + sr.Serialize ("MountPoint", wstring (*MountPoint)); + + sr.Serialize ("NoFilesystem", NoFilesystem); + sr.Serialize ("NoHardwareCrypto", NoHardwareCrypto); + sr.Serialize ("NoKernelCrypto", NoKernelCrypto); + + sr.Serialize ("PasswordNull", Password == nullptr); + if (Password) + Password->Serialize (stream); + + sr.Serialize ("PathNull", Path == nullptr); + if (Path) + sr.Serialize ("Path", wstring (*Path)); + + sr.Serialize ("PartitionInSystemEncryptionScope", PartitionInSystemEncryptionScope); + sr.Serialize ("PreserveTimestamps", PreserveTimestamps); + sr.Serialize ("Protection", static_cast <uint32> (Protection)); + + sr.Serialize ("ProtectionPasswordNull", ProtectionPassword == nullptr); + if (ProtectionPassword) + ProtectionPassword->Serialize (stream); + + Keyfile::SerializeList (stream, "ProtectionKeyfiles", ProtectionKeyfiles); + sr.Serialize ("Removable", Removable); + sr.Serialize ("SharedAccessAllowed", SharedAccessAllowed); + sr.Serialize ("SlotNumber", SlotNumber); + sr.Serialize ("UseBackupHeaders", UseBackupHeaders); + } + + TC_SERIALIZER_FACTORY_ADD_CLASS (MountOptions); +} diff --git a/src/Core/MountOptions.h b/src/Core/MountOptions.h new file mode 100644 index 00000000..23fc7ca2 --- /dev/null +++ b/src/Core/MountOptions.h @@ -0,0 +1,70 @@ +/* + Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_MountOptions +#define TC_HEADER_Core_MountOptions + +#include "Platform/Serializable.h" +#include "Volume/Keyfile.h" +#include "Volume/Volume.h" +#include "Volume/VolumeSlot.h" +#include "Volume/VolumePassword.h" + +namespace TrueCrypt +{ + struct MountOptions : public Serializable + { + MountOptions () + : + CachePassword (false), + NoFilesystem (false), + NoHardwareCrypto (false), + NoKernelCrypto (false), + PartitionInSystemEncryptionScope (false), + PreserveTimestamps (true), + Protection (VolumeProtection::None), + Removable (false), + SharedAccessAllowed (false), + SlotNumber (0), + UseBackupHeaders (false) + { + } + + MountOptions (const MountOptions &other) { CopyFrom (other); } + virtual ~MountOptions () { } + + MountOptions &operator= (const MountOptions &other) { CopyFrom (other); return *this; } + + TC_SERIALIZABLE (MountOptions); + + bool CachePassword; + wstring FilesystemOptions; + wstring FilesystemType; + shared_ptr <KeyfileList> Keyfiles; + shared_ptr <DirectoryPath> MountPoint; + bool NoFilesystem; + bool NoHardwareCrypto; + bool NoKernelCrypto; + shared_ptr <VolumePassword> Password; + bool PartitionInSystemEncryptionScope; + shared_ptr <VolumePath> Path; + bool PreserveTimestamps; + VolumeProtection::Enum Protection; + shared_ptr <VolumePassword> ProtectionPassword; + shared_ptr <KeyfileList> ProtectionKeyfiles; + bool Removable; + bool SharedAccessAllowed; + VolumeSlotNumber SlotNumber; + bool UseBackupHeaders; + + protected: + void CopyFrom (const MountOptions &other); + }; +} + +#endif // TC_HEADER_Core_MountOptions diff --git a/src/Core/RandomNumberGenerator.cpp b/src/Core/RandomNumberGenerator.cpp new file mode 100644 index 00000000..a010e7c6 --- /dev/null +++ b/src/Core/RandomNumberGenerator.cpp @@ -0,0 +1,213 @@ +/* + Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_WINDOWS +#include <sys/types.h> +#include <errno.h> +#include <fcntl.h> +#endif + +#include "RandomNumberGenerator.h" +#include "Volume/Crc32.h" + +namespace TrueCrypt +{ + void RandomNumberGenerator::AddSystemDataToPool (bool fast) + { + SecureBuffer buffer (PoolSize); + +#ifdef TC_WINDOWS +#ifndef DEBUG + throw NotImplemented (SRC_POS); +#endif +#else + int urandom = open ("/dev/urandom", O_RDONLY); + throw_sys_sub_if (urandom == -1, L"/dev/urandom"); + finally_do_arg (int, urandom, { close (finally_arg); }); + + throw_sys_sub_if (read (urandom, buffer, buffer.Size()) == -1, L"/dev/urandom"); + AddToPool (buffer); + + if (!fast) + { + // Read all bytes available in /dev/random up to buffer size + int random = open ("/dev/random", O_RDONLY | O_NONBLOCK); + throw_sys_sub_if (random == -1, L"/dev/random"); + finally_do_arg (int, random, { close (finally_arg); }); + + throw_sys_sub_if (read (random, buffer, buffer.Size()) == -1 && errno != EAGAIN, L"/dev/random"); + AddToPool (buffer); + } +#endif + } + + void RandomNumberGenerator::AddToPool (const ConstBufferPtr &data) + { + if (!Running) + throw NotInitialized (SRC_POS); + + ScopeLock lock (AccessMutex); + + for (size_t i = 0; i < data.Size(); ++i) + { + Pool[WriteOffset++] += data[i]; + + if (WriteOffset >= PoolSize) + WriteOffset = 0; + + if (++BytesAddedSincePoolHashMix >= MaxBytesAddedBeforePoolHashMix) + HashMixPool(); + } + } + + void RandomNumberGenerator::GetData (const BufferPtr &buffer, bool fast) + { + if (!Running) + throw NotInitialized (SRC_POS); + + if (buffer.Size() > PoolSize) + throw ParameterIncorrect (SRC_POS); + + ScopeLock lock (AccessMutex); + + // Poll system for data + AddSystemDataToPool (fast); + HashMixPool(); + + // Transfer bytes from pool to output buffer + for (size_t i = 0; i < buffer.Size(); ++i) + { + buffer[i] += Pool[ReadOffset++]; + + if (ReadOffset >= PoolSize) + ReadOffset = 0; + } + + // Invert and mix the pool + for (size_t i = 0; i < Pool.Size(); ++i) + { + Pool[i] = ~Pool[i]; + } + + AddSystemDataToPool (true); + HashMixPool(); + + // XOR the current pool content into the output buffer to prevent pool state leaks + for (size_t i = 0; i < buffer.Size(); ++i) + { + buffer[i] ^= Pool[ReadOffset++]; + + if (ReadOffset >= PoolSize) + ReadOffset = 0; + } + } + + shared_ptr <Hash> RandomNumberGenerator::GetHash () + { + ScopeLock lock (AccessMutex); + return PoolHash; + } + + void RandomNumberGenerator::HashMixPool () + { + BytesAddedSincePoolHashMix = 0; + + for (size_t poolPos = 0; poolPos < Pool.Size(); ) + { + // Compute the message digest of the entire pool using the selected hash function + SecureBuffer digest (PoolHash->GetDigestSize()); + PoolHash->ProcessData (Pool); + PoolHash->GetDigest (digest); + + // Add the message digest to the pool + for (size_t digestPos = 0; digestPos < digest.Size() && poolPos < Pool.Size(); ++digestPos) + { + Pool[poolPos++] += digest[digestPos]; + } + } + } + + void RandomNumberGenerator::SetHash (shared_ptr <Hash> hash) + { + ScopeLock lock (AccessMutex); + PoolHash = hash; + } + + void RandomNumberGenerator::Start () + { + ScopeLock lock (AccessMutex); + + if (IsRunning()) + return; + + BytesAddedSincePoolHashMix = 0; + ReadOffset = 0; + WriteOffset = 0; + Running = true; + EnrichedByUser = false; + + Pool.Allocate (PoolSize); + Test(); + + if (!PoolHash) + { + // First hash algorithm is the default one + PoolHash = Hash::GetAvailableAlgorithms().front(); + } + + AddSystemDataToPool (true); + } + + void RandomNumberGenerator::Stop () + { + ScopeLock lock (AccessMutex); + + if (Pool.IsAllocated()) + Pool.Free (); + + PoolHash.reset(); + + EnrichedByUser = false; + Running = false; + } + + void RandomNumberGenerator::Test () + { + shared_ptr <Hash> origPoolHash = PoolHash; + PoolHash.reset (new Ripemd160()); + + Pool.Zero(); + Buffer buffer (1); + for (size_t i = 0; i < PoolSize * 10; ++i) + { + buffer[0] = (byte) i; + AddToPool (buffer); + } + + if (Crc32::ProcessBuffer (Pool) != 0x2de46d17) + throw TestFailed (SRC_POS); + + buffer.Allocate (PoolSize); + buffer.CopyFrom (PeekPool()); + AddToPool (buffer); + + if (Crc32::ProcessBuffer (Pool) != 0xcb88e019) + throw TestFailed (SRC_POS); + + PoolHash = origPoolHash; + } + + Mutex RandomNumberGenerator::AccessMutex; + size_t RandomNumberGenerator::BytesAddedSincePoolHashMix; + bool RandomNumberGenerator::EnrichedByUser; + SecureBuffer RandomNumberGenerator::Pool; + shared_ptr <Hash> RandomNumberGenerator::PoolHash; + size_t RandomNumberGenerator::ReadOffset; + bool RandomNumberGenerator::Running = false; + size_t RandomNumberGenerator::WriteOffset; +} diff --git a/src/Core/RandomNumberGenerator.h b/src/Core/RandomNumberGenerator.h new file mode 100644 index 00000000..fb3a6917 --- /dev/null +++ b/src/Core/RandomNumberGenerator.h @@ -0,0 +1,55 @@ +/* + Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_RandomNumberGenerator +#define TC_HEADER_Core_RandomNumberGenerator + +#include "Platform/Platform.h" +#include "Volume/Hash.h" +#include "Common/Random.h" + +namespace TrueCrypt +{ + class RandomNumberGenerator + { + public: + static void AddToPool (const ConstBufferPtr &buffer); + static void GetData (const BufferPtr &buffer) { GetData (buffer, false); } + static void GetDataFast (const BufferPtr &buffer) { GetData (buffer, true); } + static shared_ptr <Hash> GetHash (); + static bool IsEnrichedByUser () { return EnrichedByUser; } + static bool IsRunning () { return Running; } + static ConstBufferPtr PeekPool () { return Pool; } + static void SetEnrichedByUserStatus (bool enriched) { EnrichedByUser = enriched; } + static void SetHash (shared_ptr <Hash> hash); + static void Start (); + static void Stop (); + + static const size_t PoolSize = RNG_POOL_SIZE; + + protected: + static void AddSystemDataToPool (bool fast); + static void GetData (const BufferPtr &buffer, bool fast); + static void HashMixPool (); + static void Test (); + RandomNumberGenerator (); + + static const size_t MaxBytesAddedBeforePoolHashMix = RANDMIX_BYTE_INTERVAL; + + static Mutex AccessMutex; + static size_t BytesAddedSincePoolHashMix; + static bool EnrichedByUser; + static SecureBuffer Pool; + static shared_ptr <Hash> PoolHash; + static size_t ReadOffset; + static bool Running; + static size_t WriteOffset; + }; +} + +#endif // TC_HEADER_Core_RandomNumberGenerator diff --git a/src/Core/Unix/CoreService.cpp b/src/Core/Unix/CoreService.cpp new file mode 100644 index 00000000..0ec636c7 --- /dev/null +++ b/src/Core/Unix/CoreService.cpp @@ -0,0 +1,544 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include "CoreService.h" +#include <fcntl.h> +#include <sys/wait.h> +#include "Platform/FileStream.h" +#include "Platform/MemoryStream.h" +#include "Platform/Serializable.h" +#include "Platform/SystemLog.h" +#include "Platform/Thread.h" +#include "Platform/Unix/Poller.h" +#include "Core/Core.h" +#include "CoreUnix.h" +#include "CoreServiceRequest.h" +#include "CoreServiceResponse.h" + +namespace TrueCrypt +{ + template <class T> + auto_ptr <T> CoreService::GetResponse () + { + auto_ptr <Serializable> deserializedObject (Serializable::DeserializeNew (ServiceOutputStream)); + + Exception *deserializedException = dynamic_cast <Exception*> (deserializedObject.get()); + if (deserializedException) + deserializedException->Throw(); + + if (dynamic_cast <T *> (deserializedObject.get()) == nullptr) + throw ParameterIncorrect (SRC_POS); + + return auto_ptr <T> (dynamic_cast <T *> (deserializedObject.release())); + } + + void CoreService::ProcessElevatedRequests () + { + int pid = fork(); + throw_sys_if (pid == -1); + if (pid == 0) + { + try + { + int f = open ("/dev/null", 0); + throw_sys_sub_if (f == -1, "/dev/null"); + throw_sys_if (dup2 (f, STDERR_FILENO) == -1); + + // Wait for sync code + while (true) + { + byte b; + throw_sys_if (read (STDIN_FILENO, &b, 1) != 1); + if (b != 0x00) + continue; + + throw_sys_if (read (STDIN_FILENO, &b, 1) != 1); + if (b != 0x11) + continue; + + throw_sys_if (read (STDIN_FILENO, &b, 1) != 1); + if (b == 0x22) + break; + } + + ElevatedPrivileges = true; + ProcessRequests (STDIN_FILENO, STDOUT_FILENO); + _exit (0); + } + catch (exception &e) + { +#ifdef DEBUG + SystemLog::WriteException (e); +#endif + } + catch (...) { } + _exit (1); + } + } + + void CoreService::ProcessRequests (int inputFD, int outputFD) + { + try + { + Core = CoreDirect; + + shared_ptr <Stream> inputStream (new FileStream (inputFD != -1 ? inputFD : InputPipe->GetReadFD())); + shared_ptr <Stream> outputStream (new FileStream (outputFD != -1 ? outputFD : OutputPipe->GetWriteFD())); + + while (true) + { + shared_ptr <CoreServiceRequest> request = Serializable::DeserializeNew <CoreServiceRequest> (inputStream); + + try + { + // ExitRequest + if (dynamic_cast <ExitRequest*> (request.get()) != nullptr) + { + if (ElevatedServiceAvailable) + request->Serialize (ServiceInputStream); + return; + } + + if (!ElevatedPrivileges && request->ElevateUserPrivileges) + { + if (!ElevatedServiceAvailable) + { + finally_do_arg (string *, &request->AdminPassword, { StringConverter::Erase (*finally_arg); }); + + CoreService::StartElevated (*request); + ElevatedServiceAvailable = true; + } + + request->Serialize (ServiceInputStream); + GetResponse <Serializable>()->Serialize (outputStream); + continue; + } + + // CheckFilesystemRequest + CheckFilesystemRequest *checkRequest = dynamic_cast <CheckFilesystemRequest*> (request.get()); + if (checkRequest) + { + Core->CheckFilesystem (checkRequest->MountedVolumeInfo, checkRequest->Repair); + + CheckFilesystemResponse().Serialize (outputStream); + continue; + } + + // DismountFilesystemRequest + DismountFilesystemRequest *dismountFsRequest = dynamic_cast <DismountFilesystemRequest*> (request.get()); + if (dismountFsRequest) + { + Core->DismountFilesystem (dismountFsRequest->MountPoint, dismountFsRequest->Force); + + DismountFilesystemResponse().Serialize (outputStream); + continue; + } + + // DismountVolumeRequest + DismountVolumeRequest *dismountRequest = dynamic_cast <DismountVolumeRequest*> (request.get()); + if (dismountRequest) + { + DismountVolumeResponse response; + response.DismountedVolumeInfo = Core->DismountVolume (dismountRequest->MountedVolumeInfo, dismountRequest->IgnoreOpenFiles, dismountRequest->SyncVolumeInfo); + response.Serialize (outputStream); + continue; + } + + // GetDeviceSectorSizeRequest + GetDeviceSectorSizeRequest *getDeviceSectorSizeRequest = dynamic_cast <GetDeviceSectorSizeRequest*> (request.get()); + if (getDeviceSectorSizeRequest) + { + GetDeviceSectorSizeResponse response; + response.Size = Core->GetDeviceSectorSize (getDeviceSectorSizeRequest->Path); + response.Serialize (outputStream); + continue; + } + + // GetDeviceSizeRequest + GetDeviceSizeRequest *getDeviceSizeRequest = dynamic_cast <GetDeviceSizeRequest*> (request.get()); + if (getDeviceSizeRequest) + { + GetDeviceSizeResponse response; + response.Size = Core->GetDeviceSize (getDeviceSizeRequest->Path); + response.Serialize (outputStream); + continue; + } + + // GetHostDevicesRequest + GetHostDevicesRequest *getHostDevicesRequest = dynamic_cast <GetHostDevicesRequest*> (request.get()); + if (getHostDevicesRequest) + { + GetHostDevicesResponse response; + response.HostDevices = Core->GetHostDevices (getHostDevicesRequest->PathListOnly); + response.Serialize (outputStream); + continue; + } + + // MountVolumeRequest + MountVolumeRequest *mountRequest = dynamic_cast <MountVolumeRequest*> (request.get()); + if (mountRequest) + { + MountVolumeResponse ( + Core->MountVolume (*mountRequest->Options) + ).Serialize (outputStream); + + continue; + } + + // SetFileOwnerRequest + SetFileOwnerRequest *setFileOwnerRequest = dynamic_cast <SetFileOwnerRequest*> (request.get()); + if (setFileOwnerRequest) + { + CoreUnix *coreUnix = dynamic_cast <CoreUnix *> (Core.get()); + if (!coreUnix) + throw ParameterIncorrect (SRC_POS); + + coreUnix->SetFileOwner (setFileOwnerRequest->Path, setFileOwnerRequest->Owner); + SetFileOwnerResponse().Serialize (outputStream); + continue; + } + + throw ParameterIncorrect (SRC_POS); + } + catch (Exception &e) + { + e.Serialize (outputStream); + } + catch (exception &e) + { + ExternalException (SRC_POS, StringConverter::ToExceptionString (e)).Serialize (outputStream); + } + } + } + catch (exception &e) + { +#ifdef DEBUG + SystemLog::WriteException (e); +#endif + throw; + } + } + + void CoreService::RequestCheckFilesystem (shared_ptr <VolumeInfo> mountedVolume, bool repair) + { + CheckFilesystemRequest request (mountedVolume, repair); + SendRequest <CheckFilesystemResponse> (request); + } + + void CoreService::RequestDismountFilesystem (const DirectoryPath &mountPoint, bool force) + { + DismountFilesystemRequest request (mountPoint, force); + SendRequest <DismountFilesystemResponse> (request); + } + + shared_ptr <VolumeInfo> CoreService::RequestDismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles, bool syncVolumeInfo) + { + DismountVolumeRequest request (mountedVolume, ignoreOpenFiles, syncVolumeInfo); + return SendRequest <DismountVolumeResponse> (request)->DismountedVolumeInfo; + } + + uint32 CoreService::RequestGetDeviceSectorSize (const DevicePath &devicePath) + { + GetDeviceSectorSizeRequest request (devicePath); + return SendRequest <GetDeviceSectorSizeResponse> (request)->Size; + } + + uint64 CoreService::RequestGetDeviceSize (const DevicePath &devicePath) + { + GetDeviceSizeRequest request (devicePath); + return SendRequest <GetDeviceSizeResponse> (request)->Size; + } + + HostDeviceList CoreService::RequestGetHostDevices (bool pathListOnly) + { + GetHostDevicesRequest request (pathListOnly); + return SendRequest <GetHostDevicesResponse> (request)->HostDevices; + } + + shared_ptr <VolumeInfo> CoreService::RequestMountVolume (MountOptions &options) + { + MountVolumeRequest request (&options); + return SendRequest <MountVolumeResponse> (request)->MountedVolumeInfo; + } + + void CoreService::RequestSetFileOwner (const FilesystemPath &path, const UserId &owner) + { + SetFileOwnerRequest request (path, owner); + SendRequest <SetFileOwnerResponse> (request); + } + + template <class T> + auto_ptr <T> CoreService::SendRequest (CoreServiceRequest &request) + { + static Mutex mutex; + ScopeLock lock (mutex); + + if (request.RequiresElevation()) + { + request.ElevateUserPrivileges = true; + request.FastElevation = !ElevatedServiceAvailable; + request.ApplicationExecutablePath = Core->GetApplicationExecutablePath(); + + while (!ElevatedServiceAvailable) + { + try + { + request.Serialize (ServiceInputStream); + auto_ptr <T> response (GetResponse <T>()); + ElevatedServiceAvailable = true; + return response; + } + catch (ElevationFailed &e) + { + if (!request.FastElevation) + { + ExceptionEventArgs args (e); + Core->WarningEvent.Raise (args); + } + + request.FastElevation = false; + (*AdminPasswordCallback) (request.AdminPassword); + } + } + } + + finally_do_arg (string *, &request.AdminPassword, { StringConverter::Erase (*finally_arg); }); + + request.Serialize (ServiceInputStream); + return GetResponse <T>(); + } + + void CoreService::Start () + { + InputPipe.reset (new Pipe()); + OutputPipe.reset (new Pipe()); + + int pid = fork(); + throw_sys_if (pid == -1); + + if (pid == 0) + { + try + { + ProcessRequests(); + _exit (0); + } + catch (...) { } + _exit (1); + } + + ServiceInputStream = shared_ptr <Stream> (new FileStream (InputPipe->GetWriteFD())); + ServiceOutputStream = shared_ptr <Stream> (new FileStream (OutputPipe->GetReadFD())); + } + + void CoreService::StartElevated (const CoreServiceRequest &request) + { + auto_ptr <Pipe> inPipe (new Pipe()); + auto_ptr <Pipe> outPipe (new Pipe()); + Pipe errPipe; + + int forkedPid = fork(); + throw_sys_if (forkedPid == -1); + + if (forkedPid == 0) + { + try + { + try + { + throw_sys_if (dup2 (inPipe->GetReadFD(), STDIN_FILENO) == -1); + throw_sys_if (dup2 (outPipe->GetWriteFD(), STDOUT_FILENO) == -1); + throw_sys_if (dup2 (errPipe.GetWriteFD(), STDERR_FILENO) == -1); + + string appPath = request.ApplicationExecutablePath; + if (appPath.empty()) + appPath = "truecrypt"; + + const char *args[] = { "sudo", "-S", "-p", "", appPath.c_str(), TC_CORE_SERVICE_CMDLINE_OPTION, nullptr }; + execvp (args[0], ((char* const*) args)); + throw SystemException (SRC_POS, args[0]); + } + catch (Exception &) + { + throw; + } + catch (exception &e) + { + throw ExternalException (SRC_POS, StringConverter::ToExceptionString (e)); + } + catch (...) + { + throw UnknownException (SRC_POS); + } + } + catch (Exception &e) + { + try + { + shared_ptr <Stream> outputStream (new FileStream (errPipe.GetWriteFD())); + e.Serialize (outputStream); + } + catch (...) { } + } + + _exit (1); + } + + vector <char> adminPassword (request.AdminPassword.size() + 1); + int timeout = 6000; + + if (request.FastElevation) + { + string dummyPassword = "dummy\n"; + adminPassword = vector <char> (dummyPassword.size()); + Memory::Copy (&adminPassword.front(), dummyPassword.c_str(), dummyPassword.size()); + timeout = 1000; + } + else + { + Memory::Copy (&adminPassword.front(), request.AdminPassword.c_str(), request.AdminPassword.size()); + adminPassword[request.AdminPassword.size()] = '\n'; + } + + if (write (inPipe->GetWriteFD(), &adminPassword.front(), adminPassword.size())) { } // Errors ignored + + Memory::Erase (&adminPassword.front(), adminPassword.size()); + + throw_sys_if (fcntl (outPipe->GetReadFD(), F_SETFL, O_NONBLOCK) == -1); + throw_sys_if (fcntl (errPipe.GetReadFD(), F_SETFL, O_NONBLOCK) == -1); + + vector <char> buffer (4096), errOutput (4096); + buffer.clear (); + errOutput.clear (); + + Poller poller (outPipe->GetReadFD(), errPipe.GetReadFD()); + int status, waitRes; + int exitCode = 1; + + try + { + do + { + ssize_t bytesRead = 0; + foreach (int fd, poller.WaitForData (timeout)) + { + bytesRead = read (fd, &buffer[0], buffer.capacity()); + if (bytesRead > 0 && fd == errPipe.GetReadFD()) + { + errOutput.insert (errOutput.end(), buffer.begin(), buffer.begin() + bytesRead); + + if (bytesRead > 5 && bytesRead < 80) // Short message captured + timeout = 200; + } + } + + if (bytesRead == 0) + { + waitRes = waitpid (forkedPid, &status, 0); + break; + } + + } while ((waitRes = waitpid (forkedPid, &status, WNOHANG)) == 0); + } + catch (TimeOut&) + { + if ((waitRes = waitpid (forkedPid, &status, WNOHANG)) == 0) + { + inPipe->Close(); + outPipe->Close(); + errPipe.Close(); + + if (request.FastElevation) + { + // Prevent defunct process + struct WaitFunctor : public Functor + { + WaitFunctor (int pid) : Pid (pid) { } + virtual void operator() () + { + int status; + for (int t = 0; t < 10 && waitpid (Pid, &status, WNOHANG) == 0; t++) + Thread::Sleep (1000); + } + int Pid; + }; + Thread thread; + thread.Start (new WaitFunctor (forkedPid)); + + throw ElevationFailed (SRC_POS, "sudo", 1, ""); + } + + waitRes = waitpid (forkedPid, &status, 0); + } + } + + if (!errOutput.empty()) + { + auto_ptr <Serializable> deserializedObject; + Exception *deserializedException = nullptr; + + try + { + shared_ptr <Stream> stream (new MemoryStream (ConstBufferPtr ((byte *) &errOutput[0], errOutput.size()))); + deserializedObject.reset (Serializable::DeserializeNew (stream)); + deserializedException = dynamic_cast <Exception*> (deserializedObject.get()); + } + catch (...) { } + + if (deserializedException) + deserializedException->Throw(); + } + + throw_sys_if (waitRes == -1); + exitCode = (WIFEXITED (status) ? WEXITSTATUS (status) : 1); + if (exitCode != 0) + { + string strErrOutput; + + if (!errOutput.empty()) + strErrOutput.insert (strErrOutput.begin(), errOutput.begin(), errOutput.end()); + + // sudo may require a tty even if -S is used + if (strErrOutput.find (" tty") != string::npos) + strErrOutput += "\nTo enable use of 'sudo' by applications without a terminal window, please disable 'requiretty' option in '/etc/sudoers'. Newer versions of sudo automatically determine whether a terminal is required ('requiretty' option is obsolete)."; + + throw ElevationFailed (SRC_POS, "sudo", exitCode, strErrOutput); + } + + throw_sys_if (fcntl (outPipe->GetReadFD(), F_SETFL, 0) == -1); + + ServiceInputStream = shared_ptr <Stream> (new FileStream (inPipe->GetWriteFD())); + ServiceOutputStream = shared_ptr <Stream> (new FileStream (outPipe->GetReadFD())); + + // Send sync code + byte sync[] = { 0, 0x11, 0x22 }; + ServiceInputStream->Write (ConstBufferPtr (sync, array_capacity (sync))); + + AdminInputPipe = inPipe; + AdminOutputPipe = outPipe; + } + + void CoreService::Stop () + { + ExitRequest exitRequest; + exitRequest.Serialize (ServiceInputStream); + } + + shared_ptr <GetStringFunctor> CoreService::AdminPasswordCallback; + + auto_ptr <Pipe> CoreService::AdminInputPipe; + auto_ptr <Pipe> CoreService::AdminOutputPipe; + + auto_ptr <Pipe> CoreService::InputPipe; + auto_ptr <Pipe> CoreService::OutputPipe; + shared_ptr <Stream> CoreService::ServiceInputStream; + shared_ptr <Stream> CoreService::ServiceOutputStream; + + bool CoreService::ElevatedPrivileges = false; + bool CoreService::ElevatedServiceAvailable = false; +} diff --git a/src/Core/Unix/CoreService.h b/src/Core/Unix/CoreService.h new file mode 100644 index 00000000..9702dc7e --- /dev/null +++ b/src/Core/Unix/CoreService.h @@ -0,0 +1,63 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_Unix_CoreService +#define TC_HEADER_Core_Unix_CoreService + +#include "CoreServiceRequest.h" +#include "Platform/Stream.h" +#include "Platform/Unix/Pipe.h" +#include "Core/Core.h" + +namespace TrueCrypt +{ + // This service facilitates process forking and elevation of user privileges + class CoreService + { + public: + static void ProcessElevatedRequests (); + static void ProcessRequests (int inputFD = -1, int outputFD = -1); + static void RequestCheckFilesystem (shared_ptr <VolumeInfo> mountedVolume, bool repair); + static void RequestDismountFilesystem (const DirectoryPath &mountPoint, bool force); + static shared_ptr <VolumeInfo> RequestDismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles = false, bool syncVolumeInfo = false); + static uint32 RequestGetDeviceSectorSize (const DevicePath &devicePath); + static uint64 RequestGetDeviceSize (const DevicePath &devicePath); + static HostDeviceList RequestGetHostDevices (bool pathListOnly); + static shared_ptr <VolumeInfo> RequestMountVolume (MountOptions &options); + static void RequestSetFileOwner (const FilesystemPath &path, const UserId &owner); + static void SetAdminPasswordCallback (shared_ptr <GetStringFunctor> functor) { AdminPasswordCallback = functor; } + static void Start (); + static void Stop (); + + protected: + template <class T> static auto_ptr <T> GetResponse (); + template <class T> static auto_ptr <T> SendRequest (CoreServiceRequest &request); + static void StartElevated (const CoreServiceRequest &request); + + static shared_ptr <GetStringFunctor> AdminPasswordCallback; + + static auto_ptr <Pipe> AdminInputPipe; + static auto_ptr <Pipe> AdminOutputPipe; + + static auto_ptr <Pipe> InputPipe; + static auto_ptr <Pipe> OutputPipe; + static shared_ptr <Stream> ServiceInputStream; + static shared_ptr <Stream> ServiceOutputStream; + + static bool ElevatedPrivileges; + static bool ElevatedServiceAvailable; + static bool Running; + + private: + CoreService (); + }; + +#define TC_CORE_SERVICE_CMDLINE_OPTION "--core-service" +} + +#endif // TC_HEADER_Core_Unix_CoreService diff --git a/src/Core/Unix/CoreServiceProxy.h b/src/Core/Unix/CoreServiceProxy.h new file mode 100644 index 00000000..2a264617 --- /dev/null +++ b/src/Core/Unix/CoreServiceProxy.h @@ -0,0 +1,152 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_Windows_CoreServiceProxy +#define TC_HEADER_Core_Windows_CoreServiceProxy + +#include "CoreService.h" +#include "Volume/VolumePasswordCache.h" + +namespace TrueCrypt +{ + template <class T> + class CoreServiceProxy : public T + { + public: + CoreServiceProxy () { } + virtual ~CoreServiceProxy () { } + + virtual void CheckFilesystem (shared_ptr <VolumeInfo> mountedVolume, bool repair) const + { + CoreService::RequestCheckFilesystem (mountedVolume, repair); + } + + virtual void DismountFilesystem (const DirectoryPath &mountPoint, bool force) const + { + CoreService::RequestDismountFilesystem (mountPoint, force); + } + + virtual shared_ptr <VolumeInfo> DismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles = false, bool syncVolumeInfo = false) + { + shared_ptr <VolumeInfo> dismountedVolumeInfo = CoreService::RequestDismountVolume (mountedVolume, ignoreOpenFiles, syncVolumeInfo); + + VolumeEventArgs eventArgs (dismountedVolumeInfo); + T::VolumeDismountedEvent.Raise (eventArgs); + + return dismountedVolumeInfo; + } + + virtual uint32 GetDeviceSectorSize (const DevicePath &devicePath) const + { + return CoreService::RequestGetDeviceSectorSize (devicePath); + } + + virtual uint64 GetDeviceSize (const DevicePath &devicePath) const + { + return CoreService::RequestGetDeviceSize (devicePath); + } + +#ifndef TC_LINUX + virtual HostDeviceList GetHostDevices (bool pathListOnly = false) const + { + if (pathListOnly) + return T::GetHostDevices (pathListOnly); + else + return CoreService::RequestGetHostDevices (pathListOnly); + } +#endif + virtual bool IsPasswordCacheEmpty () const { return VolumePasswordCache::IsEmpty(); } + + virtual shared_ptr <VolumeInfo> MountVolume (MountOptions &options) + { + shared_ptr <VolumeInfo> mountedVolume; + + if (!VolumePasswordCache::IsEmpty() + && (!options.Password || options.Password->IsEmpty()) + && (!options.Keyfiles || options.Keyfiles->empty())) + { + finally_do_arg (MountOptions*, &options, { if (finally_arg->Password) finally_arg->Password.reset(); }); + + PasswordIncorrect passwordException; + foreach (shared_ptr <VolumePassword> password, VolumePasswordCache::GetPasswords()) + { + try + { + options.Password = password; + mountedVolume = CoreService::RequestMountVolume (options); + break; + } + catch (PasswordIncorrect &e) + { + passwordException = e; + } + } + + if (!mountedVolume) + passwordException.Throw(); + } + else + { + MountOptions newOptions = options; + + newOptions.Password = Keyfile::ApplyListToPassword (options.Keyfiles, options.Password); + if (newOptions.Keyfiles) + newOptions.Keyfiles->clear(); + + newOptions.ProtectionPassword = Keyfile::ApplyListToPassword (options.ProtectionKeyfiles, options.ProtectionPassword); + if (newOptions.ProtectionKeyfiles) + newOptions.ProtectionKeyfiles->clear(); + + try + { + mountedVolume = CoreService::RequestMountVolume (newOptions); + } + catch (ProtectionPasswordIncorrect &e) + { + if (options.ProtectionKeyfiles && !options.ProtectionKeyfiles->empty()) + throw ProtectionPasswordKeyfilesIncorrect (e.what()); + throw; + } + catch (PasswordIncorrect &e) + { + if (options.Keyfiles && !options.Keyfiles->empty()) + throw PasswordKeyfilesIncorrect (e.what()); + throw; + } + + if (options.CachePassword + && ((options.Password && !options.Password->IsEmpty()) || (options.Keyfiles && !options.Keyfiles->empty()))) + { + VolumePasswordCache::Store (*Keyfile::ApplyListToPassword (options.Keyfiles, options.Password)); + } + } + + VolumeEventArgs eventArgs (mountedVolume); + T::VolumeMountedEvent.Raise (eventArgs); + + return mountedVolume; + } + + virtual void SetAdminPasswordCallback (shared_ptr <GetStringFunctor> functor) + { + CoreService::SetAdminPasswordCallback (functor); + } + + virtual void SetFileOwner (const FilesystemPath &path, const UserId &owner) const + { + CoreService::RequestSetFileOwner (path, owner); + } + + virtual void WipePasswordCache () const + { + VolumePasswordCache::Clear(); + } + }; +} + +#endif // TC_HEADER_Core_Windows_CoreServiceProxy diff --git a/src/Core/Unix/CoreServiceRequest.cpp b/src/Core/Unix/CoreServiceRequest.cpp new file mode 100644 index 00000000..49ee8418 --- /dev/null +++ b/src/Core/Unix/CoreServiceRequest.cpp @@ -0,0 +1,269 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include <errno.h> +#include "CoreServiceRequest.h" +#include "Platform/SerializerFactory.h" + +namespace TrueCrypt +{ + void CoreServiceRequest::Deserialize (shared_ptr <Stream> stream) + { + Serializer sr (stream); + sr.Deserialize ("AdminPassword", AdminPassword); + ApplicationExecutablePath = sr.DeserializeWString ("ApplicationExecutablePath"); + sr.Deserialize ("ElevateUserPrivileges", ElevateUserPrivileges); + sr.Deserialize ("FastElevation", FastElevation); + } + + void CoreServiceRequest::Serialize (shared_ptr <Stream> stream) const + { + Serializable::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("AdminPassword", AdminPassword); + sr.Serialize ("ApplicationExecutablePath", wstring (ApplicationExecutablePath)); + sr.Serialize ("ElevateUserPrivileges", ElevateUserPrivileges); + sr.Serialize ("FastElevation", FastElevation); + } + + // CheckFilesystemRequest + void CheckFilesystemRequest::Deserialize (shared_ptr <Stream> stream) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + MountedVolumeInfo = Serializable::DeserializeNew <VolumeInfo> (stream); + sr.Deserialize ("Repair", Repair); + } + + bool CheckFilesystemRequest::RequiresElevation () const + { +#ifdef TC_MACOSX + return false; +#endif + return !Core->HasAdminPrivileges(); + } + + void CheckFilesystemRequest::Serialize (shared_ptr <Stream> stream) const + { + CoreServiceRequest::Serialize (stream); + Serializer sr (stream); + MountedVolumeInfo->Serialize (stream); + sr.Serialize ("Repair", Repair); + } + + // DismountFilesystemRequest + void DismountFilesystemRequest::Deserialize (shared_ptr <Stream> stream) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + sr.Deserialize ("Force", Force); + MountPoint = sr.DeserializeWString ("MountPoint"); + } + + bool DismountFilesystemRequest::RequiresElevation () const + { + return !Core->HasAdminPrivileges(); + } + + void DismountFilesystemRequest::Serialize (shared_ptr <Stream> stream) const + { + CoreServiceRequest::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("Force", Force); + sr.Serialize ("MountPoint", wstring (MountPoint)); + } + + // DismountVolumeRequest + void DismountVolumeRequest::Deserialize (shared_ptr <Stream> stream) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + sr.Deserialize ("IgnoreOpenFiles", IgnoreOpenFiles); + sr.Deserialize ("SyncVolumeInfo", SyncVolumeInfo); + MountedVolumeInfo = Serializable::DeserializeNew <VolumeInfo> (stream); + } + + bool DismountVolumeRequest::RequiresElevation () const + { +#ifdef TC_MACOSX + if (MountedVolumeInfo->Path.IsDevice()) + { + try + { + File file; + file.Open (MountedVolumeInfo->Path, File::OpenReadWrite); + } + catch (...) + { + return true; + } + } + + return false; +#endif + return !Core->HasAdminPrivileges(); + } + + void DismountVolumeRequest::Serialize (shared_ptr <Stream> stream) const + { + CoreServiceRequest::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("IgnoreOpenFiles", IgnoreOpenFiles); + sr.Serialize ("SyncVolumeInfo", SyncVolumeInfo); + MountedVolumeInfo->Serialize (stream); + } + + // GetDeviceSectorSizeRequest + void GetDeviceSectorSizeRequest::Deserialize (shared_ptr <Stream> stream) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + Path = sr.DeserializeWString ("Path"); + } + + bool GetDeviceSectorSizeRequest::RequiresElevation () const + { + return !Core->HasAdminPrivileges(); + } + + void GetDeviceSectorSizeRequest::Serialize (shared_ptr <Stream> stream) const + { + CoreServiceRequest::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("Path", wstring (Path)); + } + + // GetDeviceSizeRequest + void GetDeviceSizeRequest::Deserialize (shared_ptr <Stream> stream) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + Path = sr.DeserializeWString ("Path"); + } + + bool GetDeviceSizeRequest::RequiresElevation () const + { + return !Core->HasAdminPrivileges(); + } + + void GetDeviceSizeRequest::Serialize (shared_ptr <Stream> stream) const + { + CoreServiceRequest::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("Path", wstring (Path)); + } + + // GetHostDevicesRequest + void GetHostDevicesRequest::Deserialize (shared_ptr <Stream> stream) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + sr.Deserialize ("PathListOnly", PathListOnly); + } + + bool GetHostDevicesRequest::RequiresElevation () const + { + return !Core->HasAdminPrivileges(); + } + + void GetHostDevicesRequest::Serialize (shared_ptr <Stream> stream) const + { + CoreServiceRequest::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("PathListOnly", PathListOnly); + } + + // ExitRequest + void ExitRequest::Deserialize (shared_ptr <Stream> stream) + { + CoreServiceRequest::Deserialize (stream); + } + + void ExitRequest::Serialize (shared_ptr <Stream> stream) const + { + CoreServiceRequest::Serialize (stream); + } + + // MountVolumeRequest + void MountVolumeRequest::Deserialize (shared_ptr <Stream> stream) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + DeserializedOptions = Serializable::DeserializeNew <MountOptions> (stream); + Options = DeserializedOptions.get(); + } + + bool MountVolumeRequest::RequiresElevation () const + { +#ifdef TC_MACOSX + if (Options->Path->IsDevice()) + { + try + { + File file; + file.Open (*Options->Path, File::OpenReadWrite); + } + catch (...) + { + return true; + } + } + + return false; +#endif + return !Core->HasAdminPrivileges(); + } + + void MountVolumeRequest::Serialize (shared_ptr <Stream> stream) const + { + CoreServiceRequest::Serialize (stream); + Serializer sr (stream); + Options->Serialize (stream); + } + + // SetFileOwnerRequest + void SetFileOwnerRequest::Deserialize (shared_ptr <Stream> stream) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + + uint64 owner; + sr.Deserialize ("Owner", owner); + Owner.SystemId = static_cast <uid_t> (owner); + + Path = sr.DeserializeWString ("Path"); + } + + bool SetFileOwnerRequest::RequiresElevation () const + { + return !Core->HasAdminPrivileges(); + } + + void SetFileOwnerRequest::Serialize (shared_ptr <Stream> stream) const + { + CoreServiceRequest::Serialize (stream); + Serializer sr (stream); + + uint64 owner = Owner.SystemId; + sr.Serialize ("Owner", owner); + + sr.Serialize ("Path", wstring (Path)); + } + + + TC_SERIALIZER_FACTORY_ADD_CLASS (CoreServiceRequest); + TC_SERIALIZER_FACTORY_ADD_CLASS (CheckFilesystemRequest); + TC_SERIALIZER_FACTORY_ADD_CLASS (DismountFilesystemRequest); + TC_SERIALIZER_FACTORY_ADD_CLASS (DismountVolumeRequest); + TC_SERIALIZER_FACTORY_ADD_CLASS (ExitRequest); + TC_SERIALIZER_FACTORY_ADD_CLASS (GetDeviceSectorSizeRequest); + TC_SERIALIZER_FACTORY_ADD_CLASS (GetDeviceSizeRequest); + TC_SERIALIZER_FACTORY_ADD_CLASS (GetHostDevicesRequest); + TC_SERIALIZER_FACTORY_ADD_CLASS (MountVolumeRequest); + TC_SERIALIZER_FACTORY_ADD_CLASS (SetFileOwnerRequest); +} diff --git a/src/Core/Unix/CoreServiceRequest.h b/src/Core/Unix/CoreServiceRequest.h new file mode 100644 index 00000000..030ac81b --- /dev/null +++ b/src/Core/Unix/CoreServiceRequest.h @@ -0,0 +1,136 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_Unix_CoreServiceRequest +#define TC_HEADER_Core_Unix_CoreServiceRequest + +#include "Platform/Serializable.h" +#include "Core/Core.h" + +namespace TrueCrypt +{ + struct CoreServiceRequest : public Serializable + { + CoreServiceRequest () : ElevateUserPrivileges (false), FastElevation (false) { } + TC_SERIALIZABLE (CoreServiceRequest); + + virtual bool RequiresElevation () const { return false; } + + string AdminPassword; + FilePath ApplicationExecutablePath; + bool ElevateUserPrivileges; + bool FastElevation; + }; + + struct CheckFilesystemRequest : CoreServiceRequest + { + CheckFilesystemRequest () { } + CheckFilesystemRequest (shared_ptr <VolumeInfo> volumeInfo, bool repair) + : MountedVolumeInfo (volumeInfo), Repair (repair) { } + TC_SERIALIZABLE (CheckFilesystemRequest); + + virtual bool RequiresElevation () const; + + shared_ptr <VolumeInfo> MountedVolumeInfo; + bool Repair; + }; + + struct DismountFilesystemRequest : CoreServiceRequest + { + DismountFilesystemRequest () { } + DismountFilesystemRequest (const DirectoryPath &mountPoint, bool force) + : Force (force), MountPoint (mountPoint) { } + TC_SERIALIZABLE (DismountFilesystemRequest); + + virtual bool RequiresElevation () const; + + bool Force; + DirectoryPath MountPoint; + }; + + struct DismountVolumeRequest : CoreServiceRequest + { + DismountVolumeRequest () { } + DismountVolumeRequest (shared_ptr <VolumeInfo> volumeInfo, bool ignoreOpenFiles, bool syncVolumeInfo) + : IgnoreOpenFiles (ignoreOpenFiles), MountedVolumeInfo (volumeInfo), SyncVolumeInfo (syncVolumeInfo) { } + TC_SERIALIZABLE (DismountVolumeRequest); + + virtual bool RequiresElevation () const; + + bool IgnoreOpenFiles; + shared_ptr <VolumeInfo> MountedVolumeInfo; + bool SyncVolumeInfo; + }; + + struct GetDeviceSectorSizeRequest : CoreServiceRequest + { + GetDeviceSectorSizeRequest () { } + GetDeviceSectorSizeRequest (const DevicePath &path) : Path (path) { } + TC_SERIALIZABLE (GetDeviceSectorSizeRequest); + + virtual bool RequiresElevation () const; + + DevicePath Path; + }; + + struct GetDeviceSizeRequest : CoreServiceRequest + { + GetDeviceSizeRequest () { } + GetDeviceSizeRequest (const DevicePath &path) : Path (path) { } + TC_SERIALIZABLE (GetDeviceSizeRequest); + + virtual bool RequiresElevation () const; + + DevicePath Path; + }; + + struct GetHostDevicesRequest : CoreServiceRequest + { + GetHostDevicesRequest () { } + GetHostDevicesRequest (bool pathListOnly) : PathListOnly (pathListOnly) { } + TC_SERIALIZABLE (GetHostDevicesRequest); + + virtual bool RequiresElevation () const; + + bool PathListOnly; + }; + + struct ExitRequest : CoreServiceRequest + { + TC_SERIALIZABLE (ExitRequest); + }; + + struct MountVolumeRequest : CoreServiceRequest + { + MountVolumeRequest () { } + MountVolumeRequest (MountOptions *options) : Options (options) { } + TC_SERIALIZABLE (MountVolumeRequest); + + virtual bool RequiresElevation () const; + + MountOptions *Options; + + protected: + shared_ptr <MountOptions> DeserializedOptions; + }; + + + struct SetFileOwnerRequest : CoreServiceRequest + { + SetFileOwnerRequest () { } + SetFileOwnerRequest (const FilesystemPath &path, const UserId &owner) : Owner (owner), Path (path) { } + TC_SERIALIZABLE (SetFileOwnerRequest); + + virtual bool RequiresElevation () const; + + UserId Owner; + FilesystemPath Path; + }; +} + +#endif // TC_HEADER_Core_Unix_CoreServiceRequest diff --git a/src/Core/Unix/CoreServiceResponse.cpp b/src/Core/Unix/CoreServiceResponse.cpp new file mode 100644 index 00000000..7809b448 --- /dev/null +++ b/src/Core/Unix/CoreServiceResponse.cpp @@ -0,0 +1,119 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include "CoreServiceResponse.h" +#include "Platform/SerializerFactory.h" + +namespace TrueCrypt +{ + // CheckFilesystemResponse + void CheckFilesystemResponse::Deserialize (shared_ptr <Stream> stream) + { + } + + void CheckFilesystemResponse::Serialize (shared_ptr <Stream> stream) const + { + Serializable::Serialize (stream); + } + + // DismountFilesystemResponse + void DismountFilesystemResponse::Deserialize (shared_ptr <Stream> stream) + { + } + + void DismountFilesystemResponse::Serialize (shared_ptr <Stream> stream) const + { + Serializable::Serialize (stream); + } + + // DismountVolumeResponse + void DismountVolumeResponse::Deserialize (shared_ptr <Stream> stream) + { + DismountedVolumeInfo = Serializable::DeserializeNew <VolumeInfo> (stream); + } + + void DismountVolumeResponse::Serialize (shared_ptr <Stream> stream) const + { + Serializable::Serialize (stream); + Serializer sr (stream); + DismountedVolumeInfo->Serialize (stream); + } + + // GetDeviceSectorSizeResponse + void GetDeviceSectorSizeResponse::Deserialize (shared_ptr <Stream> stream) + { + Serializer sr (stream); + sr.Deserialize ("Size", Size); + } + + void GetDeviceSectorSizeResponse::Serialize (shared_ptr <Stream> stream) const + { + Serializable::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("Size", Size); + } + + // GetDeviceSizeResponse + void GetDeviceSizeResponse::Deserialize (shared_ptr <Stream> stream) + { + Serializer sr (stream); + sr.Deserialize ("Size", Size); + } + + void GetDeviceSizeResponse::Serialize (shared_ptr <Stream> stream) const + { + Serializable::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("Size", Size); + } + + // GetHostDevicesResponse + void GetHostDevicesResponse::Deserialize (shared_ptr <Stream> stream) + { + Serializable::DeserializeList (stream, HostDevices); + } + + void GetHostDevicesResponse::Serialize (shared_ptr <Stream> stream) const + { + Serializable::Serialize (stream); + Serializable::SerializeList (stream, HostDevices); + } + + // MountVolumeResponse + void MountVolumeResponse::Deserialize (shared_ptr <Stream> stream) + { + Serializer sr (stream); + MountedVolumeInfo = Serializable::DeserializeNew <VolumeInfo> (stream); + } + + void MountVolumeResponse::Serialize (shared_ptr <Stream> stream) const + { + Serializable::Serialize (stream); + Serializer sr (stream); + MountedVolumeInfo->Serialize (stream); + } + + // SetFileOwnerResponse + void SetFileOwnerResponse::Deserialize (shared_ptr <Stream> stream) + { + } + + void SetFileOwnerResponse::Serialize (shared_ptr <Stream> stream) const + { + Serializable::Serialize (stream); + } + + TC_SERIALIZER_FACTORY_ADD_CLASS (CheckFilesystemResponse); + TC_SERIALIZER_FACTORY_ADD_CLASS (DismountFilesystemResponse); + TC_SERIALIZER_FACTORY_ADD_CLASS (DismountVolumeResponse); + TC_SERIALIZER_FACTORY_ADD_CLASS (GetDeviceSectorSizeResponse); + TC_SERIALIZER_FACTORY_ADD_CLASS (GetDeviceSizeResponse); + TC_SERIALIZER_FACTORY_ADD_CLASS (GetHostDevicesResponse); + TC_SERIALIZER_FACTORY_ADD_CLASS (MountVolumeResponse); + TC_SERIALIZER_FACTORY_ADD_CLASS (SetFileOwnerResponse); +} diff --git a/src/Core/Unix/CoreServiceResponse.h b/src/Core/Unix/CoreServiceResponse.h new file mode 100644 index 00000000..24c09b35 --- /dev/null +++ b/src/Core/Unix/CoreServiceResponse.h @@ -0,0 +1,84 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_Unix_CoreServiceResponse +#define TC_HEADER_Core_Unix_CoreServiceResponse + +#include "Platform/Serializable.h" +#include "Core/Core.h" + +namespace TrueCrypt +{ + struct CoreServiceResponse : public Serializable + { + }; + + struct CheckFilesystemResponse : CoreServiceResponse + { + CheckFilesystemResponse () { } + TC_SERIALIZABLE (CheckFilesystemResponse); + }; + + struct DismountFilesystemResponse : CoreServiceResponse + { + DismountFilesystemResponse () { } + TC_SERIALIZABLE (DismountFilesystemResponse); + }; + + struct DismountVolumeResponse : CoreServiceResponse + { + DismountVolumeResponse () { } + TC_SERIALIZABLE (DismountVolumeResponse); + + shared_ptr <VolumeInfo> DismountedVolumeInfo; + }; + + struct GetDeviceSectorSizeResponse : CoreServiceResponse + { + GetDeviceSectorSizeResponse () { } + GetDeviceSectorSizeResponse (uint32 size) : Size (size) { } + TC_SERIALIZABLE (GetDeviceSectorSizeResponse); + + uint32 Size; + }; + + struct GetDeviceSizeResponse : CoreServiceResponse + { + GetDeviceSizeResponse () { } + GetDeviceSizeResponse (uint64 size) : Size (size) { } + TC_SERIALIZABLE (GetDeviceSizeResponse); + + uint64 Size; + }; + + struct GetHostDevicesResponse : CoreServiceResponse + { + GetHostDevicesResponse () { } + GetHostDevicesResponse (const HostDeviceList &hostDevices) : HostDevices (hostDevices) { } + TC_SERIALIZABLE (GetHostDevicesResponse); + + HostDeviceList HostDevices; + }; + + struct MountVolumeResponse : CoreServiceResponse + { + MountVolumeResponse () { } + MountVolumeResponse (shared_ptr <VolumeInfo> volumeInfo) : MountedVolumeInfo (volumeInfo) { } + TC_SERIALIZABLE (MountVolumeResponse); + + shared_ptr <VolumeInfo> MountedVolumeInfo; + }; + + struct SetFileOwnerResponse : CoreServiceResponse + { + SetFileOwnerResponse () { } + TC_SERIALIZABLE (SetFileOwnerResponse); + }; +} + +#endif // TC_HEADER_Core_Unix_CoreServiceResponse diff --git a/src/Core/Unix/CoreUnix.cpp b/src/Core/Unix/CoreUnix.cpp new file mode 100644 index 00000000..89f34e20 --- /dev/null +++ b/src/Core/Unix/CoreUnix.cpp @@ -0,0 +1,618 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include "CoreUnix.h" +#include <errno.h> +#include <iostream> +#include <signal.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <stdio.h> +#include <unistd.h> +#include "Platform/FileStream.h" +#include "Driver/Fuse/FuseService.h" +#include "Volume/VolumePasswordCache.h" + +namespace TrueCrypt +{ + CoreUnix::CoreUnix () + { + signal (SIGPIPE, SIG_IGN); + + char *loc = setlocale (LC_ALL, ""); + if (!loc || string (loc) == "C") + setlocale (LC_ALL, "en_US.UTF-8"); + } + + CoreUnix::~CoreUnix () + { + } + + void CoreUnix::CheckFilesystem (shared_ptr <VolumeInfo> mountedVolume, bool repair) const + { + if (!mountedVolume->MountPoint.IsEmpty()) + DismountFilesystem (mountedVolume->MountPoint, false); + + list <string> args; + + args.push_back ("-T"); + args.push_back ("fsck"); + + args.push_back ("-e"); + + string xargs = "fsck "; + +#ifdef TC_LINUX + if (!repair) + xargs += "-n "; + else + xargs += "-r "; +#endif + + xargs += string (mountedVolume->VirtualDevice) + "; echo '[Done]'; read W"; + args.push_back (xargs); + + try + { + Process::Execute ("xterm", args, 1000); + } catch (TimeOut&) { } + } + + void CoreUnix::DismountFilesystem (const DirectoryPath &mountPoint, bool force) const + { + list <string> args; + +#ifdef TC_MACOSX + if (force) + args.push_back ("-f"); +#endif + args.push_back ("--"); + args.push_back (mountPoint); + + Process::Execute ("umount", args); + } + + shared_ptr <VolumeInfo> CoreUnix::DismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles, bool syncVolumeInfo) + { + if (!mountedVolume->MountPoint.IsEmpty()) + { + DismountFilesystem (mountedVolume->MountPoint, ignoreOpenFiles); + + // Delete mount directory if a default path has been used + if (string (mountedVolume->MountPoint).find (GetDefaultMountPointPrefix()) == 0) + mountedVolume->MountPoint.Delete(); + } + + try + { + DismountNativeVolume (mountedVolume); + } + catch (NotApplicable &) { } + + if (!mountedVolume->LoopDevice.IsEmpty()) + { + try + { + DetachLoopDevice (mountedVolume->LoopDevice); + } + catch (ExecutedProcessFailed&) { } + } + + if (syncVolumeInfo || mountedVolume->Protection == VolumeProtection::HiddenVolumeReadOnly) + { + sync(); + VolumeInfoList ml = GetMountedVolumes (mountedVolume->Path); + + if (ml.size() > 0) + mountedVolume = ml.front(); + } + + list <string> args; + args.push_back ("--"); + args.push_back (mountedVolume->AuxMountPoint); + + for (int t = 0; true; t++) + { + try + { + Process::Execute ("umount", args); + break; + } + catch (ExecutedProcessFailed&) + { + if (t > 10) + throw; + Thread::Sleep (200); + } + } + + try + { + mountedVolume->AuxMountPoint.Delete(); + } + catch (...) { } + + VolumeEventArgs eventArgs (mountedVolume); + VolumeDismountedEvent.Raise (eventArgs); + + return mountedVolume; + } + + bool CoreUnix::FilesystemSupportsLargeFiles (const FilePath &filePath) const + { + string path = filePath; + size_t pos; + + while ((pos = path.find_last_of ('/')) != string::npos) + { + path = path.substr (0, pos); + + if (path.empty()) + break; + + try + { + MountedFilesystemList filesystems = GetMountedFilesystems (DevicePath(), path); + if (!filesystems.empty()) + { + const MountedFilesystem &fs = *filesystems.front(); + + if (fs.Type == "fat" + || fs.Type == "fat32" + || fs.Type == "vfat" + || fs.Type == "fatfs" + || fs.Type == "msdos" + || fs.Type == "msdosfs" + || fs.Type == "umsdos" + || fs.Type == "dos" + || fs.Type == "dosfs" + || fs.Type == "pcfs" + ) + { + return false; + } + + return true; + } + } + catch (...) { } + } + + return true; // Prevent errors if the filesystem cannot be identified + } + + bool CoreUnix::FilesystemSupportsUnixPermissions (const DevicePath &devicePath) const + { + File device; + device.Open (devicePath); + + Buffer bootSector (device.GetDeviceSectorSize()); + device.SeekAt (0); + device.ReadCompleteBuffer (bootSector); + + byte *b = bootSector.Ptr(); + + return memcmp (b + 3, "NTFS", 4) != 0 + && memcmp (b + 54, "FAT", 3) != 0 + && memcmp (b + 82, "FAT32", 5) != 0 + && memcmp (b + 3, "EXFAT", 5) != 0; + } + + string CoreUnix::GetDefaultMountPointPrefix () const + { + const char *envPrefix = getenv ("TRUECRYPT_MOUNT_PREFIX"); + if (envPrefix && !string (envPrefix).empty()) + return envPrefix; + + if (FilesystemPath ("/media").IsDirectory()) + return "/media/truecrypt"; + + if (FilesystemPath ("/mnt").IsDirectory()) + return "/mnt/truecrypt"; + + return GetTempDirectory() + "/truecrypt_mnt"; + } + + uint32 CoreUnix::GetDeviceSectorSize (const DevicePath &devicePath) const + { + File dev; + dev.Open (devicePath); + return dev.GetDeviceSectorSize(); + } + + uint64 CoreUnix::GetDeviceSize (const DevicePath &devicePath) const + { + File dev; + dev.Open (devicePath); + return dev.Length(); + } + + DirectoryPath CoreUnix::GetDeviceMountPoint (const DevicePath &devicePath) const + { + DevicePath devPath = devicePath; +#ifdef TC_MACOSX + if (string (devPath).find ("/dev/rdisk") != string::npos) + devPath = string ("/dev/") + string (devicePath).substr (6); +#endif + MountedFilesystemList mountedFilesystems = GetMountedFilesystems (devPath); + + if (mountedFilesystems.size() < 1) + return DirectoryPath(); + + return mountedFilesystems.front()->MountPoint; + } + + VolumeInfoList CoreUnix::GetMountedVolumes (const VolumePath &volumePath) const + { + VolumeInfoList volumes; + + foreach_ref (const MountedFilesystem &mf, GetMountedFilesystems ()) + { + if (string (mf.MountPoint).find (GetFuseMountDirPrefix()) == string::npos) + continue; + + shared_ptr <VolumeInfo> mountedVol; + try + { + shared_ptr <File> controlFile (new File); + controlFile->Open (string (mf.MountPoint) + FuseService::GetControlPath()); + + shared_ptr <Stream> controlFileStream (new FileStream (controlFile)); + mountedVol = Serializable::DeserializeNew <VolumeInfo> (controlFileStream); + } + catch (...) + { + continue; + } + + if (!volumePath.IsEmpty() && wstring (mountedVol->Path).compare (volumePath) != 0) + continue; + + mountedVol->AuxMountPoint = mf.MountPoint; + + if (!mountedVol->VirtualDevice.IsEmpty()) + { + MountedFilesystemList mpl = GetMountedFilesystems (mountedVol->VirtualDevice); + + if (mpl.size() > 0) + mountedVol->MountPoint = mpl.front()->MountPoint; + } + + volumes.push_back (mountedVol); + + if (!volumePath.IsEmpty()) + break; + } + + return volumes; + } + + gid_t CoreUnix::GetRealGroupId () const + { + const char *env = getenv ("SUDO_GID"); + if (env) + { + try + { + string s (env); + return static_cast <gid_t> (StringConverter::ToUInt64 (s)); + } + catch (...) { } + } + + return getgid(); + } + + uid_t CoreUnix::GetRealUserId () const + { + const char *env = getenv ("SUDO_UID"); + if (env) + { + try + { + string s (env); + return static_cast <uid_t> (StringConverter::ToUInt64 (s)); + } + catch (...) { } + } + + return getuid(); + } + + string CoreUnix::GetTempDirectory () const + { + char *envDir = getenv ("TMPDIR"); + return envDir ? envDir : "/tmp"; + } + + bool CoreUnix::IsMountPointAvailable (const DirectoryPath &mountPoint) const + { + return GetMountedFilesystems (DevicePath(), mountPoint).size() == 0; + } + + void CoreUnix::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const + { + if (GetMountedFilesystems (DevicePath(), mountPoint).size() > 0) + throw MountPointUnavailable (SRC_POS); + + list <string> args; + string options; + + if (!filesystemType.empty()) + { +#ifdef TC_SOLARIS + args.push_back ("-F"); +#else + args.push_back ("-t"); +#endif + args.push_back (filesystemType); + } + + if (readOnly) + options = "-oro"; + + if (!systemMountOptions.empty()) + { + if (options.empty()) + options = "-o"; + else + options += ","; + + options += systemMountOptions; + } + + if (!options.empty()) + args.push_back (options); + + args.push_back ("--"); + args.push_back (devicePath); + args.push_back (mountPoint); + + Process::Execute ("mount", args); + } + + VolumeSlotNumber CoreUnix::MountPointToSlotNumber (const DirectoryPath &mountPoint) const + { + string mountPointStr (mountPoint); + if (mountPointStr.find (GetDefaultMountPointPrefix()) == 0) + { + try + { + return StringConverter::ToUInt32 (StringConverter::GetTrailingNumber (mountPointStr)); + } + catch (...) { } + } + return GetFirstFreeSlotNumber(); + } + + shared_ptr <VolumeInfo> CoreUnix::MountVolume (MountOptions &options) + { + CoalesceSlotNumberAndMountPoint (options); + + if (IsVolumeMounted (*options.Path)) + throw VolumeAlreadyMounted (SRC_POS); + + Cipher::EnableHwSupport (!options.NoHardwareCrypto); + + shared_ptr <Volume> volume; + + while (true) + { + try + { + volume = OpenVolume ( + options.Path, + options.PreserveTimestamps, + options.Password, + options.Keyfiles, + options.Protection, + options.ProtectionPassword, + options.ProtectionKeyfiles, + options.SharedAccessAllowed, + VolumeType::Unknown, + options.UseBackupHeaders, + options.PartitionInSystemEncryptionScope + ); + + options.Password.reset(); + } + catch (SystemException &e) + { + if (options.Protection != VolumeProtection::ReadOnly + && (e.GetErrorCode() == EROFS || e.GetErrorCode() == EACCES || e.GetErrorCode() == EPERM)) + { + // Read-only filesystem + options.Protection = VolumeProtection::ReadOnly; + continue; + } + + throw; + } + + break; + } + + if (options.Path->IsDevice()) + { + if (volume->GetFile()->GetDeviceSectorSize() != volume->GetSectorSize()) + throw ParameterIncorrect (SRC_POS); + +#if defined (TC_LINUX) + if (volume->GetSectorSize() != TC_SECTOR_SIZE_LEGACY) + { + if (options.Protection == VolumeProtection::HiddenVolumeReadOnly) + throw UnsupportedSectorSizeHiddenVolumeProtection(); + + if (options.NoKernelCrypto) + throw UnsupportedSectorSizeNoKernelCrypto(); + } +#endif + } + + // Find a free mount point for FUSE service + MountedFilesystemList mountedFilesystems = GetMountedFilesystems (); + string fuseMountPoint; + for (int i = 1; true; i++) + { + stringstream path; + path << GetTempDirectory() << "/" << GetFuseMountDirPrefix() << i; + FilesystemPath fsPath (path.str()); + + bool inUse = false; + + foreach_ref (const MountedFilesystem &mf, mountedFilesystems) + { + if (mf.MountPoint == path.str()) + { + inUse = true; + break; + } + } + + if (!inUse) + { + try + { + if (fsPath.IsDirectory()) + fsPath.Delete(); + + throw_sys_sub_if (mkdir (path.str().c_str(), S_IRUSR | S_IXUSR) == -1, path.str()); + + fuseMountPoint = fsPath; + break; + } + catch (...) + { + if (i > 255) + throw TemporaryDirectoryFailure (SRC_POS, StringConverter::ToWide (path.str())); + } + } + } + + try + { + FuseService::Mount (volume, options.SlotNumber, fuseMountPoint); + } + catch (...) + { + try + { + DirectoryPath (fuseMountPoint).Delete(); + } + catch (...) { } + throw; + } + + try + { + // Create a mount directory if a default path has been specified + bool mountDirCreated = false; + string mountPoint; + if (!options.NoFilesystem && options.MountPoint) + { + mountPoint = *options.MountPoint; + +#ifndef TC_MACOSX + if (mountPoint.find (GetDefaultMountPointPrefix()) == 0 && !options.MountPoint->IsDirectory()) + { + Directory::Create (*options.MountPoint); + try + { + throw_sys_sub_if (chown (mountPoint.c_str(), GetRealUserId(), GetRealGroupId()) == -1, mountPoint); + } catch (ParameterIncorrect&) { } + + mountDirCreated = true; + } +#endif + } + + try + { + try + { + MountVolumeNative (volume, options, fuseMountPoint); + } + catch (NotApplicable&) + { + MountAuxVolumeImage (fuseMountPoint, options); + } + } + catch (...) + { + if (mountDirCreated) + remove (mountPoint.c_str()); + throw; + } + } + catch (...) + { + try + { + VolumeInfoList mountedVolumes = GetMountedVolumes (*options.Path); + if (mountedVolumes.size() > 0) + { + shared_ptr <VolumeInfo> mountedVolume (mountedVolumes.front()); + DismountVolume (mountedVolume); + } + } + catch (...) { } + throw; + } + + VolumeInfoList mountedVolumes = GetMountedVolumes (*options.Path); + if (mountedVolumes.size() != 1) + throw ParameterIncorrect (SRC_POS); + + VolumeEventArgs eventArgs (mountedVolumes.front()); + VolumeMountedEvent.Raise (eventArgs); + + return mountedVolumes.front(); + } + + void CoreUnix::MountAuxVolumeImage (const DirectoryPath &auxMountPoint, const MountOptions &options) const + { + DevicePath loopDev = AttachFileToLoopDevice (string (auxMountPoint) + FuseService::GetVolumeImagePath(), options.Protection == VolumeProtection::ReadOnly); + + try + { + FuseService::SendAuxDeviceInfo (auxMountPoint, loopDev, loopDev); + } + catch (...) + { + try + { + DetachLoopDevice (loopDev); + } + catch (...) { } + throw; + } + + if (!options.NoFilesystem && options.MountPoint && !options.MountPoint->IsEmpty()) + { + MountFilesystem (loopDev, *options.MountPoint, + StringConverter::ToSingle (options.FilesystemType), + options.Protection == VolumeProtection::ReadOnly, + StringConverter::ToSingle (options.FilesystemOptions)); + } + } + + void CoreUnix::SetFileOwner (const FilesystemPath &path, const UserId &owner) const + { + throw_sys_if (chown (string (path).c_str(), owner.SystemId, (gid_t) -1) == -1); + } + + DirectoryPath CoreUnix::SlotNumberToMountPoint (VolumeSlotNumber slotNumber) const + { + if (slotNumber < GetFirstSlotNumber() || slotNumber > GetLastSlotNumber()) + throw ParameterIncorrect (SRC_POS); + + stringstream s; + s << GetDefaultMountPointPrefix() << slotNumber; + return s.str(); + } +} diff --git a/src/Core/Unix/CoreUnix.h b/src/Core/Unix/CoreUnix.h new file mode 100644 index 00000000..1d7152fb --- /dev/null +++ b/src/Core/Unix/CoreUnix.h @@ -0,0 +1,69 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_CoreUnix +#define TC_HEADER_Core_CoreUnix + +#include "System.h" +#include "Platform/Unix/Process.h" +#include "Core/CoreBase.h" +#include "Core/Unix/MountedFilesystem.h" + +namespace TrueCrypt +{ + class CoreUnix : public CoreBase + { + public: + CoreUnix (); + virtual ~CoreUnix (); + + virtual void CheckFilesystem (shared_ptr <VolumeInfo> mountedVolume, bool repair = false) const; + virtual void DismountFilesystem (const DirectoryPath &mountPoint, bool force) const; + virtual shared_ptr <VolumeInfo> DismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles = false, bool syncVolumeInfo = false); + virtual bool FilesystemSupportsLargeFiles (const FilePath &filePath) const; + virtual DirectoryPath GetDeviceMountPoint (const DevicePath &devicePath) const; + virtual uint32 GetDeviceSectorSize (const DevicePath &devicePath) const; + virtual uint64 GetDeviceSize (const DevicePath &devicePath) const; + virtual int GetOSMajorVersion () const { throw NotApplicable (SRC_POS); } + virtual int GetOSMinorVersion () const { throw NotApplicable (SRC_POS); } + virtual VolumeInfoList GetMountedVolumes (const VolumePath &volumePath = VolumePath()) const; + virtual bool IsDevicePresent (const DevicePath &device) const { throw NotApplicable (SRC_POS); } + virtual bool IsInPortableMode () const { return false; } + virtual bool IsMountPointAvailable (const DirectoryPath &mountPoint) const; + virtual bool IsOSVersion (int major, int minor) const { throw NotApplicable (SRC_POS); } + virtual bool IsOSVersionLower (int major, int minor) const { throw NotApplicable (SRC_POS); } + virtual bool IsPasswordCacheEmpty () const { throw NotApplicable (SRC_POS); } + virtual bool HasAdminPrivileges () const { return getuid() == 0 || geteuid() == 0; } + virtual VolumeSlotNumber MountPointToSlotNumber (const DirectoryPath &mountPoint) const; + virtual shared_ptr <VolumeInfo> MountVolume (MountOptions &options); + virtual void SetFileOwner (const FilesystemPath &path, const UserId &owner) const; + virtual DirectoryPath SlotNumberToMountPoint (VolumeSlotNumber slotNumber) const; + virtual void WipePasswordCache () const { throw NotApplicable (SRC_POS); } + + protected: + virtual DevicePath AttachFileToLoopDevice (const FilePath &filePath, bool readOnly) const { throw NotApplicable (SRC_POS); } + virtual void DetachLoopDevice (const DevicePath &devicePath) const { throw NotApplicable (SRC_POS); } + virtual void DismountNativeVolume (shared_ptr <VolumeInfo> mountedVolume) const { throw NotApplicable (SRC_POS); } + virtual bool FilesystemSupportsUnixPermissions (const DevicePath &devicePath) const; + virtual string GetDefaultMountPointPrefix () const; + virtual string GetFuseMountDirPrefix () const { return ".truecrypt_aux_mnt"; } + virtual MountedFilesystemList GetMountedFilesystems (const DevicePath &devicePath = DevicePath(), const DirectoryPath &mountPoint = DirectoryPath()) const = 0; + virtual uid_t GetRealUserId () const; + virtual gid_t GetRealGroupId () const; + virtual string GetTempDirectory () const; + virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const; + virtual void MountAuxVolumeImage (const DirectoryPath &auxMountPoint, const MountOptions &options) const; + virtual void MountVolumeNative (shared_ptr <Volume> volume, MountOptions &options, const DirectoryPath &auxMountPoint) const { throw NotApplicable (SRC_POS); } + + private: + CoreUnix (const CoreUnix &); + CoreUnix &operator= (const CoreUnix &); + }; +} + +#endif // TC_HEADER_Core_CoreUnix diff --git a/src/Core/Unix/FreeBSD/CoreFreeBSD.cpp b/src/Core/Unix/FreeBSD/CoreFreeBSD.cpp new file mode 100644 index 00000000..e0a4dd5f --- /dev/null +++ b/src/Core/Unix/FreeBSD/CoreFreeBSD.cpp @@ -0,0 +1,202 @@ +/* + Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include <fstream> +#include <stdio.h> +#include <unistd.h> +#include <sys/param.h> +#include <sys/ucred.h> +#include <sys/mount.h> +#include <sys/wait.h> +#include "CoreFreeBSD.h" +#include "Core/Unix/CoreServiceProxy.h" + +namespace TrueCrypt +{ + CoreFreeBSD::CoreFreeBSD () + { + } + + CoreFreeBSD::~CoreFreeBSD () + { + } + + DevicePath CoreFreeBSD::AttachFileToLoopDevice (const FilePath &filePath, bool readOnly) const + { + list <string> args; + args.push_back ("-a"); + args.push_back ("-t"); + args.push_back ("vnode"); + + if (readOnly) + { + args.push_back ("-o"); + args.push_back ("readonly"); + } + + args.push_back ("-f"); + args.push_back (filePath); + + string dev = StringConverter::Trim (Process::Execute ("mdconfig", args)); + + if (dev.find ("/") == string::npos) + dev = string ("/dev/") + dev; + + return dev; + } + + void CoreFreeBSD::DetachLoopDevice (const DevicePath &devicePath) const + { + list <string> args; + args.push_back ("-d"); + args.push_back ("-u"); + args.push_back (StringConverter::GetTrailingNumber (devicePath)); + + for (int t = 0; true; t++) + { + try + { + Process::Execute ("mdconfig", args); + break; + } + catch (ExecutedProcessFailed&) + { + if (t > 5) + throw; + Thread::Sleep (200); + } + } + } + + HostDeviceList CoreFreeBSD::GetHostDevices (bool pathListOnly) const + { + HostDeviceList devices; +#ifdef TC_MACOSX + const string busType = "rdisk"; +#else + foreach (const string &busType, StringConverter::Split ("ad da")) +#endif + { + for (int devNumber = 0; devNumber < 64; devNumber++) + { + stringstream devPath; + devPath << "/dev/" << busType << devNumber; + + if (FilesystemPath (devPath.str()).IsBlockDevice() || FilesystemPath (devPath.str()).IsCharacterDevice()) + { + make_shared_auto (HostDevice, device); + device->Path = devPath.str(); + if (!pathListOnly) + { + try + { + device->Size = GetDeviceSize (device->Path); + } + catch (...) + { + device->Size = 0; + } + device->MountPoint = GetDeviceMountPoint (device->Path); + device->SystemNumber = 0; + } + devices.push_back (device); + + for (int partNumber = 1; partNumber < 32; partNumber++) + { +#ifdef TC_MACOSX + const string partLetter = ""; +#else + foreach (const string &partLetter, StringConverter::Split (",a,b,c,d,e,f,g,h", ",", true)) +#endif + { + stringstream partPath; + partPath << devPath.str() << "s" << partNumber << partLetter; + + if (FilesystemPath (partPath.str()).IsBlockDevice() || FilesystemPath (partPath.str()).IsCharacterDevice()) + { + make_shared_auto (HostDevice, partition); + partition->Path = partPath.str(); + if (!pathListOnly) + { + try + { + partition->Size = GetDeviceSize (partition->Path); + } + catch (...) + { + partition->Size = 0; + } + partition->MountPoint = GetDeviceMountPoint (partition->Path); + partition->SystemNumber = 0; + } + + device->Partitions.push_back (partition); + } + } + } + } + } + } + + return devices; + } + + MountedFilesystemList CoreFreeBSD::GetMountedFilesystems (const DevicePath &devicePath, const DirectoryPath &mountPoint) const + { + + static Mutex mutex; + ScopeLock sl (mutex); + + struct statfs *sysMountList; + int count = getmntinfo (&sysMountList, MNT_NOWAIT); + throw_sys_if (count == 0); + + MountedFilesystemList mountedFilesystems; + + for (int i = 0; i < count; i++) + { + make_shared_auto (MountedFilesystem, mf); + + if (sysMountList[i].f_mntfromname[0]) + mf->Device = DevicePath (sysMountList[i].f_mntfromname); + else + continue; + + if (sysMountList[i].f_mntonname[0]) + mf->MountPoint = DirectoryPath (sysMountList[i].f_mntonname); + + mf->Type = sysMountList[i].f_fstypename; + + if ((devicePath.IsEmpty() || devicePath == mf->Device) && (mountPoint.IsEmpty() || mountPoint == mf->MountPoint)) + mountedFilesystems.push_back (mf); + } + + return mountedFilesystems; + } + + void CoreFreeBSD::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const + { + try + { + // Try to mount FAT by default as mount is unable to probe filesystem type on BSD + CoreUnix::MountFilesystem (devicePath, mountPoint, filesystemType.empty() ? "msdos" : filesystemType, readOnly, systemMountOptions); + } + catch (ExecutedProcessFailed&) + { + if (!filesystemType.empty()) + throw; + + CoreUnix::MountFilesystem (devicePath, mountPoint, filesystemType, readOnly, systemMountOptions); + } + } + +#ifdef TC_FREEBSD + auto_ptr <CoreBase> Core (new CoreServiceProxy <CoreFreeBSD>); + auto_ptr <CoreBase> CoreDirect (new CoreFreeBSD); +#endif +} diff --git a/src/Core/Unix/FreeBSD/CoreFreeBSD.h b/src/Core/Unix/FreeBSD/CoreFreeBSD.h new file mode 100644 index 00000000..a8230334 --- /dev/null +++ b/src/Core/Unix/FreeBSD/CoreFreeBSD.h @@ -0,0 +1,37 @@ +/* + Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_CoreFreeBSD +#define TC_HEADER_Core_CoreFreeBSD + +#include "System.h" +#include "Core/Unix/CoreUnix.h" + +namespace TrueCrypt +{ + class CoreFreeBSD : public CoreUnix + { + public: + CoreFreeBSD (); + virtual ~CoreFreeBSD (); + + virtual HostDeviceList GetHostDevices (bool pathListOnly = false) const; + + protected: + virtual DevicePath AttachFileToLoopDevice (const FilePath &filePath, bool readOnly) const; + virtual void DetachLoopDevice (const DevicePath &devicePath) const; + virtual MountedFilesystemList GetMountedFilesystems (const DevicePath &devicePath = DevicePath(), const DirectoryPath &mountPoint = DirectoryPath()) const; + virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const; + + private: + CoreFreeBSD (const CoreFreeBSD &); + CoreFreeBSD &operator= (const CoreFreeBSD &); + }; +} + +#endif // TC_HEADER_Core_CoreFreeBSD diff --git a/src/Core/Unix/FreeBSD/System.h b/src/Core/Unix/FreeBSD/System.h new file mode 100644 index 00000000..e0cac0ba --- /dev/null +++ b/src/Core/Unix/FreeBSD/System.h @@ -0,0 +1,12 @@ +/* + Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Platform_FreeBSD_System +#define TC_HEADER_Platform_FreeBSD_System + +#endif // TC_HEADER_Platform_FreeBSD_System diff --git a/src/Core/Unix/Linux/CoreLinux.cpp b/src/Core/Unix/Linux/CoreLinux.cpp new file mode 100644 index 00000000..634a3a23 --- /dev/null +++ b/src/Core/Unix/Linux/CoreLinux.cpp @@ -0,0 +1,477 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include <fstream> +#include <iomanip> +#include <mntent.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/mount.h> +#include <sys/wait.h> +#include "CoreLinux.h" +#include "Platform/SystemInfo.h" +#include "Platform/TextReader.h" +#include "Volume/EncryptionModeLRW.h" +#include "Volume/EncryptionModeXTS.h" +#include "Driver/Fuse/FuseService.h" +#include "Core/Unix/CoreServiceProxy.h" + +namespace TrueCrypt +{ + CoreLinux::CoreLinux () + { + } + + CoreLinux::~CoreLinux () + { + } + + DevicePath CoreLinux::AttachFileToLoopDevice (const FilePath &filePath, bool readOnly) const + { + list <string> loopPaths; + loopPaths.push_back ("/dev/loop"); + loopPaths.push_back ("/dev/loop/"); + loopPaths.push_back ("/dev/.static/dev/loop"); + + for (int devIndex = 0; devIndex < 256; devIndex++) + { + string loopDev; + foreach (const string &loopPath, loopPaths) + { + loopDev = loopPath + StringConverter::ToSingle (devIndex); + if (FilesystemPath (loopDev).IsBlockDevice()) + break; + } + + if (loopDev.empty()) + continue; + + list <string> args; + + list <string>::iterator readOnlyArg; + if (readOnly) + { + args.push_back ("-r"); + readOnlyArg = --args.end(); + } + + args.push_back ("--"); + args.push_back (loopDev); + args.push_back (filePath); + + try + { + Process::Execute ("losetup", args); + return loopDev; + } + catch (ExecutedProcessFailed&) + { + if (readOnly) + { + try + { + args.erase (readOnlyArg); + Process::Execute ("losetup", args); + return loopDev; + } + catch (ExecutedProcessFailed&) { } + } + } + } + + throw LoopDeviceSetupFailed (SRC_POS, wstring (filePath)); + } + + void CoreLinux::DetachLoopDevice (const DevicePath &devicePath) const + { + list <string> args; + args.push_back ("-d"); + args.push_back (devicePath); + + for (int t = 0; true; t++) + { + try + { + Process::Execute ("losetup", args); + break; + } + catch (ExecutedProcessFailed&) + { + if (t > 5) + throw; + Thread::Sleep (200); + } + } + } + + void CoreLinux::DismountNativeVolume (shared_ptr <VolumeInfo> mountedVolume) const + { + string devPath = mountedVolume->VirtualDevice; + + if (devPath.find ("/dev/mapper/truecrypt") != 0) + throw NotApplicable (SRC_POS); + + size_t devCount = 0; + while (FilesystemPath (devPath).IsBlockDevice()) + { + list <string> dmsetupArgs; + dmsetupArgs.push_back ("remove"); + dmsetupArgs.push_back (StringConverter::Split (devPath, "/").back()); + + for (int t = 0; true; t++) + { + try + { + Process::Execute ("dmsetup", dmsetupArgs); + break; + } + catch (...) + { + if (t > 20) + throw; + + Thread::Sleep (100); + } + } + + for (int t = 0; FilesystemPath (devPath).IsBlockDevice() && t < 20; t++) + { + Thread::Sleep (100); + } + + devPath = string (mountedVolume->VirtualDevice) + "_" + StringConverter::ToSingle (devCount++); + } + } + + HostDeviceList CoreLinux::GetHostDevices (bool pathListOnly) const + { + HostDeviceList devices; + TextReader tr ("/proc/partitions"); + + string line; + while (tr.ReadLine (line)) + { + vector <string> fields = StringConverter::Split (line); + + if (fields.size() != 4 + || fields[3].find ("loop") == 0 // skip loop devices + || fields[3].find ("cloop") == 0 + || fields[3].find ("ram") == 0 // skip RAM devices + || fields[3].find ("dm-") == 0 // skip device mapper devices + || fields[2] == "1" // skip extended partitions + ) + continue; + + try + { + StringConverter::ToUInt32 (fields[0]); + } + catch (...) + { + continue; + } + + try + { + make_shared_auto (HostDevice, hostDevice); + + hostDevice->Path = string (fields[3].find ("/dev/") == string::npos ? "/dev/" : "") + fields[3]; + + if (!pathListOnly) + { + hostDevice->Size = StringConverter::ToUInt64 (fields[2]) * 1024; + hostDevice->MountPoint = GetDeviceMountPoint (hostDevice->Path); + hostDevice->SystemNumber = 0; + } + + try + { + StringConverter::GetTrailingNumber (fields[3]); + if (devices.size() > 0) + { + HostDevice &prevDev = **--devices.end(); + if (string (hostDevice->Path).find (prevDev.Path) == 0) + { + prevDev.Partitions.push_back (hostDevice); + continue; + } + } + } + catch (...) { } + + devices.push_back (hostDevice); + continue; + } + catch (...) + { + continue; + } + } + + return devices; + } + + MountedFilesystemList CoreLinux::GetMountedFilesystems (const DevicePath &devicePath, const DirectoryPath &mountPoint) const + { + MountedFilesystemList mountedFilesystems; + DevicePath realDevicePath = devicePath; + + if (!devicePath.IsEmpty()) + { + char *resolvedPath = realpath (string (devicePath).c_str(), NULL); + if (resolvedPath) + { + realDevicePath = resolvedPath; + free (resolvedPath); + } + } + + FILE *mtab = fopen ("/etc/mtab", "r"); + + if (!mtab) + mtab = fopen ("/proc/mounts", "r"); + + throw_sys_sub_if (!mtab, "/proc/mounts"); + finally_do_arg (FILE *, mtab, { fclose (finally_arg); }); + + static Mutex mutex; + ScopeLock sl (mutex); + + struct mntent *entry; + while ((entry = getmntent (mtab)) != nullptr) + { + make_shared_auto (MountedFilesystem, mf); + + if (entry->mnt_fsname) + mf->Device = DevicePath (entry->mnt_fsname); + else + continue; + + if (entry->mnt_dir) + mf->MountPoint = DirectoryPath (entry->mnt_dir); + + if (entry->mnt_type) + mf->Type = entry->mnt_type; + + if ((devicePath.IsEmpty() || devicePath == mf->Device || realDevicePath == mf->Device) && (mountPoint.IsEmpty() || mountPoint == mf->MountPoint)) + mountedFilesystems.push_back (mf); + } + + return mountedFilesystems; + } + + void CoreLinux::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const + { + bool fsMounted = false; + + try + { + if (!FilesystemSupportsUnixPermissions (devicePath)) + { + stringstream userMountOptions; + userMountOptions << "uid=" << GetRealUserId() << ",gid=" << GetRealGroupId() << ",umask=077" << (!systemMountOptions.empty() ? "," : ""); + + CoreUnix::MountFilesystem (devicePath, mountPoint, filesystemType, readOnly, userMountOptions.str() + systemMountOptions); + fsMounted = true; + } + } + catch (...) { } + + if (!fsMounted) + CoreUnix::MountFilesystem (devicePath, mountPoint, filesystemType, readOnly, systemMountOptions); + } + + void CoreLinux::MountVolumeNative (shared_ptr <Volume> volume, MountOptions &options, const DirectoryPath &auxMountPoint) const + { + bool xts = (typeid (*volume->GetEncryptionMode()) == typeid (EncryptionModeXTS)); + bool lrw = (typeid (*volume->GetEncryptionMode()) == typeid (EncryptionModeLRW)); + + if (options.NoKernelCrypto + || (!xts && (!lrw || volume->GetEncryptionAlgorithm()->GetCiphers().size() > 1 || volume->GetEncryptionAlgorithm()->GetMinBlockSize() != 16)) + || volume->GetProtectionType() == VolumeProtection::HiddenVolumeReadOnly) + { + throw NotApplicable (SRC_POS); + } + + if (!SystemInfo::IsVersionAtLeast (2, 6, xts ? 24 : 20)) + throw NotApplicable (SRC_POS); + + // Load device mapper kernel module + list <string> execArgs; + foreach (const string &dmModule, StringConverter::Split ("dm_mod dm-mod dm")) + { + execArgs.clear(); + execArgs.push_back (dmModule); + + try + { + Process::Execute ("modprobe", execArgs); + break; + } + catch (...) { } + } + + bool loopDevAttached = false; + bool nativeDevCreated = false; + bool filesystemMounted = false; + + // Attach volume to loopback device if required + VolumePath volumePath = volume->GetPath(); + if (!volumePath.IsDevice()) + { + volumePath = AttachFileToLoopDevice (volumePath, options.Protection == VolumeProtection::ReadOnly); + loopDevAttached = true; + } + + string nativeDevPath; + + try + { + // Create virtual device using device mapper + size_t nativeDevCount = 0; + size_t secondaryKeyOffset = volume->GetEncryptionMode()->GetKey().Size(); + size_t cipherCount = volume->GetEncryptionAlgorithm()->GetCiphers().size(); + + foreach_reverse_ref (const Cipher &cipher, volume->GetEncryptionAlgorithm()->GetCiphers()) + { + stringstream dmCreateArgs; + dmCreateArgs << "0 " << volume->GetSize() / ENCRYPTION_DATA_UNIT_SIZE << " crypt "; + + // Mode + dmCreateArgs << StringConverter::ToLower (StringConverter::ToSingle (cipher.GetName())) << (xts ? (SystemInfo::IsVersionAtLeast (2, 6, 33) ? "-xts-plain64 " : "-xts-plain ") : "-lrw-benbi "); + + size_t keyArgOffset = dmCreateArgs.str().size(); + dmCreateArgs << setw (cipher.GetKeySize() * (xts ? 4 : 2) + (xts ? 0 : 16 * 2)) << 0 << setw (0); + + // Sector and data unit offset + uint64 startSector = volume->GetLayout()->GetDataOffset (volume->GetHostSize()) / ENCRYPTION_DATA_UNIT_SIZE; + + dmCreateArgs << ' ' << (xts ? startSector + volume->GetEncryptionMode()->GetSectorOffset() : 0) << ' '; + if (nativeDevCount == 0) + dmCreateArgs << string (volumePath) << ' ' << startSector; + else + dmCreateArgs << nativeDevPath << " 0"; + + SecureBuffer dmCreateArgsBuf (dmCreateArgs.str().size()); + dmCreateArgsBuf.CopyFrom (ConstBufferPtr ((byte *) dmCreateArgs.str().c_str(), dmCreateArgs.str().size())); + + // Keys + const SecureBuffer &cipherKey = cipher.GetKey(); + secondaryKeyOffset -= cipherKey.Size(); + ConstBufferPtr secondaryKey = volume->GetEncryptionMode()->GetKey().GetRange (xts ? secondaryKeyOffset : 0, xts ? cipherKey.Size() : 16); + + SecureBuffer hexStr (3); + for (size_t i = 0; i < cipherKey.Size(); ++i) + { + sprintf ((char *) hexStr.Ptr(), "%02x", (int) cipherKey[i]); + dmCreateArgsBuf.GetRange (keyArgOffset + i * 2, 2).CopyFrom (hexStr.GetRange (0, 2)); + + if (lrw && i >= 16) + continue; + + sprintf ((char *) hexStr.Ptr(), "%02x", (int) secondaryKey[i]); + dmCreateArgsBuf.GetRange (keyArgOffset + cipherKey.Size() * 2 + i * 2, 2).CopyFrom (hexStr.GetRange (0, 2)); + } + + stringstream nativeDevName; + nativeDevName << "truecrypt" << options.SlotNumber; + + if (nativeDevCount != cipherCount - 1) + nativeDevName << "_" << cipherCount - nativeDevCount - 2; + + nativeDevPath = "/dev/mapper/" + nativeDevName.str(); + + execArgs.clear(); + execArgs.push_back ("create"); + execArgs.push_back (nativeDevName.str()); + + Process::Execute ("dmsetup", execArgs, -1, nullptr, &dmCreateArgsBuf); + + // Wait for the device to be created + for (int t = 0; true; t++) + { + try + { + FilesystemPath (nativeDevPath).GetType(); + break; + } + catch (...) + { + if (t > 20) + throw; + + Thread::Sleep (100); + } + } + + nativeDevCreated = true; + ++nativeDevCount; + } + + // Test whether the device mapper is able to read and decrypt the last sector + SecureBuffer lastSectorBuf (volume->GetSectorSize()); + uint64 lastSectorOffset = volume->GetSize() - volume->GetSectorSize(); + + File nativeDev; + nativeDev.Open (nativeDevPath); + nativeDev.ReadAt (lastSectorBuf, lastSectorOffset); + + SecureBuffer lastSectorBuf2 (volume->GetSectorSize()); + volume->ReadSectors (lastSectorBuf2, lastSectorOffset); + + if (memcmp (lastSectorBuf.Ptr(), lastSectorBuf2.Ptr(), volume->GetSectorSize()) != 0) + throw KernelCryptoServiceTestFailed (SRC_POS); + + // Mount filesystem + if (!options.NoFilesystem && options.MountPoint && !options.MountPoint->IsEmpty()) + { + MountFilesystem (nativeDevPath, *options.MountPoint, + StringConverter::ToSingle (options.FilesystemType), + options.Protection == VolumeProtection::ReadOnly, + StringConverter::ToSingle (options.FilesystemOptions)); + + filesystemMounted = true; + } + + FuseService::SendAuxDeviceInfo (auxMountPoint, nativeDevPath, volumePath); + } + catch (...) + { + try + { + if (filesystemMounted) + DismountFilesystem (*options.MountPoint, true); + } + catch (...) { } + + try + { + if (nativeDevCreated) + { + make_shared_auto (VolumeInfo, vol); + vol->VirtualDevice = nativeDevPath; + DismountNativeVolume (vol); + } + } + catch (...) { } + + try + { + if (loopDevAttached) + DetachLoopDevice (volumePath); + } + catch (...) { } + + throw; + } + } + + auto_ptr <CoreBase> Core (new CoreServiceProxy <CoreLinux>); + auto_ptr <CoreBase> CoreDirect (new CoreLinux); +} diff --git a/src/Core/Unix/Linux/CoreLinux.h b/src/Core/Unix/Linux/CoreLinux.h new file mode 100644 index 00000000..5758d651 --- /dev/null +++ b/src/Core/Unix/Linux/CoreLinux.h @@ -0,0 +1,39 @@ +/* + Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_CoreLinux +#define TC_HEADER_Core_CoreLinux + +#include "System.h" +#include "Core/Unix/CoreUnix.h" + +namespace TrueCrypt +{ + class CoreLinux : public CoreUnix + { + public: + CoreLinux (); + virtual ~CoreLinux (); + + virtual HostDeviceList GetHostDevices (bool pathListOnly = false) const; + + protected: + virtual DevicePath AttachFileToLoopDevice (const FilePath &filePath, bool readOnly) const; + virtual void DetachLoopDevice (const DevicePath &devicePath) const; + virtual void DismountNativeVolume (shared_ptr <VolumeInfo> mountedVolume) const; + virtual MountedFilesystemList GetMountedFilesystems (const DevicePath &devicePath = DevicePath(), const DirectoryPath &mountPoint = DirectoryPath()) const; + virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const; + virtual void MountVolumeNative (shared_ptr <Volume> volume, MountOptions &options, const DirectoryPath &auxMountPoint) const; + + private: + CoreLinux (const CoreLinux &); + CoreLinux &operator= (const CoreLinux &); + }; +} + +#endif // TC_HEADER_Core_CoreLinux diff --git a/src/Core/Unix/Linux/System.h b/src/Core/Unix/Linux/System.h new file mode 100644 index 00000000..20a4f82d --- /dev/null +++ b/src/Core/Unix/Linux/System.h @@ -0,0 +1,12 @@ +/* + Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Platform_Linux_System +#define TC_HEADER_Platform_Linux_System + +#endif // TC_HEADER_Platform_Linux_System diff --git a/src/Core/Unix/MacOSX/CoreMacOSX.cpp b/src/Core/Unix/MacOSX/CoreMacOSX.cpp new file mode 100644 index 00000000..b7aa08c7 --- /dev/null +++ b/src/Core/Unix/MacOSX/CoreMacOSX.cpp @@ -0,0 +1,215 @@ +/* + Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include <fstream> +#include <stdio.h> +#include <unistd.h> +#include <sys/param.h> +#include <sys/ucred.h> +#include <sys/mount.h> +#include <sys/sysctl.h> +#include <sys/types.h> +#include <sys/wait.h> +#include "CoreMacOSX.h" +#include "Driver/Fuse/FuseService.h" +#include "Core/Unix/CoreServiceProxy.h" + +namespace TrueCrypt +{ + CoreMacOSX::CoreMacOSX () + { + } + + CoreMacOSX::~CoreMacOSX () + { + } + + shared_ptr <VolumeInfo> CoreMacOSX::DismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles, bool syncVolumeInfo) + { + if (!mountedVolume->VirtualDevice.IsEmpty() && mountedVolume->VirtualDevice.IsBlockDevice()) + { + list <string> args; + args.push_back ("detach"); + args.push_back (mountedVolume->VirtualDevice); + + if (ignoreOpenFiles) + args.push_back ("-force"); + + try + { + Process::Execute ("hdiutil", args); + } + catch (ExecutedProcessFailed &e) + { + if (!ignoreOpenFiles) + { + string err = e.GetErrorOutput(); + + if (err.find ("couldn't unmount") != string::npos + || err.find ("busy") != string::npos + || err.find ("49153") != string::npos) + { + throw MountedVolumeInUse (SRC_POS); + } + } + + throw; + } + } + + if (syncVolumeInfo || mountedVolume->Protection == VolumeProtection::HiddenVolumeReadOnly) + { + sync(); + VolumeInfoList ml = GetMountedVolumes (mountedVolume->Path); + + if (ml.size() > 0) + mountedVolume = ml.front(); + } + + list <string> args; + args.push_back ("--"); + args.push_back (mountedVolume->AuxMountPoint); + + for (int t = 0; true; t++) + { + try + { + Process::Execute ("umount", args); + break; + } + catch (ExecutedProcessFailed&) + { + if (t > 10) + throw; + Thread::Sleep (200); + } + } + + try + { + mountedVolume->AuxMountPoint.Delete(); + } + catch (...) { } + + return mountedVolume; + } + + void CoreMacOSX::CheckFilesystem (shared_ptr <VolumeInfo> mountedVolume, bool repair) const + { + list <string> args; + args.push_back ("/Applications/Utilities/Disk Utility.app"); + Process::Execute ("open", args); + } + + void CoreMacOSX::MountAuxVolumeImage (const DirectoryPath &auxMountPoint, const MountOptions &options) const + { + // Check FUSE version + char fuseVersionString[MAXHOSTNAMELEN + 1] = { 0 }; + size_t fuseVersionStringLength = MAXHOSTNAMELEN; + + if (sysctlbyname ("macfuse.version.number", fuseVersionString, &fuseVersionStringLength, NULL, 0) != 0) + throw HigherFuseVersionRequired (SRC_POS); + + vector <string> fuseVersion = StringConverter::Split (string (fuseVersionString), "."); + if (fuseVersion.size() < 2) + throw HigherFuseVersionRequired (SRC_POS); + + uint32 fuseVersionMajor = StringConverter::ToUInt32 (fuseVersion[0]); + uint32 fuseVersionMinor = StringConverter::ToUInt32 (fuseVersion[1]); + + if (fuseVersionMajor < 1 || (fuseVersionMajor == 1 && fuseVersionMinor < 3)) + throw HigherFuseVersionRequired (SRC_POS); + + // Mount volume image + string volImage = string (auxMountPoint) + FuseService::GetVolumeImagePath(); + + list <string> args; + args.push_back ("attach"); + args.push_back (volImage); + args.push_back ("-plist"); + args.push_back ("-noautofsck"); + args.push_back ("-imagekey"); + args.push_back ("diskimage-class=CRawDiskImage"); + + if (!options.NoFilesystem && options.MountPoint && !options.MountPoint->IsEmpty()) + { + args.push_back ("-mount"); + args.push_back ("required"); + + // Let the system specify mount point except when the user specified a non-default one + if (string (*options.MountPoint).find (GetDefaultMountPointPrefix()) != 0) + { + args.push_back ("-mountpoint"); + args.push_back (*options.MountPoint); + } + } + else + args.push_back ("-nomount"); + + if (options.Protection == VolumeProtection::ReadOnly) + args.push_back ("-readonly"); + + string xml; + + while (true) + { + try + { + xml = Process::Execute ("hdiutil", args); + break; + } + catch (ExecutedProcessFailed &e) + { + if (e.GetErrorOutput().find ("noautofsck") != string::npos) + { + args.remove ("-noautofsck"); + continue; + } + + throw; + } + } + + size_t p = xml.find ("<key>dev-entry</key>"); + if (p == string::npos) + throw ParameterIncorrect (SRC_POS); + + p = xml.find ("<string>", p); + if (p == string::npos) + throw ParameterIncorrect (SRC_POS); + p += 8; + + size_t e = xml.find ("</string>", p); + if (e == string::npos) + throw ParameterIncorrect (SRC_POS); + + DevicePath virtualDev = StringConverter::Trim (xml.substr (p, e - p)); + + try + { + FuseService::SendAuxDeviceInfo (auxMountPoint, virtualDev); + } + catch (...) + { + try + { + list <string> args; + args.push_back ("detach"); + args.push_back (volImage); + args.push_back ("-force"); + + Process::Execute ("hdiutil", args); + } + catch (ExecutedProcessFailed&) { } + throw; + } + } + + auto_ptr <CoreBase> Core (new CoreServiceProxy <CoreMacOSX>); + auto_ptr <CoreBase> CoreDirect (new CoreMacOSX); +} diff --git a/src/Core/Unix/MacOSX/CoreMacOSX.h b/src/Core/Unix/MacOSX/CoreMacOSX.h new file mode 100644 index 00000000..eee11d6f --- /dev/null +++ b/src/Core/Unix/MacOSX/CoreMacOSX.h @@ -0,0 +1,36 @@ +/* + Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_CoreMacOSX +#define TC_HEADER_Core_CoreMacOSX + +#include "System.h" +#include "Core/Unix/FreeBSD/CoreFreeBSD.h" + +namespace TrueCrypt +{ + class CoreMacOSX : public CoreFreeBSD + { + public: + CoreMacOSX (); + virtual ~CoreMacOSX (); + + virtual void CheckFilesystem (shared_ptr <VolumeInfo> mountedVolume, bool repair = false) const; + virtual shared_ptr <VolumeInfo> DismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles = false, bool syncVolumeInfo = false); + virtual string GetDefaultMountPointPrefix () const { return "/Volumes/truecrypt"; } + + protected: + virtual void MountAuxVolumeImage (const DirectoryPath &auxMountPoint, const MountOptions &options) const; + + private: + CoreMacOSX (const CoreMacOSX &); + CoreMacOSX &operator= (const CoreMacOSX &); + }; +} + +#endif // TC_HEADER_Core_CoreMacOSX diff --git a/src/Core/Unix/MacOSX/System.h b/src/Core/Unix/MacOSX/System.h new file mode 100644 index 00000000..073e17a3 --- /dev/null +++ b/src/Core/Unix/MacOSX/System.h @@ -0,0 +1,12 @@ +/* + Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Platform_MacOSX_System +#define TC_HEADER_Platform_MacOSX_System + +#endif // TC_HEADER_Platform_MacOSX_System diff --git a/src/Core/Unix/MountedFilesystem.h b/src/Core/Unix/MountedFilesystem.h new file mode 100644 index 00000000..6e704d3c --- /dev/null +++ b/src/Core/Unix/MountedFilesystem.h @@ -0,0 +1,27 @@ +/* + Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_Unix_MountedFilesystem +#define TC_HEADER_Core_Unix_MountedFilesystem + +#include "Platform/Platform.h" + +namespace TrueCrypt +{ + struct MountedFilesystem + { + public: + DevicePath Device; + DirectoryPath MountPoint; + string Type; + }; + + typedef list < shared_ptr <MountedFilesystem> > MountedFilesystemList; +} + +#endif // TC_HEADER_Core_Unix_MountedFilesystem diff --git a/src/Core/Unix/Solaris/CoreSolaris.cpp b/src/Core/Unix/Solaris/CoreSolaris.cpp new file mode 100644 index 00000000..63736db3 --- /dev/null +++ b/src/Core/Unix/Solaris/CoreSolaris.cpp @@ -0,0 +1,174 @@ +/* + Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/mntent.h> +#include <sys/mnttab.h> +#include "CoreSolaris.h" +#include "Core/Unix/CoreServiceProxy.h" + +namespace TrueCrypt +{ + CoreSolaris::CoreSolaris () + { + } + + CoreSolaris::~CoreSolaris () + { + } + + DevicePath CoreSolaris::AttachFileToLoopDevice (const FilePath &filePath, bool readOnly) const + { + list <string> args; + args.push_back ("-a"); + args.push_back (filePath); + + return StringConverter::Trim (Process::Execute ("lofiadm", args)); + } + + void CoreSolaris::DetachLoopDevice (const DevicePath &devicePath) const + { + list <string> args; + args.push_back ("-d"); + args.push_back (devicePath); + + for (int t = 0; true; t++) + { + try + { + Process::Execute ("lofiadm", args); + break; + } + catch (ExecutedProcessFailed&) + { + if (t > 5) + throw; + Thread::Sleep (200); + } + } + } + + HostDeviceList CoreSolaris::GetHostDevices (bool pathListOnly) const + { + HostDeviceList devices; + + foreach_ref (const FilePath &devPath, Directory::GetFilePaths ("/dev/rdsk", false)) + { + string drivePath = devPath; + if (drivePath.rfind ("p0") == drivePath.size() - 2) + { + make_shared_auto (HostDevice, device); + device->Path = drivePath; + + try + { + device->Size = GetDeviceSize (device->Path); + } + catch (...) + { + device->Size = 0; + } + + if (device->Size == 0) + continue; + + device->MountPoint = GetDeviceMountPoint (device->Path); + device->SystemNumber = 0; + + devices.push_back (device); + + for (int partNumber = 1; partNumber <= 32; partNumber++) + { + stringstream partPath; + partPath << drivePath.substr (0, drivePath.size() - 1) << partNumber; + + if (FilesystemPath (partPath.str()).IsBlockDevice() || FilesystemPath (partPath.str()).IsCharacterDevice()) + { + make_shared_auto (HostDevice, partition); + partition->Path = partPath.str(); + + try + { + partition->Size = GetDeviceSize (partition->Path); + } + catch (...) + { + partition->Size = 0; + } + + if (partition->Size == 0) + continue; + + partition->MountPoint = GetDeviceMountPoint (partition->Path); + partition->SystemNumber = 0; + + device->Partitions.push_back (partition); + } + } + } + } + + return devices; + } + + MountedFilesystemList CoreSolaris::GetMountedFilesystems (const DevicePath &devicePath, const DirectoryPath &mountPoint) const + { + MountedFilesystemList mountedFilesystems; + + FILE *mtab = fopen ("/etc/mnttab", "r"); + throw_sys_sub_if (!mtab, "/etc/mnttab"); + finally_do_arg (FILE *, mtab, { fclose (finally_arg); }); + + int getmntentResult; + struct mnttab entry; + while ((getmntentResult = getmntent (mtab, &entry)) == 0) + { + make_shared_auto (MountedFilesystem, mf); + + if (entry.mnt_special) + mf->Device = DevicePath (entry.mnt_special); + else + continue; + + if (entry.mnt_mountp) + mf->MountPoint = DirectoryPath (entry.mnt_mountp); + + if (entry.mnt_fstype) + mf->Type = entry.mnt_fstype; + + if ((devicePath.IsEmpty() || devicePath == mf->Device) && (mountPoint.IsEmpty() || mountPoint == mf->MountPoint)) + mountedFilesystems.push_back (mf); + } + + throw_sys_if (getmntentResult > 0); + + return mountedFilesystems; + } + + void CoreSolaris::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const + { + try + { + // Try to mount FAT by default as mount is unable to probe filesystem type on Solaris + CoreUnix::MountFilesystem (devicePath, mountPoint, filesystemType.empty() ? "pcfs" : filesystemType, readOnly, systemMountOptions); + } + catch (ExecutedProcessFailed&) + { + if (!filesystemType.empty()) + throw; + + CoreUnix::MountFilesystem (devicePath, mountPoint, filesystemType, readOnly, systemMountOptions); + } + } + + auto_ptr <CoreBase> Core (new CoreServiceProxy <CoreSolaris>); + auto_ptr <CoreBase> CoreDirect (new CoreSolaris); +} diff --git a/src/Core/Unix/Solaris/CoreSolaris.h b/src/Core/Unix/Solaris/CoreSolaris.h new file mode 100644 index 00000000..76dd1945 --- /dev/null +++ b/src/Core/Unix/Solaris/CoreSolaris.h @@ -0,0 +1,37 @@ +/* + Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Core_CoreSolaris +#define TC_HEADER_Core_CoreSolaris + +#include "System.h" +#include "Core/Unix/CoreUnix.h" + +namespace TrueCrypt +{ + class CoreSolaris : public CoreUnix + { + public: + CoreSolaris (); + virtual ~CoreSolaris (); + + virtual HostDeviceList GetHostDevices (bool pathListOnly = false) const; + + protected: + virtual DevicePath AttachFileToLoopDevice (const FilePath &filePath, bool readOnly) const; + virtual void DetachLoopDevice (const DevicePath &devicePath) const; + virtual MountedFilesystemList GetMountedFilesystems (const DevicePath &devicePath = DevicePath(), const DirectoryPath &mountPoint = DirectoryPath()) const; + virtual void MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const; + + private: + CoreSolaris (const CoreSolaris &); + CoreSolaris &operator= (const CoreSolaris &); + }; +} + +#endif // TC_HEADER_Core_CoreSolaris diff --git a/src/Core/Unix/Solaris/System.h b/src/Core/Unix/Solaris/System.h new file mode 100644 index 00000000..039dd406 --- /dev/null +++ b/src/Core/Unix/Solaris/System.h @@ -0,0 +1,12 @@ +/* + Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Platform_Solaris_System +#define TC_HEADER_Platform_Solaris_System + +#endif // TC_HEADER_Platform_Solaris_System diff --git a/src/Core/Unix/System.h b/src/Core/Unix/System.h new file mode 100644 index 00000000..63d565b5 --- /dev/null +++ b/src/Core/Unix/System.h @@ -0,0 +1,12 @@ +/* + Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Platform_Unix_System +#define TC_HEADER_Platform_Unix_System + +#endif // TC_HEADER_Platform_Unix_System diff --git a/src/Core/VolumeCreator.cpp b/src/Core/VolumeCreator.cpp new file mode 100644 index 00000000..6011efd0 --- /dev/null +++ b/src/Core/VolumeCreator.cpp @@ -0,0 +1,345 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include "Volume/EncryptionTest.h" +#include "Volume/EncryptionModeXTS.h" +#include "Core.h" + +#ifdef TC_UNIX +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#endif + +#include "VolumeCreator.h" +#include "FatFormatter.h" + +namespace TrueCrypt +{ + VolumeCreator::VolumeCreator () + : SizeDone (0) + { + } + + VolumeCreator::~VolumeCreator () + { + } + + void VolumeCreator::Abort () + { + AbortRequested = true; + } + + void VolumeCreator::CheckResult () + { + if (ThreadException) + ThreadException->Throw(); + } + + void VolumeCreator::CreationThread () + { + try + { + uint64 endOffset; + uint64 filesystemSize = Layout->GetDataSize (HostSize); + + if (filesystemSize < 1) + throw ParameterIncorrect (SRC_POS); + + DataStart = Layout->GetDataOffset (HostSize); + WriteOffset = DataStart; + endOffset = DataStart + Layout->GetDataSize (HostSize); + + VolumeFile->SeekAt (DataStart); + + // Create filesystem + if (Options->Filesystem == VolumeCreationOptions::FilesystemType::FAT) + { + if (filesystemSize < TC_MIN_FAT_FS_SIZE || filesystemSize > TC_MAX_FAT_SECTOR_COUNT * Options->SectorSize) + throw ParameterIncorrect (SRC_POS); + + struct WriteSectorCallback : public FatFormatter::WriteSectorCallback + { + WriteSectorCallback (VolumeCreator *creator) : Creator (creator), OutputBuffer (File::GetOptimalWriteSize()), OutputBufferWritePos (0) { } + + virtual bool operator() (const BufferPtr §or) + { + OutputBuffer.GetRange (OutputBufferWritePos, sector.Size()).CopyFrom (sector); + OutputBufferWritePos += sector.Size(); + + if (OutputBufferWritePos >= OutputBuffer.Size()) + FlushOutputBuffer(); + + return !Creator->AbortRequested; + } + + void FlushOutputBuffer () + { + if (OutputBufferWritePos > 0) + { + Creator->Options->EA->EncryptSectors (OutputBuffer.GetRange (0, OutputBufferWritePos), + Creator->WriteOffset / ENCRYPTION_DATA_UNIT_SIZE, OutputBufferWritePos / ENCRYPTION_DATA_UNIT_SIZE, ENCRYPTION_DATA_UNIT_SIZE); + + Creator->VolumeFile->Write (OutputBuffer.GetRange (0, OutputBufferWritePos)); + + Creator->WriteOffset += OutputBufferWritePos; + Creator->SizeDone.Set (Creator->WriteOffset - Creator->DataStart); + + OutputBufferWritePos = 0; + } + } + + VolumeCreator *Creator; + SecureBuffer OutputBuffer; + size_t OutputBufferWritePos; + }; + + WriteSectorCallback sectorWriter (this); + FatFormatter::Format (sectorWriter, filesystemSize, Options->FilesystemClusterSize, Options->SectorSize); + sectorWriter.FlushOutputBuffer(); + } + + if (!Options->Quick) + { + // Empty sectors are encrypted with different key to randomize plaintext + Core->RandomizeEncryptionAlgorithmKey (Options->EA); + + SecureBuffer outputBuffer (File::GetOptimalWriteSize()); + uint64 dataFragmentLength = outputBuffer.Size(); + + while (!AbortRequested && WriteOffset < endOffset) + { + if (WriteOffset + dataFragmentLength > endOffset) + dataFragmentLength = endOffset - WriteOffset; + + outputBuffer.Zero(); + Options->EA->EncryptSectors (outputBuffer, WriteOffset / ENCRYPTION_DATA_UNIT_SIZE, dataFragmentLength / ENCRYPTION_DATA_UNIT_SIZE, ENCRYPTION_DATA_UNIT_SIZE); + VolumeFile->Write (outputBuffer, (size_t) dataFragmentLength); + + WriteOffset += dataFragmentLength; + SizeDone.Set (WriteOffset - DataStart); + } + } + + if (!AbortRequested) + { + SizeDone.Set (Options->Size); + + // Backup header + SecureBuffer backupHeader (Layout->GetHeaderSize()); + + SecureBuffer backupHeaderSalt (VolumeHeader::GetSaltSize()); + RandomNumberGenerator::GetData (backupHeaderSalt); + + Options->VolumeHeaderKdf->DeriveKey (HeaderKey, *PasswordKey, backupHeaderSalt); + + Layout->GetHeader()->EncryptNew (backupHeader, backupHeaderSalt, HeaderKey, Options->VolumeHeaderKdf); + + if (Options->Quick || Options->Type == VolumeType::Hidden) + VolumeFile->SeekEnd (Layout->GetBackupHeaderOffset()); + + VolumeFile->Write (backupHeader); + + if (Options->Type == VolumeType::Normal) + { + // Write random data to space reserved for hidden volume backup header + Core->RandomizeEncryptionAlgorithmKey (Options->EA); + Options->EA->Encrypt (backupHeader); + + VolumeFile->Write (backupHeader); + } + + VolumeFile->Flush(); + } + } + catch (Exception &e) + { + ThreadException.reset (e.CloneNew()); + } + catch (exception &e) + { + ThreadException.reset (new ExternalException (SRC_POS, StringConverter::ToExceptionString (e))); + } + catch (...) + { + ThreadException.reset (new UnknownException (SRC_POS)); + } + + VolumeFile.reset(); + mProgressInfo.CreationInProgress = false; + } + + void VolumeCreator::CreateVolume (shared_ptr <VolumeCreationOptions> options) + { + EncryptionTest::TestAll(); + + { +#ifdef TC_UNIX + // Temporarily take ownership of a device if the user is not an administrator + UserId origDeviceOwner ((uid_t) -1); + + if (!Core->HasAdminPrivileges() && options->Path.IsDevice()) + { + origDeviceOwner = FilesystemPath (wstring (options->Path)).GetOwner(); + Core->SetFileOwner (options->Path, UserId (getuid())); + } + + finally_do_arg2 (FilesystemPath, options->Path, UserId, origDeviceOwner, + { + if (finally_arg2.SystemId != (uid_t) -1) + Core->SetFileOwner (finally_arg, finally_arg2); + }); +#endif + + VolumeFile.reset (new File); + VolumeFile->Open (options->Path, + (options->Path.IsDevice() || options->Type == VolumeType::Hidden) ? File::OpenReadWrite : File::CreateReadWrite, + File::ShareNone); + + HostSize = VolumeFile->Length(); + } + + try + { + // Sector size + if (options->Path.IsDevice()) + { + options->SectorSize = VolumeFile->GetDeviceSectorSize(); + + if (options->SectorSize < TC_MIN_VOLUME_SECTOR_SIZE + || options->SectorSize > TC_MAX_VOLUME_SECTOR_SIZE +#if !defined (TC_LINUX) + || options->SectorSize != TC_SECTOR_SIZE_LEGACY +#endif + || options->SectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0) + { + throw UnsupportedSectorSize (SRC_POS); + } + } + else + options->SectorSize = TC_SECTOR_SIZE_FILE_HOSTED_VOLUME; + + // Volume layout + switch (options->Type) + { + case VolumeType::Normal: + Layout.reset (new VolumeLayoutV2Normal()); + break; + + case VolumeType::Hidden: + Layout.reset (new VolumeLayoutV2Hidden()); + + if (HostSize < TC_MIN_HIDDEN_VOLUME_HOST_SIZE) + throw ParameterIncorrect (SRC_POS); + break; + + default: + throw ParameterIncorrect (SRC_POS); + } + + // Volume header + shared_ptr <VolumeHeader> header (Layout->GetHeader()); + SecureBuffer headerBuffer (Layout->GetHeaderSize()); + + VolumeHeaderCreationOptions headerOptions; + headerOptions.EA = options->EA; + headerOptions.Kdf = options->VolumeHeaderKdf; + headerOptions.Type = options->Type; + + headerOptions.SectorSize = options->SectorSize; + + if (options->Type == VolumeType::Hidden) + headerOptions.VolumeDataStart = HostSize - Layout->GetHeaderSize() * 2 - options->Size; + else + headerOptions.VolumeDataStart = Layout->GetHeaderSize() * 2; + + headerOptions.VolumeDataSize = Layout->GetMaxDataSize (options->Size); + + if (headerOptions.VolumeDataSize < 1) + throw ParameterIncorrect (SRC_POS); + + // Master data key + MasterKey.Allocate (options->EA->GetKeySize() * 2); + RandomNumberGenerator::GetData (MasterKey); + headerOptions.DataKey = MasterKey; + + // PKCS5 salt + SecureBuffer salt (VolumeHeader::GetSaltSize()); + RandomNumberGenerator::GetData (salt); + headerOptions.Salt = salt; + + // Header key + HeaderKey.Allocate (VolumeHeader::GetLargestSerializedKeySize()); + PasswordKey = Keyfile::ApplyListToPassword (options->Keyfiles, options->Password); + options->VolumeHeaderKdf->DeriveKey (HeaderKey, *PasswordKey, salt); + headerOptions.HeaderKey = HeaderKey; + + header->Create (headerBuffer, headerOptions); + + // Write new header + if (Layout->GetHeaderOffset() >= 0) + VolumeFile->SeekAt (Layout->GetHeaderOffset()); + else + VolumeFile->SeekEnd (Layout->GetHeaderOffset()); + + VolumeFile->Write (headerBuffer); + + if (options->Type == VolumeType::Normal) + { + // Write random data to space reserved for hidden volume header + Core->RandomizeEncryptionAlgorithmKey (options->EA); + options->EA->Encrypt (headerBuffer); + + VolumeFile->Write (headerBuffer); + } + + // Data area keys + options->EA->SetKey (MasterKey.GetRange (0, options->EA->GetKeySize())); + shared_ptr <EncryptionMode> mode (new EncryptionModeXTS ()); + mode->SetKey (MasterKey.GetRange (options->EA->GetKeySize(), options->EA->GetKeySize())); + options->EA->SetMode (mode); + + Options = options; + AbortRequested = false; + + mProgressInfo.CreationInProgress = true; + + struct ThreadFunctor : public Functor + { + ThreadFunctor (VolumeCreator *creator) : Creator (creator) { } + virtual void operator() () + { + Creator->CreationThread (); + } + VolumeCreator *Creator; + }; + + Thread thread; + thread.Start (new ThreadFunctor (this)); + } + catch (...) + { + VolumeFile.reset(); + throw; + } + } + + VolumeCreator::KeyInfo VolumeCreator::GetKeyInfo () const + { + KeyInfo info; + info.HeaderKey = HeaderKey; + info.MasterKey = MasterKey; + return info; + } + + VolumeCreator::ProgressInfo VolumeCreator::GetProgressInfo () + { + mProgressInfo.SizeDone = SizeDone.Get(); + return mProgressInfo; + } +} diff --git a/src/Core/VolumeCreator.h b/src/Core/VolumeCreator.h new file mode 100644 index 00000000..4e8cf61e --- /dev/null +++ b/src/Core/VolumeCreator.h @@ -0,0 +1,119 @@ +/* + Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Volume_VolumeCreator +#define TC_HEADER_Volume_VolumeCreator + +#include "Platform/Platform.h" +#include "Volume/Volume.h" +#include "RandomNumberGenerator.h" + +namespace TrueCrypt +{ + + struct VolumeCreationOptions + { + VolumePath Path; + VolumeType::Enum Type; + uint64 Size; + shared_ptr <VolumePassword> Password; + shared_ptr <KeyfileList> Keyfiles; + shared_ptr <Pkcs5Kdf> VolumeHeaderKdf; + shared_ptr <EncryptionAlgorithm> EA; + bool Quick; + + struct FilesystemType + { + enum Enum + { + Unknown = 0, + None, + FAT, + NTFS, + Ext2, + Ext3, + Ext4, + MacOsExt, + UFS + }; + + static Enum GetPlatformNative () + { +#ifdef TC_WINDOWS + return VolumeCreationOptions::FilesystemType::NTFS; +#elif defined (TC_LINUX) + return VolumeCreationOptions::FilesystemType::Ext3; +#elif defined (TC_MACOSX) + return VolumeCreationOptions::FilesystemType::MacOsExt; +#elif defined (TC_FREEBSD) || defined (TC_SOLARIS) + return VolumeCreationOptions::FilesystemType::UFS; +#else + return VolumeCreationOptions::FilesystemType::FAT; +#endif + } + }; + + FilesystemType::Enum Filesystem; + uint32 FilesystemClusterSize; + uint32 SectorSize; + }; + + class VolumeCreator + { + public: + + struct ProgressInfo + { + bool CreationInProgress; + uint64 TotalSize; + uint64 SizeDone; + }; + + struct KeyInfo + { + ConstBufferPtr HeaderKey; + ConstBufferPtr MasterKey; + }; + + VolumeCreator (); + virtual ~VolumeCreator (); + + void Abort (); + void CheckResult (); + void CreateVolume (shared_ptr <VolumeCreationOptions> options); + KeyInfo GetKeyInfo () const; + ProgressInfo GetProgressInfo (); + + protected: + void CreationThread (); + + volatile bool AbortRequested; + volatile bool CreationInProgress; + uint64 DataStart; + uint64 HostSize; + shared_ptr <VolumeCreationOptions> Options; + shared_ptr <Exception> ThreadException; + uint64 VolumeSize; + + shared_ptr <VolumeLayout> Layout; + shared_ptr <File> VolumeFile; + SharedVal <uint64> SizeDone; + uint64 WriteOffset; + ProgressInfo mProgressInfo; + + SecureBuffer HeaderKey; + shared_ptr <VolumePassword> PasswordKey; + SecureBuffer MasterKey; + + private: + VolumeCreator (const VolumeCreator &); + VolumeCreator &operator= (const VolumeCreator &); + }; +} + +#endif // TC_HEADER_Volume_VolumeCreator |