Annotation of truecrypt/driver/fuse/fuseservice.cpp, revision 1.1.1.1

1.1       root        1: /*
                      2:  Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
                      3: 
                      4:  Governed by the TrueCrypt License 2.4 the full text of which is contained
                      5:  in the file License.txt included in TrueCrypt binary and source code
                      6:  distribution packages.
                      7: */
                      8: 
                      9: #define FUSE_USE_VERSION  25
                     10: #include <errno.h>
                     11: #include <fcntl.h>
                     12: #include <fuse.h>
                     13: #include <iostream>
                     14: #include <string.h>
                     15: #include <stdio.h>
                     16: #include <unistd.h>
                     17: #include <time.h>
                     18: #include <sys/mman.h>
                     19: #include <sys/time.h>
                     20: #include <sys/wait.h>
                     21: 
                     22: #include "FuseService.h"
                     23: #include "Platform/FileStream.h"
                     24: #include "Platform/MemoryStream.h"
                     25: #include "Platform/Serializable.h"
                     26: #include "Platform/SystemLog.h"
                     27: #include "Platform/Unix/Pipe.h"
                     28: #include "Platform/Unix/Poller.h"
                     29: 
                     30: namespace TrueCrypt
                     31: {
                     32:        static int fuse_service_access (const char *path, int mask)
                     33:        {
                     34:                try
                     35:                {
                     36:                        if (!FuseService::CheckAccessRights())
                     37:                                return -EACCES;
                     38:                }
                     39:                catch (...)
                     40:                {
                     41:                        return FuseService::ExceptionToErrorCode();
                     42:                }
                     43: 
                     44:                return 0;
                     45:        }
                     46: 
                     47:        static void *fuse_service_init ()
                     48:        {
                     49:                return nullptr;
                     50:        }
                     51: 
                     52:        static void fuse_service_destroy (void *userdata)
                     53:        {
                     54:                FuseService::Dismount();
                     55:        }
                     56: 
                     57:        static int fuse_service_getattr (const char *path, struct stat *statData)
                     58:        {
                     59:                try
                     60:                {
                     61:                        Memory::Zero (statData, sizeof(*statData));
                     62: 
                     63:                        statData->st_uid = FuseService::GetUserId();
                     64:                        statData->st_gid = FuseService::GetGroupId();
                     65:                        statData->st_atime = time (NULL);
                     66:                        statData->st_ctime = time (NULL);
                     67:                        statData->st_mtime = time (NULL);
                     68: 
                     69:                        if (strcmp (path, "/") == 0)
                     70:                        {
                     71:                                statData->st_mode = S_IFDIR | 0500;
                     72:                                statData->st_nlink = 2;
                     73:                        }
                     74:                        else
                     75:                        {
                     76:                                if (!FuseService::CheckAccessRights())
                     77:                                        return -EACCES;
                     78: 
                     79:                                else if (strcmp (path, FuseService::GetVolumeImagePath()) == 0)
                     80:                                {
                     81:                                        statData->st_mode = S_IFREG | 0600;
                     82:                                        statData->st_nlink = 1;
                     83:                                        statData->st_size = FuseService::GetVolumeSize();
                     84:                                }
                     85:                                else if (strcmp (path, FuseService::GetControlPath()) == 0)
                     86:                                {
                     87:                                        statData->st_mode = S_IFREG | 0600;
                     88:                                        statData->st_nlink = 1;
                     89:                                        statData->st_size = FuseService::GetVolumeInfo()->Size();
                     90:                                }
                     91:                                else
                     92:                                {
                     93:                                        return -ENOENT;
                     94:                                }
                     95:                        }
                     96:                }
                     97:                catch (...)
                     98:                {
                     99:                        return FuseService::ExceptionToErrorCode();
                    100:                }
                    101: 
                    102:                return 0;
                    103:        }
                    104: 
                    105:        static int fuse_service_opendir (const char *path, struct fuse_file_info *fi)
                    106:        {
                    107:                try
                    108:                {
                    109:                        if (!FuseService::CheckAccessRights())
                    110:                                return -EACCES;
                    111: 
                    112:                        if (strcmp (path, "/") != 0)
                    113:                                return -ENOENT;
                    114:                }
                    115:                catch (...)
                    116:                {
                    117:                        return FuseService::ExceptionToErrorCode();
                    118:                }
                    119: 
                    120:                return 0;
                    121:        }
                    122: 
                    123:        static int fuse_service_open (const char *path, struct fuse_file_info *fi)
                    124:        {
                    125:                try
                    126:                {
                    127:                        if (!FuseService::CheckAccessRights())
                    128:                                return -EACCES;
                    129: 
                    130:                        if (strcmp (path, FuseService::GetVolumeImagePath()) == 0)
                    131:                                return 0;
                    132: 
                    133:                        if (strcmp (path, FuseService::GetControlPath()) == 0)
                    134:                        {
                    135:                                fi->direct_io = 1;
                    136:                                return 0;
                    137:                        }
                    138:                }
                    139:                catch (...)
                    140:                {
                    141:                        return FuseService::ExceptionToErrorCode();
                    142:                }
                    143:                return -ENOENT;
                    144:        }
                    145: 
                    146:        static int fuse_service_read (const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
                    147:        {
                    148:                try
                    149:                {
                    150:                        if (!FuseService::CheckAccessRights())
                    151:                                return -EACCES;
                    152: 
                    153:                        if (strcmp (path, FuseService::GetVolumeImagePath()) == 0)
                    154:                        {
                    155:                                try
                    156:                                {
                    157:                                        // Test for read beyond the end of the volume
                    158:                                        if (offset + size > FuseService::GetVolumeSize())
                    159:                                                size = FuseService::GetVolumeSize() - offset;
                    160: 
                    161:                                        size_t sectorSize = FuseService::GetVolumeSectorSize();
                    162:                                        if (size % sectorSize != 0 || offset % sectorSize != 0)
                    163:                                        {
                    164:                                                // Support for non-sector-aligned read operations is required by some loop device tools
                    165:                                                // which may analyze the volume image before attaching it as a device
                    166: 
                    167:                                                uint64 alignedOffset = offset - (offset % sectorSize);
                    168:                                                uint64 alignedSize = size + (offset % sectorSize);
                    169: 
                    170:                                                if (alignedSize % sectorSize != 0)
                    171:                                                        alignedSize += sectorSize - (alignedSize % sectorSize);
                    172: 
                    173:                                                SecureBuffer alignedBuffer (alignedSize);
                    174: 
                    175:                                                FuseService::ReadVolumeSectors (alignedBuffer, alignedOffset);
                    176:                                                BufferPtr ((byte *) buf, size).CopyFrom (alignedBuffer.GetRange (offset % sectorSize, size));
                    177:                                        }
                    178:                                        else
                    179:                                        {
                    180:                                                FuseService::ReadVolumeSectors (BufferPtr ((byte *) buf, size), offset);
                    181:                                        }
                    182:                                }
                    183:                                catch (MissingVolumeData)
                    184:                                {
                    185:                                        return 0;
                    186:                                }
                    187: 
                    188:                                return size;
                    189:                        }
                    190: 
                    191:                        if (strcmp (path, FuseService::GetControlPath()) == 0)
                    192:                        {
                    193:                                shared_ptr <Buffer> infoBuf = FuseService::GetVolumeInfo();
                    194:                                BufferPtr outBuf ((byte *)buf, size);
                    195: 
                    196:                                if (offset >= infoBuf->Size())
                    197:                                        return 0;
                    198: 
                    199:                                if (offset + size > infoBuf->Size())
                    200:                                        size = infoBuf->Size () - offset;
                    201: 
                    202:                                outBuf.CopyFrom (infoBuf->GetRange (offset, size));
                    203:                                return size;
                    204:                        }
                    205:                }
                    206:                catch (...)
                    207:                {
                    208:                        return FuseService::ExceptionToErrorCode();
                    209:                }
                    210: 
                    211:                return -ENOENT;
                    212:        }
                    213: 
                    214:        static int fuse_service_readdir (const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
                    215:        {
                    216:                try
                    217:                {
                    218:                        if (!FuseService::CheckAccessRights())
                    219:                                return -EACCES;
                    220: 
                    221:                        if (strcmp (path, "/") != 0)
                    222:                                return -ENOENT;
                    223: 
                    224:                        filler (buf, ".", NULL, 0);
                    225:                        filler (buf, "..", NULL, 0);
                    226:                        filler (buf, FuseService::GetVolumeImagePath() + 1, NULL, 0);
                    227:                        filler (buf, FuseService::GetControlPath() + 1, NULL, 0);
                    228:                }
                    229:                catch (...)
                    230:                {
                    231:                        return FuseService::ExceptionToErrorCode();
                    232:                }
                    233: 
                    234:                return 0;
                    235:        }
                    236: 
                    237:        static int fuse_service_write (const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
                    238:        {
                    239:                try
                    240:                {
                    241:                        if (!FuseService::CheckAccessRights())
                    242:                                return -EACCES;
                    243: 
                    244:                        if (strcmp (path, FuseService::GetVolumeImagePath()) == 0)
                    245:                        {
                    246:                                FuseService::WriteVolumeSectors (BufferPtr ((byte *) buf, size), offset);
                    247:                                return size;
                    248:                        }
                    249: 
                    250:                        if (strcmp (path, FuseService::GetControlPath()) == 0)
                    251:                        {
                    252:                                if (!FuseService::GetLoopDevice().IsEmpty())
                    253:                                        return -EACCES;
                    254: 
                    255:                                FuseService::ReceiveLoopDevice (ConstBufferPtr ((const byte *)buf, size));
                    256:                                return size;
                    257:                        }
                    258:                }
                    259: #ifdef TC_FREEBSD
                    260:                // FreeBSD apparently retries failed write operations forever, which may lead to a system crash.
                    261:                catch (VolumeReadOnly&)
                    262:                {
                    263:                        return size;
                    264:                }
                    265:                catch (VolumeProtected&)
                    266:                {
                    267:                        return size;
                    268:                }
                    269: #endif
                    270:                catch (...)
                    271:                {
                    272:                        return FuseService::ExceptionToErrorCode();
                    273:                }
                    274: 
                    275:                return -ENOENT;
                    276:        }
                    277: 
                    278:        bool FuseService::CheckAccessRights ()
                    279:        {
                    280:                return fuse_get_context()->uid == 0 || fuse_get_context()->uid == UserId;
                    281:        }
                    282: 
                    283:        void FuseService::Dismount ()
                    284:        {
                    285:                if (MountedVolume)
                    286:                {
                    287:                        // Forked shared_ptr may have wrong reference count
                    288:                        if (MountedVolume->GetFile().use_count() > 1)
                    289:                                MountedVolume->GetFile()->Close();
                    290: 
                    291:                        if (MountedVolume.use_count() > 1)
                    292:                                delete MountedVolume.get();
                    293: 
                    294:                        MountedVolume.reset();
                    295:                }
                    296:        }
                    297: 
                    298:        int FuseService::ExceptionToErrorCode ()
                    299:        {
                    300:                try
                    301:                {
                    302:                        throw;
                    303:                }
                    304:                catch (std::bad_alloc)
                    305:                {
                    306:                        return -ENOMEM;
                    307:                }
                    308:                catch (ParameterIncorrect &e)
                    309:                {
                    310:                        SystemLog::WriteException (e);
                    311:                        return -EINVAL;
                    312:                }
                    313:                catch (VolumeProtected&)
                    314:                {
                    315:                        return -EIO;
                    316:                }
                    317:                catch (VolumeReadOnly&)
                    318:                {
                    319:                        return -EPERM;
                    320:                }
                    321:                catch (SystemException &e)
                    322:                {
                    323:                        SystemLog::WriteException (e);
                    324:                        return -static_cast <int> (e.GetErrorCode());
                    325:                }
                    326:                catch (std::exception &e)
                    327:                {
                    328:                        SystemLog::WriteException (e);
                    329:                        return -EINTR;
                    330:                }
                    331:                catch (...)
                    332:                {
                    333:                        SystemLog::WriteException (UnknownException (SRC_POS));
                    334:                        return -EINTR;
                    335:                }
                    336:        }
                    337: 
                    338:        shared_ptr <Buffer> FuseService::GetVolumeInfo ()
                    339:        {
                    340:                shared_ptr <Stream> stream (new MemoryStream);
                    341: 
                    342:                {
                    343:                        ScopeLock lock (OpenVolumeInfoMutex);
                    344: 
                    345:                        OpenVolumeInfo.Set (*MountedVolume);
                    346:                        OpenVolumeInfo.SlotNumber = SlotNumber;
                    347: 
                    348:                        OpenVolumeInfo.Serialize (stream);
                    349:                }
                    350: 
                    351:                ConstBufferPtr infoBuf = dynamic_cast <MemoryStream&> (*stream);
                    352:                shared_ptr <Buffer> outBuf (new Buffer (infoBuf.Size()));
                    353:                outBuf->CopyFrom (infoBuf);
                    354: 
                    355:                return outBuf;
                    356:        }
                    357:        
                    358:        const char *FuseService::GetVolumeImagePath ()
                    359:        {
                    360: #ifdef TC_MACOSX
                    361:                return "/volume.dmg";
                    362: #else
                    363:                return "/volume";
                    364: #endif
                    365:        }
                    366: 
                    367:        uint64 FuseService::GetVolumeSize ()
                    368:        {
                    369:                if (!MountedVolume)
                    370:                        throw NotInitialized (SRC_POS);
                    371: 
                    372:                return MountedVolume->GetSize();
                    373:        }
                    374: 
                    375:        void FuseService::Mount (shared_ptr <Volume> openVolume, VolumeSlotNumber slotNumber, const string &fuseMountPoint)
                    376:        {
                    377:                list <string> args;
                    378:                args.push_back (FuseService::GetDeviceType());
                    379:                args.push_back (fuseMountPoint);
                    380: 
                    381: #ifdef TC_MACOSX
                    382:                args.push_back ("-o");
                    383:                args.push_back ("noping_diskarb");
                    384:                args.push_back ("-o");
                    385:                args.push_back ("nobrowse");
                    386: 
                    387:                if (getuid() == 0 || geteuid() == 0)
                    388: #endif
                    389:                {
                    390:                        args.push_back ("-o");
                    391:                        args.push_back ("allow_other");
                    392:                }
                    393:                
                    394:                ExecFunctor execFunctor (openVolume, slotNumber);
                    395:                Process::Execute ("fuse", args, -1, &execFunctor);
                    396: 
                    397:                for (int t = 0; true; t++)
                    398:                {
                    399:                        try
                    400:                        {
                    401:                                if (FilesystemPath (fuseMountPoint + FuseService::GetControlPath()).GetType() == FilesystemPathType::File)
                    402:                                        break;
                    403:                        }
                    404:                        catch (...)
                    405:                        {
                    406:                                if (t > 50)
                    407:                                        throw;
                    408: 
                    409:                                Thread::Sleep (100);
                    410:                        }
                    411:                }
                    412:        }
                    413: 
                    414:        void FuseService::ReadVolumeSectors (const BufferPtr &buffer, uint64 byteOffset)
                    415:        {
                    416:                if (!MountedVolume)
                    417:                        throw NotInitialized (SRC_POS);
                    418: 
                    419:                MountedVolume->ReadSectors (buffer, byteOffset);
                    420:        }
                    421: 
                    422:        void FuseService::ReceiveLoopDevice (const ConstBufferPtr &buffer)
                    423:        {
                    424:                shared_ptr <Stream> stream (new MemoryStream (buffer));
                    425:                Serializer sr (stream);
                    426: 
                    427:                ScopeLock lock (OpenVolumeInfoMutex);
                    428:                OpenVolumeInfo.VirtualDevice = OpenVolumeInfo.LoopDevice = sr.DeserializeString ("LoopDevice");
                    429:        }
                    430: 
                    431:        void FuseService::SendLoopDevice (const DirectoryPath &fuseMountPoint, const DevicePath &loopDevice)
                    432:        {
                    433:                File fuseServiceControl;
                    434:                fuseServiceControl.Open (string (fuseMountPoint) + GetControlPath(), File::OpenWrite);
                    435: 
                    436:                shared_ptr <Stream> stream (new MemoryStream);
                    437:                Serializer sr (stream);
                    438: 
                    439:                sr.Serialize ("LoopDevice", string (loopDevice));
                    440:                fuseServiceControl.Write (dynamic_cast <MemoryStream&> (*stream));
                    441:        }
                    442: 
                    443:        void FuseService::WriteVolumeSectors (const ConstBufferPtr &buffer, uint64 byteOffset)
                    444:        {
                    445:                if (!MountedVolume)
                    446:                        throw NotInitialized (SRC_POS);
                    447: 
                    448:                MountedVolume->WriteSectors (buffer, byteOffset);
                    449:        }
                    450: 
                    451:        void FuseService::ExecFunctor::operator() (int argc, char *argv[])
                    452:        {
                    453:                struct timeval tv;
                    454:                gettimeofday (&tv, NULL);
                    455:                FuseService::OpenVolumeInfo.SerialInstanceNumber = (uint64)tv.tv_sec * 1000000ULL + tv.tv_usec;
                    456: 
                    457:                FuseService::MountedVolume = MountedVolume;
                    458:                FuseService::SlotNumber = SlotNumber;
                    459: 
                    460:                FuseService::UserId = getuid();
                    461:                FuseService::GroupId = getgid();
                    462: 
                    463:                if (getenv ("SUDO_UID"))
                    464:                {
                    465:                        try
                    466:                        {
                    467:                                string s (getenv ("SUDO_UID"));
                    468:                                FuseService::UserId = static_cast <uid_t> (StringConverter::ToUInt64 (s));
                    469: 
                    470:                                if (getenv ("SUDO_GID"))
                    471:                                {
                    472:                                        s = getenv ("SUDO_GID");
                    473:                                        FuseService::GroupId = static_cast <gid_t> (StringConverter::ToUInt64 (s));
                    474:                                }
                    475:                        }
                    476:                        catch (...) { }
                    477:                }
                    478: 
                    479:                static fuse_operations fuse_service_oper;
                    480: 
                    481:                fuse_service_oper.access = fuse_service_access;
                    482:                fuse_service_oper.destroy = fuse_service_destroy;
                    483:                fuse_service_oper.getattr = fuse_service_getattr;
                    484:                fuse_service_oper.init = fuse_service_init;
                    485:                fuse_service_oper.open = fuse_service_open;
                    486:                fuse_service_oper.opendir = fuse_service_opendir;
                    487:                fuse_service_oper.read = fuse_service_read;
                    488:                fuse_service_oper.readdir = fuse_service_readdir;
                    489:                fuse_service_oper.write = fuse_service_write;
                    490: 
                    491:                _exit (fuse_main (argc, argv, &fuse_service_oper));
                    492:        }
                    493: 
                    494:        VolumeInfo FuseService::OpenVolumeInfo;
                    495:        Mutex FuseService::OpenVolumeInfoMutex;
                    496:        shared_ptr <Volume> FuseService::MountedVolume;
                    497:        VolumeSlotNumber FuseService::SlotNumber;
                    498:        uid_t FuseService::UserId;
                    499:        gid_t FuseService::GroupId;
                    500: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.