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