"Fossies" - the Fresh Open Source Software Archive

Member "src/Core/Unix/CoreUnix.cpp" (10 Oct 2018, 14901 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 "CoreUnix.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.22_Source_vs_1.23_Source.

    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 "CoreUnix.h"
   14 #include <errno.h>
   15 #include <iostream>
   16 #include <signal.h>
   17 #include <sys/stat.h>
   18 #include <sys/types.h>
   19 #include <stdio.h>
   20 #include <unistd.h>
   21 #include "Platform/FileStream.h"
   22 #include "Driver/Fuse/FuseService.h"
   23 #include "Volume/VolumePasswordCache.h"
   24 
   25 namespace VeraCrypt
   26 {
   27     CoreUnix::CoreUnix ()
   28     {
   29         signal (SIGPIPE, SIG_IGN);
   30 
   31         char *loc = setlocale (LC_ALL, "");
   32         if (!loc || string (loc) == "C")
   33             setlocale (LC_ALL, "en_US.UTF-8");
   34     }
   35 
   36     CoreUnix::~CoreUnix ()
   37     {
   38     }
   39 
   40     void CoreUnix::CheckFilesystem (shared_ptr <VolumeInfo> mountedVolume, bool repair) const
   41     {
   42         if (!mountedVolume->MountPoint.IsEmpty())
   43             DismountFilesystem (mountedVolume->MountPoint, false);
   44 
   45         list <string> args;
   46 
   47         args.push_back ("-T");
   48         args.push_back ("fsck");
   49 
   50         args.push_back ("-e");
   51 
   52         string xargs = "fsck ";
   53 
   54 #ifdef TC_LINUX
   55         if (!repair)
   56             xargs += "-n ";
   57         else
   58             xargs += "-r ";
   59 #endif
   60 
   61         xargs += string (mountedVolume->VirtualDevice) + "; echo '[Done]'; read W";
   62         args.push_back (xargs);
   63 
   64         try
   65         {
   66             Process::Execute ("xterm", args, 1000);
   67         } catch (TimeOut&) { }
   68 #ifdef TC_LINUX
   69         catch (SystemException&)
   70         {
   71             // xterm not available. Try with KDE konsole if it exists
   72             struct stat sb;
   73             if (stat("/usr/bin/konsole", &sb) == 0)
   74             {
   75                 args.clear ();
   76                 args.push_back ("--title");
   77                 args.push_back ("fsck");
   78                 args.push_back ("--caption");
   79                 args.push_back ("fsck");
   80                 args.push_back ("-e");
   81                 args.push_back ("sh");
   82                 args.push_back ("-c");
   83                 args.push_back (xargs);
   84                 try
   85                 {
   86                     Process::Execute ("konsole", args, 1000);
   87                 } catch (TimeOut&) { }
   88             }
   89             else
   90                 throw;
   91         }
   92 #endif
   93     }
   94 
   95     void CoreUnix::DismountFilesystem (const DirectoryPath &mountPoint, bool force) const
   96     {
   97         list <string> args;
   98 
   99 #ifdef TC_MACOSX
  100         if (force)
  101             args.push_back ("-f");
  102 #endif
  103         args.push_back ("--");
  104         args.push_back (mountPoint);
  105 
  106         Process::Execute ("umount", args);
  107     }
  108 
  109     shared_ptr <VolumeInfo> CoreUnix::DismountVolume (shared_ptr <VolumeInfo> mountedVolume, bool ignoreOpenFiles, bool syncVolumeInfo)
  110     {
  111         if (!mountedVolume->MountPoint.IsEmpty())
  112         {
  113             DismountFilesystem (mountedVolume->MountPoint, ignoreOpenFiles);
  114 
  115             // Delete mount directory if a default path has been used
  116             if (string (mountedVolume->MountPoint).find (GetDefaultMountPointPrefix()) == 0)
  117                 mountedVolume->MountPoint.Delete();
  118         }
  119 
  120         try
  121         {
  122             DismountNativeVolume (mountedVolume);
  123         }
  124         catch (NotApplicable &) { }
  125 
  126         if (!mountedVolume->LoopDevice.IsEmpty())
  127         {
  128             try
  129             {
  130                 DetachLoopDevice (mountedVolume->LoopDevice);
  131             }
  132             catch (ExecutedProcessFailed&) { }
  133         }
  134 
  135         if (syncVolumeInfo || mountedVolume->Protection == VolumeProtection::HiddenVolumeReadOnly)
  136         {
  137             sync();
  138             VolumeInfoList ml = GetMountedVolumes (mountedVolume->Path);
  139 
  140             if (ml.size() > 0)
  141                 mountedVolume = ml.front();
  142         }
  143 
  144         list <string> args;
  145         args.push_back ("--");
  146         args.push_back (mountedVolume->AuxMountPoint);
  147 
  148         for (int t = 0; true; t++)
  149         {
  150             try
  151             {
  152                 Process::Execute ("umount", args);
  153                 break;
  154             }
  155             catch (ExecutedProcessFailed&)
  156             {
  157                 if (t > 10)
  158                     throw;
  159                 Thread::Sleep (200);
  160             }
  161         }
  162 
  163         try
  164         {
  165             mountedVolume->AuxMountPoint.Delete();
  166         }
  167         catch (...) { }
  168 
  169         VolumeEventArgs eventArgs (mountedVolume);
  170         VolumeDismountedEvent.Raise (eventArgs);
  171 
  172         return mountedVolume;
  173     }
  174 
  175     bool CoreUnix::FilesystemSupportsLargeFiles (const FilePath &filePath) const
  176     {
  177         string path = filePath;
  178         size_t pos;
  179 
  180         while ((pos = path.find_last_of ('/')) != string::npos)
  181         {
  182             path = path.substr (0, pos);
  183 
  184             if (path.empty())
  185                 break;
  186 
  187             try
  188             {
  189                 MountedFilesystemList filesystems = GetMountedFilesystems (DevicePath(), path);
  190                 if (!filesystems.empty())
  191                 {
  192                     const MountedFilesystem &fs = *filesystems.front();
  193 
  194                     if (fs.Type == "fat"
  195                         || fs.Type == "fat32"
  196                         || fs.Type == "vfat"
  197                         || fs.Type == "fatfs"
  198                         || fs.Type == "msdos"
  199                         || fs.Type == "msdosfs"
  200                         || fs.Type == "umsdos"
  201                         || fs.Type == "dos"
  202                         || fs.Type == "dosfs"
  203                         || fs.Type == "pcfs"
  204                         )
  205                     {
  206                         return false;
  207                     }
  208 
  209                     return true;
  210                 }
  211             }
  212             catch (...) { }
  213         }
  214 
  215         return true;    // Prevent errors if the filesystem cannot be identified
  216     }
  217 
  218     bool CoreUnix::FilesystemSupportsUnixPermissions (const DevicePath &devicePath) const
  219     {
  220         File device;
  221         device.Open (devicePath);
  222 
  223         Buffer bootSector (device.GetDeviceSectorSize());
  224         device.SeekAt (0);
  225         device.ReadCompleteBuffer (bootSector);
  226 
  227         byte *b = bootSector.Ptr();
  228 
  229         return memcmp (b + 3,  "NTFS", 4) != 0
  230             && memcmp (b + 54, "FAT", 3) != 0
  231             && memcmp (b + 82, "FAT32", 5) != 0
  232             && memcmp (b + 3,  "EXFAT", 5) != 0;
  233     }
  234 
  235     string CoreUnix::GetDefaultMountPointPrefix () const
  236     {
  237         const char *envPrefix = getenv ("VERACRYPT_MOUNT_PREFIX");
  238         if (envPrefix && !string (envPrefix).empty())
  239             return envPrefix;
  240 
  241         if (FilesystemPath ("/media").IsDirectory())
  242             return "/media/veracrypt";
  243 
  244         if (FilesystemPath ("/mnt").IsDirectory())
  245             return "/mnt/veracrypt";
  246 
  247         return GetTempDirectory() + "/veracrypt_mnt";
  248     }
  249 
  250     uint32 CoreUnix::GetDeviceSectorSize (const DevicePath &devicePath) const
  251     {
  252         File dev;
  253         dev.Open (devicePath);
  254         return dev.GetDeviceSectorSize();
  255     }
  256 
  257     uint64 CoreUnix::GetDeviceSize (const DevicePath &devicePath) const
  258     {
  259         File dev;
  260         dev.Open (devicePath);
  261         return dev.Length();
  262     }
  263 
  264     DirectoryPath CoreUnix::GetDeviceMountPoint (const DevicePath &devicePath) const
  265     {
  266         DevicePath devPath = devicePath;
  267 #ifdef TC_MACOSX
  268         if (string (devPath).find ("/dev/rdisk") != string::npos)
  269             devPath = string ("/dev/") + string (devicePath).substr (6);
  270 #endif
  271         MountedFilesystemList mountedFilesystems = GetMountedFilesystems (devPath);
  272 
  273         if (mountedFilesystems.size() < 1)
  274             return DirectoryPath();
  275 
  276         return mountedFilesystems.front()->MountPoint;
  277     }
  278 
  279     VolumeInfoList CoreUnix::GetMountedVolumes (const VolumePath &volumePath) const
  280     {
  281         VolumeInfoList volumes;
  282 
  283         foreach_ref (const MountedFilesystem &mf, GetMountedFilesystems ())
  284         {
  285             if (string (mf.MountPoint).find (GetFuseMountDirPrefix()) == string::npos)
  286                 continue;
  287 
  288             shared_ptr <VolumeInfo> mountedVol;
  289             try
  290             {
  291                 shared_ptr <File> controlFile (new File);
  292                 controlFile->Open (string (mf.MountPoint) + FuseService::GetControlPath());
  293 
  294                 shared_ptr <Stream> controlFileStream (new FileStream (controlFile));
  295                 mountedVol = Serializable::DeserializeNew <VolumeInfo> (controlFileStream);
  296             }
  297             catch (...)
  298             {
  299                 continue;
  300             }
  301 
  302             if (!volumePath.IsEmpty() && wstring (mountedVol->Path).compare (volumePath) != 0)
  303                 continue;
  304 
  305             mountedVol->AuxMountPoint = mf.MountPoint;
  306 
  307             if (!mountedVol->VirtualDevice.IsEmpty())
  308             {
  309                 MountedFilesystemList mpl = GetMountedFilesystems (mountedVol->VirtualDevice);
  310 
  311                 if (mpl.size() > 0)
  312                     mountedVol->MountPoint = mpl.front()->MountPoint;
  313             }
  314 
  315             volumes.push_back (mountedVol);
  316 
  317             if (!volumePath.IsEmpty())
  318                 break;
  319         }
  320 
  321         return volumes;
  322     }
  323 
  324     gid_t CoreUnix::GetRealGroupId () const
  325     {
  326         const char *env = getenv ("SUDO_GID");
  327         if (env)
  328         {
  329             try
  330             {
  331                 string s (env);
  332                 return static_cast <gid_t> (StringConverter::ToUInt64 (s));
  333             }
  334             catch (...) { }
  335         }
  336 
  337         return getgid();
  338     }
  339 
  340     uid_t CoreUnix::GetRealUserId () const
  341     {
  342         const char *env = getenv ("SUDO_UID");
  343         if (env)
  344         {
  345             try
  346             {
  347                 string s (env);
  348                 return static_cast <uid_t> (StringConverter::ToUInt64 (s));
  349             }
  350             catch (...) { }
  351         }
  352 
  353         return getuid();
  354     }
  355 
  356     string CoreUnix::GetTempDirectory () const
  357     {
  358         char *envDir = getenv ("TMPDIR");
  359         return envDir ? envDir : "/tmp";
  360     }
  361 
  362     bool CoreUnix::IsMountPointAvailable (const DirectoryPath &mountPoint) const
  363     {
  364         return GetMountedFilesystems (DevicePath(), mountPoint).size() == 0;
  365     }
  366 
  367     void CoreUnix::MountFilesystem (const DevicePath &devicePath, const DirectoryPath &mountPoint, const string &filesystemType, bool readOnly, const string &systemMountOptions) const
  368     {
  369         if (GetMountedFilesystems (DevicePath(), mountPoint).size() > 0)
  370             throw MountPointUnavailable (SRC_POS);
  371 
  372         list <string> args;
  373         string options;
  374 
  375         if (!filesystemType.empty())
  376         {
  377 #ifdef TC_SOLARIS
  378             args.push_back ("-F");
  379 #else
  380             args.push_back ("-t");
  381 #endif
  382             args.push_back (filesystemType);
  383         }
  384 
  385         if (readOnly)
  386             options = "-oro";
  387 
  388         if (!systemMountOptions.empty())
  389         {
  390             if (options.empty())
  391                 options = "-o";
  392             else
  393                 options += ",";
  394 
  395             options += systemMountOptions;
  396         }
  397 
  398         if (!options.empty())
  399             args.push_back (options);
  400 
  401         args.push_back ("--");
  402         args.push_back (devicePath);
  403         args.push_back (mountPoint);
  404 
  405         Process::Execute ("mount", args);
  406     }
  407 
  408     VolumeSlotNumber CoreUnix::MountPointToSlotNumber (const DirectoryPath &mountPoint) const
  409     {
  410         string mountPointStr (mountPoint);
  411         if (mountPointStr.find (GetDefaultMountPointPrefix()) == 0)
  412         {
  413             try
  414             {
  415                 return StringConverter::ToUInt32 (StringConverter::GetTrailingNumber (mountPointStr));
  416             }
  417             catch (...) { }
  418         }
  419         return GetFirstFreeSlotNumber();
  420     }
  421 
  422     shared_ptr <VolumeInfo> CoreUnix::MountVolume (MountOptions &options)
  423     {
  424         CoalesceSlotNumberAndMountPoint (options);
  425 
  426         if (IsVolumeMounted (*options.Path))
  427             throw VolumeAlreadyMounted (SRC_POS);
  428 
  429         Cipher::EnableHwSupport (!options.NoHardwareCrypto);
  430 
  431         shared_ptr <Volume> volume;
  432 
  433         while (true)
  434         {
  435             try
  436             {
  437                 volume = OpenVolume (
  438                     options.Path,
  439                     options.PreserveTimestamps,
  440                     options.Password,
  441                     options.Pim,
  442                     options.Kdf,
  443                     options.TrueCryptMode,
  444                     options.Keyfiles,
  445                     options.Protection,
  446                     options.ProtectionPassword,
  447                     options.ProtectionPim,
  448                     options.ProtectionKdf,
  449                     options.ProtectionKeyfiles,
  450                     options.SharedAccessAllowed,
  451                     VolumeType::Unknown,
  452                     options.UseBackupHeaders,
  453                     options.PartitionInSystemEncryptionScope
  454                     );
  455 
  456                 options.Password.reset();
  457             }
  458             catch (SystemException &e)
  459             {
  460                 if (options.Protection != VolumeProtection::ReadOnly
  461                     && (e.GetErrorCode() == EROFS || e.GetErrorCode() == EACCES || e.GetErrorCode() == EPERM))
  462                 {
  463                     // Read-only filesystem
  464                     options.Protection = VolumeProtection::ReadOnly;
  465                     continue;
  466                 }
  467 
  468                 throw;
  469             }
  470 
  471             break;
  472         }
  473 
  474         if (options.Path->IsDevice())
  475         {
  476             if (volume->GetFile()->GetDeviceSectorSize() != volume->GetSectorSize())
  477                 throw ParameterIncorrect (SRC_POS);
  478         }
  479 
  480         // Find a free mount point for FUSE service
  481         MountedFilesystemList mountedFilesystems = GetMountedFilesystems ();
  482         string fuseMountPoint;
  483         for (int i = 1; true; i++)
  484         {
  485             stringstream path;
  486             path << GetTempDirectory() << "/" << GetFuseMountDirPrefix() << i;
  487             FilesystemPath fsPath (path.str());
  488 
  489             bool inUse = false;
  490 
  491             foreach_ref (const MountedFilesystem &mf, mountedFilesystems)
  492             {
  493                 if (mf.MountPoint == path.str())
  494                 {
  495                     inUse = true;
  496                     break;
  497                 }
  498             }
  499 
  500             if (!inUse)
  501             {
  502                 try
  503                 {
  504                     if (fsPath.IsDirectory())
  505                         fsPath.Delete();
  506 
  507                     throw_sys_sub_if (mkdir (path.str().c_str(), S_IRUSR | S_IXUSR) == -1, path.str());
  508 
  509                     fuseMountPoint = fsPath;
  510                     break;
  511                 }
  512                 catch (...)
  513                 {
  514                     if (i > 255)
  515                         throw TemporaryDirectoryFailure (SRC_POS, StringConverter::ToWide (path.str()));
  516                 }
  517             }
  518         }
  519 
  520         try
  521         {
  522             FuseService::Mount (volume, options.SlotNumber, fuseMountPoint);
  523         }
  524         catch (...)
  525         {
  526             try
  527             {
  528                 DirectoryPath (fuseMountPoint).Delete();
  529             }
  530             catch (...) { }
  531             throw;
  532         }
  533 
  534         try
  535         {
  536             // Create a mount directory if a default path has been specified
  537             bool mountDirCreated = false;
  538             string mountPoint;
  539             if (!options.NoFilesystem && options.MountPoint)
  540             {
  541                 mountPoint = *options.MountPoint;
  542 
  543 #ifndef TC_MACOSX
  544                 if (mountPoint.find (GetDefaultMountPointPrefix()) == 0 && !options.MountPoint->IsDirectory())
  545                 {
  546                     Directory::Create (*options.MountPoint);
  547                     try
  548                     {
  549                         throw_sys_sub_if (chown (mountPoint.c_str(), GetRealUserId(), GetRealGroupId()) == -1, mountPoint);
  550                     } catch (ParameterIncorrect&) { }
  551 
  552                     mountDirCreated = true;
  553                 }
  554 #endif
  555             }
  556 
  557             try
  558             {
  559                 try
  560                 {
  561                     MountVolumeNative (volume, options, fuseMountPoint);
  562                 }
  563                 catch (NotApplicable&)
  564                 {
  565                     MountAuxVolumeImage (fuseMountPoint, options);
  566                 }
  567             }
  568             catch (...)
  569             {
  570                 if (mountDirCreated)
  571                     remove (mountPoint.c_str());
  572                 throw;
  573             }
  574 
  575 #ifndef TC_MACOSX
  576             // set again correct ownership of the mount point to avoid any issues
  577             if (!options.NoFilesystem && options.MountPoint)
  578             {
  579                 mountPoint = *options.MountPoint;
  580 
  581                 if (mountPoint.find (GetDefaultMountPointPrefix()) == 0)
  582                 {
  583                     try
  584                     {
  585                         chown (mountPoint.c_str(), GetRealUserId(), GetRealGroupId());
  586                     } catch (...) { }
  587                 }
  588             }
  589 #endif
  590 
  591         }
  592         catch (...)
  593         {
  594             try
  595             {
  596                 VolumeInfoList mountedVolumes = GetMountedVolumes (*options.Path);
  597                 if (mountedVolumes.size() > 0)
  598                 {
  599                     shared_ptr <VolumeInfo> mountedVolume (mountedVolumes.front());
  600                     DismountVolume (mountedVolume);
  601                 }
  602             }
  603             catch (...) { }
  604             throw;
  605         }
  606 
  607         VolumeInfoList mountedVolumes = GetMountedVolumes (*options.Path);
  608         if (mountedVolumes.size() != 1)
  609             throw ParameterIncorrect (SRC_POS);
  610 
  611         VolumeEventArgs eventArgs (mountedVolumes.front());
  612         VolumeMountedEvent.Raise (eventArgs);
  613 
  614         return mountedVolumes.front();
  615     }
  616 
  617     void CoreUnix::MountAuxVolumeImage (const DirectoryPath &auxMountPoint, const MountOptions &options) const
  618     {
  619         DevicePath loopDev = AttachFileToLoopDevice (string (auxMountPoint) + FuseService::GetVolumeImagePath(), options.Protection == VolumeProtection::ReadOnly);
  620 
  621         try
  622         {
  623             FuseService::SendAuxDeviceInfo (auxMountPoint, loopDev, loopDev);
  624         }
  625         catch (...)
  626         {
  627             try
  628             {
  629                 DetachLoopDevice (loopDev);
  630             }
  631             catch (...) { }
  632             throw;
  633         }
  634 
  635         if (!options.NoFilesystem && options.MountPoint && !options.MountPoint->IsEmpty())
  636         {
  637             MountFilesystem (loopDev, *options.MountPoint,
  638                 StringConverter::ToSingle (options.FilesystemType),
  639                 options.Protection == VolumeProtection::ReadOnly,
  640                 StringConverter::ToSingle (options.FilesystemOptions));
  641         }
  642     }
  643 
  644     void CoreUnix::SetFileOwner (const FilesystemPath &path, const UserId &owner) const
  645     {
  646         throw_sys_if (chown (string (path).c_str(), owner.SystemId, (gid_t) -1) == -1);
  647     }
  648 
  649     DirectoryPath CoreUnix::SlotNumberToMountPoint (VolumeSlotNumber slotNumber) const
  650     {
  651         if (slotNumber < GetFirstSlotNumber() || slotNumber > GetLastSlotNumber())
  652             throw ParameterIncorrect (SRC_POS);
  653 
  654         stringstream s;
  655         s << GetDefaultMountPointPrefix() << slotNumber;
  656         return s.str();
  657     }
  658 }