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