"Fossies" - the Fresh Open Source Software Archive

Member "src/Core/Unix/CoreService.cpp" (10 Oct 2018, 15560 Bytes) of package /windows/misc/VeraCrypt_1.23-Hotfix-2_Source.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "CoreService.cpp" see the Fossies "Dox" file reference documentation.

    1 /*
    2  Derived from source code of TrueCrypt 7.1a, which is
    3  Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
    4  by the TrueCrypt License 3.0.
    5 
    6  Modifications and additions to the original source code (contained in this file)
    7  and all other portions of this file are Copyright (c) 2013-2017 IDRIX
    8  and are governed by the Apache License 2.0 the full text of which is
    9  contained in the file License.txt included in VeraCrypt binary and source
   10  code distribution packages.
   11 */
   12 
   13 #include "CoreService.h"
   14 #include <fcntl.h>
   15 #include <sys/wait.h>
   16 #include "Platform/FileStream.h"
   17 #include "Platform/MemoryStream.h"
   18 #include "Platform/Serializable.h"
   19 #include "Platform/SystemLog.h"
   20 #include "Platform/Thread.h"
   21 #include "Platform/Unix/Poller.h"
   22 #include "Core/Core.h"
   23 #include "CoreUnix.h"
   24 #include "CoreServiceRequest.h"
   25 #include "CoreServiceResponse.h"
   26 
   27 namespace VeraCrypt
   28 {
   29     template <class T>
   30     auto_ptr <T> CoreService::GetResponse ()
   31     {
   32         auto_ptr <Serializable> deserializedObject (Serializable::DeserializeNew (ServiceOutputStream));
   33 
   34         Exception *deserializedException = dynamic_cast <Exception*> (deserializedObject.get());
   35         if (deserializedException)
   36             deserializedException->Throw();
   37 
   38         if (dynamic_cast <T *> (deserializedObject.get()) == nullptr)
   39             throw ParameterIncorrect (SRC_POS);
   40 
   41         return auto_ptr <T> (dynamic_cast <T *> (deserializedObject.release()));
   42     }
   43 
   44     void CoreService::ProcessElevatedRequests ()
   45     {
   46         int pid = fork();
   47         throw_sys_if (pid == -1);
   48         if (pid == 0)
   49         {
   50             try
   51             {
   52                 int f = open ("/dev/null", 0);
   53                 throw_sys_sub_if (f == -1, "/dev/null");
   54                 throw_sys_if (dup2 (f, STDERR_FILENO) == -1);
   55 
   56                 // Wait for sync code
   57                 while (true)
   58                 {
   59                     byte b;
   60                     throw_sys_if (read (STDIN_FILENO, &b, 1) != 1);
   61                     if (b != 0x00)
   62                         continue;
   63 
   64                     throw_sys_if (read (STDIN_FILENO, &b, 1) != 1);
   65                     if (b != 0x11)
   66                         continue;
   67 
   68                     throw_sys_if (read (STDIN_FILENO, &b, 1) != 1);
   69                     if (b == 0x22)
   70                         break;
   71                 }
   72 
   73                 ElevatedPrivileges = true;
   74                 ProcessRequests (STDIN_FILENO, STDOUT_FILENO);
   75                 _exit (0);
   76             }
   77             catch (exception &e)
   78             {
   79 #ifdef DEBUG
   80                 SystemLog::WriteException (e);
   81 #endif
   82             }
   83             catch (...) { }
   84             _exit (1);
   85         }
   86     }
   87 
   88     void CoreService::ProcessRequests (int inputFD, int outputFD)
   89     {
   90         try
   91         {
   92             Core = CoreDirect;
   93 
   94             shared_ptr <Stream> inputStream (new FileStream (inputFD != -1 ? inputFD : InputPipe->GetReadFD()));
   95             shared_ptr <Stream> outputStream (new FileStream (outputFD != -1 ? outputFD : OutputPipe->GetWriteFD()));
   96 
   97             while (true)
   98             {
   99                 shared_ptr <CoreServiceRequest> request = Serializable::DeserializeNew <CoreServiceRequest> (inputStream);
  100 
  101                 try
  102                 {
  103                     // ExitRequest
  104                     if (dynamic_cast <ExitRequest*> (request.get()) != nullptr)
  105                     {
  106                         if (ElevatedServiceAvailable)
  107                             request->Serialize (ServiceInputStream);
  108                         return;
  109                     }
  110 
  111                     if (!ElevatedPrivileges && request->ElevateUserPrivileges)
  112                     {
  113                         if (!ElevatedServiceAvailable)
  114                         {
  115                             finally_do_arg (string *, &request->AdminPassword, { StringConverter::Erase (*finally_arg); });
  116 
  117                             CoreService::StartElevated (*request);
  118                             ElevatedServiceAvailable = true;
  119                         }
  120 
  121                         request->Serialize (ServiceInputStream);
  122                         GetResponse <Serializable>()->Serialize (outputStream);
  123                         continue;
  124                     }
  125 
  126                     // CheckFilesystemRequest
  127                     CheckFilesystemRequest *checkRequest = dynamic_cast <CheckFilesystemRequest*> (request.get());
  128                     if (checkRequest)
  129                     {
  130                         Core->CheckFilesystem (checkRequest->MountedVolumeInfo, checkRequest->Repair);
  131 
  132                         CheckFilesystemResponse().Serialize (outputStream);
  133                         continue;
  134                     }
  135 
  136                     // DismountFilesystemRequest
  137                     DismountFilesystemRequest *dismountFsRequest = dynamic_cast <DismountFilesystemRequest*> (request.get());
  138                     if (dismountFsRequest)
  139                     {
  140                         Core->DismountFilesystem (dismountFsRequest->MountPoint, dismountFsRequest->Force);
  141 
  142                         DismountFilesystemResponse().Serialize (outputStream);
  143                         continue;
  144                     }
  145 
  146                     // DismountVolumeRequest
  147                     DismountVolumeRequest *dismountRequest = dynamic_cast <DismountVolumeRequest*> (request.get());
  148                     if (dismountRequest)
  149                     {
  150                         DismountVolumeResponse response;
  151                         response.DismountedVolumeInfo = Core->DismountVolume (dismountRequest->MountedVolumeInfo, dismountRequest->IgnoreOpenFiles, dismountRequest->SyncVolumeInfo);
  152                         response.Serialize (outputStream);
  153                         continue;
  154                     }
  155 
  156                     // GetDeviceSectorSizeRequest
  157                     GetDeviceSectorSizeRequest *getDeviceSectorSizeRequest = dynamic_cast <GetDeviceSectorSizeRequest*> (request.get());
  158                     if (getDeviceSectorSizeRequest)
  159                     {
  160                         GetDeviceSectorSizeResponse response;
  161                         response.Size = Core->GetDeviceSectorSize (getDeviceSectorSizeRequest->Path);
  162                         response.Serialize (outputStream);
  163                         continue;
  164                     }
  165 
  166                     // GetDeviceSizeRequest
  167                     GetDeviceSizeRequest *getDeviceSizeRequest = dynamic_cast <GetDeviceSizeRequest*> (request.get());
  168                     if (getDeviceSizeRequest)
  169                     {
  170                         GetDeviceSizeResponse response;
  171                         response.Size = Core->GetDeviceSize (getDeviceSizeRequest->Path);
  172                         response.Serialize (outputStream);
  173                         continue;
  174                     }
  175 
  176                     // GetHostDevicesRequest
  177                     GetHostDevicesRequest *getHostDevicesRequest = dynamic_cast <GetHostDevicesRequest*> (request.get());
  178                     if (getHostDevicesRequest)
  179                     {
  180                         GetHostDevicesResponse response;
  181                         response.HostDevices = Core->GetHostDevices (getHostDevicesRequest->PathListOnly);
  182                         response.Serialize (outputStream);
  183                         continue;
  184                     }
  185 
  186                     // MountVolumeRequest
  187                     MountVolumeRequest *mountRequest = dynamic_cast <MountVolumeRequest*> (request.get());
  188                     if (mountRequest)
  189                     {
  190                         MountVolumeResponse (
  191                             Core->MountVolume (*mountRequest->Options)
  192                         ).Serialize (outputStream);
  193 
  194                         continue;
  195                     }
  196 
  197                     // SetFileOwnerRequest
  198                     SetFileOwnerRequest *setFileOwnerRequest = dynamic_cast <SetFileOwnerRequest*> (request.get());
  199                     if (setFileOwnerRequest)
  200                     {
  201                         CoreUnix *coreUnix = dynamic_cast <CoreUnix *> (Core.get());
  202                         if (!coreUnix)
  203                             throw ParameterIncorrect (SRC_POS);
  204 
  205                         coreUnix->SetFileOwner (setFileOwnerRequest->Path, setFileOwnerRequest->Owner);
  206                         SetFileOwnerResponse().Serialize (outputStream);
  207                         continue;
  208                     }
  209 
  210                     throw ParameterIncorrect (SRC_POS);
  211                 }
  212                 catch (Exception &e)
  213                 {
  214                     e.Serialize (outputStream);
  215                 }
  216                 catch (exception &e)
  217                 {
  218                     ExternalException (SRC_POS, StringConverter::ToExceptionString (e)).Serialize (outputStream);
  219                 }
  220             }
  221         }
  222         catch (exception &e)
  223         {
  224 #ifdef DEBUG
  225             SystemLog::WriteException (e);
  226 #endif
  227             throw;
  228         }
  229     }
  230 
  231     void CoreService::RequestCheckFilesystem (shared_ptr <VolumeInfo> mountedVolume, bool repair)
  232     {
  233         CheckFilesystemRequest request (mountedVolume, repair);
  234         SendRequest <CheckFilesystemResponse> (request);
  235     }
  236 
  237     void CoreService::RequestDismountFilesystem (const DirectoryPath &mountPoint, bool force)
  238     {
  239         DismountFilesystemRequest request (mountPoint, force);
  240         SendRequest <DismountFilesystemResponse> (request);
  241     }
  242 
  243     shared_ptr <VolumeInfo> CoreService::RequestDismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles, bool syncVolumeInfo)
  244     {
  245         DismountVolumeRequest request (mountedVolume, ignoreOpenFiles, syncVolumeInfo);
  246         return SendRequest <DismountVolumeResponse> (request)->DismountedVolumeInfo;
  247     }
  248 
  249     uint32 CoreService::RequestGetDeviceSectorSize (const DevicePath &devicePath)
  250     {
  251         GetDeviceSectorSizeRequest request (devicePath);
  252         return SendRequest <GetDeviceSectorSizeResponse> (request)->Size;
  253     }
  254 
  255     uint64 CoreService::RequestGetDeviceSize (const DevicePath &devicePath)
  256     {
  257         GetDeviceSizeRequest request (devicePath);
  258         return SendRequest <GetDeviceSizeResponse> (request)->Size;
  259     }
  260 
  261     HostDeviceList CoreService::RequestGetHostDevices (bool pathListOnly)
  262     {
  263         GetHostDevicesRequest request (pathListOnly);
  264         return SendRequest <GetHostDevicesResponse> (request)->HostDevices;
  265     }
  266 
  267     shared_ptr <VolumeInfo> CoreService::RequestMountVolume (MountOptions &options)
  268     {
  269         MountVolumeRequest request (&options);
  270         return SendRequest <MountVolumeResponse> (request)->MountedVolumeInfo;
  271     }
  272 
  273     void CoreService::RequestSetFileOwner (const FilesystemPath &path, const UserId &owner)
  274     {
  275         SetFileOwnerRequest request (path, owner);
  276         SendRequest <SetFileOwnerResponse> (request);
  277     }
  278 
  279     template <class T>
  280     auto_ptr <T> CoreService::SendRequest (CoreServiceRequest &request)
  281     {
  282         static Mutex mutex;
  283         ScopeLock lock (mutex);
  284 
  285         if (request.RequiresElevation())
  286         {
  287             request.ElevateUserPrivileges = true;
  288             request.FastElevation = !ElevatedServiceAvailable;
  289             request.ApplicationExecutablePath = Core->GetApplicationExecutablePath();
  290 
  291             while (!ElevatedServiceAvailable)
  292             {
  293                 try
  294                 {
  295                     request.Serialize (ServiceInputStream);
  296                     auto_ptr <T> response (GetResponse <T>());
  297                     ElevatedServiceAvailable = true;
  298                     return response;
  299                 }
  300                 catch (ElevationFailed &e)
  301                 {
  302                     if (!request.FastElevation)
  303                     {
  304                         ExceptionEventArgs args (e);
  305                         Core->WarningEvent.Raise (args);
  306                     }
  307 
  308                     request.FastElevation = false;
  309                     (*AdminPasswordCallback) (request.AdminPassword);
  310                 }
  311             }
  312         }
  313 
  314         finally_do_arg (string *, &request.AdminPassword, { StringConverter::Erase (*finally_arg); });
  315 
  316         request.Serialize (ServiceInputStream);
  317         return GetResponse <T>();
  318     }
  319 
  320     void CoreService::Start ()
  321     {
  322         InputPipe.reset (new Pipe());
  323         OutputPipe.reset (new Pipe());
  324 
  325         int pid = fork();
  326         throw_sys_if (pid == -1);
  327 
  328         if (pid == 0)
  329         {
  330             try
  331             {
  332                 ProcessRequests();
  333                 _exit (0);
  334             }
  335             catch (...) { }
  336             _exit (1);
  337         }
  338 
  339         ServiceInputStream = shared_ptr <Stream> (new FileStream (InputPipe->GetWriteFD()));
  340         ServiceOutputStream = shared_ptr <Stream> (new FileStream (OutputPipe->GetReadFD()));
  341     }
  342 
  343     void CoreService::StartElevated (const CoreServiceRequest &request)
  344     {
  345         auto_ptr <Pipe> inPipe (new Pipe());
  346         auto_ptr <Pipe> outPipe (new Pipe());
  347         Pipe errPipe;
  348 
  349         int forkedPid = fork();
  350         throw_sys_if (forkedPid == -1);
  351 
  352         if (forkedPid == 0)
  353         {
  354             try
  355             {
  356                 try
  357                 {
  358                     throw_sys_if (dup2 (inPipe->GetReadFD(), STDIN_FILENO) == -1);
  359                     throw_sys_if (dup2 (outPipe->GetWriteFD(), STDOUT_FILENO) == -1);
  360                     throw_sys_if (dup2 (errPipe.GetWriteFD(), STDERR_FILENO) == -1);
  361 
  362                     string appPath = request.ApplicationExecutablePath;
  363                     if (appPath.empty())
  364                         appPath = "veracrypt";
  365 
  366                     const char *args[] = { "sudo", "-S", "-p", "", appPath.c_str(), TC_CORE_SERVICE_CMDLINE_OPTION, nullptr };
  367                     execvp (args[0], ((char* const*) args));
  368                     throw SystemException (SRC_POS, args[0]);
  369                 }
  370                 catch (Exception &)
  371                 {
  372                     throw;
  373                 }
  374                 catch (exception &e)
  375                 {
  376                     throw ExternalException (SRC_POS, StringConverter::ToExceptionString (e));
  377                 }
  378                 catch (...)
  379                 {
  380                     throw UnknownException (SRC_POS);
  381                 }
  382             }
  383             catch (Exception &e)
  384             {
  385                 try
  386                 {
  387                     shared_ptr <Stream> outputStream (new FileStream (errPipe.GetWriteFD()));
  388                     e.Serialize (outputStream);
  389                 }
  390                 catch (...) { }
  391             }
  392 
  393             _exit (1);
  394         }
  395 
  396         vector <char> adminPassword (request.AdminPassword.size() + 1);
  397         int timeout = 6000;
  398 
  399         if (request.FastElevation)
  400         {
  401             string dummyPassword = "dummy\n";
  402             adminPassword = vector <char> (dummyPassword.size());
  403             Memory::Copy (&adminPassword.front(), dummyPassword.c_str(), dummyPassword.size());
  404             timeout = 1000;
  405         }
  406         else
  407         {
  408             Memory::Copy (&adminPassword.front(), request.AdminPassword.c_str(), request.AdminPassword.size());
  409             adminPassword[request.AdminPassword.size()] = '\n';
  410         }
  411 
  412         if (write (inPipe->GetWriteFD(), &adminPassword.front(), adminPassword.size())) { } // Errors ignored
  413 
  414         Memory::Erase (&adminPassword.front(), adminPassword.size());
  415 
  416         throw_sys_if (fcntl (outPipe->GetReadFD(), F_SETFL, O_NONBLOCK) == -1);
  417         throw_sys_if (fcntl (errPipe.GetReadFD(), F_SETFL, O_NONBLOCK) == -1);
  418 
  419         vector <char> buffer (4096), errOutput (4096);
  420         buffer.clear ();
  421         errOutput.clear ();
  422 
  423         Poller poller (outPipe->GetReadFD(), errPipe.GetReadFD());
  424         int status, waitRes;
  425         int exitCode = 1;
  426 
  427         try
  428         {
  429             do
  430             {
  431                 ssize_t bytesRead = 0;
  432                 foreach (int fd, poller.WaitForData (timeout))
  433                 {
  434                     bytesRead = read (fd, &buffer[0], buffer.capacity());
  435                     if (bytesRead > 0 && fd == errPipe.GetReadFD())
  436                     {
  437                         errOutput.insert (errOutput.end(), buffer.begin(), buffer.begin() + bytesRead);
  438 
  439                         if (bytesRead > 5 && bytesRead < 80)  // Short message captured
  440                             timeout = 200;
  441                     }
  442                 }
  443 
  444                 if (bytesRead == 0)
  445                 {
  446                     waitRes = waitpid (forkedPid, &status, 0);
  447                     break;
  448                 }
  449 
  450             } while ((waitRes = waitpid (forkedPid, &status, WNOHANG)) == 0);
  451         }
  452         catch (TimeOut&)
  453         {
  454             if ((waitRes = waitpid (forkedPid, &status, WNOHANG)) == 0)
  455             {
  456                 inPipe->Close();
  457                 outPipe->Close();
  458                 errPipe.Close();
  459 
  460                 if (request.FastElevation)
  461                 {
  462                     // Prevent defunct process
  463                     struct WaitFunctor : public Functor
  464                     {
  465                         WaitFunctor (int pid) : Pid (pid) { }
  466                         virtual void operator() ()
  467                         {
  468                             int status;
  469                             for (int t = 0; t < 10 && waitpid (Pid, &status, WNOHANG) == 0; t++)
  470                                 Thread::Sleep (1000);
  471                         }
  472                         int Pid;
  473                     };
  474                     Thread thread;
  475                     thread.Start (new WaitFunctor (forkedPid));
  476 
  477                     throw ElevationFailed (SRC_POS, "sudo", 1, "");
  478                 }
  479 
  480                 waitRes = waitpid (forkedPid, &status, 0);
  481             }
  482         }
  483 
  484         if (!errOutput.empty())
  485         {
  486             auto_ptr <Serializable> deserializedObject;
  487             Exception *deserializedException = nullptr;
  488 
  489             try
  490             {
  491                 shared_ptr <Stream> stream (new MemoryStream (ConstBufferPtr ((byte *) &errOutput[0], errOutput.size())));
  492                 deserializedObject.reset (Serializable::DeserializeNew (stream));
  493                 deserializedException = dynamic_cast <Exception*> (deserializedObject.get());
  494             }
  495             catch (...) { }
  496 
  497             if (deserializedException)
  498                 deserializedException->Throw();
  499         }
  500 
  501         throw_sys_if (waitRes == -1);
  502         exitCode = (WIFEXITED (status) ? WEXITSTATUS (status) : 1);
  503         if (exitCode != 0)
  504         {
  505             string strErrOutput;
  506 
  507             if (!errOutput.empty())
  508                 strErrOutput.insert (strErrOutput.begin(), errOutput.begin(), errOutput.end());
  509 
  510             // sudo may require a tty even if -S is used
  511             if (strErrOutput.find (" tty") != string::npos)
  512                 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).";
  513 
  514             throw ElevationFailed (SRC_POS, "sudo", exitCode, strErrOutput);
  515         }
  516 
  517         throw_sys_if (fcntl (outPipe->GetReadFD(), F_SETFL, 0) == -1);
  518 
  519         ServiceInputStream = shared_ptr <Stream> (new FileStream (inPipe->GetWriteFD()));
  520         ServiceOutputStream = shared_ptr <Stream> (new FileStream (outPipe->GetReadFD()));
  521 
  522         // Send sync code
  523         byte sync[] = { 0, 0x11, 0x22 };
  524         ServiceInputStream->Write (ConstBufferPtr (sync, array_capacity (sync)));
  525 
  526         AdminInputPipe = inPipe;
  527         AdminOutputPipe = outPipe;
  528     }
  529 
  530     void CoreService::Stop ()
  531     {
  532         ExitRequest exitRequest;
  533         exitRequest.Serialize (ServiceInputStream);
  534     }
  535 
  536     shared_ptr <GetStringFunctor> CoreService::AdminPasswordCallback;
  537 
  538     auto_ptr <Pipe> CoreService::AdminInputPipe;
  539     auto_ptr <Pipe> CoreService::AdminOutputPipe;
  540 
  541     auto_ptr <Pipe> CoreService::InputPipe;
  542     auto_ptr <Pipe> CoreService::OutputPipe;
  543     shared_ptr <Stream> CoreService::ServiceInputStream;
  544     shared_ptr <Stream> CoreService::ServiceOutputStream;
  545 
  546     bool CoreService::ElevatedPrivileges = false;
  547     bool CoreService::ElevatedServiceAvailable = false;
  548 }