|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.