|
|
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.