diff --git a/src/Core/CoreBase.cpp b/src/Core/CoreBase.cpp index 5eadd6d2..c4bc9721 100644 --- a/src/Core/CoreBase.cpp +++ b/src/Core/CoreBase.cpp @@ -20,9 +20,7 @@ namespace VeraCrypt { CoreBase::CoreBase () : DeviceChangeInProgress (false) -#if defined(TC_LINUX ) || defined (TC_FREEBSD) , UseDummySudoPassword (false) -#endif #if defined(TC_UNIX) ,AllowInsecureMount (false) #endif diff --git a/src/Core/Unix/CoreService.cpp b/src/Core/Unix/CoreService.cpp index e69df959..014b5c8f 100644 --- a/src/Core/Unix/CoreService.cpp +++ b/src/Core/Unix/CoreService.cpp @@ -110,8 +110,7 @@ namespace VeraCrypt } #endif - template - unique_ptr CoreService::GetResponse () + unique_ptr CoreService::GetResponseObject () { unique_ptr deserializedObject (Serializable::DeserializeNew (ServiceOutputStream)); @@ -119,6 +118,14 @@ namespace VeraCrypt if (deserializedException) deserializedException->Throw(); + return deserializedObject; + } + + template + unique_ptr CoreService::GetResponse () + { + unique_ptr deserializedObject (GetResponseObject()); + if (dynamic_cast (deserializedObject.get()) == nullptr) throw ParameterIncorrect (SRC_POS); @@ -199,14 +206,21 @@ namespace VeraCrypt if (!ElevatedPrivileges && request->ElevateUserPrivileges) { + bool elevatedServiceStarted = false; + if (!ElevatedServiceAvailable) { finally_do_arg (string *, &request->AdminPassword, { StringConverter::Erase (*finally_arg); }); CoreService::StartElevated (*request); ElevatedServiceAvailable = true; + elevatedServiceStarted = true; } + // Report sudo/elevated-service success before executing the request. + if (elevatedServiceStarted) + ElevatedServiceStartedResponse().Serialize (outputStream); + request->Serialize (ServiceInputStream); GetResponse ()->Serialize (outputStream); continue; @@ -424,6 +438,7 @@ namespace VeraCrypt request.UserEnvPATH = Core->GetUserEnvPATH(); request.UseDummySudoPassword = Core->GetUseDummySudoPassword(); request.AllowInsecureMount = Core->GetAllowInsecureMount(); + finally_do_arg (string *, &request.AdminPassword, { StringConverter::Erase (*finally_arg); }); if (request.RequiresElevation()) { @@ -482,12 +497,28 @@ namespace VeraCrypt try { request.Serialize (ServiceInputStream); - unique_ptr response (GetResponse ()); + + unique_ptr response (GetResponseObject()); + if (dynamic_cast (response.get()) != nullptr) + { + // The elevated channel is usable even if the forwarded request fails. + // Any later failure must be propagated as the real error rather than + // triggering another administrator-password prompt. + ElevatedServiceAvailable = true; + return GetResponse (); + } + + if (dynamic_cast (response.get()) == nullptr) + throw ParameterIncorrect (SRC_POS); + ElevatedServiceAvailable = true; - return response; + return unique_ptr (dynamic_cast (response.release())); } catch (ElevationFailed &e) { + if (ElevatedServiceAvailable) + throw; + if (!request.FastElevation) { ExceptionEventArgs args (e); @@ -502,8 +533,6 @@ namespace VeraCrypt } } - finally_do_arg (string *, &request.AdminPassword, { StringConverter::Erase (*finally_arg); }); - request.Serialize (ServiceInputStream); return GetResponse (); } diff --git a/src/Core/Unix/CoreService.h b/src/Core/Unix/CoreService.h index 59dc32b1..fb772bd8 100644 --- a/src/Core/Unix/CoreService.h +++ b/src/Core/Unix/CoreService.h @@ -46,6 +46,7 @@ namespace VeraCrypt static void Stop (); protected: + static unique_ptr GetResponseObject (); template static unique_ptr GetResponse (); template static unique_ptr SendRequest (CoreServiceRequest &request); static void StartElevated (const CoreServiceRequest &request); diff --git a/src/Core/Unix/CoreServiceResponse.cpp b/src/Core/Unix/CoreServiceResponse.cpp index b1741b76..e14eea2b 100644 --- a/src/Core/Unix/CoreServiceResponse.cpp +++ b/src/Core/Unix/CoreServiceResponse.cpp @@ -15,6 +15,16 @@ namespace VeraCrypt { + // ElevatedServiceStartedResponse + void ElevatedServiceStartedResponse::Deserialize (shared_ptr stream) + { + } + + void ElevatedServiceStartedResponse::Serialize (shared_ptr stream) const + { + Serializable::Serialize (stream); + } + // CheckFilesystemResponse void CheckFilesystemResponse::Deserialize (shared_ptr stream) { @@ -124,6 +134,7 @@ namespace VeraCrypt Serializable::Serialize (stream); } + TC_SERIALIZER_FACTORY_ADD_CLASS (ElevatedServiceStartedResponse); TC_SERIALIZER_FACTORY_ADD_CLASS (CheckFilesystemResponse); TC_SERIALIZER_FACTORY_ADD_CLASS (DismountFilesystemResponse); TC_SERIALIZER_FACTORY_ADD_CLASS (DismountVolumeResponse); diff --git a/src/Core/Unix/CoreServiceResponse.h b/src/Core/Unix/CoreServiceResponse.h index c792ad31..d6c318ba 100644 --- a/src/Core/Unix/CoreServiceResponse.h +++ b/src/Core/Unix/CoreServiceResponse.h @@ -22,6 +22,12 @@ namespace VeraCrypt { }; + struct ElevatedServiceStartedResponse : CoreServiceResponse + { + ElevatedServiceStartedResponse () { } + TC_SERIALIZABLE (ElevatedServiceStartedResponse); + }; + struct CheckFilesystemResponse : CoreServiceResponse { CheckFilesystemResponse () { }