From 3cb7fdea950dd2d0377f0d9ad8a88fcb7c48b842 Mon Sep 17 00:00:00 2001 From: Jedidiah Barber Date: Wed, 14 Jul 2021 11:27:03 +1200 Subject: Initial mirror commit --- Core/Unix/CoreService.cpp | 544 +++++++++++++++++++++++++++++++++ Core/Unix/CoreService.h | 63 ++++ Core/Unix/CoreServiceProxy.h | 152 ++++++++++ Core/Unix/CoreServiceRequest.cpp | 269 +++++++++++++++++ Core/Unix/CoreServiceRequest.h | 136 +++++++++ Core/Unix/CoreServiceResponse.cpp | 119 ++++++++ Core/Unix/CoreServiceResponse.h | 84 ++++++ Core/Unix/CoreUnix.cpp | 618 ++++++++++++++++++++++++++++++++++++++ Core/Unix/CoreUnix.h | 69 +++++ Core/Unix/FreeBSD/CoreFreeBSD.cpp | 202 +++++++++++++ Core/Unix/FreeBSD/CoreFreeBSD.h | 37 +++ Core/Unix/FreeBSD/System.h | 12 + Core/Unix/Linux/CoreLinux.cpp | 477 +++++++++++++++++++++++++++++ Core/Unix/Linux/CoreLinux.h | 39 +++ Core/Unix/Linux/System.h | 12 + Core/Unix/MacOSX/CoreMacOSX.cpp | 215 +++++++++++++ Core/Unix/MacOSX/CoreMacOSX.h | 36 +++ Core/Unix/MacOSX/System.h | 12 + Core/Unix/MountedFilesystem.h | 27 ++ Core/Unix/Solaris/CoreSolaris.cpp | 174 +++++++++++ Core/Unix/Solaris/CoreSolaris.h | 37 +++ Core/Unix/Solaris/System.h | 12 + Core/Unix/System.h | 12 + 23 files changed, 3358 insertions(+) create mode 100644 Core/Unix/CoreService.cpp create mode 100644 Core/Unix/CoreService.h create mode 100644 Core/Unix/CoreServiceProxy.h create mode 100644 Core/Unix/CoreServiceRequest.cpp create mode 100644 Core/Unix/CoreServiceRequest.h create mode 100644 Core/Unix/CoreServiceResponse.cpp create mode 100644 Core/Unix/CoreServiceResponse.h create mode 100644 Core/Unix/CoreUnix.cpp create mode 100644 Core/Unix/CoreUnix.h create mode 100644 Core/Unix/FreeBSD/CoreFreeBSD.cpp create mode 100644 Core/Unix/FreeBSD/CoreFreeBSD.h create mode 100644 Core/Unix/FreeBSD/System.h create mode 100644 Core/Unix/Linux/CoreLinux.cpp create mode 100644 Core/Unix/Linux/CoreLinux.h create mode 100644 Core/Unix/Linux/System.h create mode 100644 Core/Unix/MacOSX/CoreMacOSX.cpp create mode 100644 Core/Unix/MacOSX/CoreMacOSX.h create mode 100644 Core/Unix/MacOSX/System.h create mode 100644 Core/Unix/MountedFilesystem.h create mode 100644 Core/Unix/Solaris/CoreSolaris.cpp create mode 100644 Core/Unix/Solaris/CoreSolaris.h create mode 100644 Core/Unix/Solaris/System.h create mode 100644 Core/Unix/System.h (limited to 'Core/Unix') diff --git a/Core/Unix/CoreService.cpp b/Core/Unix/CoreService.cpp new file mode 100644 index 0000000..0ec636c --- /dev/null +++ b/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 +#include +#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 + auto_ptr CoreService::GetResponse () + { + auto_ptr deserializedObject (Serializable::DeserializeNew (ServiceOutputStream)); + + Exception *deserializedException = dynamic_cast (deserializedObject.get()); + if (deserializedException) + deserializedException->Throw(); + + if (dynamic_cast (deserializedObject.get()) == nullptr) + throw ParameterIncorrect (SRC_POS); + + return auto_ptr (dynamic_cast (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 inputStream (new FileStream (inputFD != -1 ? inputFD : InputPipe->GetReadFD())); + shared_ptr outputStream (new FileStream (outputFD != -1 ? outputFD : OutputPipe->GetWriteFD())); + + while (true) + { + shared_ptr request = Serializable::DeserializeNew (inputStream); + + try + { + // ExitRequest + if (dynamic_cast (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 ()->Serialize (outputStream); + continue; + } + + // CheckFilesystemRequest + CheckFilesystemRequest *checkRequest = dynamic_cast (request.get()); + if (checkRequest) + { + Core->CheckFilesystem (checkRequest->MountedVolumeInfo, checkRequest->Repair); + + CheckFilesystemResponse().Serialize (outputStream); + continue; + } + + // DismountFilesystemRequest + DismountFilesystemRequest *dismountFsRequest = dynamic_cast (request.get()); + if (dismountFsRequest) + { + Core->DismountFilesystem (dismountFsRequest->MountPoint, dismountFsRequest->Force); + + DismountFilesystemResponse().Serialize (outputStream); + continue; + } + + // DismountVolumeRequest + DismountVolumeRequest *dismountRequest = dynamic_cast (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 (request.get()); + if (getDeviceSectorSizeRequest) + { + GetDeviceSectorSizeResponse response; + response.Size = Core->GetDeviceSectorSize (getDeviceSectorSizeRequest->Path); + response.Serialize (outputStream); + continue; + } + + // GetDeviceSizeRequest + GetDeviceSizeRequest *getDeviceSizeRequest = dynamic_cast (request.get()); + if (getDeviceSizeRequest) + { + GetDeviceSizeResponse response; + response.Size = Core->GetDeviceSize (getDeviceSizeRequest->Path); + response.Serialize (outputStream); + continue; + } + + // GetHostDevicesRequest + GetHostDevicesRequest *getHostDevicesRequest = dynamic_cast (request.get()); + if (getHostDevicesRequest) + { + GetHostDevicesResponse response; + response.HostDevices = Core->GetHostDevices (getHostDevicesRequest->PathListOnly); + response.Serialize (outputStream); + continue; + } + + // MountVolumeRequest + MountVolumeRequest *mountRequest = dynamic_cast (request.get()); + if (mountRequest) + { + MountVolumeResponse ( + Core->MountVolume (*mountRequest->Options) + ).Serialize (outputStream); + + continue; + } + + // SetFileOwnerRequest + SetFileOwnerRequest *setFileOwnerRequest = dynamic_cast (request.get()); + if (setFileOwnerRequest) + { + CoreUnix *coreUnix = dynamic_cast (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 mountedVolume, bool repair) + { + CheckFilesystemRequest request (mountedVolume, repair); + SendRequest (request); + } + + void CoreService::RequestDismountFilesystem (const DirectoryPath &mountPoint, bool force) + { + DismountFilesystemRequest request (mountPoint, force); + SendRequest (request); + } + + shared_ptr CoreService::RequestDismountVolume (shared_ptr mountedVolume, bool ignoreOpenFiles, bool syncVolumeInfo) + { + DismountVolumeRequest request (mountedVolume, ignoreOpenFiles, syncVolumeInfo); + return SendRequest (request)->DismountedVolumeInfo; + } + + uint32 CoreService::RequestGetDeviceSectorSize (const DevicePath &devicePath) + { + GetDeviceSectorSizeRequest request (devicePath); + return SendRequest (request)->Size; + } + + uint64 CoreService::RequestGetDeviceSize (const DevicePath &devicePath) + { + GetDeviceSizeRequest request (devicePath); + return SendRequest (request)->Size; + } + + HostDeviceList CoreService::RequestGetHostDevices (bool pathListOnly) + { + GetHostDevicesRequest request (pathListOnly); + return SendRequest (request)->HostDevices; + } + + shared_ptr CoreService::RequestMountVolume (MountOptions &options) + { + MountVolumeRequest request (&options); + return SendRequest (request)->MountedVolumeInfo; + } + + void CoreService::RequestSetFileOwner (const FilesystemPath &path, const UserId &owner) + { + SetFileOwnerRequest request (path, owner); + SendRequest (request); + } + + template + auto_ptr 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 response (GetResponse ()); + 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 (); + } + + 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 (new FileStream (InputPipe->GetWriteFD())); + ServiceOutputStream = shared_ptr (new FileStream (OutputPipe->GetReadFD())); + } + + void CoreService::StartElevated (const CoreServiceRequest &request) + { + auto_ptr inPipe (new Pipe()); + auto_ptr 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 outputStream (new FileStream (errPipe.GetWriteFD())); + e.Serialize (outputStream); + } + catch (...) { } + } + + _exit (1); + } + + vector adminPassword (request.AdminPassword.size() + 1); + int timeout = 6000; + + if (request.FastElevation) + { + string dummyPassword = "dummy\n"; + adminPassword = vector (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 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 deserializedObject; + Exception *deserializedException = nullptr; + + try + { + shared_ptr stream (new MemoryStream (ConstBufferPtr ((byte *) &errOutput[0], errOutput.size()))); + deserializedObject.reset (Serializable::DeserializeNew (stream)); + deserializedException = dynamic_cast (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 (new FileStream (inPipe->GetWriteFD())); + ServiceOutputStream = shared_ptr (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 CoreService::AdminPasswordCallback; + + auto_ptr CoreService::AdminInputPipe; + auto_ptr CoreService::AdminOutputPipe; + + auto_ptr CoreService::InputPipe; + auto_ptr CoreService::OutputPipe; + shared_ptr CoreService::ServiceInputStream; + shared_ptr CoreService::ServiceOutputStream; + + bool CoreService::ElevatedPrivileges = false; + bool CoreService::ElevatedServiceAvailable = false; +} diff --git a/Core/Unix/CoreService.h b/Core/Unix/CoreService.h new file mode 100644 index 0000000..9702dc7 --- /dev/null +++ b/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 mountedVolume, bool repair); + static void RequestDismountFilesystem (const DirectoryPath &mountPoint, bool force); + static shared_ptr RequestDismountVolume (shared_ptr 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 RequestMountVolume (MountOptions &options); + static void RequestSetFileOwner (const FilesystemPath &path, const UserId &owner); + static void SetAdminPasswordCallback (shared_ptr functor) { AdminPasswordCallback = functor; } + static void Start (); + static void Stop (); + + protected: + template static auto_ptr GetResponse (); + template static auto_ptr SendRequest (CoreServiceRequest &request); + static void StartElevated (const CoreServiceRequest &request); + + static shared_ptr AdminPasswordCallback; + + static auto_ptr AdminInputPipe; + static auto_ptr AdminOutputPipe; + + static auto_ptr InputPipe; + static auto_ptr OutputPipe; + static shared_ptr ServiceInputStream; + static shared_ptr 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/Core/Unix/CoreServiceProxy.h b/Core/Unix/CoreServiceProxy.h new file mode 100644 index 0000000..2a26461 --- /dev/null +++ b/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 CoreServiceProxy : public T + { + public: + CoreServiceProxy () { } + virtual ~CoreServiceProxy () { } + + virtual void CheckFilesystem (shared_ptr mountedVolume, bool repair) const + { + CoreService::RequestCheckFilesystem (mountedVolume, repair); + } + + virtual void DismountFilesystem (const DirectoryPath &mountPoint, bool force) const + { + CoreService::RequestDismountFilesystem (mountPoint, force); + } + + virtual shared_ptr DismountVolume (shared_ptr mountedVolume, bool ignoreOpenFiles = false, bool syncVolumeInfo = false) + { + shared_ptr 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 MountVolume (MountOptions &options) + { + shared_ptr 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 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 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/Core/Unix/CoreServiceRequest.cpp b/Core/Unix/CoreServiceRequest.cpp new file mode 100644 index 0000000..49ee841 --- /dev/null +++ b/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 +#include "CoreServiceRequest.h" +#include "Platform/SerializerFactory.h" + +namespace TrueCrypt +{ + void CoreServiceRequest::Deserialize (shared_ptr 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) 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) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + MountedVolumeInfo = Serializable::DeserializeNew (stream); + sr.Deserialize ("Repair", Repair); + } + + bool CheckFilesystemRequest::RequiresElevation () const + { +#ifdef TC_MACOSX + return false; +#endif + return !Core->HasAdminPrivileges(); + } + + void CheckFilesystemRequest::Serialize (shared_ptr stream) const + { + CoreServiceRequest::Serialize (stream); + Serializer sr (stream); + MountedVolumeInfo->Serialize (stream); + sr.Serialize ("Repair", Repair); + } + + // DismountFilesystemRequest + void DismountFilesystemRequest::Deserialize (shared_ptr 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) const + { + CoreServiceRequest::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("Force", Force); + sr.Serialize ("MountPoint", wstring (MountPoint)); + } + + // DismountVolumeRequest + void DismountVolumeRequest::Deserialize (shared_ptr stream) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + sr.Deserialize ("IgnoreOpenFiles", IgnoreOpenFiles); + sr.Deserialize ("SyncVolumeInfo", SyncVolumeInfo); + MountedVolumeInfo = Serializable::DeserializeNew (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) 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) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + Path = sr.DeserializeWString ("Path"); + } + + bool GetDeviceSectorSizeRequest::RequiresElevation () const + { + return !Core->HasAdminPrivileges(); + } + + void GetDeviceSectorSizeRequest::Serialize (shared_ptr stream) const + { + CoreServiceRequest::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("Path", wstring (Path)); + } + + // GetDeviceSizeRequest + void GetDeviceSizeRequest::Deserialize (shared_ptr stream) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + Path = sr.DeserializeWString ("Path"); + } + + bool GetDeviceSizeRequest::RequiresElevation () const + { + return !Core->HasAdminPrivileges(); + } + + void GetDeviceSizeRequest::Serialize (shared_ptr stream) const + { + CoreServiceRequest::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("Path", wstring (Path)); + } + + // GetHostDevicesRequest + void GetHostDevicesRequest::Deserialize (shared_ptr stream) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + sr.Deserialize ("PathListOnly", PathListOnly); + } + + bool GetHostDevicesRequest::RequiresElevation () const + { + return !Core->HasAdminPrivileges(); + } + + void GetHostDevicesRequest::Serialize (shared_ptr stream) const + { + CoreServiceRequest::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("PathListOnly", PathListOnly); + } + + // ExitRequest + void ExitRequest::Deserialize (shared_ptr stream) + { + CoreServiceRequest::Deserialize (stream); + } + + void ExitRequest::Serialize (shared_ptr stream) const + { + CoreServiceRequest::Serialize (stream); + } + + // MountVolumeRequest + void MountVolumeRequest::Deserialize (shared_ptr stream) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + DeserializedOptions = Serializable::DeserializeNew (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) const + { + CoreServiceRequest::Serialize (stream); + Serializer sr (stream); + Options->Serialize (stream); + } + + // SetFileOwnerRequest + void SetFileOwnerRequest::Deserialize (shared_ptr stream) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + + uint64 owner; + sr.Deserialize ("Owner", owner); + Owner.SystemId = static_cast (owner); + + Path = sr.DeserializeWString ("Path"); + } + + bool SetFileOwnerRequest::RequiresElevation () const + { + return !Core->HasAdminPrivileges(); + } + + void SetFileOwnerRequest::Serialize (shared_ptr 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/Core/Unix/CoreServiceRequest.h b/Core/Unix/CoreServiceRequest.h new file mode 100644 index 0000000..030ac81 --- /dev/null +++ b/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, bool repair) + : MountedVolumeInfo (volumeInfo), Repair (repair) { } + TC_SERIALIZABLE (CheckFilesystemRequest); + + virtual bool RequiresElevation () const; + + shared_ptr 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, bool ignoreOpenFiles, bool syncVolumeInfo) + : IgnoreOpenFiles (ignoreOpenFiles), MountedVolumeInfo (volumeInfo), SyncVolumeInfo (syncVolumeInfo) { } + TC_SERIALIZABLE (DismountVolumeRequest); + + virtual bool RequiresElevation () const; + + bool IgnoreOpenFiles; + shared_ptr 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 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/Core/Unix/CoreServiceResponse.cpp b/Core/Unix/CoreServiceResponse.cpp new file mode 100644 index 0000000..7809b44 --- /dev/null +++ b/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) + { + } + + void CheckFilesystemResponse::Serialize (shared_ptr stream) const + { + Serializable::Serialize (stream); + } + + // DismountFilesystemResponse + void DismountFilesystemResponse::Deserialize (shared_ptr stream) + { + } + + void DismountFilesystemResponse::Serialize (shared_ptr stream) const + { + Serializable::Serialize (stream); + } + + // DismountVolumeResponse + void DismountVolumeResponse::Deserialize (shared_ptr stream) + { + DismountedVolumeInfo = Serializable::DeserializeNew (stream); + } + + void DismountVolumeResponse::Serialize (shared_ptr stream) const + { + Serializable::Serialize (stream); + Serializer sr (stream); + DismountedVolumeInfo->Serialize (stream); + } + + // GetDeviceSectorSizeResponse + void GetDeviceSectorSizeResponse::Deserialize (shared_ptr stream) + { + Serializer sr (stream); + sr.Deserialize ("Size", Size); + } + + void GetDeviceSectorSizeResponse::Serialize (shared_ptr stream) const + { + Serializable::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("Size", Size); + } + + // GetDeviceSizeResponse + void GetDeviceSizeResponse::Deserialize (shared_ptr stream) + { + Serializer sr (stream); + sr.Deserialize ("Size", Size); + } + + void GetDeviceSizeResponse::Serialize (shared_ptr stream) const + { + Serializable::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("Size", Size); + } + + // GetHostDevicesResponse + void GetHostDevicesResponse::Deserialize (shared_ptr stream) + { + Serializable::DeserializeList (stream, HostDevices); + } + + void GetHostDevicesResponse::Serialize (shared_ptr stream) const + { + Serializable::Serialize (stream); + Serializable::SerializeList (stream, HostDevices); + } + + // MountVolumeResponse + void MountVolumeResponse::Deserialize (shared_ptr stream) + { + Serializer sr (stream); + MountedVolumeInfo = Serializable::DeserializeNew (stream); + } + + void MountVolumeResponse::Serialize (shared_ptr stream) const + { + Serializable::Serialize (stream); + Serializer sr (stream); + MountedVolumeInfo->Serialize (stream); + } + + // SetFileOwnerResponse + void SetFileOwnerResponse::Deserialize (shared_ptr stream) + { + } + + void SetFileOwnerResponse::Serialize (shared_ptr 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/Core/Unix/CoreServiceResponse.h b/Core/Unix/CoreServiceResponse.h new file mode 100644 index 0000000..24c09b3 --- /dev/null +++ b/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 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) : MountedVolumeInfo (volumeInfo) { } + TC_SERIALIZABLE (MountVolumeResponse); + + shared_ptr MountedVolumeInfo; + }; + + struct SetFileOwnerResponse : CoreServiceResponse + { + SetFileOwnerResponse () { } + TC_SERIALIZABLE (SetFileOwnerResponse); + }; +} + +#endif // TC_HEADER_Core_Unix_CoreServiceResponse diff --git a/Core/Unix/CoreUnix.cpp b/Core/Unix/CoreUnix.cpp new file mode 100644 index 0000000..89f34e2 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include +#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 mountedVolume, bool repair) const + { + if (!mountedVolume->MountPoint.IsEmpty()) + DismountFilesystem (mountedVolume->MountPoint, false); + + list 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 args; + +#ifdef TC_MACOSX + if (force) + args.push_back ("-f"); +#endif + args.push_back ("--"); + args.push_back (mountPoint); + + Process::Execute ("umount", args); + } + + shared_ptr CoreUnix::DismountVolume (shared_ptr 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 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 mountedVol; + try + { + shared_ptr controlFile (new File); + controlFile->Open (string (mf.MountPoint) + FuseService::GetControlPath()); + + shared_ptr controlFileStream (new FileStream (controlFile)); + mountedVol = Serializable::DeserializeNew (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 (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 (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 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 CoreUnix::MountVolume (MountOptions &options) + { + CoalesceSlotNumberAndMountPoint (options); + + if (IsVolumeMounted (*options.Path)) + throw VolumeAlreadyMounted (SRC_POS); + + Cipher::EnableHwSupport (!options.NoHardwareCrypto); + + shared_ptr 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 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/Core/Unix/CoreUnix.h b/Core/Unix/CoreUnix.h new file mode 100644 index 0000000..1d7152f --- /dev/null +++ b/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 mountedVolume, bool repair = false) const; + virtual void DismountFilesystem (const DirectoryPath &mountPoint, bool force) const; + virtual shared_ptr DismountVolume (shared_ptr 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 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 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, 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/Core/Unix/FreeBSD/CoreFreeBSD.cpp b/Core/Unix/FreeBSD/CoreFreeBSD.cpp new file mode 100644 index 0000000..e0a4dd5 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include +#include "CoreFreeBSD.h" +#include "Core/Unix/CoreServiceProxy.h" + +namespace TrueCrypt +{ + CoreFreeBSD::CoreFreeBSD () + { + } + + CoreFreeBSD::~CoreFreeBSD () + { + } + + DevicePath CoreFreeBSD::AttachFileToLoopDevice (const FilePath &filePath, bool readOnly) const + { + list 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 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 Core (new CoreServiceProxy ); + auto_ptr CoreDirect (new CoreFreeBSD); +#endif +} diff --git a/Core/Unix/FreeBSD/CoreFreeBSD.h b/Core/Unix/FreeBSD/CoreFreeBSD.h new file mode 100644 index 0000000..a823033 --- /dev/null +++ b/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/Core/Unix/FreeBSD/System.h b/Core/Unix/FreeBSD/System.h new file mode 100644 index 0000000..e0cac0b --- /dev/null +++ b/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/Core/Unix/Linux/CoreLinux.cpp b/Core/Unix/Linux/CoreLinux.cpp new file mode 100644 index 0000000..634a3a2 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include +#include +#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 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 args; + + list ::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 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 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 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 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, 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 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 Core (new CoreServiceProxy ); + auto_ptr CoreDirect (new CoreLinux); +} diff --git a/Core/Unix/Linux/CoreLinux.h b/Core/Unix/Linux/CoreLinux.h new file mode 100644 index 0000000..5758d65 --- /dev/null +++ b/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 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, MountOptions &options, const DirectoryPath &auxMountPoint) const; + + private: + CoreLinux (const CoreLinux &); + CoreLinux &operator= (const CoreLinux &); + }; +} + +#endif // TC_HEADER_Core_CoreLinux diff --git a/Core/Unix/Linux/System.h b/Core/Unix/Linux/System.h new file mode 100644 index 0000000..20a4f82 --- /dev/null +++ b/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/Core/Unix/MacOSX/CoreMacOSX.cpp b/Core/Unix/MacOSX/CoreMacOSX.cpp new file mode 100644 index 0000000..b7aa08c --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "CoreMacOSX.h" +#include "Driver/Fuse/FuseService.h" +#include "Core/Unix/CoreServiceProxy.h" + +namespace TrueCrypt +{ + CoreMacOSX::CoreMacOSX () + { + } + + CoreMacOSX::~CoreMacOSX () + { + } + + shared_ptr CoreMacOSX::DismountVolume (shared_ptr mountedVolume, bool ignoreOpenFiles, bool syncVolumeInfo) + { + if (!mountedVolume->VirtualDevice.IsEmpty() && mountedVolume->VirtualDevice.IsBlockDevice()) + { + list 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 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 mountedVolume, bool repair) const + { + list 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 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 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 ("dev-entry"); + if (p == string::npos) + throw ParameterIncorrect (SRC_POS); + + p = xml.find ("", p); + if (p == string::npos) + throw ParameterIncorrect (SRC_POS); + p += 8; + + size_t e = xml.find ("", 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 args; + args.push_back ("detach"); + args.push_back (volImage); + args.push_back ("-force"); + + Process::Execute ("hdiutil", args); + } + catch (ExecutedProcessFailed&) { } + throw; + } + } + + auto_ptr Core (new CoreServiceProxy ); + auto_ptr CoreDirect (new CoreMacOSX); +} diff --git a/Core/Unix/MacOSX/CoreMacOSX.h b/Core/Unix/MacOSX/CoreMacOSX.h new file mode 100644 index 0000000..eee11d6 --- /dev/null +++ b/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 mountedVolume, bool repair = false) const; + virtual shared_ptr DismountVolume (shared_ptr 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/Core/Unix/MacOSX/System.h b/Core/Unix/MacOSX/System.h new file mode 100644 index 0000000..073e17a --- /dev/null +++ b/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/Core/Unix/MountedFilesystem.h b/Core/Unix/MountedFilesystem.h new file mode 100644 index 0000000..6e704d3 --- /dev/null +++ b/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 > MountedFilesystemList; +} + +#endif // TC_HEADER_Core_Unix_MountedFilesystem diff --git a/Core/Unix/Solaris/CoreSolaris.cpp b/Core/Unix/Solaris/CoreSolaris.cpp new file mode 100644 index 0000000..63736db --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include "CoreSolaris.h" +#include "Core/Unix/CoreServiceProxy.h" + +namespace TrueCrypt +{ + CoreSolaris::CoreSolaris () + { + } + + CoreSolaris::~CoreSolaris () + { + } + + DevicePath CoreSolaris::AttachFileToLoopDevice (const FilePath &filePath, bool readOnly) const + { + list args; + args.push_back ("-a"); + args.push_back (filePath); + + return StringConverter::Trim (Process::Execute ("lofiadm", args)); + } + + void CoreSolaris::DetachLoopDevice (const DevicePath &devicePath) const + { + list 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 Core (new CoreServiceProxy ); + auto_ptr CoreDirect (new CoreSolaris); +} diff --git a/Core/Unix/Solaris/CoreSolaris.h b/Core/Unix/Solaris/CoreSolaris.h new file mode 100644 index 0000000..76dd194 --- /dev/null +++ b/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/Core/Unix/Solaris/System.h b/Core/Unix/Solaris/System.h new file mode 100644 index 0000000..039dd40 --- /dev/null +++ b/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/Core/Unix/System.h b/Core/Unix/System.h new file mode 100644 index 0000000..63d565b --- /dev/null +++ b/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 -- cgit