VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Core/Unix
diff options
context:
space:
mode:
authorMounir IDRASSI <mounir.idrassi@idrix.fr>2014-05-31 18:44:53 +0200
committerMounir IDRASSI <mounir.idrassi@idrix.fr>2014-11-08 23:18:59 +0100
commit7ffce028d04a6b13ef762e2b89c34b688e8ca59d (patch)
treeeefedb6e94de5b26fa963675969490c641c29077 /src/Core/Unix
parent97011f179cfd3dcd12446ef4ccb6964c8e52c3db (diff)
downloadVeraCrypt-7ffce028d04a6b13ef762e2b89c34b688e8ca59d.tar.gz
VeraCrypt-7ffce028d04a6b13ef762e2b89c34b688e8ca59d.zip
Add TrueCrypt 7.1a MacOSX/Linux specific source files.
Diffstat (limited to 'src/Core/Unix')
-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
23 files changed, 3358 insertions, 0 deletions
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