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