|
|
1.1.1.10 root 1: /*
1.1.1.12 root 2: Legal Notice: Some portions of the source code contained in this file were
3: derived from the source code of Encryption for the Masses 2.02a, which is
4: Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
5: Agreement for Encryption for the Masses'. Modifications and additions to
6: the original source code (contained in this file) and all other portions of
7: this file are Copyright (c) 2003-2008 TrueCrypt Foundation and are governed
1.1.1.15 root 8: by the TrueCrypt License 2.6 the full text of which is contained in the
1.1.1.12 root 9: file License.txt included in TrueCrypt binary and source code distribution
1.1.1.10 root 10: packages. */
1.1 root 11:
12: #include "TCdefs.h"
1.1.1.15 root 13: #include <wchar.h>
1.1.1.6 root 14: #include "Crypto.h"
15: #include "Volumes.h"
1.1 root 16:
1.1.1.6 root 17: #include "Apidrvr.h"
1.1.1.14 root 18: #include "DriveFilter.h"
1.1.1.6 root 19: #include "Ntdriver.h"
20: #include "Ntvol.h"
1.1.1.14 root 21: #include "VolumeFilter.h"
1.1 root 22:
1.1.1.13 root 23: #include "Boot/Windows/BootCommon.h"
24:
1.1.1.6 root 25: #include "Cache.h"
1.1 root 26:
1.1.1.10 root 27: #if 0 && _DEBUG
28: #define EXTRA_INFO 1
29: #endif
1.1 root 30:
31: #pragma warning( disable : 4127 )
32:
1.1.1.14 root 33: volatile BOOL ProbingHostDeviceForWrite = FALSE;
34:
35:
1.1.1.15 root 36: NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
1.1 root 37: PEXTENSION Extension,
1.1.1.6 root 38: MOUNT_STRUCT *mount,
1.1 root 39: PWSTR pwszMountVolume,
40: BOOL bRawDevice)
41: {
42: FILE_STANDARD_INFORMATION FileStandardInfo;
43: FILE_BASIC_INFORMATION FileBasicInfo;
44: OBJECT_ATTRIBUTES oaFileAttributes;
45: UNICODE_STRING FullFileName;
46: IO_STATUS_BLOCK IoStatusBlock;
1.1.1.6 root 47: PCRYPTO_INFO cryptoInfoPtr = NULL;
48: PCRYPTO_INFO tmpCryptoInfo = NULL;
1.1 root 49: LARGE_INTEGER lDiskLength;
1.1.1.15 root 50: __int64 partitionStartingOffset = 0;
1.1.1.6 root 51: int volumeType;
1.1.1.4 root 52: char *readBuffer = 0;
1.1.1.5 root 53: NTSTATUS ntStatus = 0;
1.1.1.15 root 54: BOOL forceAccessCheck = (!bRawDevice && !(OsMajorVersion == 5 &&OsMinorVersion == 0)); // Windows 2000 does not support OBJ_FORCE_ACCESS_CHECK attribute
1.1 root 55:
56: Extension->pfoDeviceFile = NULL;
57: Extension->hDeviceFile = NULL;
1.1.1.6 root 58: Extension->bTimeStampValid = FALSE;
1.1 root 59:
1.1.1.4 root 60: RtlInitUnicodeString (&FullFileName, pwszMountVolume);
1.1.1.15 root 61: InitializeObjectAttributes (&oaFileAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | (forceAccessCheck ? OBJ_FORCE_ACCESS_CHECK : 0), NULL, NULL);
1.1.1.4 root 62: KeInitializeEvent (&Extension->keVolumeEvent, NotificationEvent, FALSE);
63:
1.1.1.15 root 64: if (Extension->SecurityClientContextValid)
65: {
66: ntStatus = SeImpersonateClientEx (&Extension->SecurityClientContext, NULL);
67: if (!NT_SUCCESS (ntStatus))
68: goto error;
69: }
70:
1.1.1.4 root 71: // If we are opening a device, query its size first
72: if (bRawDevice)
1.1 root 73: {
1.1.1.5 root 74: PARTITION_INFORMATION pi;
1.1.1.10 root 75: PARTITION_INFORMATION_EX pix;
1.1.1.15 root 76: LARGE_INTEGER diskLengthInfo;
1.1.1.4 root 77: DISK_GEOMETRY dg;
1.1 root 78:
1.1.1.4 root 79: ntStatus = IoGetDeviceObjectPointer (&FullFileName,
80: FILE_READ_DATA,
81: &Extension->pfoDeviceFile,
82: &Extension->pFsdDevice);
83:
84: if (!NT_SUCCESS (ntStatus))
85: goto error;
86:
1.1.1.12 root 87: if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_DRIVE_GEOMETRY, (char *) &dg, sizeof (dg))))
1.1.1.4 root 88: {
1.1.1.10 root 89: lDiskLength.QuadPart = dg.Cylinders.QuadPart * dg.SectorsPerTrack * dg.TracksPerCylinder * dg.BytesPerSector;
90: mount->BytesPerSector = dg.BytesPerSector;
1.1.1.4 root 91: }
1.1.1.5 root 92: else
1.1.1.10 root 93: lDiskLength.QuadPart = 0;
1.1.1.4 root 94:
1.1.1.10 root 95: // Drive geometry is used only when IOCTL_DISK_GET_PARTITION_INFO fails
1.1.1.12 root 96: if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_PARTITION_INFO_EX, (char *) &pix, sizeof (pix))))
1.1.1.13 root 97: {
1.1.1.10 root 98: lDiskLength.QuadPart = pix.PartitionLength.QuadPart;
1.1.1.13 root 99: partitionStartingOffset = pix.StartingOffset.QuadPart;
100: }
1.1.1.10 root 101: // Windows 2000 does not support IOCTL_DISK_GET_PARTITION_INFO_EX
1.1.1.12 root 102: else if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_PARTITION_INFO, (char *) &pi, sizeof (pi))))
1.1.1.13 root 103: {
1.1.1.10 root 104: lDiskLength.QuadPart = pi.PartitionLength.QuadPart;
1.1.1.13 root 105: partitionStartingOffset = pi.StartingOffset.QuadPart;
106: }
1.1.1.15 root 107: else if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_LENGTH_INFO, &diskLengthInfo, sizeof (diskLengthInfo))))
108: {
109: lDiskLength = diskLengthInfo;
110: }
1.1 root 111:
1.1.1.14 root 112: ProbingHostDeviceForWrite = TRUE;
113:
114: if (!mount->bMountReadOnly
115: && TCSendHostDeviceIoControlRequest (DeviceObject, Extension,
116: IsHiddenSystemRunning() ? TC_IOCTL_DISK_IS_WRITABLE : IOCTL_DISK_IS_WRITABLE, NULL, 0) == STATUS_MEDIA_WRITE_PROTECTED)
1.1.1.10 root 117: {
118: mount->bMountReadOnly = TRUE;
119: DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
1.1.1.4 root 120: }
1.1.1.14 root 121:
122: ProbingHostDeviceForWrite = FALSE;
1.1.1.4 root 123: }
1.1 root 124:
1.1.1.10 root 125: if (mount->BytesPerSector == 0)
126: mount->BytesPerSector = SECTOR_SIZE;
127:
128: Extension->HostBytesPerSector = mount->BytesPerSector;
129:
1.1.1.4 root 130: // Open the volume hosting file/device
131: if (!mount->bMountReadOnly)
132: {
133: ntStatus = ZwCreateFile (&Extension->hDeviceFile,
134: GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
135: &oaFileAttributes,
136: &IoStatusBlock,
137: NULL,
138: FILE_ATTRIBUTE_NORMAL |
139: FILE_ATTRIBUTE_SYSTEM,
140: mount->bExclusiveAccess ? 0 : FILE_SHARE_READ | FILE_SHARE_WRITE,
141: FILE_OPEN,
1.1.1.10 root 142: FILE_RANDOM_ACCESS |
1.1.1.4 root 143: FILE_WRITE_THROUGH |
1.1.1.10 root 144: (Extension->HostBytesPerSector == SECTOR_SIZE ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
1.1.1.4 root 145: FILE_SYNCHRONOUS_IO_NONALERT,
146: NULL,
147: 0);
148: }
1.1 root 149:
1.1.1.10 root 150: /* 26-4-99 NT for some partitions returns this code, it is really a access denied */
1.1 root 151: if (ntStatus == 0xc000001b)
152: ntStatus = STATUS_ACCESS_DENIED;
1.1.1.16! root 153:
! 154: mount->VolumeMountedReadOnlyAfterAccessDenied = FALSE;
! 155:
1.1.1.4 root 156: if (mount->bMountReadOnly || ntStatus == STATUS_ACCESS_DENIED)
1.1 root 157: {
158: ntStatus = ZwCreateFile (&Extension->hDeviceFile,
1.1.1.4 root 159: GENERIC_READ | SYNCHRONIZE,
160: &oaFileAttributes,
161: &IoStatusBlock,
162: NULL,
163: FILE_ATTRIBUTE_NORMAL |
164: FILE_ATTRIBUTE_SYSTEM,
1.1.1.8 root 165: mount->bExclusiveAccess ? FILE_SHARE_READ : FILE_SHARE_READ | FILE_SHARE_WRITE,
1.1.1.4 root 166: FILE_OPEN,
1.1.1.10 root 167: FILE_RANDOM_ACCESS |
1.1.1.4 root 168: FILE_WRITE_THROUGH |
1.1.1.11 root 169: (Extension->HostBytesPerSector == SECTOR_SIZE ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
1.1.1.4 root 170: FILE_SYNCHRONOUS_IO_NONALERT,
171: NULL,
172: 0);
1.1.1.11 root 173:
1.1.1.16! root 174: if (NT_SUCCESS (ntStatus) && !mount->bMountReadOnly)
! 175: mount->VolumeMountedReadOnlyAfterAccessDenied = TRUE;
! 176:
1.1 root 177: Extension->bReadOnly = TRUE;
1.1.1.11 root 178: DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
1.1 root 179: }
180: else
181: Extension->bReadOnly = FALSE;
182:
183: /* 26-4-99 NT for some partitions returns this code, it is really a
1.1.1.4 root 184: access denied */
1.1 root 185: if (ntStatus == 0xc000001b)
186: {
187: /* Partitions which return this code can still be opened with
1.1.1.4 root 188: FILE_SHARE_READ but this causes NT problems elsewhere in
189: particular if you do FILE_SHARE_READ NT will die later if
1.1.1.12 root 190: anyone even tries to open the partition (or file for that
1.1.1.4 root 191: matter...) */
1.1 root 192: ntStatus = STATUS_SHARING_VIOLATION;
193: }
194:
195: if (!NT_SUCCESS (ntStatus))
196: {
197: goto error;
198: }
199:
1.1.1.4 root 200: // If we have opened a file, query its size now
1.1 root 201: if (bRawDevice == FALSE)
202: {
203: ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
1.1.1.4 root 204: &IoStatusBlock,
205: &FileBasicInfo,
206: sizeof (FileBasicInfo),
207: FileBasicInformation);
1.1 root 208:
209: if (NT_SUCCESS (ntStatus))
1.1.1.4 root 210: {
1.1.1.6 root 211: if (mount->bPreserveTimestamp)
212: {
213: /* Remember the container timestamp. (Used to reset access/modification file date/time
214: of file-hosted volumes upon dismount or after unsuccessful mount attempt to preserve
215: plausible deniability of hidden volumes.) */
216: Extension->fileCreationTime = FileBasicInfo.CreationTime;
217: Extension->fileLastAccessTime = FileBasicInfo.LastAccessTime;
218: Extension->fileLastWriteTime = FileBasicInfo.LastWriteTime;
219: Extension->fileLastChangeTime = FileBasicInfo.ChangeTime;
220: Extension->bTimeStampValid = TRUE;
221: }
1.1.1.4 root 222:
1.1 root 223: ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
1.1.1.4 root 224: &IoStatusBlock,
225: &FileStandardInfo,
226: sizeof (FileStandardInfo),
227: FileStandardInformation);
228: }
1.1 root 229:
230: if (!NT_SUCCESS (ntStatus))
231: {
232: Dump ("ZwQueryInformationFile failed while opening file: NTSTATUS 0x%08x\n",
1.1.1.4 root 233: ntStatus);
1.1 root 234: goto error;
235: }
1.1.1.4 root 236:
237: lDiskLength.QuadPart = FileStandardInfo.EndOfFile.QuadPart;
1.1 root 238:
239: if (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_COMPRESSED)
240: {
241: Dump ("File \"%ls\" is marked as compressed - not supported!\n", pwszMountVolume);
242: mount->nReturnCode = ERR_COMPRESSION_NOT_SUPPORTED;
243: ntStatus = STATUS_SUCCESS;
244: goto error;
245: }
246:
247: ntStatus = ObReferenceObjectByHandle (Extension->hDeviceFile,
1.1.1.4 root 248: FILE_ALL_ACCESS,
249: *IoFileObjectType,
250: KernelMode,
251: &Extension->pfoDeviceFile,
252: 0);
1.1 root 253:
254: if (!NT_SUCCESS (ntStatus))
255: {
256: goto error;
257: }
258:
1.1.1.4 root 259: /* Get the FSD device for the file (probably either NTFS or FAT) */
1.1 root 260: Extension->pFsdDevice = IoGetRelatedDeviceObject (Extension->pfoDeviceFile);
261: }
1.1.1.15 root 262: else
263: {
264: // Try to gain "raw" access to the partition in case there is a live filesystem on it (otherwise,
265: // the NTFS driver guards hidden sectors and prevents mounting using a backup header e.g. after the user
266: // accidentally quick-formats a dismounted partition-hosted TrueCrypt volume as NTFS).
267:
268: PFILE_OBJECT pfoTmpDeviceFile = NULL;
269:
270: if (NT_SUCCESS (ObReferenceObjectByHandle (Extension->hDeviceFile, FILE_ALL_ACCESS, *IoFileObjectType, KernelMode, &pfoTmpDeviceFile, NULL))
271: && pfoTmpDeviceFile != NULL)
272: {
273: TCFsctlCall (pfoTmpDeviceFile, FSCTL_ALLOW_EXTENDED_DASD_IO, NULL, 0, NULL, 0);
274: ObDereferenceObject (pfoTmpDeviceFile);
275: }
276: }
1.1 root 277:
1.1.1.4 root 278: // Check volume size
1.1.1.14 root 279: if (lDiskLength.QuadPart < TC_MIN_VOLUME_SIZE_LEGACY || lDiskLength.QuadPart > TC_MAX_VOLUME_SIZE)
1.1.1.4 root 280: {
281: mount->nReturnCode = ERR_VOL_SIZE_WRONG;
282: ntStatus = STATUS_SUCCESS;
283: goto error;
284: }
1.1.1.6 root 285:
1.1.1.4 root 286: Extension->DiskLength = lDiskLength.QuadPart;
1.1 root 287:
1.1.1.15 root 288: readBuffer = TCalloc (max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, PAGE_SIZE));
1.1.1.4 root 289: if (readBuffer == NULL)
290: {
291: ntStatus = STATUS_INSUFFICIENT_RESOURCES;
292: goto error;
293: }
1.1 root 294:
1.1.1.6 root 295: // Go through all volume types (e.g., normal, hidden)
1.1.1.14 root 296: for (volumeType = TC_VOLUME_TYPE_NORMAL;
297: volumeType < TC_VOLUME_TYPE_COUNT;
1.1.1.6 root 298: volumeType++)
1.1.1.4 root 299: {
1.1.1.14 root 300: Dump ("Trying to open volume type %d\n", volumeType);
301:
1.1.1.13 root 302: if (mount->bPartitionInInactiveSysEncScope
1.1.1.14 root 303: && volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY)
1.1.1.13 root 304: continue;
305:
1.1.1.6 root 306: /* Read the volume header */
1.1 root 307:
1.1.1.14 root 308: if (!mount->bPartitionInInactiveSysEncScope
309: || (mount->bPartitionInInactiveSysEncScope && volumeType == TC_VOLUME_TYPE_HIDDEN))
1.1.1.13 root 310: {
1.1.1.14 root 311: // Header of a volume that is not within the scope of system encryption, or
312: // header of a system hidden volume (containing a hidden OS)
313:
314: LARGE_INTEGER headerOffset;
315:
316: if (mount->UseBackupHeader && lDiskLength.QuadPart <= TC_TOTAL_VOLUME_HEADERS_SIZE)
317: continue;
318:
319: switch (volumeType)
320: {
321: case TC_VOLUME_TYPE_NORMAL:
322: headerOffset.QuadPart = mount->UseBackupHeader ? lDiskLength.QuadPart - TC_VOLUME_HEADER_GROUP_SIZE : TC_VOLUME_HEADER_OFFSET;
323: break;
324:
325: case TC_VOLUME_TYPE_HIDDEN:
326: if (lDiskLength.QuadPart <= TC_VOLUME_HEADER_GROUP_SIZE)
327: continue;
328:
329: headerOffset.QuadPart = mount->UseBackupHeader ? lDiskLength.QuadPart - TC_HIDDEN_VOLUME_HEADER_OFFSET : TC_HIDDEN_VOLUME_HEADER_OFFSET;
330: break;
331:
332: case TC_VOLUME_TYPE_HIDDEN_LEGACY:
333: if (mount->UseBackupHeader)
334: continue;
335:
336: headerOffset.QuadPart = lDiskLength.QuadPart - TC_HIDDEN_VOLUME_HEADER_OFFSET_LEGACY;
337: break;
338: }
339:
340: Dump ("Reading volume header at %I64d\n", headerOffset.QuadPart);
1.1.1.13 root 341:
342: ntStatus = ZwReadFile (Extension->hDeviceFile,
1.1.1.6 root 343: NULL,
344: NULL,
345: NULL,
346: &IoStatusBlock,
347: readBuffer,
1.1.1.14 root 348: TC_VOLUME_HEADER_EFFECTIVE_SIZE,
349: &headerOffset,
1.1.1.6 root 350: NULL);
1.1.1.13 root 351: }
352: else
353: {
354: // Header of a partition that is within the scope of system encryption
355:
356: WCHAR parentDrivePath [47+1] = {0};
357: HANDLE hParentDeviceFile = NULL;
358: UNICODE_STRING FullParentPath;
359: OBJECT_ATTRIBUTES oaParentFileAttributes;
360: LARGE_INTEGER parentKeyDataOffset;
361:
362: _snwprintf (parentDrivePath,
363: sizeof (parentDrivePath) / sizeof (WCHAR) - 1,
364: WIDE ("\\Device\\Harddisk%d\\Partition0"),
365: mount->nPartitionInInactiveSysEncScopeDriveNo);
366:
367: Dump ("Mounting partition within scope of system encryption (reading key data from: %ls)\n", parentDrivePath);
368:
369: RtlInitUnicodeString (&FullParentPath, parentDrivePath);
370: InitializeObjectAttributes (&oaParentFileAttributes, &FullParentPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
371:
372: ntStatus = ZwCreateFile (&hParentDeviceFile,
373: GENERIC_READ | SYNCHRONIZE,
374: &oaParentFileAttributes,
375: &IoStatusBlock,
376: NULL,
377: FILE_ATTRIBUTE_NORMAL |
378: FILE_ATTRIBUTE_SYSTEM,
379: FILE_SHARE_READ | FILE_SHARE_WRITE,
380: FILE_OPEN,
381: FILE_RANDOM_ACCESS |
382: FILE_WRITE_THROUGH |
383: (Extension->HostBytesPerSector == SECTOR_SIZE ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
384: FILE_SYNCHRONOUS_IO_NONALERT,
385: NULL,
386: 0);
387:
388: if (!NT_SUCCESS (ntStatus))
389: {
390: if (hParentDeviceFile != NULL)
391: ZwClose (hParentDeviceFile);
392:
393: Dump ("Cannot open %ls\n", parentDrivePath);
394:
395: goto error;
396: }
397:
1.1.1.14 root 398: parentKeyDataOffset.QuadPart = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
1.1.1.13 root 399:
400: ntStatus = ZwReadFile (hParentDeviceFile,
401: NULL,
402: NULL,
403: NULL,
404: &IoStatusBlock,
405: readBuffer,
1.1.1.14 root 406: TC_VOLUME_HEADER_EFFECTIVE_SIZE,
1.1.1.13 root 407: &parentKeyDataOffset,
408: NULL);
409:
410: if (hParentDeviceFile != NULL)
411: ZwClose (hParentDeviceFile);
412: }
1.1.1.6 root 413:
1.1.1.15 root 414: if (!NT_SUCCESS (ntStatus) && ntStatus != STATUS_END_OF_FILE)
1.1 root 415: {
1.1.1.6 root 416: Dump ("Read failed: NTSTATUS 0x%08x\n", ntStatus);
1.1.1.14 root 417: goto error;
1.1 root 418: }
419:
1.1.1.15 root 420: if (ntStatus == STATUS_END_OF_FILE || IoStatusBlock.Information != TC_VOLUME_HEADER_EFFECTIVE_SIZE)
1.1.1.6 root 421: {
1.1.1.14 root 422: Dump ("Read didn't read enough data\n");
1.1.1.15 root 423:
424: // If FSCTL_ALLOW_EXTENDED_DASD_IO failed and there is a live filesystem on the partition, then the
425: // filesystem driver may report EOF when we are reading hidden sectors (when the filesystem is
426: // shorter than the partition). This can happen for example after the user quick-formats a dismounted
427: // partition-hosted TrueCrypt volume and then tries to mount the volume using the embedded backup header.
428: memset (readBuffer, 0, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1.1.1.6 root 429: }
1.1 root 430:
1.1.1.6 root 431: /* Attempt to recognize the volume (decrypt the header) */
1.1 root 432:
1.1.1.15 root 433: ReadVolumeHeaderRecoveryMode = mount->RecoveryMode;
434:
1.1.1.14 root 435: if ((volumeType == TC_VOLUME_TYPE_HIDDEN || volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY) && mount->bProtectHiddenVolume)
1.1.1.6 root 436: {
1.1.1.15 root 437: mount->nReturnCode = ReadVolumeHeaderWCache (
1.1.1.14 root 438: FALSE,
1.1.1.6 root 439: mount->bCache,
440: readBuffer,
441: &mount->ProtectedHidVolPassword,
442: &tmpCryptoInfo);
443: }
444: else
445: {
1.1.1.15 root 446: mount->nReturnCode = ReadVolumeHeaderWCache (
1.1.1.14 root 447: mount->bPartitionInInactiveSysEncScope && volumeType == TC_VOLUME_TYPE_NORMAL,
1.1.1.6 root 448: mount->bCache,
449: readBuffer,
450: &mount->VolumePassword,
451: &Extension->cryptoInfo);
452: }
1.1.1.4 root 453:
1.1.1.15 root 454: ReadVolumeHeaderRecoveryMode = FALSE;
455:
1.1.1.6 root 456: if (mount->nReturnCode == 0 || mount->nReturnCode == ERR_CIPHER_INIT_WEAK_KEY)
457: {
458: /* Volume header successfully decrypted */
1.1 root 459:
1.1.1.14 root 460: Dump ("Volume header decrypted\n");
461: Dump ("Required program version = %x\n", (int) Extension->cryptoInfo->RequiredProgramVersion);
462: Dump ("Legacy volume = %d\n", (int) Extension->cryptoInfo->LegacyVolume);
463:
464: if (IsHiddenSystemRunning() && !Extension->cryptoInfo->hiddenVolume)
465: {
466: Extension->bReadOnly = mount->bMountReadOnly = TRUE;
467: HiddenSysLeakProtectionCount++;
468: }
469:
1.1.1.6 root 470: Extension->cryptoInfo->bProtectHiddenVolume = FALSE;
471: Extension->cryptoInfo->bHiddenVolProtectionAction = FALSE;
1.1 root 472:
1.1.1.13 root 473: Extension->cryptoInfo->bPartitionInInactiveSysEncScope = mount->bPartitionInInactiveSysEncScope;
474:
1.1.1.15 root 475: if (volumeType == TC_VOLUME_TYPE_NORMAL)
1.1.1.13 root 476: {
1.1.1.15 root 477: if (mount->bPartitionInInactiveSysEncScope)
1.1.1.13 root 478: {
1.1.1.15 root 479: if (Extension->cryptoInfo->EncryptedAreaStart.Value > (unsigned __int64) partitionStartingOffset
480: || Extension->cryptoInfo->EncryptedAreaStart.Value + Extension->cryptoInfo->VolumeSize.Value <= (unsigned __int64) partitionStartingOffset)
481: {
482: // The partition is not within the key scope of system encryption
483: mount->nReturnCode = ERR_PASSWORD_WRONG;
484: ntStatus = STATUS_SUCCESS;
485: goto error;
486: }
487:
488: if (Extension->cryptoInfo->EncryptedAreaLength.Value != Extension->cryptoInfo->VolumeSize.Value)
489: {
490: // Partial encryption is not supported for volumes mounted as regular
491: mount->nReturnCode = ERR_ENCRYPTION_NOT_COMPLETED;
492: ntStatus = STATUS_SUCCESS;
493: goto error;
494: }
495: }
496: else if (Extension->cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC)
497: {
498: if (Extension->cryptoInfo->EncryptedAreaLength.Value != Extension->cryptoInfo->VolumeSize.Value)
499: {
500: // Non-system in-place encryption process has not been completed on this volume
501: mount->nReturnCode = ERR_NONSYS_INPLACE_ENC_INCOMPLETE;
502: ntStatus = STATUS_SUCCESS;
503: goto error;
504: }
1.1.1.13 root 505: }
506: }
507:
1.1.1.14 root 508: Extension->cryptoInfo->FirstDataUnitNo.Value = 0;
1.1 root 509:
1.1.1.14 root 510: if (Extension->cryptoInfo->hiddenVolume && IsHiddenSystemRunning())
511: {
512: // Prevent mount of a hidden system partition if the system hosted on it is currently running
513: if (memcmp (Extension->cryptoInfo->master_keydata, GetSystemDriveCryptoInfo()->master_keydata, EAGetKeySize (Extension->cryptoInfo->ea)) == 0)
1.1.1.13 root 514: {
1.1.1.14 root 515: mount->nReturnCode = ERR_VOL_ALREADY_MOUNTED;
516: ntStatus = STATUS_SUCCESS;
517: goto error;
1.1.1.13 root 518: }
1.1.1.14 root 519: }
520:
521: switch (volumeType)
522: {
523: case TC_VOLUME_TYPE_NORMAL:
1.1.1.13 root 524:
1.1.1.6 root 525: Extension->cryptoInfo->hiddenVolume = FALSE;
1.1.1.13 root 526:
1.1.1.14 root 527: if (mount->bPartitionInInactiveSysEncScope)
528: {
529: Extension->cryptoInfo->volDataAreaOffset = 0;
530: Extension->DiskLength = lDiskLength.QuadPart;
531: Extension->cryptoInfo->FirstDataUnitNo.Value = partitionStartingOffset / ENCRYPTION_DATA_UNIT_SIZE;
532: }
533: else if (Extension->cryptoInfo->LegacyVolume)
534: {
535: Extension->cryptoInfo->volDataAreaOffset = TC_VOLUME_HEADER_SIZE_LEGACY;
536: Extension->DiskLength = lDiskLength.QuadPart - TC_VOLUME_HEADER_SIZE_LEGACY;
537: }
538: else
539: {
540: Extension->cryptoInfo->volDataAreaOffset = Extension->cryptoInfo->EncryptedAreaStart.Value;
541: Extension->DiskLength = Extension->cryptoInfo->VolumeSize.Value;
542: }
1.1.1.6 root 543:
544: break;
545:
1.1.1.14 root 546: case TC_VOLUME_TYPE_HIDDEN:
547: case TC_VOLUME_TYPE_HIDDEN_LEGACY:
1.1.1.6 root 548:
549: cryptoInfoPtr = mount->bProtectHiddenVolume ? tmpCryptoInfo : Extension->cryptoInfo;
550:
1.1.1.14 root 551: if (volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY)
552: Extension->cryptoInfo->hiddenVolumeOffset = lDiskLength.QuadPart - cryptoInfoPtr->hiddenVolumeSize - TC_HIDDEN_VOLUME_HEADER_OFFSET_LEGACY;
553: else
554: Extension->cryptoInfo->hiddenVolumeOffset = cryptoInfoPtr->EncryptedAreaStart.Value;
1.1.1.6 root 555:
1.1.1.14 root 556: Dump ("Hidden volume offset = %I64d\n", Extension->cryptoInfo->hiddenVolumeOffset);
557: Dump ("Hidden volume size = %I64d\n", cryptoInfoPtr->hiddenVolumeSize);
558: Dump ("Hidden volume end = %I64d\n", Extension->cryptoInfo->hiddenVolumeOffset + cryptoInfoPtr->hiddenVolumeSize - 1);
1.1.1.6 root 559:
560: // Validate the offset
1.1.1.12 root 561: if (Extension->cryptoInfo->hiddenVolumeOffset % ENCRYPTION_DATA_UNIT_SIZE != 0)
1.1.1.6 root 562: {
563: mount->nReturnCode = ERR_VOL_SIZE_WRONG;
564: ntStatus = STATUS_SUCCESS;
565: goto error;
566: }
567:
568: // If we are supposed to actually mount the hidden volume (not just to protect it)
569: if (!mount->bProtectHiddenVolume)
570: {
571: Extension->DiskLength = cryptoInfoPtr->hiddenVolumeSize;
572: Extension->cryptoInfo->hiddenVolume = TRUE;
1.1.1.13 root 573: Extension->cryptoInfo->volDataAreaOffset = Extension->cryptoInfo->hiddenVolumeOffset;
1.1.1.6 root 574: }
575: else
576: {
577: // Hidden volume protection
578: Extension->cryptoInfo->hiddenVolume = FALSE;
579: Extension->cryptoInfo->bProtectHiddenVolume = TRUE;
1.1.1.14 root 580:
581: Extension->cryptoInfo->hiddenVolumeProtectedSize = tmpCryptoInfo->hiddenVolumeSize;
1.1.1.13 root 582:
1.1.1.14 root 583: if (volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY)
584: Extension->cryptoInfo->hiddenVolumeProtectedSize += TC_VOLUME_HEADER_SIZE_LEGACY;
1.1.1.13 root 585:
1.1.1.14 root 586: Dump ("Hidden volume protection active: %I64d-%I64d (%I64d)\n", Extension->cryptoInfo->hiddenVolumeOffset, Extension->cryptoInfo->hiddenVolumeProtectedSize + Extension->cryptoInfo->hiddenVolumeOffset - 1, Extension->cryptoInfo->hiddenVolumeProtectedSize);
1.1.1.6 root 587: }
1.1.1.4 root 588:
1.1.1.6 root 589: break;
590: }
1.1.1.4 root 591:
1.1.1.14 root 592: Dump ("Volume data offset = %I64d\n", Extension->cryptoInfo->volDataAreaOffset);
593: Dump ("Volume data size = %I64d\n", Extension->DiskLength);
594: Dump ("Volume data end = %I64d\n", Extension->cryptoInfo->volDataAreaOffset + Extension->DiskLength - 1);
595:
1.1.1.15 root 596: if (Extension->DiskLength == 0)
597: {
598: Dump ("Incorrect volume size\n");
599: continue;
600: }
601:
1.1.1.6 root 602: // If this is a hidden volume, make sure we are supposed to actually
603: // mount it (i.e. not just to protect it)
1.1.1.14 root 604: if (volumeType == TC_VOLUME_TYPE_NORMAL || !mount->bProtectHiddenVolume)
1.1.1.4 root 605: {
1.1.1.6 root 606: // Calculate virtual volume geometry
607: Extension->TracksPerCylinder = 1;
608: Extension->SectorsPerTrack = 1;
1.1.1.10 root 609: Extension->BytesPerSector = SECTOR_SIZE;
610: Extension->NumberOfCylinders = Extension->DiskLength / SECTOR_SIZE;
1.1.1.6 root 611: Extension->PartitionType = 0;
612:
613: Extension->bRawDevice = bRawDevice;
1.1.1.7 root 614:
1.1.1.8 root 615: memset (Extension->wszVolume, 0, sizeof (Extension->wszVolume));
1.1.1.7 root 616: if (wcsstr (pwszMountVolume, WIDE ("\\??\\UNC\\")) == pwszMountVolume)
617: {
618: /* UNC path */
619: _snwprintf (Extension->wszVolume,
620: sizeof (Extension->wszVolume) / sizeof (WCHAR) - 1,
621: WIDE ("\\??\\\\%s"),
622: pwszMountVolume + 7);
623: }
1.1.1.6 root 624: else
625: {
1.1.1.7 root 626: wcsncpy (Extension->wszVolume, pwszMountVolume, sizeof (Extension->wszVolume) / sizeof (WCHAR) - 1);
1.1.1.6 root 627: }
1.1.1.4 root 628: }
629:
1.1.1.6 root 630: // If we are to protect a hidden volume we cannot exit yet, for we must also
631: // decrypt the hidden volume header.
1.1.1.14 root 632: if (!(volumeType == TC_VOLUME_TYPE_NORMAL && mount->bProtectHiddenVolume))
1.1.1.4 root 633: {
1.1.1.6 root 634: TCfree (readBuffer);
1.1.1.4 root 635:
1.1.1.6 root 636: if (tmpCryptoInfo != NULL)
1.1.1.14 root 637: {
1.1.1.6 root 638: crypto_close (tmpCryptoInfo);
1.1.1.14 root 639: tmpCryptoInfo = NULL;
640: }
1.1.1.6 root 641:
642: return STATUS_SUCCESS;
643: }
1.1.1.4 root 644: }
1.1.1.14 root 645: else if ((mount->bProtectHiddenVolume && volumeType == TC_VOLUME_TYPE_NORMAL)
1.1.1.6 root 646: || mount->nReturnCode != ERR_PASSWORD_WRONG)
1.1.1.4 root 647: {
1.1.1.6 root 648: /* If we are not supposed to protect a hidden volume, the only error that is
649: tolerated is ERR_PASSWORD_WRONG (to allow mounting a possible hidden volume).
1.1.1.4 root 650:
1.1.1.6 root 651: If we _are_ supposed to protect a hidden volume, we do not tolerate any error
652: (both volume headers must be successfully decrypted). */
1.1 root 653:
1.1.1.6 root 654: break;
1.1 root 655: }
656: }
657:
658: /* Failed due to some non-OS reason so we drop through and return NT
659: SUCCESS then nReturnCode is checked later in user-mode */
660:
661: if (mount->nReturnCode == ERR_OUTOFMEMORY)
662: ntStatus = STATUS_INSUFFICIENT_RESOURCES;
663: else
664: ntStatus = STATUS_SUCCESS;
665:
1.1.1.4 root 666: error:
1.1.1.14 root 667: if (mount->nReturnCode == ERR_SUCCESS)
668: mount->nReturnCode = ERR_PASSWORD_WRONG;
669:
670: if (tmpCryptoInfo != NULL)
671: {
672: crypto_close (tmpCryptoInfo);
673: tmpCryptoInfo = NULL;
674: }
675:
676: if (Extension->cryptoInfo)
677: {
678: crypto_close (Extension->cryptoInfo);
679: Extension->cryptoInfo = NULL;
680: }
681:
1.1.1.6 root 682: if (Extension->bTimeStampValid)
1.1.1.4 root 683: {
684: /* Restore the container timestamp to preserve plausible deniability of possible hidden volume. */
685: RestoreTimeStamp (Extension);
686: }
1.1 root 687:
688: /* Close the hDeviceFile */
689: if (Extension->hDeviceFile != NULL)
690: ZwClose (Extension->hDeviceFile);
691:
692: /* The cryptoInfo pointer is deallocated if the readheader routines
693: fail so there is no need to deallocate here */
694:
695: /* Dereference the user-mode file object */
696: if (Extension->pfoDeviceFile != NULL)
697: ObDereferenceObject (Extension->pfoDeviceFile);
698:
1.1.1.4 root 699: /* Free the tmp IO buffers */
1.1 root 700: if (readBuffer != NULL)
701: TCfree (readBuffer);
702:
703: return ntStatus;
704: }
705:
1.1.1.14 root 706: void TCCloseVolume (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
1.1 root 707: {
708: if (DeviceObject); /* Remove compiler warning */
709:
710: if (Extension->hDeviceFile != NULL)
1.1.1.4 root 711: {
1.1.1.6 root 712: if (Extension->bRawDevice == FALSE
713: && Extension->bTimeStampValid)
1.1.1.4 root 714: {
715: /* Restore the container timestamp to preserve plausible deniability of possible hidden volume. */
716: RestoreTimeStamp (Extension);
717: }
1.1.1.6 root 718: ZwClose (Extension->hDeviceFile);
1.1.1.4 root 719: }
1.1 root 720: ObDereferenceObject (Extension->pfoDeviceFile);
721: crypto_close (Extension->cryptoInfo);
722: }
723:
724:
1.1.1.14 root 725: NTSTATUS TCSendHostDeviceIoControlRequest (PDEVICE_OBJECT DeviceObject,
1.1 root 726: PEXTENSION Extension,
727: ULONG IoControlCode,
1.1.1.15 root 728: void *OutputBuffer,
729: ULONG OutputBufferSize)
1.1 root 730: {
731: IO_STATUS_BLOCK IoStatusBlock;
732: NTSTATUS ntStatus;
733: PIRP Irp;
734:
735: if (DeviceObject); /* Remove compiler warning */
736:
737: KeClearEvent (&Extension->keVolumeEvent);
738:
739: Irp = IoBuildDeviceIoControlRequest (IoControlCode,
740: Extension->pFsdDevice,
741: NULL, 0,
742: OutputBuffer, OutputBufferSize,
743: FALSE,
744: &Extension->keVolumeEvent,
745: &IoStatusBlock);
746:
747: if (Irp == NULL)
748: {
749: Dump ("IRP allocation failed\n");
750: return STATUS_INSUFFICIENT_RESOURCES;
751: }
752:
1.1.1.5 root 753: // Disk device may be used by filesystem driver which needs file object
754: IoGetNextIrpStackLocation (Irp) -> FileObject = Extension->pfoDeviceFile;
755:
1.1 root 756: ntStatus = IoCallDriver (Extension->pFsdDevice, Irp);
757: if (ntStatus == STATUS_PENDING)
758: {
1.1.1.12 root 759: KeWaitForSingleObject (&Extension->keVolumeEvent, Executive, KernelMode, FALSE, NULL);
1.1 root 760: ntStatus = IoStatusBlock.Status;
761: }
762:
763: return ntStatus;
764: }
765:
1.1.1.14 root 766: NTSTATUS COMPLETE_IRP (PDEVICE_OBJECT DeviceObject,
1.1 root 767: PIRP Irp,
768: NTSTATUS IrpStatus,
1.1.1.4 root 769: ULONG_PTR IrpInformation)
1.1 root 770: {
771: Irp->IoStatus.Status = IrpStatus;
772: Irp->IoStatus.Information = IrpInformation;
773:
774: if (DeviceObject); /* Remove compiler warning */
775:
1.1.1.10 root 776: #if EXTRA_INFO
777: if (!NT_SUCCESS (IrpStatus))
778: {
779: PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
780: Dump ("COMPLETE_IRP FAILING IRP %ls Flags 0x%08x vpb 0x%08x NTSTATUS 0x%08x\n", TCTranslateCode (irpSp->MajorFunction),
781: (ULONG) DeviceObject->Flags, (ULONG) DeviceObject->Vpb->Flags, IrpStatus);
782: }
783: else
784: {
785: PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
786: Dump ("COMPLETE_IRP SUCCESS IRP %ls Flags 0x%08x vpb 0x%08x NTSTATUS 0x%08x\n", TCTranslateCode (irpSp->MajorFunction),
787: (ULONG) DeviceObject->Flags, (ULONG) DeviceObject->Vpb->Flags, IrpStatus);
788: }
1.1 root 789: #endif
790: IoCompleteRequest (Irp, IO_NO_INCREMENT);
791: return IrpStatus;
792: }
1.1.1.4 root 793:
794: // Restores the container timestamp to preserve plausible deniability of possible hidden volume.
795: static void RestoreTimeStamp (PEXTENSION Extension)
796: {
797: NTSTATUS ntStatus;
798: FILE_BASIC_INFORMATION FileBasicInfo;
799: IO_STATUS_BLOCK IoStatusBlock;
800:
1.1.1.6 root 801: if (Extension->hDeviceFile != NULL
802: && Extension->bRawDevice == FALSE
803: && Extension->bReadOnly == FALSE
804: && Extension->bTimeStampValid)
1.1.1.4 root 805: {
806: ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
807: &IoStatusBlock,
808: &FileBasicInfo,
809: sizeof (FileBasicInfo),
810: FileBasicInformation);
811:
812: if (!NT_SUCCESS (ntStatus))
813: {
814: Dump ("ZwQueryInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n",
815: ntStatus);
816: }
817: else
818: {
819: FileBasicInfo.CreationTime = Extension->fileCreationTime;
820: FileBasicInfo.LastAccessTime = Extension->fileLastAccessTime;
821: FileBasicInfo.LastWriteTime = Extension->fileLastWriteTime;
822: FileBasicInfo.ChangeTime = Extension->fileLastChangeTime;
823:
824: ntStatus = ZwSetInformationFile(
825: Extension->hDeviceFile,
826: &IoStatusBlock,
827: &FileBasicInfo,
828: sizeof (FileBasicInfo),
829: FileBasicInformation);
830:
831: if (!NT_SUCCESS (ntStatus))
832: Dump ("ZwSetInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n",ntStatus);
833: }
834: }
835: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.