VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Core
diff options
context:
space:
mode:
Diffstat (limited to 'src/Core')
-rw-r--r--src/Core/Core.h20
-rw-r--r--src/Core/Core.make27
-rw-r--r--src/Core/CoreBase.cpp279
-rw-r--r--src/Core/CoreBase.h99
-rw-r--r--src/Core/CoreException.cpp29
-rw-r--r--src/Core/CoreException.h52
-rw-r--r--src/Core/FatFormatter.cpp384
-rw-r--r--src/Core/FatFormatter.h29
-rw-r--r--src/Core/HostDevice.cpp47
-rw-r--r--src/Core/HostDevice.h45
-rw-r--r--src/Core/MountOptions.cpp129
-rw-r--r--src/Core/MountOptions.h70
-rw-r--r--src/Core/RandomNumberGenerator.cpp213
-rw-r--r--src/Core/RandomNumberGenerator.h55
-rw-r--r--src/Core/Unix/CoreService.cpp544
-rw-r--r--src/Core/Unix/CoreService.h63
-rw-r--r--src/Core/Unix/CoreServiceProxy.h152
-rw-r--r--src/Core/Unix/CoreServiceRequest.cpp269
-rw-r--r--src/Core/Unix/CoreServiceRequest.h136
-rw-r--r--src/Core/Unix/CoreServiceResponse.cpp119
-rw-r--r--src/Core/Unix/CoreServiceResponse.h84
-rw-r--r--src/Core/Unix/CoreUnix.cpp618
-rw-r--r--src/Core/Unix/CoreUnix.h69
-rw-r--r--src/Core/Unix/FreeBSD/CoreFreeBSD.cpp202
-rw-r--r--src/Core/Unix/FreeBSD/CoreFreeBSD.h37
-rw-r--r--src/Core/Unix/FreeBSD/System.h12
-rw-r--r--src/Core/Unix/Linux/CoreLinux.cpp477
-rw-r--r--src/Core/Unix/Linux/CoreLinux.h39
-rw-r--r--src/Core/Unix/Linux/System.h12
-rw-r--r--src/Core/Unix/MacOSX/CoreMacOSX.cpp215
-rw-r--r--src/Core/Unix/MacOSX/CoreMacOSX.h36
-rw-r--r--src/Core/Unix/MacOSX/System.h12
-rw-r--r--src/Core/Unix/MountedFilesystem.h27
-rw-r--r--src/Core/Unix/Solaris/CoreSolaris.cpp174
-rw-r--r--src/Core/Unix/Solaris/CoreSolaris.h37
-rw-r--r--src/Core/Unix/Solaris/System.h12
-rw-r--r--src/Core/Unix/System.h12
-rw-r--r--src/Core/VolumeCreator.cpp345
-rw-r--r--src/Core/VolumeCreator.h119
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 &sector) = 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 &sector)
+ {
+ 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