diff --git a/src/Core/Unix/CoreService.cpp b/src/Core/Unix/CoreService.cpp index 376aeedd..b886985d 100644 --- a/src/Core/Unix/CoreService.cpp +++ b/src/Core/Unix/CoreService.cpp @@ -20,6 +20,7 @@ #include "Platform/SystemLog.h" #include "Platform/Thread.h" #include "Platform/Unix/Poller.h" +#include "Platform/Unix/Process.h" #include "Core/Core.h" #include "CoreUnix.h" #include "CoreServiceRequest.h" @@ -27,6 +28,66 @@ namespace VeraCrypt { +#ifdef TC_MACOSX + static bool IsMacOSXDevicePathWithPrefix (const string &path, const string &prefix) + { + if (path.find (prefix) != 0 || path.size() <= prefix.size()) + return false; + + size_t index = prefix.size(); + while (index < path.size() && path[index] >= '0' && path[index] <= '9') + ++index; + + if (index == prefix.size()) + return false; + + if (index == path.size()) + return true; + + if (path[index++] != 's') + return false; + + size_t sliceStart = index; + while (index < path.size() && path[index] >= '0' && path[index] <= '9') + ++index; + + return index > sliceStart && index == path.size(); + } + + static bool IsMacOSXFormatterDevicePath (const string &path) + { + return IsMacOSXDevicePathWithPrefix (path, "/dev/disk") + || IsMacOSXDevicePathWithPrefix (path, "/dev/rdisk"); + } + + static list BuildMacOSXAPFSFormatterArguments (const ExecuteMacOSXAPFSFormatterRequest &request) + { + if (!IsMacOSXFormatterDevicePath (request.Device)) + throw ParameterIncorrect (SRC_POS); + + if (request.OwnerUserId > static_cast ((uid_t) -1) + || request.OwnerGroupId > static_cast ((gid_t) -1)) + { + throw ParameterIncorrect (SRC_POS); + } + + stringstream uid; + stringstream gid; + list arguments; + + uid << request.OwnerUserId; + gid << request.OwnerGroupId; + + arguments.push_back ("-U"); + arguments.push_back (uid.str()); + arguments.push_back ("-G"); + arguments.push_back (gid.str()); + arguments.push_back (string (request.Device)); + + return arguments; + } +#endif + template unique_ptr CoreService::GetResponse () { @@ -201,6 +262,17 @@ namespace VeraCrypt continue; } +#ifdef TC_MACOSX + // ExecuteMacOSXAPFSFormatterRequest + ExecuteMacOSXAPFSFormatterRequest *executeAPFSFormatterRequest = dynamic_cast (request.get()); + if (executeAPFSFormatterRequest) + { + Process::Execute (CoreService::GetMacOSXAPFSFormatterPath(), BuildMacOSXAPFSFormatterArguments (*executeAPFSFormatterRequest)); + ExecuteMacOSXAPFSFormatterResponse().Serialize (outputStream); + continue; + } +#endif + // MountVolumeRequest MountVolumeRequest *mountRequest = dynamic_cast (request.get()); if (mountRequest) @@ -290,6 +362,19 @@ namespace VeraCrypt return SendRequest (request)->HostDevices; } +#ifdef TC_MACOSX + const char *CoreService::GetMacOSXAPFSFormatterPath () + { + return "/sbin/newfs_apfs"; + } + + void CoreService::RequestExecuteMacOSXAPFSFormatter (const DevicePath &devicePath, uint64 userId, uint64 groupId) + { + ExecuteMacOSXAPFSFormatterRequest request (devicePath, userId, groupId); + SendRequest (request); + } +#endif + shared_ptr CoreService::RequestMountVolume (MountOptions &options) { MountVolumeRequest request (&options); diff --git a/src/Core/Unix/CoreService.h b/src/Core/Unix/CoreService.h index 6d4ce479..b74b226f 100644 --- a/src/Core/Unix/CoreService.h +++ b/src/Core/Unix/CoreService.h @@ -35,6 +35,10 @@ namespace VeraCrypt static uint32 RequestGetDeviceSectorSize (const DevicePath &devicePath); static uint64 RequestGetDeviceSize (const DevicePath &devicePath); static HostDeviceList RequestGetHostDevices (bool pathListOnly); +#ifdef TC_MACOSX + static const char *GetMacOSXAPFSFormatterPath (); + static void RequestExecuteMacOSXAPFSFormatter (const DevicePath &devicePath, uint64 userId, uint64 groupId); +#endif static shared_ptr RequestMountVolume (MountOptions &options); static void RequestSetFileOwner (const FilesystemPath &path, const UserId &owner); static void SetAdminPasswordCallback (shared_ptr functor) { AdminPasswordCallback = functor; } diff --git a/src/Core/Unix/CoreServiceRequest.cpp b/src/Core/Unix/CoreServiceRequest.cpp index ffecbb1a..c6e0b96e 100644 --- a/src/Core/Unix/CoreServiceRequest.cpp +++ b/src/Core/Unix/CoreServiceRequest.cpp @@ -219,6 +219,32 @@ namespace VeraCrypt CoreServiceRequest::Serialize (stream); } +#ifdef TC_MACOSX + // ExecuteMacOSXAPFSFormatterRequest + void ExecuteMacOSXAPFSFormatterRequest::Deserialize (shared_ptr stream) + { + CoreServiceRequest::Deserialize (stream); + Serializer sr (stream); + Device = sr.DeserializeWString ("Device"); + sr.Deserialize ("OwnerGroupId", OwnerGroupId); + sr.Deserialize ("OwnerUserId", OwnerUserId); + } + + bool ExecuteMacOSXAPFSFormatterRequest::RequiresElevation () const + { + return !Core->HasAdminPrivileges(); + } + + void ExecuteMacOSXAPFSFormatterRequest::Serialize (shared_ptr stream) const + { + CoreServiceRequest::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("Device", wstring (Device)); + sr.Serialize ("OwnerGroupId", OwnerGroupId); + sr.Serialize ("OwnerUserId", OwnerUserId); + } +#endif + // MountVolumeRequest void MountVolumeRequest::Deserialize (shared_ptr stream) { @@ -294,6 +320,9 @@ namespace VeraCrypt TC_SERIALIZER_FACTORY_ADD_CLASS (EmergencyDismountVolumeRequest); #endif TC_SERIALIZER_FACTORY_ADD_CLASS (ExitRequest); +#ifdef TC_MACOSX + TC_SERIALIZER_FACTORY_ADD_CLASS (ExecuteMacOSXAPFSFormatterRequest); +#endif TC_SERIALIZER_FACTORY_ADD_CLASS (GetDeviceSectorSizeRequest); TC_SERIALIZER_FACTORY_ADD_CLASS (GetDeviceSizeRequest); TC_SERIALIZER_FACTORY_ADD_CLASS (GetHostDevicesRequest); diff --git a/src/Core/Unix/CoreServiceRequest.h b/src/Core/Unix/CoreServiceRequest.h index c65a3c56..bd0df1ea 100644 --- a/src/Core/Unix/CoreServiceRequest.h +++ b/src/Core/Unix/CoreServiceRequest.h @@ -126,6 +126,22 @@ namespace VeraCrypt TC_SERIALIZABLE (ExitRequest); }; +#ifdef TC_MACOSX + struct ExecuteMacOSXAPFSFormatterRequest : CoreServiceRequest + { + ExecuteMacOSXAPFSFormatterRequest () { } + ExecuteMacOSXAPFSFormatterRequest (const DevicePath &devicePath, uint64 userId, uint64 groupId) + : Device (devicePath), OwnerGroupId (groupId), OwnerUserId (userId) { } + TC_SERIALIZABLE (ExecuteMacOSXAPFSFormatterRequest); + + virtual bool RequiresElevation () const; + + DevicePath Device; + uint64 OwnerGroupId; + uint64 OwnerUserId; + }; +#endif + struct MountVolumeRequest : CoreServiceRequest { MountVolumeRequest () { } diff --git a/src/Core/Unix/CoreServiceResponse.cpp b/src/Core/Unix/CoreServiceResponse.cpp index 59d9d090..758e8663 100644 --- a/src/Core/Unix/CoreServiceResponse.cpp +++ b/src/Core/Unix/CoreServiceResponse.cpp @@ -88,6 +88,18 @@ namespace VeraCrypt Serializable::SerializeList (stream, HostDevices); } +#ifdef TC_MACOSX + // ExecuteMacOSXAPFSFormatterResponse + void ExecuteMacOSXAPFSFormatterResponse::Deserialize (shared_ptr stream) + { + } + + void ExecuteMacOSXAPFSFormatterResponse::Serialize (shared_ptr stream) const + { + Serializable::Serialize (stream); + } +#endif + // MountVolumeResponse void MountVolumeResponse::Deserialize (shared_ptr stream) { @@ -118,6 +130,9 @@ namespace VeraCrypt TC_SERIALIZER_FACTORY_ADD_CLASS (GetDeviceSectorSizeResponse); TC_SERIALIZER_FACTORY_ADD_CLASS (GetDeviceSizeResponse); TC_SERIALIZER_FACTORY_ADD_CLASS (GetHostDevicesResponse); +#ifdef TC_MACOSX + TC_SERIALIZER_FACTORY_ADD_CLASS (ExecuteMacOSXAPFSFormatterResponse); +#endif TC_SERIALIZER_FACTORY_ADD_CLASS (MountVolumeResponse); TC_SERIALIZER_FACTORY_ADD_CLASS (SetFileOwnerResponse); } diff --git a/src/Core/Unix/CoreServiceResponse.h b/src/Core/Unix/CoreServiceResponse.h index a741db0f..b323f9d8 100644 --- a/src/Core/Unix/CoreServiceResponse.h +++ b/src/Core/Unix/CoreServiceResponse.h @@ -69,6 +69,14 @@ namespace VeraCrypt HostDeviceList HostDevices; }; +#ifdef TC_MACOSX + struct ExecuteMacOSXAPFSFormatterResponse : CoreServiceResponse + { + ExecuteMacOSXAPFSFormatterResponse () { } + TC_SERIALIZABLE (ExecuteMacOSXAPFSFormatterResponse); + }; +#endif + struct MountVolumeResponse : CoreServiceResponse { MountVolumeResponse () { } diff --git a/src/Main/Forms/VolumeCreationWizard.cpp b/src/Main/Forms/VolumeCreationWizard.cpp index ed72f839..0e975705 100644 --- a/src/Main/Forms/VolumeCreationWizard.cpp +++ b/src/Main/Forms/VolumeCreationWizard.cpp @@ -843,7 +843,9 @@ namespace VeraCrypt { RestoreMacOSXFormatterDeviceOwners (*finally_arg); }); - PrepareMacOSXFormatterDevice (virtualDevice, changedDeviceOwners); + bool useElevatedAPFSFormatter = UseElevatedMacOSXAPFSFormatter (fsFormatter); + if (!useElevatedAPFSFormatter) + PrepareMacOSXFormatterDevice (virtualDevice, changedDeviceOwners); #else UserId origDeviceOwner ((uid_t) -1); @@ -888,10 +890,19 @@ namespace VeraCrypt } } +#ifdef TC_MACOSX + if (IsMacOSXAPFSFormatter (fsFormatter) && !useElevatedAPFSFormatter) + AddMacOSXAPFSFormatterUserArgs (args); +#endif + args.push_back (string (virtualDevice)); SetCreationProgressText (StringFormatter (LangString["FORMAT_STAGE_CREATING_FILESYSTEM"], fsFormatter)); +#ifdef TC_MACOSX + ExecuteMacOSXFilesystemFormatter (fsFormatter, args); +#else Process::Execute (fsFormatter, args); +#endif SetCreationProgressText (LangString["FORMAT_STAGE_DISMOUNTING_TEMP_VOLUME"]); } #endif // TC_UNIX diff --git a/src/Main/MacOSXFormatterDevice.h b/src/Main/MacOSXFormatterDevice.h index 4eb7d3e4..d09337a3 100644 --- a/src/Main/MacOSXFormatterDevice.h +++ b/src/Main/MacOSXFormatterDevice.h @@ -14,6 +14,8 @@ #ifdef TC_MACOSX #include +#include "Core/Unix/CoreService.h" +#include "Platform/Unix/Process.h" namespace VeraCrypt { @@ -59,6 +61,33 @@ namespace VeraCrypt return deviceIdentifier; } + inline bool IsMacOSXAPFSFormatter (const string &fsFormatter) + { + size_t namePos = fsFormatter.find_last_of ('/'); + string fsFormatterName = namePos == string::npos ? fsFormatter : fsFormatter.substr (namePos + 1); + return fsFormatterName == "newfs_apfs"; + } + + inline bool UseElevatedMacOSXAPFSFormatter (const string &fsFormatter) + { + return IsMacOSXAPFSFormatter (fsFormatter) && !Core->HasAdminPrivileges(); + } + + inline void AddMacOSXAPFSFormatterUserArgs (list &args) + { + stringstream uid; + stringstream gid; + + // The APFS formatter may run elevated, so preserve the invoking user's ownership. + uid << getuid(); + gid << getgid(); + + args.push_back ("-U"); + args.push_back (uid.str()); + args.push_back ("-G"); + args.push_back (gid.str()); + } + struct MacOSXFormatterDeviceOwnerRestore { MacOSXFormatterDeviceOwnerRestore (const FilesystemPath &path, const UserId &owner) @@ -125,6 +154,20 @@ namespace VeraCrypt catch (...) { } } } + + inline void ExecuteMacOSXFilesystemFormatter (const string &fsFormatter, const list &args) + { + if (UseElevatedMacOSXAPFSFormatter (fsFormatter)) + { + if (args.empty()) + throw ParameterIncorrect (SRC_POS); + + CoreService::RequestExecuteMacOSXAPFSFormatter (DevicePath (args.back()), getuid(), getgid()); + return; + } + + Process::Execute (IsMacOSXAPFSFormatter (fsFormatter) ? CoreService::GetMacOSXAPFSFormatterPath() : fsFormatter, args); + } } #endif // TC_MACOSX diff --git a/src/Main/TextUserInterface.cpp b/src/Main/TextUserInterface.cpp index a132c581..4b563a28 100644 --- a/src/Main/TextUserInterface.cpp +++ b/src/Main/TextUserInterface.cpp @@ -1078,7 +1078,9 @@ namespace VeraCrypt { RestoreMacOSXFormatterDeviceOwners (*finally_arg); }); - PrepareMacOSXFormatterDevice (virtualDevice, changedDeviceOwners); + bool useElevatedAPFSFormatter = UseElevatedMacOSXAPFSFormatter (fsFormatter); + if (!useElevatedAPFSFormatter) + PrepareMacOSXFormatterDevice (virtualDevice, changedDeviceOwners); #else UserId origDeviceOwner ((uid_t) -1); @@ -1123,9 +1125,18 @@ namespace VeraCrypt } } +#ifdef TC_MACOSX + if (IsMacOSXAPFSFormatter (fsFormatter) && !useElevatedAPFSFormatter) + AddMacOSXAPFSFormatterUserArgs (args); +#endif + args.push_back (string (virtualDevice)); +#ifdef TC_MACOSX + ExecuteMacOSXFilesystemFormatter (fsFormatter, args); +#else Process::Execute (fsFormatter, args); +#endif } #endif // TC_UNIX