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