From fc37cc4a02ed13d1a73b941a9f80975600fd1b99 Mon Sep 17 00:00:00 2001 From: David Foerster Date: Tue, 10 May 2016 20:20:14 +0200 Subject: Normalize all line terminators --- src/Driver/Ntdriver.c | 7126 ++++++++++++++++++++++++------------------------- 1 file changed, 3563 insertions(+), 3563 deletions(-) (limited to 'src/Driver/Ntdriver.c') diff --git a/src/Driver/Ntdriver.c b/src/Driver/Ntdriver.c index eeea7815..c771b3ce 100644 --- a/src/Driver/Ntdriver.c +++ b/src/Driver/Ntdriver.c @@ -1,3563 +1,3563 @@ -/* - Legal Notice: Some portions of the source code contained in this file were - derived from the source code of TrueCrypt 7.1a, which is - Copyright (c) 2003-2012 TrueCrypt Developers Association and which is - governed by the TrueCrypt License 3.0, also from the source code of - Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux - and which is governed by the 'License Agreement for Encryption for the Masses' - Modifications and additions to the original source code (contained in this file) - and all other portions of this file are Copyright (c) 2013-2016 IDRIX - and are governed by the Apache License 2.0 the full text of which is - contained in the file License.txt included in VeraCrypt binary and source - code distribution packages. */ - -#include "TCdefs.h" -#include -#include "Crypto.h" -#include "Fat.h" -#include "Tests.h" -#include "cpu.h" - -#include "Apidrvr.h" -#include "Boot/Windows/BootDefs.h" -#include "EncryptedIoQueue.h" -#include "EncryptionThreadPool.h" -#include "Ntdriver.h" -#include "Ntvol.h" -#include "DriveFilter.h" -#include "DumpFilter.h" -#include "Cache.h" -#include "Volumes.h" -#include "VolumeFilter.h" - -#include -#include -#include -#include -#include - -#include -#include - -/* Init section, which is thrown away as soon as DriverEntry returns */ -#pragma alloc_text(INIT,DriverEntry) -#pragma alloc_text(INIT,TCCreateRootDeviceObject) - -PDRIVER_OBJECT TCDriverObject; -PDEVICE_OBJECT RootDeviceObject = NULL; -static KMUTEX RootDeviceControlMutex; -BOOL DriverShuttingDown = FALSE; -BOOL SelfTestsPassed; -int LastUniqueVolumeId; -ULONG OsMajorVersion = 0; -ULONG OsMinorVersion; -BOOL DriverUnloadDisabled = FALSE; -BOOL PortableMode = FALSE; -BOOL VolumeClassFilterRegistered = FALSE; -BOOL CacheBootPassword = FALSE; -BOOL CacheBootPim = FALSE; -BOOL NonAdminSystemFavoritesAccessDisabled = FALSE; -static size_t EncryptionThreadPoolFreeCpuCountLimit = 0; -static BOOL SystemFavoriteVolumeDirty = FALSE; -static BOOL PagingFileCreationPrevented = FALSE; -static BOOL EnableExtendedIoctlSupport = FALSE; - -PDEVICE_OBJECT VirtualVolumeDeviceObjects[MAX_MOUNTED_VOLUME_DRIVE_NUMBER + 1]; - - -NTSTATUS DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) -{ - PKEY_VALUE_PARTIAL_INFORMATION startKeyValue; - LONG version; - int i; - - Dump ("DriverEntry " TC_APP_NAME " " VERSION_STRING "\n"); - - DetectX86Features (); - - PsGetVersion (&OsMajorVersion, &OsMinorVersion, NULL, NULL); - - // Load dump filter if the main driver is already loaded - if (NT_SUCCESS (TCDeviceIoControl (NT_ROOT_PREFIX, TC_IOCTL_GET_DRIVER_VERSION, NULL, 0, &version, sizeof (version)))) - return DumpFilterEntry ((PFILTER_EXTENSION) DriverObject, (PFILTER_INITIALIZATION_DATA) RegistryPath); - - TCDriverObject = DriverObject; - memset (VirtualVolumeDeviceObjects, 0, sizeof (VirtualVolumeDeviceObjects)); - - ReadRegistryConfigFlags (TRUE); - EncryptionThreadPoolStart (EncryptionThreadPoolFreeCpuCountLimit); - SelfTestsPassed = AutoTestAlgorithms(); - - // Enable device class filters and load boot arguments if the driver is set to start at system boot - - if (NT_SUCCESS (TCReadRegistryKey (RegistryPath, L"Start", &startKeyValue))) - { - if (startKeyValue->Type == REG_DWORD && *((uint32 *) startKeyValue->Data) == SERVICE_BOOT_START) - { - if (!SelfTestsPassed) - TC_BUG_CHECK (STATUS_INVALID_PARAMETER); - - LoadBootArguments(); - VolumeClassFilterRegistered = IsVolumeClassFilterRegistered(); - - DriverObject->DriverExtension->AddDevice = DriverAddDevice; - } - - TCfree (startKeyValue); - } - - for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i) - { - DriverObject->MajorFunction[i] = TCDispatchQueueIRP; - } - - DriverObject->DriverUnload = TCUnloadDriver; - return TCCreateRootDeviceObject (DriverObject); -} - - -NTSTATUS DriverAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo) -{ -#ifdef DEBUG - char nameInfoBuffer[128]; - POBJECT_NAME_INFORMATION nameInfo = (POBJECT_NAME_INFORMATION) nameInfoBuffer; - ULONG nameInfoSize; - Dump ("AddDevice pdo=%p type=%x name=%ws\n", pdo, pdo->DeviceType, NT_SUCCESS (ObQueryNameString (pdo, nameInfo, sizeof (nameInfoBuffer), &nameInfoSize)) ? nameInfo->Name.Buffer : L"?"); -#endif - - if (VolumeClassFilterRegistered && BootArgsValid && BootArgs.HiddenSystemPartitionStart != 0) - { - PWSTR interfaceLinks = NULL; - if (NT_SUCCESS (IoGetDeviceInterfaces (&GUID_DEVINTERFACE_VOLUME, pdo, DEVICE_INTERFACE_INCLUDE_NONACTIVE, &interfaceLinks)) && interfaceLinks) - { - if (interfaceLinks[0] != UNICODE_NULL) - { - Dump ("Volume pdo=%p interface=%ws\n", pdo, interfaceLinks); - ExFreePool (interfaceLinks); - - return VolumeFilterAddDevice (driverObject, pdo); - } - - ExFreePool (interfaceLinks); - } - } - - return DriveFilterAddDevice (driverObject, pdo); -} - - -// Dumps a memory region to debug output -void DumpMemory (void *mem, int size) -{ - unsigned char str[20]; - unsigned char *m = mem; - int i,j; - - for (j = 0; j < size / 8; j++) - { - memset (str,0,sizeof str); - for (i = 0; i < 8; i++) - { - if (m[i] > ' ' && m[i] <= '~') - str[i]=m[i]; - else - str[i]='.'; - } - - Dump ("0x%08p %02x %02x %02x %02x %02x %02x %02x %02x %s\n", - m, m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], str); - - m+=8; - } -} - - -BOOL ValidateIOBufferSize (PIRP irp, size_t requiredBufferSize, ValidateIOBufferSizeType type) -{ - PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp); - BOOL input = (type == ValidateInput || type == ValidateInputOutput); - BOOL output = (type == ValidateOutput || type == ValidateInputOutput); - - if ((input && irpSp->Parameters.DeviceIoControl.InputBufferLength < requiredBufferSize) - || (output && irpSp->Parameters.DeviceIoControl.OutputBufferLength < requiredBufferSize)) - { - Dump ("STATUS_BUFFER_TOO_SMALL ioctl=0x%x,%d in=%d out=%d reqsize=%d insize=%d outsize=%d\n", (int) (irpSp->Parameters.DeviceIoControl.IoControlCode >> 16), (int) ((irpSp->Parameters.DeviceIoControl.IoControlCode & 0x1FFF) >> 2), input, output, requiredBufferSize, irpSp->Parameters.DeviceIoControl.InputBufferLength, irpSp->Parameters.DeviceIoControl.OutputBufferLength); - - irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; - irp->IoStatus.Information = 0; - return FALSE; - } - - if (!input && output) - memset (irp->AssociatedIrp.SystemBuffer, 0, irpSp->Parameters.DeviceIoControl.OutputBufferLength); - - return TRUE; -} - - -PDEVICE_OBJECT GetVirtualVolumeDeviceObject (int driveNumber) -{ - if (driveNumber < MIN_MOUNTED_VOLUME_DRIVE_NUMBER || driveNumber > MAX_MOUNTED_VOLUME_DRIVE_NUMBER) - return NULL; - - return VirtualVolumeDeviceObjects[driveNumber]; -} - - -/* TCDispatchQueueIRP queues any IRP's so that they can be processed later - by the thread -- or in some cases handles them immediately! */ -NTSTATUS TCDispatchQueueIRP (PDEVICE_OBJECT DeviceObject, PIRP Irp) -{ - PEXTENSION Extension = (PEXTENSION) DeviceObject->DeviceExtension; - PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp); - NTSTATUS ntStatus; - -#ifdef _DEBUG - if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL && (Extension->bRootDevice || Extension->IsVolumeDevice)) - { - switch (irpSp->Parameters.DeviceIoControl.IoControlCode) - { - case TC_IOCTL_GET_MOUNTED_VOLUMES: - case TC_IOCTL_GET_PASSWORD_CACHE_STATUS: - case TC_IOCTL_GET_PORTABLE_MODE_STATUS: - case TC_IOCTL_SET_PORTABLE_MODE_STATUS: - case TC_IOCTL_OPEN_TEST: - case TC_IOCTL_GET_RESOLVED_SYMLINK: - case TC_IOCTL_GET_DEVICE_REFCOUNT: - case TC_IOCTL_GET_DRIVE_PARTITION_INFO: - case TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES: - case TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS: - case TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS: - case TC_IOCTL_GET_WARNING_FLAGS: - case TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING: - case IOCTL_DISK_CHECK_VERIFY: - break; - - default: - Dump ("%ls (0x%x %d)\n", - TCTranslateCode (irpSp->Parameters.DeviceIoControl.IoControlCode), - (int) (irpSp->Parameters.DeviceIoControl.IoControlCode >> 16), - (int) ((irpSp->Parameters.DeviceIoControl.IoControlCode & 0x1FFF) >> 2)); - } - } -#endif - - if (!Extension->bRootDevice) - { - // Drive filter IRP - if (Extension->IsDriveFilterDevice) - return DriveFilterDispatchIrp (DeviceObject, Irp); - - // Volume filter IRP - if (Extension->IsVolumeFilterDevice) - return VolumeFilterDispatchIrp (DeviceObject, Irp); - } - - switch (irpSp->MajorFunction) - { - case IRP_MJ_CLOSE: - case IRP_MJ_CREATE: - case IRP_MJ_CLEANUP: - return COMPLETE_IRP (DeviceObject, Irp, STATUS_SUCCESS, 0); - - case IRP_MJ_SHUTDOWN: - if (Extension->bRootDevice) - { - Dump ("Driver shutting down\n"); - DriverShuttingDown = TRUE; - - if (EncryptionSetupThread) - while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES); - - if (DecoySystemWipeThread) - while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES); - - OnShutdownPending(); - } - - return COMPLETE_IRP (DeviceObject, Irp, STATUS_SUCCESS, 0); - - case IRP_MJ_FLUSH_BUFFERS: - case IRP_MJ_READ: - case IRP_MJ_WRITE: - case IRP_MJ_DEVICE_CONTROL: - - if (Extension->bRootDevice) - { - if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) - { - NTSTATUS status = KeWaitForMutexObject (&RootDeviceControlMutex, Executive, KernelMode, FALSE, NULL); - if (!NT_SUCCESS (status)) - return status; - - status = ProcessMainDeviceControlIrp (DeviceObject, Extension, Irp); - - KeReleaseMutex (&RootDeviceControlMutex, FALSE); - return status; - } - break; - } - - if (Extension->bShuttingDown) - { - Dump ("Device %d shutting down: STATUS_DELETE_PENDING\n", Extension->nDosDriveNo); - return TCCompleteDiskIrp (Irp, STATUS_DELETE_PENDING, 0); - } - - if (Extension->bRemovable - && (DeviceObject->Flags & DO_VERIFY_VOLUME) - && !(irpSp->Flags & SL_OVERRIDE_VERIFY_VOLUME) - && irpSp->MajorFunction != IRP_MJ_FLUSH_BUFFERS) - { - Dump ("Removable device %d has DO_VERIFY_VOLUME flag: STATUS_DEVICE_NOT_READY\n", Extension->nDosDriveNo); - return TCCompleteDiskIrp (Irp, STATUS_DEVICE_NOT_READY, 0); - } - - switch (irpSp->MajorFunction) - { - case IRP_MJ_READ: - case IRP_MJ_WRITE: - ntStatus = EncryptedIoQueueAddIrp (&Extension->Queue, Irp); - - if (ntStatus != STATUS_PENDING) - TCCompleteDiskIrp (Irp, ntStatus, 0); - - return ntStatus; - - case IRP_MJ_DEVICE_CONTROL: - ntStatus = IoAcquireRemoveLock (&Extension->Queue.RemoveLock, Irp); - if (!NT_SUCCESS (ntStatus)) - return TCCompleteIrp (Irp, ntStatus, 0); - - IoMarkIrpPending (Irp); - - ExInterlockedInsertTailList (&Extension->ListEntry, &Irp->Tail.Overlay.ListEntry, &Extension->ListSpinLock); - KeReleaseSemaphore (&Extension->RequestSemaphore, IO_DISK_INCREMENT, 1, FALSE); - - return STATUS_PENDING; - - case IRP_MJ_FLUSH_BUFFERS: - return TCCompleteDiskIrp (Irp, STATUS_SUCCESS, 0); - } - - break; - - case IRP_MJ_PNP: - if (!Extension->bRootDevice - && Extension->IsVolumeDevice - && irpSp->MinorFunction == IRP_MN_DEVICE_USAGE_NOTIFICATION - && irpSp->Parameters.UsageNotification.Type == DeviceUsageTypePaging - && irpSp->Parameters.UsageNotification.InPath) - { - PagingFileCreationPrevented = TRUE; - return TCCompleteIrp (Irp, STATUS_UNSUCCESSFUL, 0); - } - break; - } - - return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0); -} - -NTSTATUS TCCreateRootDeviceObject (PDRIVER_OBJECT DriverObject) -{ - UNICODE_STRING Win32NameString, ntUnicodeString; - WCHAR dosname[32], ntname[32]; - PDEVICE_OBJECT DeviceObject; - NTSTATUS ntStatus; - BOOL *bRootExtension; - - Dump ("TCCreateRootDeviceObject BEGIN\n"); - ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); - - RtlStringCbCopyW (dosname, sizeof(dosname),(LPWSTR) DOS_ROOT_PREFIX); - RtlStringCbCopyW (ntname, sizeof(ntname),(LPWSTR) NT_ROOT_PREFIX); - RtlInitUnicodeString (&ntUnicodeString, ntname); - RtlInitUnicodeString (&Win32NameString, dosname); - - Dump ("Creating root device nt=%ls dos=%ls\n", ntname, dosname); - - ntStatus = IoCreateDevice ( - DriverObject, - sizeof (BOOL), - &ntUnicodeString, - FILE_DEVICE_UNKNOWN, - FILE_DEVICE_SECURE_OPEN, - FALSE, - &DeviceObject); - - if (!NT_SUCCESS (ntStatus)) - { - Dump ("TCCreateRootDeviceObject NTSTATUS = 0x%08x END\n", ntStatus); - return ntStatus;/* Failed to create DeviceObject */ - } - - DeviceObject->Flags |= DO_DIRECT_IO; - DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; - - /* Setup the device extension */ - bRootExtension = (BOOL *) DeviceObject->DeviceExtension; - *bRootExtension = TRUE; - - KeInitializeMutex (&RootDeviceControlMutex, 0); - - ntStatus = IoCreateSymbolicLink (&Win32NameString, &ntUnicodeString); - - if (!NT_SUCCESS (ntStatus)) - { - Dump ("TCCreateRootDeviceObject NTSTATUS = 0x%08x END\n", ntStatus); - IoDeleteDevice (DeviceObject); - return ntStatus; - } - - IoRegisterShutdownNotification (DeviceObject); - RootDeviceObject = DeviceObject; - - Dump ("TCCreateRootDeviceObject STATUS_SUCCESS END\n"); - return STATUS_SUCCESS; -} - -NTSTATUS TCCreateDeviceObject (PDRIVER_OBJECT DriverObject, - PDEVICE_OBJECT * ppDeviceObject, - MOUNT_STRUCT * mount) -{ - UNICODE_STRING ntUnicodeString; - WCHAR ntname[32]; - PEXTENSION Extension; - NTSTATUS ntStatus; - ULONG devChars = 0; -#if defined (DEBUG) - WCHAR dosname[32]; -#endif - - Dump ("TCCreateDeviceObject BEGIN\n"); - ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); - - TCGetNTNameFromNumber (ntname, sizeof(ntname),mount->nDosDriveNo); - RtlInitUnicodeString (&ntUnicodeString, ntname); -#if defined (DEBUG) - TCGetDosNameFromNumber (dosname, sizeof(dosname),mount->nDosDriveNo, DeviceNamespaceDefault); -#endif - - devChars = FILE_DEVICE_SECURE_OPEN; - devChars |= mount->bMountReadOnly ? FILE_READ_ONLY_DEVICE : 0; - devChars |= mount->bMountRemovable ? FILE_REMOVABLE_MEDIA : 0; - - Dump ("Creating device nt=%ls dos=%ls\n", ntname, dosname); - - ntStatus = IoCreateDevice ( - DriverObject, /* Our Driver Object */ - sizeof (EXTENSION), /* Size of state information */ - &ntUnicodeString, /* Device name "\Device\Name" */ - FILE_DEVICE_DISK, /* Device type */ - devChars, /* Device characteristics */ - FALSE, /* Exclusive device */ - ppDeviceObject); /* Returned ptr to Device Object */ - - if (!NT_SUCCESS (ntStatus)) - { - Dump ("TCCreateDeviceObject NTSTATUS = 0x%08x END\n", ntStatus); - return ntStatus;/* Failed to create DeviceObject */ - } - /* Initialize device object and extension. */ - - (*ppDeviceObject)->Flags |= DO_DIRECT_IO; - (*ppDeviceObject)->StackSize += 6; // Reduce occurrence of NO_MORE_IRP_STACK_LOCATIONS bug check caused by buggy drivers - - /* Setup the device extension */ - Extension = (PEXTENSION) (*ppDeviceObject)->DeviceExtension; - memset (Extension, 0, sizeof (EXTENSION)); - - Extension->IsVolumeDevice = TRUE; - Extension->nDosDriveNo = mount->nDosDriveNo; - Extension->bRemovable = mount->bMountRemovable; - Extension->PartitionInInactiveSysEncScope = mount->bPartitionInInactiveSysEncScope; - Extension->SystemFavorite = mount->SystemFavorite; - - KeInitializeEvent (&Extension->keCreateEvent, SynchronizationEvent, FALSE); - KeInitializeSemaphore (&Extension->RequestSemaphore, 0L, MAXLONG); - KeInitializeSpinLock (&Extension->ListSpinLock); - InitializeListHead (&Extension->ListEntry); - IoInitializeRemoveLock (&Extension->Queue.RemoveLock, 'LRCV', 0, 0); - - VirtualVolumeDeviceObjects[mount->nDosDriveNo] = *ppDeviceObject; - - Dump ("TCCreateDeviceObject STATUS_SUCCESS END\n"); - - return STATUS_SUCCESS; -} - - -BOOL RootDeviceControlMutexAcquireNoWait () -{ - NTSTATUS status; - LARGE_INTEGER timeout; - timeout.QuadPart = 0; - - status = KeWaitForMutexObject (&RootDeviceControlMutex, Executive, KernelMode, FALSE, &timeout); - return NT_SUCCESS (status) && status != STATUS_TIMEOUT; -} - - -void RootDeviceControlMutexRelease () -{ - KeReleaseMutex (&RootDeviceControlMutex, FALSE); -} - - -NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, PIRP Irp) -{ - PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp); - - switch (irpSp->Parameters.DeviceIoControl.IoControlCode) - { - - case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: - if (!ValidateIOBufferSize (Irp, sizeof (MOUNTDEV_NAME), ValidateOutput)) - { - Irp->IoStatus.Information = sizeof (MOUNTDEV_NAME); - Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; - } - else - { - ULONG outLength; - UNICODE_STRING ntUnicodeString; - WCHAR ntName[256]; - PMOUNTDEV_NAME outputBuffer = (PMOUNTDEV_NAME) Irp->AssociatedIrp.SystemBuffer; - - TCGetNTNameFromNumber (ntName, sizeof(ntName),Extension->nDosDriveNo); - RtlInitUnicodeString (&ntUnicodeString, ntName); - - outputBuffer->NameLength = ntUnicodeString.Length; - outLength = ntUnicodeString.Length + sizeof(USHORT); - - if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength) - { - Irp->IoStatus.Information = sizeof (MOUNTDEV_NAME); - Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; - - break; - } - - RtlCopyMemory ((PCHAR)outputBuffer->Name,ntUnicodeString.Buffer, ntUnicodeString.Length); - - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = outLength; - - Dump ("name = %ls\n",ntName); - } - break; - - case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: - if (!ValidateIOBufferSize (Irp, sizeof (MOUNTDEV_UNIQUE_ID), ValidateOutput)) - { - Irp->IoStatus.Information = sizeof (MOUNTDEV_UNIQUE_ID); - Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; - } - else - { - ULONG outLength; - UCHAR volId[128], tmp[] = { 0,0 }; - PMOUNTDEV_UNIQUE_ID outputBuffer = (PMOUNTDEV_UNIQUE_ID) Irp->AssociatedIrp.SystemBuffer; - - RtlStringCbCopyA (volId, sizeof(volId),TC_UNIQUE_ID_PREFIX); - tmp[0] = 'A' + (UCHAR) Extension->nDosDriveNo; - RtlStringCbCatA (volId, sizeof(volId),tmp); - - outputBuffer->UniqueIdLength = (USHORT) strlen (volId); - outLength = (ULONG) (strlen (volId) + sizeof (USHORT)); - - if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength) - { - Irp->IoStatus.Information = sizeof (MOUNTDEV_UNIQUE_ID); - Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; - break; - } - - RtlCopyMemory ((PCHAR)outputBuffer->UniqueId, volId, strlen (volId)); - - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = outLength; - - Dump ("id = %s\n",volId); - } - break; - - case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME: - { - ULONG outLength; - UNICODE_STRING ntUnicodeString; - WCHAR ntName[256]; - PMOUNTDEV_SUGGESTED_LINK_NAME outputBuffer = (PMOUNTDEV_SUGGESTED_LINK_NAME) Irp->AssociatedIrp.SystemBuffer; - - if (!ValidateIOBufferSize (Irp, sizeof (MOUNTDEV_SUGGESTED_LINK_NAME), ValidateOutput)) - { - Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; - Irp->IoStatus.Information = 0; - break; - } - - TCGetDosNameFromNumber (ntName, sizeof(ntName),Extension->nDosDriveNo, DeviceNamespaceDefault); - RtlInitUnicodeString (&ntUnicodeString, ntName); - - outLength = FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME,Name) + ntUnicodeString.Length; - - outputBuffer->UseOnlyIfThereAreNoOtherLinks = FALSE; - outputBuffer->NameLength = ntUnicodeString.Length; - - if(irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength) - { - Irp->IoStatus.Information = sizeof (MOUNTDEV_SUGGESTED_LINK_NAME); - Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; - break; - } - - RtlCopyMemory ((PCHAR)outputBuffer->Name,ntUnicodeString.Buffer, ntUnicodeString.Length); - - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = outLength; - - Dump ("link = %ls\n",ntName); - } - break; - - case IOCTL_DISK_GET_MEDIA_TYPES: - case IOCTL_DISK_GET_DRIVE_GEOMETRY: - /* Return the drive geometry for the disk. Note that we - return values which were made up to suit the disk size. */ - if (ValidateIOBufferSize (Irp, sizeof (DISK_GEOMETRY), ValidateOutput)) - { - PDISK_GEOMETRY outputBuffer = (PDISK_GEOMETRY) - Irp->AssociatedIrp.SystemBuffer; - - outputBuffer->MediaType = Extension->bRemovable ? RemovableMedia : FixedMedia; - outputBuffer->Cylinders.QuadPart = Extension->NumberOfCylinders; - outputBuffer->TracksPerCylinder = Extension->TracksPerCylinder; - outputBuffer->SectorsPerTrack = Extension->SectorsPerTrack; - outputBuffer->BytesPerSector = Extension->BytesPerSector; - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = sizeof (DISK_GEOMETRY); - } - break; - - case IOCTL_STORAGE_QUERY_PROPERTY: - if (EnableExtendedIoctlSupport) - { - if (ValidateIOBufferSize (Irp, sizeof (STORAGE_PROPERTY_QUERY), ValidateInput)) - { - PSTORAGE_PROPERTY_QUERY pStoragePropQuery = (PSTORAGE_PROPERTY_QUERY) Irp->AssociatedIrp.SystemBuffer; - STORAGE_QUERY_TYPE type = pStoragePropQuery->QueryType; - - /* return error if an unsupported type is encountered */ - Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; - Irp->IoStatus.Information = 0; - - if ( (pStoragePropQuery->PropertyId == StorageAccessAlignmentProperty) - || (pStoragePropQuery->PropertyId == StorageDeviceProperty) - ) - { - if (type == PropertyExistsQuery) - { - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = 0; - } - else if (type == PropertyStandardQuery) - { - switch (pStoragePropQuery->PropertyId) - { - case StorageDeviceProperty: - { - if (ValidateIOBufferSize (Irp, sizeof (STORAGE_DEVICE_DESCRIPTOR), ValidateOutput)) - { - PSTORAGE_DEVICE_DESCRIPTOR outputBuffer = (PSTORAGE_DEVICE_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer; - - outputBuffer->Version = sizeof(STORAGE_DEVICE_DESCRIPTOR); - outputBuffer->Size = sizeof(STORAGE_DEVICE_DESCRIPTOR); - outputBuffer->DeviceType = FILE_DEVICE_DISK; - outputBuffer->RemovableMedia = Extension->bRemovable? TRUE : FALSE; - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = sizeof (STORAGE_DEVICE_DESCRIPTOR); - } - } - break; - case StorageAccessAlignmentProperty: - { - if (ValidateIOBufferSize (Irp, sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR), ValidateOutput)) - { - PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR outputBuffer = (PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer; - - outputBuffer->Version = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR); - outputBuffer->Size = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR); - outputBuffer->BytesPerLogicalSector = Extension->BytesPerSector; - outputBuffer->BytesPerPhysicalSector = Extension->HostBytesPerPhysicalSector; - outputBuffer->BytesOffsetForSectorAlignment = Extension->BytesOffsetForSectorAlignment; - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR); - } - } - break; - } - } - } - } - } - else - return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0); - - break; - - case IOCTL_DISK_GET_PARTITION_INFO: - if (ValidateIOBufferSize (Irp, sizeof (PARTITION_INFORMATION), ValidateOutput)) - { - PPARTITION_INFORMATION outputBuffer = (PPARTITION_INFORMATION) - Irp->AssociatedIrp.SystemBuffer; - - outputBuffer->PartitionType = Extension->PartitionType; - outputBuffer->BootIndicator = FALSE; - outputBuffer->RecognizedPartition = TRUE; - outputBuffer->RewritePartition = FALSE; - outputBuffer->StartingOffset.QuadPart = Extension->BytesPerSector; - outputBuffer->PartitionLength.QuadPart= Extension->DiskLength; - outputBuffer->HiddenSectors = 0; - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = sizeof (PARTITION_INFORMATION); - } - break; - - case IOCTL_DISK_GET_PARTITION_INFO_EX: - if (ValidateIOBufferSize (Irp, sizeof (PARTITION_INFORMATION_EX), ValidateOutput)) - { - PPARTITION_INFORMATION_EX outputBuffer = (PPARTITION_INFORMATION_EX) Irp->AssociatedIrp.SystemBuffer; - - outputBuffer->PartitionStyle = PARTITION_STYLE_MBR; - outputBuffer->RewritePartition = FALSE; - outputBuffer->StartingOffset.QuadPart = Extension->BytesPerSector; - outputBuffer->PartitionLength.QuadPart= Extension->DiskLength; - outputBuffer->Mbr.PartitionType = Extension->PartitionType; - outputBuffer->Mbr.BootIndicator = FALSE; - outputBuffer->Mbr.RecognizedPartition = TRUE; - outputBuffer->Mbr.HiddenSectors = 0; - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = sizeof (PARTITION_INFORMATION_EX); - } - break; - - case IOCTL_DISK_GET_DRIVE_LAYOUT: - if (ValidateIOBufferSize (Irp, sizeof (DRIVE_LAYOUT_INFORMATION), ValidateOutput)) - { - PDRIVE_LAYOUT_INFORMATION outputBuffer = (PDRIVE_LAYOUT_INFORMATION) - Irp->AssociatedIrp.SystemBuffer; - - outputBuffer->PartitionCount = 1; - outputBuffer->Signature = 0; - - outputBuffer->PartitionEntry->PartitionType = Extension->PartitionType; - outputBuffer->PartitionEntry->BootIndicator = FALSE; - outputBuffer->PartitionEntry->RecognizedPartition = TRUE; - outputBuffer->PartitionEntry->RewritePartition = FALSE; - outputBuffer->PartitionEntry->StartingOffset.QuadPart = Extension->BytesPerSector; - outputBuffer->PartitionEntry->PartitionLength.QuadPart = Extension->DiskLength; - outputBuffer->PartitionEntry->HiddenSectors = 0; - - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = sizeof (PARTITION_INFORMATION); - } - break; - - case IOCTL_DISK_GET_LENGTH_INFO: - if (!ValidateIOBufferSize (Irp, sizeof (GET_LENGTH_INFORMATION), ValidateOutput)) - { - Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; - Irp->IoStatus.Information = sizeof (GET_LENGTH_INFORMATION); - } - else - { - PGET_LENGTH_INFORMATION outputBuffer = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer; - - outputBuffer->Length.QuadPart = Extension->DiskLength; - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = sizeof (GET_LENGTH_INFORMATION); - } - break; - - case IOCTL_DISK_VERIFY: - if (ValidateIOBufferSize (Irp, sizeof (VERIFY_INFORMATION), ValidateInput)) - { - HRESULT hResult; - ULONGLONG ullStartingOffset, ullNewOffset, ullEndOffset; - PVERIFY_INFORMATION pVerifyInformation; - pVerifyInformation = (PVERIFY_INFORMATION) Irp->AssociatedIrp.SystemBuffer; - - ullStartingOffset = (ULONGLONG) pVerifyInformation->StartingOffset.QuadPart; - hResult = ULongLongAdd(ullStartingOffset, - (ULONGLONG) Extension->cryptoInfo->hiddenVolume ? Extension->cryptoInfo->hiddenVolumeOffset : Extension->cryptoInfo->volDataAreaOffset, - &ullNewOffset); - if (hResult != S_OK) - Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; - else if (S_OK != ULongLongAdd(ullStartingOffset, (ULONGLONG) pVerifyInformation->Length, &ullEndOffset)) - Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; - else if (ullEndOffset > (ULONGLONG) Extension->DiskLength) - Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; - else - { - IO_STATUS_BLOCK ioStatus; - PVOID buffer = TCalloc (max (pVerifyInformation->Length, PAGE_SIZE)); - - if (!buffer) - { - Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; - } - else - { - LARGE_INTEGER offset = pVerifyInformation->StartingOffset; - offset.QuadPart = ullNewOffset; - - Irp->IoStatus.Status = ZwReadFile (Extension->hDeviceFile, NULL, NULL, NULL, &ioStatus, buffer, pVerifyInformation->Length, &offset, NULL); - TCfree (buffer); - - if (NT_SUCCESS (Irp->IoStatus.Status) && ioStatus.Information != pVerifyInformation->Length) - Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; - } - } - - Irp->IoStatus.Information = 0; - } - break; - - case IOCTL_DISK_CHECK_VERIFY: - case IOCTL_STORAGE_CHECK_VERIFY: - { - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = 0; - - if (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof (ULONG)) - { - *((ULONG *) Irp->AssociatedIrp.SystemBuffer) = 0; - Irp->IoStatus.Information = sizeof (ULONG); - } - } - break; - - case IOCTL_DISK_IS_WRITABLE: - { - if (Extension->bReadOnly) - Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED; - else - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = 0; - - } - break; - - case IOCTL_VOLUME_ONLINE: - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = 0; - break; - - case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS: - - // Vista's filesystem defragmenter fails if IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS does not succeed. - if (!(OsMajorVersion == 6 && OsMinorVersion == 0)) - { - Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; - Irp->IoStatus.Information = 0; - } - else if (ValidateIOBufferSize (Irp, sizeof (VOLUME_DISK_EXTENTS), ValidateOutput)) - { - VOLUME_DISK_EXTENTS *extents = (VOLUME_DISK_EXTENTS *) Irp->AssociatedIrp.SystemBuffer; - - // No extent data can be returned as this is not a physical drive. - memset (extents, 0, sizeof (*extents)); - extents->NumberOfDiskExtents = 0; - - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = sizeof (*extents); - } - break; - - default: - return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0); - } - -#ifdef DEBUG - if (!NT_SUCCESS (Irp->IoStatus.Status)) - { - Dump ("IOCTL error 0x%08x (0x%x %d)\n", - Irp->IoStatus.Status, - (int) (irpSp->Parameters.DeviceIoControl.IoControlCode >> 16), - (int) ((irpSp->Parameters.DeviceIoControl.IoControlCode & 0x1FFF) >> 2)); - } -#endif - - return TCCompleteDiskIrp (Irp, Irp->IoStatus.Status, Irp->IoStatus.Information); -} - - -NTSTATUS ProcessMainDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, PIRP Irp) -{ - PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp); - NTSTATUS ntStatus; - - switch (irpSp->Parameters.DeviceIoControl.IoControlCode) - { - case TC_IOCTL_GET_DRIVER_VERSION: - case TC_IOCTL_LEGACY_GET_DRIVER_VERSION: - if (ValidateIOBufferSize (Irp, sizeof (LONG), ValidateOutput)) - { - LONG tmp = VERSION_NUM; - memcpy (Irp->AssociatedIrp.SystemBuffer, &tmp, 4); - Irp->IoStatus.Information = sizeof (LONG); - Irp->IoStatus.Status = STATUS_SUCCESS; - } - break; - - case TC_IOCTL_GET_DEVICE_REFCOUNT: - if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput)) - { - *(int *) Irp->AssociatedIrp.SystemBuffer = DeviceObject->ReferenceCount; - Irp->IoStatus.Information = sizeof (int); - Irp->IoStatus.Status = STATUS_SUCCESS; - } - break; - - case TC_IOCTL_IS_DRIVER_UNLOAD_DISABLED: - if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput)) - { - LONG deviceObjectCount = 0; - - *(int *) Irp->AssociatedIrp.SystemBuffer = DriverUnloadDisabled; - - if (IoEnumerateDeviceObjectList (TCDriverObject, NULL, 0, &deviceObjectCount) == STATUS_BUFFER_TOO_SMALL && deviceObjectCount > 1) - *(int *) Irp->AssociatedIrp.SystemBuffer = TRUE; - - Irp->IoStatus.Information = sizeof (int); - Irp->IoStatus.Status = STATUS_SUCCESS; - } - break; - - case TC_IOCTL_IS_ANY_VOLUME_MOUNTED: - if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput)) - { - int drive; - *(int *) Irp->AssociatedIrp.SystemBuffer = 0; - - for (drive = MIN_MOUNTED_VOLUME_DRIVE_NUMBER; drive <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; ++drive) - { - if (GetVirtualVolumeDeviceObject (drive)) - { - *(int *) Irp->AssociatedIrp.SystemBuffer = 1; - break; - } - } - - if (IsBootDriveMounted()) - *(int *) Irp->AssociatedIrp.SystemBuffer = 1; - - Irp->IoStatus.Information = sizeof (int); - Irp->IoStatus.Status = STATUS_SUCCESS; - } - break; - - case TC_IOCTL_OPEN_TEST: - { - OPEN_TEST_STRUCT *opentest = (OPEN_TEST_STRUCT *) Irp->AssociatedIrp.SystemBuffer; - OBJECT_ATTRIBUTES ObjectAttributes; - HANDLE NtFileHandle; - UNICODE_STRING FullFileName; - IO_STATUS_BLOCK IoStatus; - LARGE_INTEGER offset; - ACCESS_MASK access = FILE_READ_ATTRIBUTES; - - if (!ValidateIOBufferSize (Irp, sizeof (OPEN_TEST_STRUCT), ValidateInputOutput)) - break; - - EnsureNullTerminatedString (opentest->wszFileName, sizeof (opentest->wszFileName)); - RtlInitUnicodeString (&FullFileName, opentest->wszFileName); - - InitializeObjectAttributes (&ObjectAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); - - if (opentest->bDetectTCBootLoader || opentest->DetectFilesystem || opentest->bMatchVolumeID) - access |= FILE_READ_DATA; - - ntStatus = ZwCreateFile (&NtFileHandle, - SYNCHRONIZE | access, &ObjectAttributes, &IoStatus, NULL, - 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); - - if (NT_SUCCESS (ntStatus)) - { - opentest->TCBootLoaderDetected = FALSE; - opentest->FilesystemDetected = FALSE; - opentest->VolumeIDMatched = FALSE; - - if (opentest->bDetectTCBootLoader || opentest->DetectFilesystem || opentest->bMatchVolumeID) - { - byte *readBuffer = TCalloc (TC_MAX_VOLUME_SECTOR_SIZE); - if (!readBuffer) - { - ntStatus = STATUS_INSUFFICIENT_RESOURCES; - } - else - { - if (opentest->bDetectTCBootLoader || opentest->DetectFilesystem) - { - // Determine if the first sector contains a portion of the VeraCrypt Boot Loader - - offset.QuadPart = 0; - - ntStatus = ZwReadFile (NtFileHandle, - NULL, - NULL, - NULL, - &IoStatus, - readBuffer, - TC_MAX_VOLUME_SECTOR_SIZE, - &offset, - NULL); - - if (NT_SUCCESS (ntStatus)) - { - size_t i; - - if (opentest->bDetectTCBootLoader && IoStatus.Information >= TC_SECTOR_SIZE_BIOS) - { - // Search for the string "VeraCrypt" - for (i = 0; i < TC_SECTOR_SIZE_BIOS - strlen (TC_APP_NAME); ++i) - { - if (memcmp (readBuffer + i, TC_APP_NAME, strlen (TC_APP_NAME)) == 0) - { - opentest->TCBootLoaderDetected = TRUE; - break; - } - } - } - - if (opentest->DetectFilesystem && IoStatus.Information >= sizeof (int64)) - { - switch (BE64 (*(uint64 *) readBuffer)) - { - case 0xEB52904E54465320: // NTFS - case 0xEB3C904D53444F53: // FAT16 - case 0xEB58904D53444F53: // FAT32 - case 0xEB76904558464154: // exFAT - - opentest->FilesystemDetected = TRUE; - break; - } - } - } - } - - if (opentest->bMatchVolumeID) - { - int volumeType; - BYTE volumeID[VOLUME_ID_SIZE]; - - // Go through all volume types (e.g., normal, hidden) - for (volumeType = TC_VOLUME_TYPE_NORMAL; - volumeType < TC_VOLUME_TYPE_COUNT; - volumeType++) - { - /* Read the volume header */ - switch (volumeType) - { - case TC_VOLUME_TYPE_NORMAL: - offset.QuadPart = TC_VOLUME_HEADER_OFFSET; - break; - - case TC_VOLUME_TYPE_HIDDEN: - - offset.QuadPart = TC_HIDDEN_VOLUME_HEADER_OFFSET; - break; - } - - ntStatus = ZwReadFile (NtFileHandle, - NULL, - NULL, - NULL, - &IoStatus, - readBuffer, - TC_MAX_VOLUME_SECTOR_SIZE, - &offset, - NULL); - - if (NT_SUCCESS (ntStatus)) - { - /* compute the ID of this volume: SHA-256 of the effective header */ - sha256 (volumeID, readBuffer, TC_VOLUME_HEADER_EFFECTIVE_SIZE); - - if (0 == memcmp (volumeID, opentest->volumeID, VOLUME_ID_SIZE)) - { - opentest->VolumeIDMatched = TRUE; - break; - } - } - } - } - - TCfree (readBuffer); - } - } - - ZwClose (NtFileHandle); - Dump ("Open test on file %ls success.\n", opentest->wszFileName); - } - else - { -#if 0 - Dump ("Open test on file %ls failed NTSTATUS 0x%08x\n", opentest->wszFileName, ntStatus); -#endif - } - - Irp->IoStatus.Information = NT_SUCCESS (ntStatus) ? sizeof (OPEN_TEST_STRUCT) : 0; - Irp->IoStatus.Status = ntStatus; - } - break; - - case TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG: - { - GetSystemDriveConfigurationRequest *request = (GetSystemDriveConfigurationRequest *) Irp->AssociatedIrp.SystemBuffer; - OBJECT_ATTRIBUTES ObjectAttributes; - HANDLE NtFileHandle; - UNICODE_STRING FullFileName; - IO_STATUS_BLOCK IoStatus; - LARGE_INTEGER offset; - byte readBuffer [TC_SECTOR_SIZE_BIOS]; - - if (!ValidateIOBufferSize (Irp, sizeof (GetSystemDriveConfigurationRequest), ValidateInputOutput)) - break; - - EnsureNullTerminatedString (request->DevicePath, sizeof (request->DevicePath)); - RtlInitUnicodeString (&FullFileName, request->DevicePath); - - InitializeObjectAttributes (&ObjectAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); - - ntStatus = ZwCreateFile (&NtFileHandle, - SYNCHRONIZE | GENERIC_READ, &ObjectAttributes, &IoStatus, NULL, - FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT | FILE_RANDOM_ACCESS, NULL, 0); - - if (NT_SUCCESS (ntStatus)) - { - // Determine if the first sector contains a portion of the VeraCrypt Boot Loader - offset.QuadPart = 0; // MBR - - ntStatus = ZwReadFile (NtFileHandle, - NULL, - NULL, - NULL, - &IoStatus, - readBuffer, - sizeof(readBuffer), - &offset, - NULL); - - if (NT_SUCCESS (ntStatus)) - { - size_t i; - - // Check for dynamic drive - request->DriveIsDynamic = FALSE; - - if (readBuffer[510] == 0x55 && readBuffer[511] == 0xaa) - { - int i; - for (i = 0; i < 4; ++i) - { - if (readBuffer[446 + i * 16 + 4] == PARTITION_LDM) - { - request->DriveIsDynamic = TRUE; - break; - } - } - } - - request->BootLoaderVersion = 0; - request->Configuration = 0; - request->UserConfiguration = 0; - request->CustomUserMessage[0] = 0; - - // Search for the string "VeraCrypt" - for (i = 0; i < sizeof (readBuffer) - strlen (TC_APP_NAME); ++i) - { - if (memcmp (readBuffer + i, TC_APP_NAME, strlen (TC_APP_NAME)) == 0) - { - request->BootLoaderVersion = BE16 (*(uint16 *) (readBuffer + TC_BOOT_SECTOR_VERSION_OFFSET)); - request->Configuration = readBuffer[TC_BOOT_SECTOR_CONFIG_OFFSET]; - - if (request->BootLoaderVersion != 0 && request->BootLoaderVersion <= VERSION_NUM) - { - request->UserConfiguration = readBuffer[TC_BOOT_SECTOR_USER_CONFIG_OFFSET]; - memcpy (request->CustomUserMessage, readBuffer + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH); - } - break; - } - } - - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = sizeof (*request); - } - else - { - Irp->IoStatus.Status = ntStatus; - Irp->IoStatus.Information = 0; - } - - ZwClose (NtFileHandle); - - } - else - { - Irp->IoStatus.Status = ntStatus; - Irp->IoStatus.Information = 0; - } - } - break; - - case TC_IOCTL_WIPE_PASSWORD_CACHE: - WipeCache (); - - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = 0; - break; - - case TC_IOCTL_GET_PASSWORD_CACHE_STATUS: - Irp->IoStatus.Status = cacheEmpty ? STATUS_PIPE_EMPTY : STATUS_SUCCESS; - Irp->IoStatus.Information = 0; - break; - - case TC_IOCTL_SET_PORTABLE_MODE_STATUS: - if (!UserCanAccessDriveDevice()) - { - Irp->IoStatus.Status = STATUS_ACCESS_DENIED; - Irp->IoStatus.Information = 0; - } - else - { - PortableMode = TRUE; - Dump ("Setting portable mode\n"); - } - break; - - case TC_IOCTL_GET_PORTABLE_MODE_STATUS: - Irp->IoStatus.Status = PortableMode ? STATUS_SUCCESS : STATUS_PIPE_EMPTY; - Irp->IoStatus.Information = 0; - break; - - case TC_IOCTL_GET_MOUNTED_VOLUMES: - - if (ValidateIOBufferSize (Irp, sizeof (MOUNT_LIST_STRUCT), ValidateOutput)) - { - MOUNT_LIST_STRUCT *list = (MOUNT_LIST_STRUCT *) Irp->AssociatedIrp.SystemBuffer; - PDEVICE_OBJECT ListDevice; - int drive; - - list->ulMountedDrives = 0; - - for (drive = MIN_MOUNTED_VOLUME_DRIVE_NUMBER; drive <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; ++drive) - { - PEXTENSION ListExtension; - - ListDevice = GetVirtualVolumeDeviceObject (drive); - if (!ListDevice) - continue; - - ListExtension = (PEXTENSION) ListDevice->DeviceExtension; - if (IsVolumeAccessibleByCurrentUser (ListExtension)) - { - list->ulMountedDrives |= (1 << ListExtension->nDosDriveNo); - RtlStringCbCopyW (list->wszVolume[ListExtension->nDosDriveNo], sizeof(list->wszVolume[ListExtension->nDosDriveNo]),ListExtension->wszVolume); - RtlStringCbCopyW (list->wszLabel[ListExtension->nDosDriveNo], sizeof(list->wszLabel[ListExtension->nDosDriveNo]),ListExtension->wszLabel); - memcpy (list->volumeID[ListExtension->nDosDriveNo], ListExtension->volumeID, VOLUME_ID_SIZE); - list->diskLength[ListExtension->nDosDriveNo] = ListExtension->DiskLength; - list->ea[ListExtension->nDosDriveNo] = ListExtension->cryptoInfo->ea; - if (ListExtension->cryptoInfo->hiddenVolume) - list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_HIDDEN; // Hidden volume - else if (ListExtension->cryptoInfo->bHiddenVolProtectionAction) - list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_OUTER_VOL_WRITE_PREVENTED; // Normal/outer volume (hidden volume protected AND write already prevented) - else if (ListExtension->cryptoInfo->bProtectHiddenVolume) - list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_OUTER; // Normal/outer volume (hidden volume protected) - else - list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_NORMAL; // Normal volume - list->truecryptMode[ListExtension->nDosDriveNo] = ListExtension->cryptoInfo->bTrueCryptMode; - } - } - - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = sizeof (MOUNT_LIST_STRUCT); - } - break; - - case TC_IOCTL_LEGACY_GET_MOUNTED_VOLUMES: - if (ValidateIOBufferSize (Irp, sizeof (uint32), ValidateOutput)) - { - // Prevent the user from downgrading to versions lower than 5.0 by faking mounted volumes. - // The user could render the system unbootable by downgrading when boot encryption - // is active or being set up. - - memset (Irp->AssociatedIrp.SystemBuffer, 0, irpSp->Parameters.DeviceIoControl.OutputBufferLength); - *(uint32 *) Irp->AssociatedIrp.SystemBuffer = 0xffffFFFF; - - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = irpSp->Parameters.DeviceIoControl.OutputBufferLength; - } - break; - - case TC_IOCTL_GET_VOLUME_PROPERTIES: - if (ValidateIOBufferSize (Irp, sizeof (VOLUME_PROPERTIES_STRUCT), ValidateInputOutput)) - { - VOLUME_PROPERTIES_STRUCT *prop = (VOLUME_PROPERTIES_STRUCT *) Irp->AssociatedIrp.SystemBuffer; - PDEVICE_OBJECT ListDevice = GetVirtualVolumeDeviceObject (prop->driveNo); - - Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; - Irp->IoStatus.Information = 0; - - if (ListDevice) - { - PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension; - if (IsVolumeAccessibleByCurrentUser (ListExtension)) - { - prop->uniqueId = ListExtension->UniqueVolumeId; - RtlStringCbCopyW (prop->wszVolume, sizeof(prop->wszVolume),ListExtension->wszVolume); - RtlStringCbCopyW (prop->wszLabel, sizeof(prop->wszLabel),ListExtension->wszLabel); - memcpy (prop->volumeID, ListExtension->volumeID, VOLUME_ID_SIZE); - prop->bDriverSetLabel = ListExtension->bDriverSetLabel; - prop->diskLength = ListExtension->DiskLength; - prop->ea = ListExtension->cryptoInfo->ea; - prop->mode = ListExtension->cryptoInfo->mode; - prop->pkcs5 = ListExtension->cryptoInfo->pkcs5; - prop->pkcs5Iterations = ListExtension->cryptoInfo->noIterations; - prop->volumePim = ListExtension->cryptoInfo->volumePim; -#if 0 - prop->volumeCreationTime = ListExtension->cryptoInfo->volume_creation_time; - prop->headerCreationTime = ListExtension->cryptoInfo->header_creation_time; -#endif - prop->volumeHeaderFlags = ListExtension->cryptoInfo->HeaderFlags; - prop->readOnly = ListExtension->bReadOnly; - prop->removable = ListExtension->bRemovable; - prop->partitionInInactiveSysEncScope = ListExtension->PartitionInInactiveSysEncScope; - prop->hiddenVolume = ListExtension->cryptoInfo->hiddenVolume; - - if (ListExtension->cryptoInfo->bProtectHiddenVolume) - prop->hiddenVolProtection = ListExtension->cryptoInfo->bHiddenVolProtectionAction ? HIDVOL_PROT_STATUS_ACTION_TAKEN : HIDVOL_PROT_STATUS_ACTIVE; - else - prop->hiddenVolProtection = HIDVOL_PROT_STATUS_NONE; - - prop->totalBytesRead = ListExtension->Queue.TotalBytesRead; - prop->totalBytesWritten = ListExtension->Queue.TotalBytesWritten; - - prop->volFormatVersion = ListExtension->cryptoInfo->LegacyVolume ? TC_VOLUME_FORMAT_VERSION_PRE_6_0 : TC_VOLUME_FORMAT_VERSION; - - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = sizeof (VOLUME_PROPERTIES_STRUCT); - } - } - } - break; - - case TC_IOCTL_GET_RESOLVED_SYMLINK: - if (ValidateIOBufferSize (Irp, sizeof (RESOLVE_SYMLINK_STRUCT), ValidateInputOutput)) - { - RESOLVE_SYMLINK_STRUCT *resolve = (RESOLVE_SYMLINK_STRUCT *) Irp->AssociatedIrp.SystemBuffer; - { - NTSTATUS ntStatus; - - EnsureNullTerminatedString (resolve->symLinkName, sizeof (resolve->symLinkName)); - - ntStatus = SymbolicLinkToTarget (resolve->symLinkName, - resolve->targetName, - sizeof (resolve->targetName)); - - Irp->IoStatus.Information = sizeof (RESOLVE_SYMLINK_STRUCT); - Irp->IoStatus.Status = ntStatus; - } - } - break; - - case TC_IOCTL_GET_DRIVE_PARTITION_INFO: - if (ValidateIOBufferSize (Irp, sizeof (DISK_PARTITION_INFO_STRUCT), ValidateInputOutput)) - { - DISK_PARTITION_INFO_STRUCT *info = (DISK_PARTITION_INFO_STRUCT *) Irp->AssociatedIrp.SystemBuffer; - { - PARTITION_INFORMATION_EX pi; - NTSTATUS ntStatus; - - EnsureNullTerminatedString (info->deviceName, sizeof (info->deviceName)); - - ntStatus = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &pi, sizeof (pi)); - if (NT_SUCCESS(ntStatus)) - { - memset (&info->partInfo, 0, sizeof (info->partInfo)); - - info->partInfo.PartitionLength = pi.PartitionLength; - info->partInfo.PartitionNumber = pi.PartitionNumber; - info->partInfo.StartingOffset = pi.StartingOffset; - - if (pi.PartitionStyle == PARTITION_STYLE_MBR) - { - info->partInfo.PartitionType = pi.Mbr.PartitionType; - info->partInfo.BootIndicator = pi.Mbr.BootIndicator; - } - - info->IsGPT = pi.PartitionStyle == PARTITION_STYLE_GPT; - } - else - { - // Windows 2000 does not support IOCTL_DISK_GET_PARTITION_INFO_EX - ntStatus = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &info->partInfo, sizeof (info->partInfo)); - info->IsGPT = FALSE; - } - - if (!NT_SUCCESS (ntStatus)) - { - GET_LENGTH_INFORMATION lengthInfo; - ntStatus = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &lengthInfo, sizeof (lengthInfo)); - - if (NT_SUCCESS (ntStatus)) - { - memset (&info->partInfo, 0, sizeof (info->partInfo)); - info->partInfo.PartitionLength = lengthInfo.Length; - } - } - - info->IsDynamic = FALSE; - - if (NT_SUCCESS (ntStatus) && OsMajorVersion >= 6) - { -# define IOCTL_VOLUME_IS_DYNAMIC CTL_CODE(IOCTL_VOLUME_BASE, 18, METHOD_BUFFERED, FILE_ANY_ACCESS) - if (!NT_SUCCESS (TCDeviceIoControl (info->deviceName, IOCTL_VOLUME_IS_DYNAMIC, NULL, 0, &info->IsDynamic, sizeof (info->IsDynamic)))) - info->IsDynamic = FALSE; - } - - Irp->IoStatus.Information = sizeof (DISK_PARTITION_INFO_STRUCT); - Irp->IoStatus.Status = ntStatus; - } - } - break; - - case TC_IOCTL_GET_DRIVE_GEOMETRY: - if (ValidateIOBufferSize (Irp, sizeof (DISK_GEOMETRY_STRUCT), ValidateInputOutput)) - { - DISK_GEOMETRY_STRUCT *g = (DISK_GEOMETRY_STRUCT *) Irp->AssociatedIrp.SystemBuffer; - { - NTSTATUS ntStatus; - - EnsureNullTerminatedString (g->deviceName, sizeof (g->deviceName)); - - ntStatus = TCDeviceIoControl (g->deviceName, - IOCTL_DISK_GET_DRIVE_GEOMETRY, - NULL, 0, &g->diskGeometry, sizeof (g->diskGeometry)); - - Irp->IoStatus.Information = sizeof (DISK_GEOMETRY_STRUCT); - Irp->IoStatus.Status = ntStatus; - } - } - break; - - case TC_IOCTL_PROBE_REAL_DRIVE_SIZE: - if (ValidateIOBufferSize (Irp, sizeof (ProbeRealDriveSizeRequest), ValidateInputOutput)) - { - ProbeRealDriveSizeRequest *request = (ProbeRealDriveSizeRequest *) Irp->AssociatedIrp.SystemBuffer; - NTSTATUS status; - UNICODE_STRING name; - PFILE_OBJECT fileObject; - PDEVICE_OBJECT deviceObject; - - EnsureNullTerminatedString (request->DeviceName, sizeof (request->DeviceName)); - - RtlInitUnicodeString (&name, request->DeviceName); - status = IoGetDeviceObjectPointer (&name, FILE_READ_ATTRIBUTES, &fileObject, &deviceObject); - if (!NT_SUCCESS (status)) - { - Irp->IoStatus.Information = 0; - Irp->IoStatus.Status = status; - break; - } - - status = ProbeRealDriveSize (deviceObject, &request->RealDriveSize); - ObDereferenceObject (fileObject); - - if (status == STATUS_TIMEOUT) - { - request->TimeOut = TRUE; - Irp->IoStatus.Information = sizeof (ProbeRealDriveSizeRequest); - Irp->IoStatus.Status = STATUS_SUCCESS; - } - else if (!NT_SUCCESS (status)) - { - Irp->IoStatus.Information = 0; - Irp->IoStatus.Status = status; - } - else - { - request->TimeOut = FALSE; - Irp->IoStatus.Information = sizeof (ProbeRealDriveSizeRequest); - Irp->IoStatus.Status = status; - } - } - break; - - case TC_IOCTL_MOUNT_VOLUME: - if (ValidateIOBufferSize (Irp, sizeof (MOUNT_STRUCT), ValidateInputOutput)) - { - MOUNT_STRUCT *mount = (MOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer; - - if (mount->VolumePassword.Length > MAX_PASSWORD || mount->ProtectedHidVolPassword.Length > MAX_PASSWORD - || mount->pkcs5_prf < 0 || mount->pkcs5_prf > LAST_PRF_ID - || mount->VolumePim < -1 || mount->VolumePim == INT_MAX - || mount->ProtectedHidVolPkcs5Prf < 0 || mount->ProtectedHidVolPkcs5Prf > LAST_PRF_ID - || (mount->bTrueCryptMode != FALSE && mount->bTrueCryptMode != TRUE) - ) - { - Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; - Irp->IoStatus.Information = 0; - break; - } - - EnsureNullTerminatedString (mount->wszVolume, sizeof (mount->wszVolume)); - EnsureNullTerminatedString (mount->wszLabel, sizeof (mount->wszLabel)); - - Irp->IoStatus.Information = sizeof (MOUNT_STRUCT); - Irp->IoStatus.Status = MountDevice (DeviceObject, mount); - - burn (&mount->VolumePassword, sizeof (mount->VolumePassword)); - burn (&mount->ProtectedHidVolPassword, sizeof (mount->ProtectedHidVolPassword)); - burn (&mount->pkcs5_prf, sizeof (mount->pkcs5_prf)); - burn (&mount->VolumePim, sizeof (mount->VolumePim)); - burn (&mount->bTrueCryptMode, sizeof (mount->bTrueCryptMode)); - burn (&mount->ProtectedHidVolPkcs5Prf, sizeof (mount->ProtectedHidVolPkcs5Prf)); - burn (&mount->ProtectedHidVolPim, sizeof (mount->ProtectedHidVolPim)); - } - break; - - case TC_IOCTL_DISMOUNT_VOLUME: - if (ValidateIOBufferSize (Irp, sizeof (UNMOUNT_STRUCT), ValidateInputOutput)) - { - UNMOUNT_STRUCT *unmount = (UNMOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer; - PDEVICE_OBJECT ListDevice = GetVirtualVolumeDeviceObject (unmount->nDosDriveNo); - - unmount->nReturnCode = ERR_DRIVE_NOT_FOUND; - - if (ListDevice) - { - PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension; - - if (IsVolumeAccessibleByCurrentUser (ListExtension)) - unmount->nReturnCode = UnmountDevice (unmount, ListDevice, unmount->ignoreOpenFiles); - } - - Irp->IoStatus.Information = sizeof (UNMOUNT_STRUCT); - Irp->IoStatus.Status = STATUS_SUCCESS; - } - break; - - case TC_IOCTL_DISMOUNT_ALL_VOLUMES: - if (ValidateIOBufferSize (Irp, sizeof (UNMOUNT_STRUCT), ValidateInputOutput)) - { - UNMOUNT_STRUCT *unmount = (UNMOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer; - - unmount->nReturnCode = UnmountAllDevices (unmount, unmount->ignoreOpenFiles); - - Irp->IoStatus.Information = sizeof (UNMOUNT_STRUCT); - Irp->IoStatus.Status = STATUS_SUCCESS; - } - break; - - case TC_IOCTL_BOOT_ENCRYPTION_SETUP: - Irp->IoStatus.Status = StartBootEncryptionSetup (DeviceObject, Irp, irpSp); - Irp->IoStatus.Information = 0; - break; - - case TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP: - Irp->IoStatus.Status = AbortBootEncryptionSetup(); - Irp->IoStatus.Information = 0; - break; - - case TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS: - GetBootEncryptionStatus (Irp, irpSp); - break; - - case TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT: - Irp->IoStatus.Information = 0; - Irp->IoStatus.Status = GetSetupResult(); - break; - - case TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES: - GetBootDriveVolumeProperties (Irp, irpSp); - break; - - case TC_IOCTL_GET_BOOT_LOADER_VERSION: - GetBootLoaderVersion (Irp, irpSp); - break; - - case TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER: - ReopenBootVolumeHeader (Irp, irpSp); - break; - - case VC_IOCTL_GET_BOOT_LOADER_FINGERPRINT: - GetBootLoaderFingerprint (Irp, irpSp); - break; - - case TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME: - GetBootEncryptionAlgorithmName (Irp, irpSp); - break; - - case TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING: - if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput)) - { - *(int *) Irp->AssociatedIrp.SystemBuffer = IsHiddenSystemRunning() ? 1 : 0; - Irp->IoStatus.Information = sizeof (int); - Irp->IoStatus.Status = STATUS_SUCCESS; - } - break; - - case TC_IOCTL_START_DECOY_SYSTEM_WIPE: - Irp->IoStatus.Status = StartDecoySystemWipe (DeviceObject, Irp, irpSp); - Irp->IoStatus.Information = 0; - break; - - case TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE: - Irp->IoStatus.Status = AbortDecoySystemWipe(); - Irp->IoStatus.Information = 0; - break; - - case TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT: - Irp->IoStatus.Status = GetDecoySystemWipeResult(); - Irp->IoStatus.Information = 0; - break; - - case TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS: - GetDecoySystemWipeStatus (Irp, irpSp); - break; - - case TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR: - Irp->IoStatus.Status = WriteBootDriveSector (Irp, irpSp); - Irp->IoStatus.Information = 0; - break; - - case TC_IOCTL_GET_WARNING_FLAGS: - if (ValidateIOBufferSize (Irp, sizeof (GetWarningFlagsRequest), ValidateOutput)) - { - GetWarningFlagsRequest *flags = (GetWarningFlagsRequest *) Irp->AssociatedIrp.SystemBuffer; - - flags->PagingFileCreationPrevented = PagingFileCreationPrevented; - PagingFileCreationPrevented = FALSE; - flags->SystemFavoriteVolumeDirty = SystemFavoriteVolumeDirty; - SystemFavoriteVolumeDirty = FALSE; - - Irp->IoStatus.Information = sizeof (GetWarningFlagsRequest); - Irp->IoStatus.Status = STATUS_SUCCESS; - } - break; - - case TC_IOCTL_SET_SYSTEM_FAVORITE_VOLUME_DIRTY: - if (UserCanAccessDriveDevice()) - { - SystemFavoriteVolumeDirty = TRUE; - Irp->IoStatus.Status = STATUS_SUCCESS; - } - else - Irp->IoStatus.Status = STATUS_ACCESS_DENIED; - - Irp->IoStatus.Information = 0; - break; - - case TC_IOCTL_REREAD_DRIVER_CONFIG: - Irp->IoStatus.Status = ReadRegistryConfigFlags (FALSE); - Irp->IoStatus.Information = 0; - break; - - case TC_IOCTL_GET_SYSTEM_DRIVE_DUMP_CONFIG: - if ( (ValidateIOBufferSize (Irp, sizeof (GetSystemDriveDumpConfigRequest), ValidateOutput)) - && (Irp->RequestorMode == KernelMode) - ) - { - GetSystemDriveDumpConfigRequest *request = (GetSystemDriveDumpConfigRequest *) Irp->AssociatedIrp.SystemBuffer; - - request->BootDriveFilterExtension = GetBootDriveFilterExtension(); - if (IsBootDriveMounted() && request->BootDriveFilterExtension) - { - request->HwEncryptionEnabled = IsHwEncryptionEnabled(); - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = sizeof (*request); - } - else - { - Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; - Irp->IoStatus.Information = 0; - } - } - break; - - default: - return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0); - } - - -#ifdef DEBUG - if (!NT_SUCCESS (Irp->IoStatus.Status)) - { - switch (irpSp->Parameters.DeviceIoControl.IoControlCode) - { - case TC_IOCTL_GET_MOUNTED_VOLUMES: - case TC_IOCTL_GET_PASSWORD_CACHE_STATUS: - case TC_IOCTL_GET_PORTABLE_MODE_STATUS: - case TC_IOCTL_SET_PORTABLE_MODE_STATUS: - case TC_IOCTL_OPEN_TEST: - case TC_IOCTL_GET_RESOLVED_SYMLINK: - case TC_IOCTL_GET_DRIVE_PARTITION_INFO: - case TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES: - case TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS: - case TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING: - break; - - default: - Dump ("IOCTL error 0x%08x\n", Irp->IoStatus.Status); - } - } -#endif - - return TCCompleteIrp (Irp, Irp->IoStatus.Status, Irp->IoStatus.Information); -} - - -NTSTATUS TCStartThread (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread) -{ - return TCStartThreadInProcess (threadProc, threadArg, kThread, NULL); -} - - -NTSTATUS TCStartThreadInProcess (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread, PEPROCESS process) -{ - NTSTATUS status; - HANDLE threadHandle; - HANDLE processHandle = NULL; - OBJECT_ATTRIBUTES threadObjAttributes; - - if (process) - { - status = ObOpenObjectByPointer (process, OBJ_KERNEL_HANDLE, NULL, 0, NULL, KernelMode, &processHandle); - if (!NT_SUCCESS (status)) - return status; - } - - InitializeObjectAttributes (&threadObjAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); - - status = PsCreateSystemThread (&threadHandle, THREAD_ALL_ACCESS, &threadObjAttributes, processHandle, NULL, threadProc, threadArg); - if (!NT_SUCCESS (status)) - return status; - - status = ObReferenceObjectByHandle (threadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, (PVOID *) kThread, NULL); - if (!NT_SUCCESS (status)) - { - ZwClose (threadHandle); - *kThread = NULL; - return status; - } - - if (processHandle) - ZwClose (processHandle); - - ZwClose (threadHandle); - return STATUS_SUCCESS; -} - - -void TCStopThread (PKTHREAD kThread, PKEVENT wakeUpEvent) -{ - if (wakeUpEvent) - KeSetEvent (wakeUpEvent, 0, FALSE); - - KeWaitForSingleObject (kThread, Executive, KernelMode, FALSE, NULL); - ObDereferenceObject (kThread); -} - - -NTSTATUS TCStartVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, MOUNT_STRUCT * mount) -{ - PTHREAD_BLOCK pThreadBlock = TCalloc (sizeof (THREAD_BLOCK)); - HANDLE hThread; - NTSTATUS ntStatus; - OBJECT_ATTRIBUTES threadObjAttributes; - SECURITY_QUALITY_OF_SERVICE qos; - - Dump ("Starting thread...\n"); - - if (pThreadBlock == NULL) - { - return STATUS_INSUFFICIENT_RESOURCES; - } - else - { - pThreadBlock->DeviceObject = DeviceObject; - pThreadBlock->mount = mount; - } - - qos.Length = sizeof (qos); - qos.ContextTrackingMode = SECURITY_STATIC_TRACKING; - qos.EffectiveOnly = TRUE; - qos.ImpersonationLevel = SecurityImpersonation; - - ntStatus = SeCreateClientSecurity (PsGetCurrentThread(), &qos, FALSE, &Extension->SecurityClientContext); - if (!NT_SUCCESS (ntStatus)) - goto ret; - - Extension->SecurityClientContextValid = TRUE; - - Extension->bThreadShouldQuit = FALSE; - - InitializeObjectAttributes (&threadObjAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); - - ntStatus = PsCreateSystemThread (&hThread, - THREAD_ALL_ACCESS, - &threadObjAttributes, - NULL, - NULL, - VolumeThreadProc, - pThreadBlock); - - if (!NT_SUCCESS (ntStatus)) - { - Dump ("PsCreateSystemThread Failed END\n"); - goto ret; - } - - ntStatus = ObReferenceObjectByHandle (hThread, - THREAD_ALL_ACCESS, - NULL, - KernelMode, - &Extension->peThread, - NULL); - - ZwClose (hThread); - - if (!NT_SUCCESS (ntStatus)) - goto ret; - - Dump ("Waiting for thread to initialize...\n"); - - KeWaitForSingleObject (&Extension->keCreateEvent, - Executive, - KernelMode, - FALSE, - NULL); - - Dump ("Waiting completed! Thread returns 0x%08x\n", pThreadBlock->ntCreateStatus); - ntStatus = pThreadBlock->ntCreateStatus; - -ret: - TCfree (pThreadBlock); - return ntStatus; -} - -void TCStopVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension) -{ - NTSTATUS ntStatus; - - UNREFERENCED_PARAMETER (DeviceObject); /* Remove compiler warning */ - - Dump ("Signalling thread to quit...\n"); - - Extension->bThreadShouldQuit = TRUE; - - KeReleaseSemaphore (&Extension->RequestSemaphore, - 0, - 1, - TRUE); - - ntStatus = KeWaitForSingleObject (Extension->peThread, - Executive, - KernelMode, - FALSE, - NULL); - - ASSERT (NT_SUCCESS (ntStatus)); - - ObDereferenceObject (Extension->peThread); - Extension->peThread = NULL; - - Dump ("Thread exited\n"); -} - - -// Suspend current thread for a number of milliseconds -void TCSleep (int milliSeconds) -{ - PKTIMER timer = (PKTIMER) TCalloc (sizeof (KTIMER)); - LARGE_INTEGER duetime; - - if (!timer) - return; - - duetime.QuadPart = (__int64) milliSeconds * -10000; - KeInitializeTimerEx(timer, NotificationTimer); - KeSetTimerEx(timer, duetime, 0, NULL); - - KeWaitForSingleObject (timer, Executive, KernelMode, FALSE, NULL); - - TCfree (timer); -} - -BOOL IsDeviceName(wchar_t wszVolume[TC_MAX_PATH]) -{ - if ( (wszVolume[0] == '\\') - && (wszVolume[1] == 'D' || wszVolume[1] == 'd') - && (wszVolume[2] == 'E' || wszVolume[2] == 'e') - && (wszVolume[3] == 'V' || wszVolume[3] == 'v') - && (wszVolume[4] == 'I' || wszVolume[4] == 'i') - && (wszVolume[5] == 'C' || wszVolume[5] == 'c') - && (wszVolume[6] == 'E' || wszVolume[6] == 'e') - ) - { - return TRUE; - } - else - return FALSE; -} - -/* VolumeThreadProc does all the work of processing IRP's, and dispatching them - to either the ReadWrite function or the DeviceControl function */ -VOID VolumeThreadProc (PVOID Context) -{ - PTHREAD_BLOCK pThreadBlock = (PTHREAD_BLOCK) Context; - PDEVICE_OBJECT DeviceObject = pThreadBlock->DeviceObject; - PEXTENSION Extension = (PEXTENSION) DeviceObject->DeviceExtension; - BOOL bDevice; - - /* Set thread priority to lowest realtime level. */ - KeSetPriorityThread (KeGetCurrentThread (), LOW_REALTIME_PRIORITY); - - Dump ("Mount THREAD OPENING VOLUME BEGIN\n"); - - if ( !IsDeviceName (pThreadBlock->mount->wszVolume)) - { - RtlStringCbCopyW (pThreadBlock->wszMountVolume, sizeof(pThreadBlock->wszMountVolume),WIDE ("\\??\\")); - RtlStringCbCatW (pThreadBlock->wszMountVolume, sizeof(pThreadBlock->wszMountVolume),pThreadBlock->mount->wszVolume); - bDevice = FALSE; - } - else - { - pThreadBlock->wszMountVolume[0] = 0; - RtlStringCbCatW (pThreadBlock->wszMountVolume, sizeof(pThreadBlock->wszMountVolume),pThreadBlock->mount->wszVolume); - bDevice = TRUE; - } - - Dump ("Mount THREAD request for File %ls DriveNumber %d Device = %d\n", - pThreadBlock->wszMountVolume, pThreadBlock->mount->nDosDriveNo, bDevice); - - pThreadBlock->ntCreateStatus = TCOpenVolume (DeviceObject, - Extension, - pThreadBlock->mount, - pThreadBlock->wszMountVolume, - bDevice); - - if (!NT_SUCCESS (pThreadBlock->ntCreateStatus) || pThreadBlock->mount->nReturnCode != 0) - { - KeSetEvent (&Extension->keCreateEvent, 0, FALSE); - PsTerminateSystemThread (STATUS_SUCCESS); - } - - // Start IO queue - Extension->Queue.IsFilterDevice = FALSE; - Extension->Queue.DeviceObject = DeviceObject; - Extension->Queue.CryptoInfo = Extension->cryptoInfo; - Extension->Queue.HostFileHandle = Extension->hDeviceFile; - Extension->Queue.VirtualDeviceLength = Extension->DiskLength; - Extension->Queue.MaxReadAheadOffset.QuadPart = Extension->HostLength; - - if (Extension->SecurityClientContextValid) - Extension->Queue.SecurityClientContext = &Extension->SecurityClientContext; - else - Extension->Queue.SecurityClientContext = NULL; - - pThreadBlock->ntCreateStatus = EncryptedIoQueueStart (&Extension->Queue); - - if (!NT_SUCCESS (pThreadBlock->ntCreateStatus)) - { - TCCloseVolume (DeviceObject, Extension); - - pThreadBlock->mount->nReturnCode = ERR_OS_ERROR; - KeSetEvent (&Extension->keCreateEvent, 0, FALSE); - PsTerminateSystemThread (STATUS_SUCCESS); - } - - KeSetEvent (&Extension->keCreateEvent, 0, FALSE); - /* From this point on pThreadBlock cannot be used as it will have been released! */ - pThreadBlock = NULL; - - for (;;) - { - /* Wait for a request from the dispatch routines. */ - KeWaitForSingleObject ((PVOID) & Extension->RequestSemaphore, Executive, KernelMode, FALSE, NULL); - - for (;;) - { - PIO_STACK_LOCATION irpSp; - PLIST_ENTRY request; - PIRP irp; - - request = ExInterlockedRemoveHeadList (&Extension->ListEntry, &Extension->ListSpinLock); - if (request == NULL) - break; - - irp = CONTAINING_RECORD (request, IRP, Tail.Overlay.ListEntry); - irpSp = IoGetCurrentIrpStackLocation (irp); - - ASSERT (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL); - - ProcessVolumeDeviceControlIrp (DeviceObject, Extension, irp); - IoReleaseRemoveLock (&Extension->Queue.RemoveLock, irp); - } - - if (Extension->bThreadShouldQuit) - { - Dump ("Closing volume\n"); - EncryptedIoQueueStop (&Extension->Queue); - - TCCloseVolume (DeviceObject, Extension); - PsTerminateSystemThread (STATUS_SUCCESS); - } - } -} - -void TCGetNTNameFromNumber (LPWSTR ntname, int cbNtName, int nDriveNo) -{ - WCHAR tmp[2] = - {0, 0}; - int j = nDriveNo + (WCHAR) 'A'; - - tmp[0] = (short) j; - RtlStringCbCopyW (ntname, cbNtName,(LPWSTR) NT_MOUNT_PREFIX); - RtlStringCbCatW (ntname, cbNtName, tmp); -} - -void TCGetDosNameFromNumber (LPWSTR dosname,int cbDosName, int nDriveNo, DeviceNamespaceType namespaceType) -{ - WCHAR tmp[3] = - {0, ':', 0}; - int j = nDriveNo + (WCHAR) 'A'; - - tmp[0] = (short) j; - - if (DeviceNamespaceGlobal == namespaceType) - { - RtlStringCbCopyW (dosname, cbDosName, (LPWSTR) DOS_MOUNT_PREFIX_GLOBAL); - } - else - { - RtlStringCbCopyW (dosname, cbDosName, (LPWSTR) DOS_MOUNT_PREFIX_DEFAULT); - } - - RtlStringCbCatW (dosname, cbDosName, tmp); -} - -#ifdef _DEBUG -LPWSTR TCTranslateCode (ULONG ulCode) -{ - switch (ulCode) - { -#define TC_CASE_RET_NAME(CODE) case CODE : return L###CODE - - TC_CASE_RET_NAME (TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP); - TC_CASE_RET_NAME (TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE); - TC_CASE_RET_NAME (TC_IOCTL_BOOT_ENCRYPTION_SETUP); - TC_CASE_RET_NAME (TC_IOCTL_DISMOUNT_ALL_VOLUMES); - TC_CASE_RET_NAME (TC_IOCTL_DISMOUNT_VOLUME); - TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES); - TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME); - TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT); - TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS); - TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_LOADER_VERSION); - TC_CASE_RET_NAME (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT); - TC_CASE_RET_NAME (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS); - TC_CASE_RET_NAME (TC_IOCTL_GET_DEVICE_REFCOUNT); - TC_CASE_RET_NAME (TC_IOCTL_GET_DRIVE_GEOMETRY); - TC_CASE_RET_NAME (TC_IOCTL_GET_DRIVE_PARTITION_INFO); - TC_CASE_RET_NAME (TC_IOCTL_GET_DRIVER_VERSION); - TC_CASE_RET_NAME (TC_IOCTL_GET_MOUNTED_VOLUMES); - TC_CASE_RET_NAME (TC_IOCTL_GET_PASSWORD_CACHE_STATUS); - TC_CASE_RET_NAME (TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG); - TC_CASE_RET_NAME (TC_IOCTL_GET_PORTABLE_MODE_STATUS); - TC_CASE_RET_NAME (TC_IOCTL_SET_PORTABLE_MODE_STATUS); - TC_CASE_RET_NAME (TC_IOCTL_GET_RESOLVED_SYMLINK); - TC_CASE_RET_NAME (TC_IOCTL_GET_SYSTEM_DRIVE_DUMP_CONFIG); - TC_CASE_RET_NAME (TC_IOCTL_GET_VOLUME_PROPERTIES); - TC_CASE_RET_NAME (TC_IOCTL_GET_WARNING_FLAGS); - TC_CASE_RET_NAME (TC_IOCTL_DISK_IS_WRITABLE); - TC_CASE_RET_NAME (TC_IOCTL_IS_ANY_VOLUME_MOUNTED); - TC_CASE_RET_NAME (TC_IOCTL_IS_DRIVER_UNLOAD_DISABLED); - TC_CASE_RET_NAME (TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING); - TC_CASE_RET_NAME (TC_IOCTL_MOUNT_VOLUME); - TC_CASE_RET_NAME (TC_IOCTL_OPEN_TEST); - TC_CASE_RET_NAME (TC_IOCTL_PROBE_REAL_DRIVE_SIZE); - TC_CASE_RET_NAME (TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER); - TC_CASE_RET_NAME (TC_IOCTL_REREAD_DRIVER_CONFIG); - TC_CASE_RET_NAME (TC_IOCTL_SET_SYSTEM_FAVORITE_VOLUME_DIRTY); - TC_CASE_RET_NAME (TC_IOCTL_START_DECOY_SYSTEM_WIPE); - TC_CASE_RET_NAME (TC_IOCTL_WIPE_PASSWORD_CACHE); - TC_CASE_RET_NAME (TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR); - - TC_CASE_RET_NAME (IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS); - -#undef TC_CASE_RET_NAME - } - - if (ulCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) - return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_GEOMETRY"); - else if (ulCode == IOCTL_DISK_GET_DRIVE_GEOMETRY_EX) - return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX"); - else if (ulCode == IOCTL_MOUNTDEV_QUERY_DEVICE_NAME) - return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME"); - else if (ulCode == IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME) - return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME"); - else if (ulCode == IOCTL_MOUNTDEV_QUERY_UNIQUE_ID) - return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_UNIQUE_ID"); - else if (ulCode == IOCTL_VOLUME_ONLINE) - return (LPWSTR) _T ("IOCTL_VOLUME_ONLINE"); - else if (ulCode == IOCTL_MOUNTDEV_LINK_CREATED) - return (LPWSTR) _T ("IOCTL_MOUNTDEV_LINK_CREATED"); - else if (ulCode == IOCTL_MOUNTDEV_LINK_DELETED) - return (LPWSTR) _T ("IOCTL_MOUNTDEV_LINK_DELETED"); - else if (ulCode == IOCTL_MOUNTMGR_QUERY_POINTS) - return (LPWSTR) _T ("IOCTL_MOUNTMGR_QUERY_POINTS"); - else if (ulCode == IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED) - return (LPWSTR) _T ("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED"); - else if (ulCode == IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED) - return (LPWSTR) _T ("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED"); - else if (ulCode == IOCTL_DISK_GET_LENGTH_INFO) - return (LPWSTR) _T ("IOCTL_DISK_GET_LENGTH_INFO"); - else if (ulCode == IOCTL_STORAGE_GET_DEVICE_NUMBER) - return (LPWSTR) _T ("IOCTL_STORAGE_GET_DEVICE_NUMBER"); - else if (ulCode == IOCTL_DISK_GET_PARTITION_INFO) - return (LPWSTR) _T ("IOCTL_DISK_GET_PARTITION_INFO"); - else if (ulCode == IOCTL_DISK_GET_PARTITION_INFO_EX) - return (LPWSTR) _T ("IOCTL_DISK_GET_PARTITION_INFO_EX"); - else if (ulCode == IOCTL_DISK_SET_PARTITION_INFO) - return (LPWSTR) _T ("IOCTL_DISK_SET_PARTITION_INFO"); - else if (ulCode == IOCTL_DISK_GET_DRIVE_LAYOUT) - return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_LAYOUT"); - else if (ulCode == IOCTL_DISK_SET_DRIVE_LAYOUT_EX) - return (LPWSTR) _T ("IOCTL_DISK_SET_DRIVE_LAYOUT_EX"); - else if (ulCode == IOCTL_DISK_VERIFY) - return (LPWSTR) _T ("IOCTL_DISK_VERIFY"); - else if (ulCode == IOCTL_DISK_FORMAT_TRACKS) - return (LPWSTR) _T ("IOCTL_DISK_FORMAT_TRACKS"); - else if (ulCode == IOCTL_DISK_REASSIGN_BLOCKS) - return (LPWSTR) _T ("IOCTL_DISK_REASSIGN_BLOCKS"); - else if (ulCode == IOCTL_DISK_PERFORMANCE) - return (LPWSTR) _T ("IOCTL_DISK_PERFORMANCE"); - else if (ulCode == IOCTL_DISK_IS_WRITABLE) - return (LPWSTR) _T ("IOCTL_DISK_IS_WRITABLE"); - else if (ulCode == IOCTL_DISK_LOGGING) - return (LPWSTR) _T ("IOCTL_DISK_LOGGING"); - else if (ulCode == IOCTL_DISK_FORMAT_TRACKS_EX) - return (LPWSTR) _T ("IOCTL_DISK_FORMAT_TRACKS_EX"); - else if (ulCode == IOCTL_DISK_HISTOGRAM_STRUCTURE) - return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_STRUCTURE"); - else if (ulCode == IOCTL_DISK_HISTOGRAM_DATA) - return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_DATA"); - else if (ulCode == IOCTL_DISK_HISTOGRAM_RESET) - return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_RESET"); - else if (ulCode == IOCTL_DISK_REQUEST_STRUCTURE) - return (LPWSTR) _T ("IOCTL_DISK_REQUEST_STRUCTURE"); - else if (ulCode == IOCTL_DISK_REQUEST_DATA) - return (LPWSTR) _T ("IOCTL_DISK_REQUEST_DATA"); - else if (ulCode == IOCTL_DISK_CONTROLLER_NUMBER) - return (LPWSTR) _T ("IOCTL_DISK_CONTROLLER_NUMBER"); - else if (ulCode == SMART_GET_VERSION) - return (LPWSTR) _T ("SMART_GET_VERSION"); - else if (ulCode == SMART_SEND_DRIVE_COMMAND) - return (LPWSTR) _T ("SMART_SEND_DRIVE_COMMAND"); - else if (ulCode == SMART_RCV_DRIVE_DATA) - return (LPWSTR) _T ("SMART_RCV_DRIVE_DATA"); - else if (ulCode == IOCTL_DISK_INTERNAL_SET_VERIFY) - return (LPWSTR) _T ("IOCTL_DISK_INTERNAL_SET_VERIFY"); - else if (ulCode == IOCTL_DISK_INTERNAL_CLEAR_VERIFY) - return (LPWSTR) _T ("IOCTL_DISK_INTERNAL_CLEAR_VERIFY"); - else if (ulCode == IOCTL_DISK_CHECK_VERIFY) - return (LPWSTR) _T ("IOCTL_DISK_CHECK_VERIFY"); - else if (ulCode == IOCTL_DISK_MEDIA_REMOVAL) - return (LPWSTR) _T ("IOCTL_DISK_MEDIA_REMOVAL"); - else if (ulCode == IOCTL_DISK_EJECT_MEDIA) - return (LPWSTR) _T ("IOCTL_DISK_EJECT_MEDIA"); - else if (ulCode == IOCTL_DISK_LOAD_MEDIA) - return (LPWSTR) _T ("IOCTL_DISK_LOAD_MEDIA"); - else if (ulCode == IOCTL_DISK_RESERVE) - return (LPWSTR) _T ("IOCTL_DISK_RESERVE"); - else if (ulCode == IOCTL_DISK_RELEASE) - return (LPWSTR) _T ("IOCTL_DISK_RELEASE"); - else if (ulCode == IOCTL_DISK_FIND_NEW_DEVICES) - return (LPWSTR) _T ("IOCTL_DISK_FIND_NEW_DEVICES"); - else if (ulCode == IOCTL_DISK_GET_MEDIA_TYPES) - return (LPWSTR) _T ("IOCTL_DISK_GET_MEDIA_TYPES"); - else if (ulCode == IOCTL_STORAGE_SET_HOTPLUG_INFO) - return (LPWSTR) _T ("IOCTL_STORAGE_SET_HOTPLUG_INFO"); - else if (ulCode == IRP_MJ_READ) - return (LPWSTR) _T ("IRP_MJ_READ"); - else if (ulCode == IRP_MJ_WRITE) - return (LPWSTR) _T ("IRP_MJ_WRITE"); - else if (ulCode == IRP_MJ_CREATE) - return (LPWSTR) _T ("IRP_MJ_CREATE"); - else if (ulCode == IRP_MJ_CLOSE) - return (LPWSTR) _T ("IRP_MJ_CLOSE"); - else if (ulCode == IRP_MJ_CLEANUP) - return (LPWSTR) _T ("IRP_MJ_CLEANUP"); - else if (ulCode == IRP_MJ_FLUSH_BUFFERS) - return (LPWSTR) _T ("IRP_MJ_FLUSH_BUFFERS"); - else if (ulCode == IRP_MJ_SHUTDOWN) - return (LPWSTR) _T ("IRP_MJ_SHUTDOWN"); - else if (ulCode == IRP_MJ_DEVICE_CONTROL) - return (LPWSTR) _T ("IRP_MJ_DEVICE_CONTROL"); - else - { - return (LPWSTR) _T ("IOCTL"); - } -} - -#endif - -void TCDeleteDeviceObject (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension) -{ - UNICODE_STRING Win32NameString; - NTSTATUS ntStatus; - - Dump ("TCDeleteDeviceObject BEGIN\n"); - - if (Extension->bRootDevice) - { - RtlInitUnicodeString (&Win32NameString, (LPWSTR) DOS_ROOT_PREFIX); - ntStatus = IoDeleteSymbolicLink (&Win32NameString); - if (!NT_SUCCESS (ntStatus)) - Dump ("IoDeleteSymbolicLink failed ntStatus = 0x%08x\n", ntStatus); - - RootDeviceObject = NULL; - } - else - { - if (Extension->peThread != NULL) - TCStopVolumeThread (DeviceObject, Extension); - - if (Extension->UserSid) - TCfree (Extension->UserSid); - - if (Extension->SecurityClientContextValid) - { - if (OsMajorVersion == 5 && OsMinorVersion == 0) - { - ObDereferenceObject (Extension->SecurityClientContext.ClientToken); - } - else - { - // Windows 2000 does not support PsDereferenceImpersonationToken() used by SeDeleteClientSecurity(). - // TODO: Use only SeDeleteClientSecurity() once support for Windows 2000 is dropped. - - VOID (*PsDereferenceImpersonationTokenD) (PACCESS_TOKEN ImpersonationToken); - UNICODE_STRING name; - RtlInitUnicodeString (&name, L"PsDereferenceImpersonationToken"); - - PsDereferenceImpersonationTokenD = MmGetSystemRoutineAddress (&name); - if (!PsDereferenceImpersonationTokenD) - TC_BUG_CHECK (STATUS_NOT_IMPLEMENTED); - -# define PsDereferencePrimaryToken -# define PsDereferenceImpersonationToken PsDereferenceImpersonationTokenD - - SeDeleteClientSecurity (&Extension->SecurityClientContext); - -# undef PsDereferencePrimaryToken -# undef PsDereferenceImpersonationToken - } - } - - VirtualVolumeDeviceObjects[Extension->nDosDriveNo] = NULL; - } - - IoDeleteDevice (DeviceObject); - - Dump ("TCDeleteDeviceObject END\n"); -} - - -VOID TCUnloadDriver (PDRIVER_OBJECT DriverObject) -{ - Dump ("TCUnloadDriver BEGIN\n"); - - OnShutdownPending(); - - if (IsBootDriveMounted()) - TC_BUG_CHECK (STATUS_INVALID_DEVICE_STATE); - - EncryptionThreadPoolStop(); - TCDeleteDeviceObject (RootDeviceObject, (PEXTENSION) RootDeviceObject->DeviceExtension); - - Dump ("TCUnloadDriver END\n"); -} - - -void OnShutdownPending () -{ - UNMOUNT_STRUCT unmount; - memset (&unmount, 0, sizeof (unmount)); - unmount.ignoreOpenFiles = TRUE; - - while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_DISMOUNT_ALL_VOLUMES, &unmount, sizeof (unmount), &unmount, sizeof (unmount)) == STATUS_INSUFFICIENT_RESOURCES || unmount.HiddenVolumeProtectionTriggered) - unmount.HiddenVolumeProtectionTriggered = FALSE; - - while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_WIPE_PASSWORD_CACHE, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES); -} - - -NTSTATUS TCDeviceIoControl (PWSTR deviceName, ULONG IoControlCode, void *InputBuffer, ULONG InputBufferSize, void *OutputBuffer, ULONG OutputBufferSize) -{ - IO_STATUS_BLOCK ioStatusBlock; - NTSTATUS ntStatus; - PIRP irp; - PFILE_OBJECT fileObject; - PDEVICE_OBJECT deviceObject; - KEVENT event; - UNICODE_STRING name; - - RtlInitUnicodeString(&name, deviceName); - ntStatus = IoGetDeviceObjectPointer (&name, FILE_READ_ATTRIBUTES, &fileObject, &deviceObject); - - if (!NT_SUCCESS (ntStatus)) - return ntStatus; - - KeInitializeEvent(&event, NotificationEvent, FALSE); - - irp = IoBuildDeviceIoControlRequest (IoControlCode, - deviceObject, - InputBuffer, InputBufferSize, - OutputBuffer, OutputBufferSize, - FALSE, - &event, - &ioStatusBlock); - - if (irp == NULL) - { - Dump ("IRP allocation failed\n"); - ntStatus = STATUS_INSUFFICIENT_RESOURCES; - goto ret; - } - - IoGetNextIrpStackLocation (irp)->FileObject = fileObject; - - ntStatus = IoCallDriver (deviceObject, irp); - if (ntStatus == STATUS_PENDING) - { - KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL); - ntStatus = ioStatusBlock.Status; - } - -ret: - ObDereferenceObject (fileObject); - return ntStatus; -} - - -typedef struct -{ - PDEVICE_OBJECT deviceObject; ULONG ioControlCode; void *inputBuffer; int inputBufferSize; void *outputBuffer; int outputBufferSize; - NTSTATUS Status; - KEVENT WorkItemCompletedEvent; -} SendDeviceIoControlRequestWorkItemArgs; - - -static VOID SendDeviceIoControlRequestWorkItemRoutine (PDEVICE_OBJECT rootDeviceObject, SendDeviceIoControlRequestWorkItemArgs *arg) -{ - arg->Status = SendDeviceIoControlRequest (arg->deviceObject, arg->ioControlCode, arg->inputBuffer, arg->inputBufferSize, arg->outputBuffer, arg->outputBufferSize); - KeSetEvent (&arg->WorkItemCompletedEvent, IO_NO_INCREMENT, FALSE); -} - - -NTSTATUS SendDeviceIoControlRequest (PDEVICE_OBJECT deviceObject, ULONG ioControlCode, void *inputBuffer, int inputBufferSize, void *outputBuffer, int outputBufferSize) -{ - IO_STATUS_BLOCK ioStatusBlock; - NTSTATUS status; - PIRP irp; - KEVENT event; - - if (KeGetCurrentIrql() > APC_LEVEL) - { - SendDeviceIoControlRequestWorkItemArgs args; - - PIO_WORKITEM workItem = IoAllocateWorkItem (RootDeviceObject); - if (!workItem) - return STATUS_INSUFFICIENT_RESOURCES; - - args.deviceObject = deviceObject; - args.ioControlCode = ioControlCode; - args.inputBuffer = inputBuffer; - args.inputBufferSize = inputBufferSize; - args.outputBuffer = outputBuffer; - args.outputBufferSize = outputBufferSize; - - KeInitializeEvent (&args.WorkItemCompletedEvent, SynchronizationEvent, FALSE); - IoQueueWorkItem (workItem, SendDeviceIoControlRequestWorkItemRoutine, DelayedWorkQueue, &args); - - KeWaitForSingleObject (&args.WorkItemCompletedEvent, Executive, KernelMode, FALSE, NULL); - IoFreeWorkItem (workItem); - - return args.Status; - } - - KeInitializeEvent (&event, NotificationEvent, FALSE); - - irp = IoBuildDeviceIoControlRequest (ioControlCode, deviceObject, inputBuffer, inputBufferSize, - outputBuffer, outputBufferSize, FALSE, &event, &ioStatusBlock); - - if (!irp) - return STATUS_INSUFFICIENT_RESOURCES; - - ObReferenceObject (deviceObject); - - status = IoCallDriver (deviceObject, irp); - if (status == STATUS_PENDING) - { - KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL); - status = ioStatusBlock.Status; - } - - ObDereferenceObject (deviceObject); - return status; -} - - -NTSTATUS ProbeRealDriveSize (PDEVICE_OBJECT driveDeviceObject, LARGE_INTEGER *driveSize) -{ - NTSTATUS status; - LARGE_INTEGER sysLength; - LARGE_INTEGER offset; - byte *sectorBuffer; - ULONGLONG startTime; - - if (!UserCanAccessDriveDevice()) - return STATUS_ACCESS_DENIED; - - sectorBuffer = TCalloc (TC_SECTOR_SIZE_BIOS); - if (!sectorBuffer) - return STATUS_INSUFFICIENT_RESOURCES; - - status = SendDeviceIoControlRequest (driveDeviceObject, IOCTL_DISK_GET_LENGTH_INFO, - NULL, 0, &sysLength, sizeof (sysLength)); - - if (!NT_SUCCESS (status)) - { - Dump ("Failed to get drive size - error %x\n", status); - TCfree (sectorBuffer); - return status; - } - - startTime = KeQueryInterruptTime (); - for (offset.QuadPart = sysLength.QuadPart; ; offset.QuadPart += TC_SECTOR_SIZE_BIOS) - { - status = TCReadDevice (driveDeviceObject, sectorBuffer, offset, TC_SECTOR_SIZE_BIOS); - - if (NT_SUCCESS (status)) - status = TCWriteDevice (driveDeviceObject, sectorBuffer, offset, TC_SECTOR_SIZE_BIOS); - - if (!NT_SUCCESS (status)) - { - driveSize->QuadPart = offset.QuadPart; - Dump ("Real drive size = %I64d bytes (%I64d hidden)\n", driveSize->QuadPart, driveSize->QuadPart - sysLength.QuadPart); - TCfree (sectorBuffer); - return STATUS_SUCCESS; - } - - if (KeQueryInterruptTime() - startTime > 3ULL * 60 * 1000 * 1000 * 10) - { - // Abort if probing for more than 3 minutes - driveSize->QuadPart = sysLength.QuadPart; - TCfree (sectorBuffer); - return STATUS_TIMEOUT; - } - } -} - - -NTSTATUS TCOpenFsVolume (PEXTENSION Extension, PHANDLE volumeHandle, PFILE_OBJECT * fileObject) -{ - NTSTATUS ntStatus; - OBJECT_ATTRIBUTES objectAttributes; - UNICODE_STRING fullFileName; - IO_STATUS_BLOCK ioStatus; - WCHAR volumeName[TC_MAX_PATH]; - - TCGetNTNameFromNumber (volumeName, sizeof(volumeName),Extension->nDosDriveNo); - RtlInitUnicodeString (&fullFileName, volumeName); - InitializeObjectAttributes (&objectAttributes, &fullFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); - - ntStatus = ZwCreateFile (volumeHandle, - SYNCHRONIZE | GENERIC_READ, - &objectAttributes, - &ioStatus, - NULL, - FILE_ATTRIBUTE_NORMAL, - FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_OPEN, - FILE_SYNCHRONOUS_IO_NONALERT, - NULL, - 0); - - Dump ("Volume %ls open NTSTATUS 0x%08x\n", volumeName, ntStatus); - - if (!NT_SUCCESS (ntStatus)) - return ntStatus; - - ntStatus = ObReferenceObjectByHandle (*volumeHandle, - FILE_READ_DATA, - NULL, - KernelMode, - fileObject, - NULL); - - if (!NT_SUCCESS (ntStatus)) - ZwClose (*volumeHandle); - - return ntStatus; -} - - -void TCCloseFsVolume (HANDLE volumeHandle, PFILE_OBJECT fileObject) -{ - ObDereferenceObject (fileObject); - ZwClose (volumeHandle); -} - - -static NTSTATUS TCReadWriteDevice (BOOL write, PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length) -{ - NTSTATUS status; - IO_STATUS_BLOCK ioStatusBlock; - PIRP irp; - KEVENT completionEvent; - - ASSERT (KeGetCurrentIrql() <= APC_LEVEL); - - KeInitializeEvent (&completionEvent, NotificationEvent, FALSE); - irp = IoBuildSynchronousFsdRequest (write ? IRP_MJ_WRITE : IRP_MJ_READ, deviceObject, buffer, length, &offset, &completionEvent, &ioStatusBlock); - if (!irp) - return STATUS_INSUFFICIENT_RESOURCES; - - ObReferenceObject (deviceObject); - status = IoCallDriver (deviceObject, irp); - - if (status == STATUS_PENDING) - { - status = KeWaitForSingleObject (&completionEvent, Executive, KernelMode, FALSE, NULL); - if (NT_SUCCESS (status)) - status = ioStatusBlock.Status; - } - - ObDereferenceObject (deviceObject); - return status; -} - - -NTSTATUS TCReadDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length) -{ - return TCReadWriteDevice (FALSE, deviceObject, buffer, offset, length); -} - - -NTSTATUS TCWriteDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length) -{ - return TCReadWriteDevice (TRUE, deviceObject, buffer, offset, length); -} - - -NTSTATUS TCFsctlCall (PFILE_OBJECT fileObject, LONG IoControlCode, - void *InputBuffer, int InputBufferSize, void *OutputBuffer, int OutputBufferSize) -{ - IO_STATUS_BLOCK ioStatusBlock; - NTSTATUS ntStatus; - PIRP irp; - KEVENT event; - PIO_STACK_LOCATION stack; - PDEVICE_OBJECT deviceObject = IoGetRelatedDeviceObject (fileObject); - - KeInitializeEvent(&event, NotificationEvent, FALSE); - - irp = IoBuildDeviceIoControlRequest (IoControlCode, - deviceObject, - InputBuffer, InputBufferSize, - OutputBuffer, OutputBufferSize, - FALSE, - &event, - &ioStatusBlock); - - if (irp == NULL) - return STATUS_INSUFFICIENT_RESOURCES; - - stack = IoGetNextIrpStackLocation(irp); - - stack->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; - stack->MinorFunction = IRP_MN_USER_FS_REQUEST; - stack->FileObject = fileObject; - - ntStatus = IoCallDriver (deviceObject, irp); - if (ntStatus == STATUS_PENDING) - { - KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL); - ntStatus = ioStatusBlock.Status; - } - - return ntStatus; -} - - -NTSTATUS CreateDriveLink (int nDosDriveNo) -{ - WCHAR dev[128], link[128]; - UNICODE_STRING deviceName, symLink; - NTSTATUS ntStatus; - - TCGetNTNameFromNumber (dev, sizeof(dev),nDosDriveNo); - TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, DeviceNamespaceDefault); - - RtlInitUnicodeString (&deviceName, dev); - RtlInitUnicodeString (&symLink, link); - - ntStatus = IoCreateSymbolicLink (&symLink, &deviceName); - Dump ("IoCreateSymbolicLink returned %X\n", ntStatus); - return ntStatus; -} - - -NTSTATUS RemoveDriveLink (int nDosDriveNo) -{ - WCHAR link[256]; - UNICODE_STRING symLink; - NTSTATUS ntStatus; - - TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, DeviceNamespaceDefault); - RtlInitUnicodeString (&symLink, link); - - ntStatus = IoDeleteSymbolicLink (&symLink); - Dump ("IoDeleteSymbolicLink returned %X\n", ntStatus); - return ntStatus; -} - - -NTSTATUS MountManagerMount (MOUNT_STRUCT *mount) -{ - NTSTATUS ntStatus; - WCHAR arrVolume[256]; - char buf[200]; - PMOUNTMGR_TARGET_NAME in = (PMOUNTMGR_TARGET_NAME) buf; - PMOUNTMGR_CREATE_POINT_INPUT point = (PMOUNTMGR_CREATE_POINT_INPUT) buf; - - TCGetNTNameFromNumber (arrVolume, sizeof(arrVolume),mount->nDosDriveNo); - in->DeviceNameLength = (USHORT) wcslen (arrVolume) * 2; - RtlStringCbCopyW(in->DeviceName, sizeof(buf) - sizeof(in->DeviceNameLength),arrVolume); - - ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION, - in, (ULONG) (sizeof (in->DeviceNameLength) + wcslen (arrVolume) * 2), 0, 0); - - memset (buf, 0, sizeof buf); - TCGetDosNameFromNumber ((PWSTR) &point[1], sizeof(buf) - sizeof(MOUNTMGR_CREATE_POINT_INPUT),mount->nDosDriveNo, DeviceNamespaceDefault); - - point->SymbolicLinkNameOffset = sizeof (MOUNTMGR_CREATE_POINT_INPUT); - point->SymbolicLinkNameLength = (USHORT) wcslen ((PWSTR) &point[1]) * 2; - - point->DeviceNameOffset = point->SymbolicLinkNameOffset + point->SymbolicLinkNameLength; - TCGetNTNameFromNumber ((PWSTR) (buf + point->DeviceNameOffset), sizeof(buf) - point->DeviceNameOffset,mount->nDosDriveNo); - point->DeviceNameLength = (USHORT) wcslen ((PWSTR) (buf + point->DeviceNameOffset)) * 2; - - ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_CREATE_POINT, point, - point->DeviceNameOffset + point->DeviceNameLength, 0, 0); - - return ntStatus; -} - - -NTSTATUS MountManagerUnmount (int nDosDriveNo) -{ - NTSTATUS ntStatus; - char buf[256], out[300]; - PMOUNTMGR_MOUNT_POINT in = (PMOUNTMGR_MOUNT_POINT) buf; - - memset (buf, 0, sizeof buf); - - TCGetDosNameFromNumber ((PWSTR) &in[1], sizeof(buf) - sizeof(MOUNTMGR_MOUNT_POINT),nDosDriveNo, DeviceNamespaceDefault); - - // Only symbolic link can be deleted with IOCTL_MOUNTMGR_DELETE_POINTS. If any other entry is specified, the mount manager will ignore subsequent IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION for the same volume ID. - in->SymbolicLinkNameOffset = sizeof (MOUNTMGR_MOUNT_POINT); - in->SymbolicLinkNameLength = (USHORT) wcslen ((PWCHAR) &in[1]) * 2; - - ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_DELETE_POINTS, - in, sizeof(MOUNTMGR_MOUNT_POINT) + in->SymbolicLinkNameLength, out, sizeof out); - - Dump ("IOCTL_MOUNTMGR_DELETE_POINTS returned 0x%08x\n", ntStatus); - - return ntStatus; -} - - -NTSTATUS MountDevice (PDEVICE_OBJECT DeviceObject, MOUNT_STRUCT *mount) -{ - PDEVICE_OBJECT NewDeviceObject; - NTSTATUS ntStatus; - - // Make sure the user is asking for a reasonable nDosDriveNo - if (mount->nDosDriveNo >= 0 && mount->nDosDriveNo <= 25 - && IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceDefault) // drive letter must not exist both locally and globally - && IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceGlobal) - ) - { - Dump ("Mount request looks valid\n"); - } - else - { - Dump ("WARNING: MOUNT DRIVE LETTER INVALID\n"); - mount->nReturnCode = ERR_DRIVE_NOT_FOUND; - return ERR_DRIVE_NOT_FOUND; - } - - if (!SelfTestsPassed) - { - mount->nReturnCode = ERR_SELF_TESTS_FAILED; - return ERR_SELF_TESTS_FAILED; - } - - ntStatus = TCCreateDeviceObject (DeviceObject->DriverObject, &NewDeviceObject, mount); - - if (!NT_SUCCESS (ntStatus)) - { - Dump ("Mount CREATE DEVICE ERROR, ntStatus = 0x%08x\n", ntStatus); - return ntStatus; - } - else - { - PEXTENSION NewExtension = (PEXTENSION) NewDeviceObject->DeviceExtension; - SECURITY_SUBJECT_CONTEXT subContext; - PACCESS_TOKEN accessToken; - - SeCaptureSubjectContext (&subContext); - SeLockSubjectContext(&subContext); - if (subContext.ClientToken && subContext.ImpersonationLevel >= SecurityImpersonation) - accessToken = subContext.ClientToken; - else - accessToken = subContext.PrimaryToken; - - if (!accessToken) - { - ntStatus = STATUS_INVALID_PARAMETER; - } - else - { - PTOKEN_USER tokenUser; - - ntStatus = SeQueryInformationToken (accessToken, TokenUser, &tokenUser); - if (NT_SUCCESS (ntStatus)) - { - ULONG sidLength = RtlLengthSid (tokenUser->User.Sid); - - NewExtension->UserSid = TCalloc (sidLength); - if (!NewExtension->UserSid) - ntStatus = STATUS_INSUFFICIENT_RESOURCES; - else - ntStatus = RtlCopySid (sidLength, NewExtension->UserSid, tokenUser->User.Sid); - - ExFreePool (tokenUser); // Documented in newer versions of WDK - } - } - - SeUnlockSubjectContext(&subContext); - SeReleaseSubjectContext (&subContext); - - if (NT_SUCCESS (ntStatus)) - ntStatus = TCStartVolumeThread (NewDeviceObject, NewExtension, mount); - - if (!NT_SUCCESS (ntStatus)) - { - Dump ("Mount FAILURE NT ERROR, ntStatus = 0x%08x\n", ntStatus); - TCDeleteDeviceObject (NewDeviceObject, NewExtension); - return ntStatus; - } - else - { - if (mount->nReturnCode == 0) - { - HANDLE volumeHandle; - PFILE_OBJECT volumeFileObject; - ULONG labelLen = (ULONG) wcslen (mount->wszLabel); - BOOL bIsNTFS = FALSE; - ULONG labelMaxLen, labelEffectiveLen; - - Dump ("Mount SUCCESS TC code = 0x%08x READ-ONLY = %d\n", mount->nReturnCode, NewExtension->bReadOnly); - - if (NewExtension->bReadOnly) - NewDeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE; - - NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; - - NewExtension->UniqueVolumeId = LastUniqueVolumeId++; - - // check again that the drive letter is available globally and locally - if ( !IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceDefault) - || !IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceGlobal) - ) - { - TCDeleteDeviceObject (NewDeviceObject, NewExtension); - mount->nReturnCode = ERR_DRIVE_NOT_FOUND; - return ERR_DRIVE_NOT_FOUND; - } - - if (mount->bMountManager) - MountManagerMount (mount); - - NewExtension->bMountManager = mount->bMountManager; - - // We create symbolic link even if mount manager is notified of - // arriving volume as it apparently sometimes fails to create the link - CreateDriveLink (mount->nDosDriveNo); - - mount->FilesystemDirty = FALSE; - - if (NT_SUCCESS (TCOpenFsVolume (NewExtension, &volumeHandle, &volumeFileObject))) - { - __try - { - ULONG fsStatus; - - if (NT_SUCCESS (TCFsctlCall (volumeFileObject, FSCTL_IS_VOLUME_DIRTY, NULL, 0, &fsStatus, sizeof (fsStatus))) - && (fsStatus & VOLUME_IS_DIRTY)) - { - mount->FilesystemDirty = TRUE; - } - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - mount->FilesystemDirty = TRUE; - } - - // detect if the filesystem is NTFS or FAT - __try - { - NTFS_VOLUME_DATA_BUFFER ntfsData; - if (NT_SUCCESS (TCFsctlCall (volumeFileObject, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &ntfsData, sizeof (ntfsData)))) - { - bIsNTFS = TRUE; - } - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - bIsNTFS = FALSE; - } - - NewExtension->bIsNTFS = bIsNTFS; - mount->bIsNTFS = bIsNTFS; - - if (labelLen > 0) - { - if (bIsNTFS) - labelMaxLen = 32; // NTFS maximum label length - else - labelMaxLen = 11; // FAT maximum label length - - // calculate label effective length - labelEffectiveLen = labelLen > labelMaxLen? labelMaxLen : labelLen; - - // correct the label in the device - memset (&NewExtension->wszLabel[labelEffectiveLen], 0, 33 - labelEffectiveLen); - memcpy (mount->wszLabel, NewExtension->wszLabel, 33); - - // set the volume label - __try - { - IO_STATUS_BLOCK ioblock; - ULONG labelInfoSize = sizeof(FILE_FS_LABEL_INFORMATION) + (labelEffectiveLen * sizeof(WCHAR)); - FILE_FS_LABEL_INFORMATION* labelInfo = (FILE_FS_LABEL_INFORMATION*) TCalloc (labelInfoSize); - labelInfo->VolumeLabelLength = labelEffectiveLen * sizeof(WCHAR); - memcpy (labelInfo->VolumeLabel, mount->wszLabel, labelInfo->VolumeLabelLength); - - if (STATUS_SUCCESS == ZwSetVolumeInformationFile (volumeHandle, &ioblock, labelInfo, labelInfoSize, FileFsLabelInformation)) - { - mount->bDriverSetLabel = TRUE; - NewExtension->bDriverSetLabel = TRUE; - } - - TCfree(labelInfo); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - - } - } - - TCCloseFsVolume (volumeHandle, volumeFileObject); - } - } - else - { - Dump ("Mount FAILURE TC code = 0x%08x\n", mount->nReturnCode); - TCDeleteDeviceObject (NewDeviceObject, NewExtension); - } - - return STATUS_SUCCESS; - } - } -} - -NTSTATUS UnmountDevice (UNMOUNT_STRUCT *unmountRequest, PDEVICE_OBJECT deviceObject, BOOL ignoreOpenFiles) -{ - PEXTENSION extension = deviceObject->DeviceExtension; - NTSTATUS ntStatus; - HANDLE volumeHandle; - PFILE_OBJECT volumeFileObject; - - Dump ("UnmountDevice %d\n", extension->nDosDriveNo); - - ntStatus = TCOpenFsVolume (extension, &volumeHandle, &volumeFileObject); - - if (NT_SUCCESS (ntStatus)) - { - int dismountRetry; - - // Dismounting a writable NTFS filesystem prevents the driver from being unloaded on Windows 7 - if (IsOSAtLeast (WIN_7) && !extension->bReadOnly) - { - NTFS_VOLUME_DATA_BUFFER ntfsData; - - if (NT_SUCCESS (TCFsctlCall (volumeFileObject, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &ntfsData, sizeof (ntfsData)))) - DriverUnloadDisabled = TRUE; - } - - // Lock volume - ntStatus = TCFsctlCall (volumeFileObject, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0); - Dump ("FSCTL_LOCK_VOLUME returned %X\n", ntStatus); - - if (!NT_SUCCESS (ntStatus) && !ignoreOpenFiles) - { - TCCloseFsVolume (volumeHandle, volumeFileObject); - return ERR_FILES_OPEN; - } - - // Dismount volume - for (dismountRetry = 0; dismountRetry < 200; ++dismountRetry) - { - ntStatus = TCFsctlCall (volumeFileObject, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0); - Dump ("FSCTL_DISMOUNT_VOLUME returned %X\n", ntStatus); - - if (NT_SUCCESS (ntStatus) || ntStatus == STATUS_VOLUME_DISMOUNTED) - break; - - if (!ignoreOpenFiles) - { - TCCloseFsVolume (volumeHandle, volumeFileObject); - return ERR_FILES_OPEN; - } - - TCSleep (100); - } - } - else - { - // Volume cannot be opened => force dismount if allowed - if (!ignoreOpenFiles) - return ERR_FILES_OPEN; - else - volumeHandle = NULL; - } - - if (extension->bMountManager) - MountManagerUnmount (extension->nDosDriveNo); - - // We always remove symbolic link as mount manager might fail to do so - RemoveDriveLink (extension->nDosDriveNo); - - extension->bShuttingDown = TRUE; - - ntStatus = IoAcquireRemoveLock (&extension->Queue.RemoveLock, NULL); - ASSERT (NT_SUCCESS (ntStatus)); - IoReleaseRemoveLockAndWait (&extension->Queue.RemoveLock, NULL); - - if (volumeHandle != NULL) - TCCloseFsVolume (volumeHandle, volumeFileObject); - - if (unmountRequest) - { - PCRYPTO_INFO cryptoInfo = ((PEXTENSION) deviceObject->DeviceExtension)->cryptoInfo; - unmountRequest->HiddenVolumeProtectionTriggered = (cryptoInfo->bProtectHiddenVolume && cryptoInfo->bHiddenVolProtectionAction); - } - - TCDeleteDeviceObject (deviceObject, (PEXTENSION) deviceObject->DeviceExtension); - return 0; -} - - -static PDEVICE_OBJECT FindVolumeWithHighestUniqueId (int maxUniqueId) -{ - PDEVICE_OBJECT highestIdDevice = NULL; - int highestId = -1; - int drive; - - for (drive = MIN_MOUNTED_VOLUME_DRIVE_NUMBER; drive <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; ++drive) - { - PDEVICE_OBJECT device = GetVirtualVolumeDeviceObject (drive); - if (device) - { - PEXTENSION extension = (PEXTENSION) device->DeviceExtension; - if (extension->UniqueVolumeId > highestId && extension->UniqueVolumeId <= maxUniqueId) - { - highestId = extension->UniqueVolumeId; - highestIdDevice = device; - } - } - } - - return highestIdDevice; -} - - -NTSTATUS UnmountAllDevices (UNMOUNT_STRUCT *unmountRequest, BOOL ignoreOpenFiles) -{ - NTSTATUS status = 0; - PDEVICE_OBJECT ListDevice; - int maxUniqueId = LastUniqueVolumeId; - - Dump ("Unmounting all volumes\n"); - - if (unmountRequest) - unmountRequest->HiddenVolumeProtectionTriggered = FALSE; - - // Dismount volumes in the reverse order they were mounted to properly dismount nested volumes - while ((ListDevice = FindVolumeWithHighestUniqueId (maxUniqueId)) != NULL) - { - PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension; - maxUniqueId = ListExtension->UniqueVolumeId - 1; - - if (IsVolumeAccessibleByCurrentUser (ListExtension)) - { - NTSTATUS ntStatus; - - if (unmountRequest) - unmountRequest->nDosDriveNo = ListExtension->nDosDriveNo; - - ntStatus = UnmountDevice (unmountRequest, ListDevice, ignoreOpenFiles); - status = ntStatus == 0 ? status : ntStatus; - - if (unmountRequest && unmountRequest->HiddenVolumeProtectionTriggered) - break; - } - } - - return status; -} - -// Resolves symbolic link name to its target name -NTSTATUS SymbolicLinkToTarget (PWSTR symlinkName, PWSTR targetName, USHORT maxTargetNameLength) -{ - NTSTATUS ntStatus; - OBJECT_ATTRIBUTES objectAttributes; - UNICODE_STRING fullFileName; - HANDLE handle; - - RtlInitUnicodeString (&fullFileName, symlinkName); - InitializeObjectAttributes (&objectAttributes, &fullFileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); - - ntStatus = ZwOpenSymbolicLinkObject (&handle, GENERIC_READ, &objectAttributes); - - if (NT_SUCCESS (ntStatus)) - { - UNICODE_STRING target; - target.Buffer = targetName; - target.Length = 0; - target.MaximumLength = maxTargetNameLength; - memset (targetName, 0, maxTargetNameLength); - - ntStatus = ZwQuerySymbolicLinkObject (handle, &target, NULL); - - ZwClose (handle); - } - - return ntStatus; -} - - -// Checks if two regions overlap (borders are parts of regions) -BOOL RegionsOverlap (unsigned __int64 start1, unsigned __int64 end1, unsigned __int64 start2, unsigned __int64 end2) -{ - return (start1 < start2) ? (end1 >= start2) : (start1 <= end2); -} - - -void GetIntersection (uint64 start1, uint32 length1, uint64 start2, uint64 end2, uint64 *intersectStart, uint32 *intersectLength) -{ - uint64 end1 = start1 + length1 - 1; - uint64 intersectEnd = (end1 <= end2) ? end1 : end2; - - *intersectStart = (start1 >= start2) ? start1 : start2; - *intersectLength = (uint32) ((*intersectStart > intersectEnd) ? 0 : intersectEnd + 1 - *intersectStart); - - if (*intersectLength == 0) - *intersectStart = start1; -} - - -BOOL IsAccessibleByUser (PUNICODE_STRING objectFileName, BOOL readOnly) -{ - OBJECT_ATTRIBUTES fileObjAttributes; - IO_STATUS_BLOCK ioStatusBlock; - HANDLE fileHandle; - NTSTATUS status; - - ASSERT (!IoIsSystemThread (PsGetCurrentThread())); - - InitializeObjectAttributes (&fileObjAttributes, objectFileName, OBJ_CASE_INSENSITIVE | OBJ_FORCE_ACCESS_CHECK | OBJ_KERNEL_HANDLE, NULL, NULL); - - status = ZwCreateFile (&fileHandle, - readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, - &fileObjAttributes, - &ioStatusBlock, - NULL, - FILE_ATTRIBUTE_NORMAL, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - FILE_OPEN, - FILE_SYNCHRONOUS_IO_NONALERT, - NULL, - 0); - - if (NT_SUCCESS (status)) - { - ZwClose (fileHandle); - return TRUE; - } - - return FALSE; -} - - -BOOL UserCanAccessDriveDevice () -{ - UNICODE_STRING name; - RtlInitUnicodeString (&name, L"\\Device\\MountPointManager"); - - return IsAccessibleByUser (&name, FALSE); -} - -BOOL IsDriveLetterAvailable (int nDosDriveNo, DeviceNamespaceType namespaceType) -{ - OBJECT_ATTRIBUTES objectAttributes; - UNICODE_STRING objectName; - WCHAR link[128]; - HANDLE handle; - NTSTATUS ntStatus; - - TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, namespaceType); - RtlInitUnicodeString (&objectName, link); - InitializeObjectAttributes (&objectAttributes, &objectName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); - - if (NT_SUCCESS (ntStatus = ZwOpenSymbolicLinkObject (&handle, GENERIC_READ, &objectAttributes))) - { - ZwClose (handle); - return FALSE; - } - - return (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND)? TRUE : FALSE; -} - - -NTSTATUS TCCompleteIrp (PIRP irp, NTSTATUS status, ULONG_PTR information) -{ - irp->IoStatus.Status = status; - irp->IoStatus.Information = information; - IoCompleteRequest (irp, IO_NO_INCREMENT); - return status; -} - - -NTSTATUS TCCompleteDiskIrp (PIRP irp, NTSTATUS status, ULONG_PTR information) -{ - irp->IoStatus.Status = status; - irp->IoStatus.Information = information; - IoCompleteRequest (irp, NT_SUCCESS (status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT); - return status; -} - - -size_t GetCpuCount () -{ - KAFFINITY activeCpuMap = KeQueryActiveProcessors(); - size_t mapSize = sizeof (activeCpuMap) * 8; - size_t cpuCount = 0; - - while (mapSize--) - { - if (activeCpuMap & 1) - ++cpuCount; - - activeCpuMap >>= 1; - } - - if (cpuCount == 0) - return 1; - - return cpuCount; -} - - -void EnsureNullTerminatedString (wchar_t *str, size_t maxSizeInBytes) -{ - ASSERT ((maxSizeInBytes & 1) == 0); - str[maxSizeInBytes / sizeof (wchar_t) - 1] = 0; -} - - -void *AllocateMemoryWithTimeout (size_t size, int retryDelay, int timeout) -{ - LARGE_INTEGER waitInterval; - waitInterval.QuadPart = retryDelay * -10000; - - ASSERT (KeGetCurrentIrql() <= APC_LEVEL); - ASSERT (retryDelay > 0 && retryDelay <= timeout); - - while (TRUE) - { - void *memory = TCalloc (size); - if (memory) - return memory; - - timeout -= retryDelay; - if (timeout <= 0) - break; - - KeDelayExecutionThread (KernelMode, FALSE, &waitInterval); - } - - return NULL; -} - - -NTSTATUS TCReadRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, PKEY_VALUE_PARTIAL_INFORMATION *keyData) -{ - OBJECT_ATTRIBUTES regObjAttribs; - HANDLE regKeyHandle; - NTSTATUS status; - UNICODE_STRING valName; - ULONG size = 0; - ULONG resultSize; - - InitializeObjectAttributes (®ObjAttribs, keyPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); - status = ZwOpenKey (®KeyHandle, KEY_READ, ®ObjAttribs); - if (!NT_SUCCESS (status)) - return status; - - RtlInitUnicodeString (&valName, keyValueName); - status = ZwQueryValueKey (regKeyHandle, &valName, KeyValuePartialInformation, NULL, 0, &size); - - if (!NT_SUCCESS (status) && status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL) - { - ZwClose (regKeyHandle); - return status; - } - - if (size == 0) - { - ZwClose (regKeyHandle); - return STATUS_NO_DATA_DETECTED; - } - - *keyData = (PKEY_VALUE_PARTIAL_INFORMATION) TCalloc (size); - if (!*keyData) - { - ZwClose (regKeyHandle); - return STATUS_INSUFFICIENT_RESOURCES; - } - - status = ZwQueryValueKey (regKeyHandle, &valName, KeyValuePartialInformation, *keyData, size, &resultSize); - - ZwClose (regKeyHandle); - return status; -} - - -NTSTATUS TCWriteRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, ULONG keyValueType, void *valueData, ULONG valueSize) -{ - OBJECT_ATTRIBUTES regObjAttribs; - HANDLE regKeyHandle; - NTSTATUS status; - UNICODE_STRING valName; - - InitializeObjectAttributes (®ObjAttribs, keyPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); - status = ZwOpenKey (®KeyHandle, KEY_READ | KEY_WRITE, ®ObjAttribs); - if (!NT_SUCCESS (status)) - return status; - - RtlInitUnicodeString (&valName, keyValueName); - - status = ZwSetValueKey (regKeyHandle, &valName, 0, keyValueType, valueData, valueSize); - - ZwClose (regKeyHandle); - return status; -} - - -BOOL IsVolumeClassFilterRegistered () -{ - UNICODE_STRING name; - NTSTATUS status; - BOOL registered = FALSE; - - PKEY_VALUE_PARTIAL_INFORMATION data; - - RtlInitUnicodeString (&name, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Class\\{71A27CDD-812A-11D0-BEC7-08002BE2092F}"); - status = TCReadRegistryKey (&name, L"UpperFilters", &data); - - if (NT_SUCCESS (status)) - { - if (data->Type == REG_MULTI_SZ && data->DataLength >= 9 * sizeof (wchar_t)) - { - // Search for the string "veracrypt" - ULONG i; - for (i = 0; i <= data->DataLength - 9 * sizeof (wchar_t); ++i) - { - if (memcmp (data->Data + i, L"veracrypt", 9 * sizeof (wchar_t)) == 0) - { - Dump ("Volume class filter active\n"); - registered = TRUE; - break; - } - } - } - - TCfree (data); - } - - return registered; -} - - -NTSTATUS ReadRegistryConfigFlags (BOOL driverEntry) -{ - PKEY_VALUE_PARTIAL_INFORMATION data; - UNICODE_STRING name; - NTSTATUS status; - uint32 flags = 0; - - RtlInitUnicodeString (&name, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\veracrypt"); - status = TCReadRegistryKey (&name, TC_DRIVER_CONFIG_REG_VALUE_NAME, &data); - - if (NT_SUCCESS (status)) - { - if (data->Type == REG_DWORD) - { - flags = *(uint32 *) data->Data; - Dump ("Configuration flags = 0x%x\n", flags); - - if (driverEntry) - { - if (flags & (TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD | TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD_FOR_SYS_FAVORITES)) - CacheBootPassword = TRUE; - - if (flags & TC_DRIVER_CONFIG_DISABLE_NONADMIN_SYS_FAVORITES_ACCESS) - NonAdminSystemFavoritesAccessDisabled = TRUE; - - if (flags & TC_DRIVER_CONFIG_CACHE_BOOT_PIM) - CacheBootPim = TRUE; - } - - EnableHwEncryption ((flags & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION) ? FALSE : TRUE); - - EnableExtendedIoctlSupport = (flags & TC_DRIVER_CONFIG_ENABLE_EXTENDED_IOCTL)? TRUE : FALSE; - } - else - status = STATUS_INVALID_PARAMETER; - - TCfree (data); - } - - if (driverEntry && NT_SUCCESS (TCReadRegistryKey (&name, TC_ENCRYPTION_FREE_CPU_COUNT_REG_VALUE_NAME, &data))) - { - if (data->Type == REG_DWORD) - EncryptionThreadPoolFreeCpuCountLimit = *(uint32 *) data->Data; - - TCfree (data); - } - - return status; -} - - -NTSTATUS WriteRegistryConfigFlags (uint32 flags) -{ - UNICODE_STRING name; - RtlInitUnicodeString (&name, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\veracrypt"); - - return TCWriteRegistryKey (&name, TC_DRIVER_CONFIG_REG_VALUE_NAME, REG_DWORD, &flags, sizeof (flags)); -} - - -NTSTATUS GetDeviceSectorSize (PDEVICE_OBJECT deviceObject, ULONG *bytesPerSector) -{ - NTSTATUS status; - DISK_GEOMETRY geometry; - - status = SendDeviceIoControlRequest (deviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof (geometry)); - - if (!NT_SUCCESS (status)) - return status; - - *bytesPerSector = geometry.BytesPerSector; - return STATUS_SUCCESS; -} - - -NTSTATUS ZeroUnreadableSectors (PDEVICE_OBJECT deviceObject, LARGE_INTEGER startOffset, ULONG size, uint64 *zeroedSectorCount) -{ - NTSTATUS status; - ULONG sectorSize; - ULONG sectorCount; - byte *sectorBuffer = NULL; - - *zeroedSectorCount = 0; - - status = GetDeviceSectorSize (deviceObject, §orSize); - if (!NT_SUCCESS (status)) - return status; - - sectorBuffer = TCalloc (sectorSize); - if (!sectorBuffer) - return STATUS_INSUFFICIENT_RESOURCES; - - for (sectorCount = size / sectorSize; sectorCount > 0; --sectorCount, startOffset.QuadPart += sectorSize) - { - status = TCReadDevice (deviceObject, sectorBuffer, startOffset, sectorSize); - if (!NT_SUCCESS (status)) - { - Dump ("Zeroing sector at %I64d\n", startOffset.QuadPart); - memset (sectorBuffer, 0, sectorSize); - - status = TCWriteDevice (deviceObject, sectorBuffer, startOffset, sectorSize); - if (!NT_SUCCESS (status)) - goto err; - - ++(*zeroedSectorCount); - } - } - - status = STATUS_SUCCESS; - -err: - if (sectorBuffer) - TCfree (sectorBuffer); - - return status; -} - - -NTSTATUS ReadDeviceSkipUnreadableSectors (PDEVICE_OBJECT deviceObject, byte *buffer, LARGE_INTEGER startOffset, ULONG size, uint64 *badSectorCount) -{ - NTSTATUS status; - ULONG sectorSize; - ULONG sectorCount; - - *badSectorCount = 0; - - status = GetDeviceSectorSize (deviceObject, §orSize); - if (!NT_SUCCESS (status)) - return status; - - for (sectorCount = size / sectorSize; sectorCount > 0; --sectorCount, startOffset.QuadPart += sectorSize, buffer += sectorSize) - { - status = TCReadDevice (deviceObject, buffer, startOffset, sectorSize); - if (!NT_SUCCESS (status)) - { - Dump ("Skipping bad sector at %I64d\n", startOffset.QuadPart); - memset (buffer, 0, sectorSize); - ++(*badSectorCount); - } - } - - return STATUS_SUCCESS; -} - - -BOOL IsVolumeAccessibleByCurrentUser (PEXTENSION volumeDeviceExtension) -{ - SECURITY_SUBJECT_CONTEXT subContext; - PACCESS_TOKEN accessToken; - PTOKEN_USER tokenUser; - BOOL result = FALSE; - - if (IoIsSystemThread (PsGetCurrentThread()) - || UserCanAccessDriveDevice() - || !volumeDeviceExtension->UserSid - || (volumeDeviceExtension->SystemFavorite && !NonAdminSystemFavoritesAccessDisabled)) - { - return TRUE; - } - - SeCaptureSubjectContext (&subContext); - SeLockSubjectContext(&subContext); - if (subContext.ClientToken && subContext.ImpersonationLevel >= SecurityImpersonation) - accessToken = subContext.ClientToken; - else - accessToken = subContext.PrimaryToken; - - if (!accessToken) - goto ret; - - if (SeTokenIsAdmin (accessToken)) - { - result = TRUE; - goto ret; - } - - if (!NT_SUCCESS (SeQueryInformationToken (accessToken, TokenUser, &tokenUser))) - goto ret; - - result = RtlEqualSid (volumeDeviceExtension->UserSid, tokenUser->User.Sid); - ExFreePool (tokenUser); // Documented in newer versions of WDK - -ret: - SeUnlockSubjectContext(&subContext); - SeReleaseSubjectContext (&subContext); - return result; -} - - -void GetElapsedTimeInit (LARGE_INTEGER *lastPerfCounter) -{ - *lastPerfCounter = KeQueryPerformanceCounter (NULL); -} - - -// Returns elapsed time in microseconds since last call -int64 GetElapsedTime (LARGE_INTEGER *lastPerfCounter) -{ - LARGE_INTEGER freq; - LARGE_INTEGER counter = KeQueryPerformanceCounter (&freq); - - int64 elapsed = (counter.QuadPart - lastPerfCounter->QuadPart) * 1000000LL / freq.QuadPart; - *lastPerfCounter = counter; - - return elapsed; -} - - -BOOL IsOSAtLeast (OSVersionEnum reqMinOS) -{ - /* When updating this function, update IsOSVersionAtLeast() in Dlgcode.c too. */ - - ULONG major = 0, minor = 0; - - ASSERT (OsMajorVersion != 0); - - switch (reqMinOS) - { - case WIN_2000: major = 5; minor = 0; break; - case WIN_XP: major = 5; minor = 1; break; - case WIN_SERVER_2003: major = 5; minor = 2; break; - case WIN_VISTA: major = 6; minor = 0; break; - case WIN_7: major = 6; minor = 1; break; - case WIN_8: major = 6; minor = 2; break; - case WIN_8_1: major = 6; minor = 3; break; - case WIN_10: major = 10; minor = 0; break; - - default: - TC_THROW_FATAL_EXCEPTION; - break; - } - - return ((OsMajorVersion << 16 | OsMinorVersion << 8) - >= (major << 16 | minor << 8)); -} +/* + Legal Notice: Some portions of the source code contained in this file were + derived from the source code of TrueCrypt 7.1a, which is + Copyright (c) 2003-2012 TrueCrypt Developers Association and which is + governed by the TrueCrypt License 3.0, also from the source code of + Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux + and which is governed by the 'License Agreement for Encryption for the Masses' + Modifications and additions to the original source code (contained in this file) + and all other portions of this file are Copyright (c) 2013-2016 IDRIX + and are governed by the Apache License 2.0 the full text of which is + contained in the file License.txt included in VeraCrypt binary and source + code distribution packages. */ + +#include "TCdefs.h" +#include +#include "Crypto.h" +#include "Fat.h" +#include "Tests.h" +#include "cpu.h" + +#include "Apidrvr.h" +#include "Boot/Windows/BootDefs.h" +#include "EncryptedIoQueue.h" +#include "EncryptionThreadPool.h" +#include "Ntdriver.h" +#include "Ntvol.h" +#include "DriveFilter.h" +#include "DumpFilter.h" +#include "Cache.h" +#include "Volumes.h" +#include "VolumeFilter.h" + +#include +#include +#include +#include +#include + +#include +#include + +/* Init section, which is thrown away as soon as DriverEntry returns */ +#pragma alloc_text(INIT,DriverEntry) +#pragma alloc_text(INIT,TCCreateRootDeviceObject) + +PDRIVER_OBJECT TCDriverObject; +PDEVICE_OBJECT RootDeviceObject = NULL; +static KMUTEX RootDeviceControlMutex; +BOOL DriverShuttingDown = FALSE; +BOOL SelfTestsPassed; +int LastUniqueVolumeId; +ULONG OsMajorVersion = 0; +ULONG OsMinorVersion; +BOOL DriverUnloadDisabled = FALSE; +BOOL PortableMode = FALSE; +BOOL VolumeClassFilterRegistered = FALSE; +BOOL CacheBootPassword = FALSE; +BOOL CacheBootPim = FALSE; +BOOL NonAdminSystemFavoritesAccessDisabled = FALSE; +static size_t EncryptionThreadPoolFreeCpuCountLimit = 0; +static BOOL SystemFavoriteVolumeDirty = FALSE; +static BOOL PagingFileCreationPrevented = FALSE; +static BOOL EnableExtendedIoctlSupport = FALSE; + +PDEVICE_OBJECT VirtualVolumeDeviceObjects[MAX_MOUNTED_VOLUME_DRIVE_NUMBER + 1]; + + +NTSTATUS DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) +{ + PKEY_VALUE_PARTIAL_INFORMATION startKeyValue; + LONG version; + int i; + + Dump ("DriverEntry " TC_APP_NAME " " VERSION_STRING "\n"); + + DetectX86Features (); + + PsGetVersion (&OsMajorVersion, &OsMinorVersion, NULL, NULL); + + // Load dump filter if the main driver is already loaded + if (NT_SUCCESS (TCDeviceIoControl (NT_ROOT_PREFIX, TC_IOCTL_GET_DRIVER_VERSION, NULL, 0, &version, sizeof (version)))) + return DumpFilterEntry ((PFILTER_EXTENSION) DriverObject, (PFILTER_INITIALIZATION_DATA) RegistryPath); + + TCDriverObject = DriverObject; + memset (VirtualVolumeDeviceObjects, 0, sizeof (VirtualVolumeDeviceObjects)); + + ReadRegistryConfigFlags (TRUE); + EncryptionThreadPoolStart (EncryptionThreadPoolFreeCpuCountLimit); + SelfTestsPassed = AutoTestAlgorithms(); + + // Enable device class filters and load boot arguments if the driver is set to start at system boot + + if (NT_SUCCESS (TCReadRegistryKey (RegistryPath, L"Start", &startKeyValue))) + { + if (startKeyValue->Type == REG_DWORD && *((uint32 *) startKeyValue->Data) == SERVICE_BOOT_START) + { + if (!SelfTestsPassed) + TC_BUG_CHECK (STATUS_INVALID_PARAMETER); + + LoadBootArguments(); + VolumeClassFilterRegistered = IsVolumeClassFilterRegistered(); + + DriverObject->DriverExtension->AddDevice = DriverAddDevice; + } + + TCfree (startKeyValue); + } + + for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i) + { + DriverObject->MajorFunction[i] = TCDispatchQueueIRP; + } + + DriverObject->DriverUnload = TCUnloadDriver; + return TCCreateRootDeviceObject (DriverObject); +} + + +NTSTATUS DriverAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo) +{ +#ifdef DEBUG + char nameInfoBuffer[128]; + POBJECT_NAME_INFORMATION nameInfo = (POBJECT_NAME_INFORMATION) nameInfoBuffer; + ULONG nameInfoSize; + Dump ("AddDevice pdo=%p type=%x name=%ws\n", pdo, pdo->DeviceType, NT_SUCCESS (ObQueryNameString (pdo, nameInfo, sizeof (nameInfoBuffer), &nameInfoSize)) ? nameInfo->Name.Buffer : L"?"); +#endif + + if (VolumeClassFilterRegistered && BootArgsValid && BootArgs.HiddenSystemPartitionStart != 0) + { + PWSTR interfaceLinks = NULL; + if (NT_SUCCESS (IoGetDeviceInterfaces (&GUID_DEVINTERFACE_VOLUME, pdo, DEVICE_INTERFACE_INCLUDE_NONACTIVE, &interfaceLinks)) && interfaceLinks) + { + if (interfaceLinks[0] != UNICODE_NULL) + { + Dump ("Volume pdo=%p interface=%ws\n", pdo, interfaceLinks); + ExFreePool (interfaceLinks); + + return VolumeFilterAddDevice (driverObject, pdo); + } + + ExFreePool (interfaceLinks); + } + } + + return DriveFilterAddDevice (driverObject, pdo); +} + + +// Dumps a memory region to debug output +void DumpMemory (void *mem, int size) +{ + unsigned char str[20]; + unsigned char *m = mem; + int i,j; + + for (j = 0; j < size / 8; j++) + { + memset (str,0,sizeof str); + for (i = 0; i < 8; i++) + { + if (m[i] > ' ' && m[i] <= '~') + str[i]=m[i]; + else + str[i]='.'; + } + + Dump ("0x%08p %02x %02x %02x %02x %02x %02x %02x %02x %s\n", + m, m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], str); + + m+=8; + } +} + + +BOOL ValidateIOBufferSize (PIRP irp, size_t requiredBufferSize, ValidateIOBufferSizeType type) +{ + PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp); + BOOL input = (type == ValidateInput || type == ValidateInputOutput); + BOOL output = (type == ValidateOutput || type == ValidateInputOutput); + + if ((input && irpSp->Parameters.DeviceIoControl.InputBufferLength < requiredBufferSize) + || (output && irpSp->Parameters.DeviceIoControl.OutputBufferLength < requiredBufferSize)) + { + Dump ("STATUS_BUFFER_TOO_SMALL ioctl=0x%x,%d in=%d out=%d reqsize=%d insize=%d outsize=%d\n", (int) (irpSp->Parameters.DeviceIoControl.IoControlCode >> 16), (int) ((irpSp->Parameters.DeviceIoControl.IoControlCode & 0x1FFF) >> 2), input, output, requiredBufferSize, irpSp->Parameters.DeviceIoControl.InputBufferLength, irpSp->Parameters.DeviceIoControl.OutputBufferLength); + + irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + irp->IoStatus.Information = 0; + return FALSE; + } + + if (!input && output) + memset (irp->AssociatedIrp.SystemBuffer, 0, irpSp->Parameters.DeviceIoControl.OutputBufferLength); + + return TRUE; +} + + +PDEVICE_OBJECT GetVirtualVolumeDeviceObject (int driveNumber) +{ + if (driveNumber < MIN_MOUNTED_VOLUME_DRIVE_NUMBER || driveNumber > MAX_MOUNTED_VOLUME_DRIVE_NUMBER) + return NULL; + + return VirtualVolumeDeviceObjects[driveNumber]; +} + + +/* TCDispatchQueueIRP queues any IRP's so that they can be processed later + by the thread -- or in some cases handles them immediately! */ +NTSTATUS TCDispatchQueueIRP (PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + PEXTENSION Extension = (PEXTENSION) DeviceObject->DeviceExtension; + PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp); + NTSTATUS ntStatus; + +#ifdef _DEBUG + if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL && (Extension->bRootDevice || Extension->IsVolumeDevice)) + { + switch (irpSp->Parameters.DeviceIoControl.IoControlCode) + { + case TC_IOCTL_GET_MOUNTED_VOLUMES: + case TC_IOCTL_GET_PASSWORD_CACHE_STATUS: + case TC_IOCTL_GET_PORTABLE_MODE_STATUS: + case TC_IOCTL_SET_PORTABLE_MODE_STATUS: + case TC_IOCTL_OPEN_TEST: + case TC_IOCTL_GET_RESOLVED_SYMLINK: + case TC_IOCTL_GET_DEVICE_REFCOUNT: + case TC_IOCTL_GET_DRIVE_PARTITION_INFO: + case TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES: + case TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS: + case TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS: + case TC_IOCTL_GET_WARNING_FLAGS: + case TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING: + case IOCTL_DISK_CHECK_VERIFY: + break; + + default: + Dump ("%ls (0x%x %d)\n", + TCTranslateCode (irpSp->Parameters.DeviceIoControl.IoControlCode), + (int) (irpSp->Parameters.DeviceIoControl.IoControlCode >> 16), + (int) ((irpSp->Parameters.DeviceIoControl.IoControlCode & 0x1FFF) >> 2)); + } + } +#endif + + if (!Extension->bRootDevice) + { + // Drive filter IRP + if (Extension->IsDriveFilterDevice) + return DriveFilterDispatchIrp (DeviceObject, Irp); + + // Volume filter IRP + if (Extension->IsVolumeFilterDevice) + return VolumeFilterDispatchIrp (DeviceObject, Irp); + } + + switch (irpSp->MajorFunction) + { + case IRP_MJ_CLOSE: + case IRP_MJ_CREATE: + case IRP_MJ_CLEANUP: + return COMPLETE_IRP (DeviceObject, Irp, STATUS_SUCCESS, 0); + + case IRP_MJ_SHUTDOWN: + if (Extension->bRootDevice) + { + Dump ("Driver shutting down\n"); + DriverShuttingDown = TRUE; + + if (EncryptionSetupThread) + while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES); + + if (DecoySystemWipeThread) + while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES); + + OnShutdownPending(); + } + + return COMPLETE_IRP (DeviceObject, Irp, STATUS_SUCCESS, 0); + + case IRP_MJ_FLUSH_BUFFERS: + case IRP_MJ_READ: + case IRP_MJ_WRITE: + case IRP_MJ_DEVICE_CONTROL: + + if (Extension->bRootDevice) + { + if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) + { + NTSTATUS status = KeWaitForMutexObject (&RootDeviceControlMutex, Executive, KernelMode, FALSE, NULL); + if (!NT_SUCCESS (status)) + return status; + + status = ProcessMainDeviceControlIrp (DeviceObject, Extension, Irp); + + KeReleaseMutex (&RootDeviceControlMutex, FALSE); + return status; + } + break; + } + + if (Extension->bShuttingDown) + { + Dump ("Device %d shutting down: STATUS_DELETE_PENDING\n", Extension->nDosDriveNo); + return TCCompleteDiskIrp (Irp, STATUS_DELETE_PENDING, 0); + } + + if (Extension->bRemovable + && (DeviceObject->Flags & DO_VERIFY_VOLUME) + && !(irpSp->Flags & SL_OVERRIDE_VERIFY_VOLUME) + && irpSp->MajorFunction != IRP_MJ_FLUSH_BUFFERS) + { + Dump ("Removable device %d has DO_VERIFY_VOLUME flag: STATUS_DEVICE_NOT_READY\n", Extension->nDosDriveNo); + return TCCompleteDiskIrp (Irp, STATUS_DEVICE_NOT_READY, 0); + } + + switch (irpSp->MajorFunction) + { + case IRP_MJ_READ: + case IRP_MJ_WRITE: + ntStatus = EncryptedIoQueueAddIrp (&Extension->Queue, Irp); + + if (ntStatus != STATUS_PENDING) + TCCompleteDiskIrp (Irp, ntStatus, 0); + + return ntStatus; + + case IRP_MJ_DEVICE_CONTROL: + ntStatus = IoAcquireRemoveLock (&Extension->Queue.RemoveLock, Irp); + if (!NT_SUCCESS (ntStatus)) + return TCCompleteIrp (Irp, ntStatus, 0); + + IoMarkIrpPending (Irp); + + ExInterlockedInsertTailList (&Extension->ListEntry, &Irp->Tail.Overlay.ListEntry, &Extension->ListSpinLock); + KeReleaseSemaphore (&Extension->RequestSemaphore, IO_DISK_INCREMENT, 1, FALSE); + + return STATUS_PENDING; + + case IRP_MJ_FLUSH_BUFFERS: + return TCCompleteDiskIrp (Irp, STATUS_SUCCESS, 0); + } + + break; + + case IRP_MJ_PNP: + if (!Extension->bRootDevice + && Extension->IsVolumeDevice + && irpSp->MinorFunction == IRP_MN_DEVICE_USAGE_NOTIFICATION + && irpSp->Parameters.UsageNotification.Type == DeviceUsageTypePaging + && irpSp->Parameters.UsageNotification.InPath) + { + PagingFileCreationPrevented = TRUE; + return TCCompleteIrp (Irp, STATUS_UNSUCCESSFUL, 0); + } + break; + } + + return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0); +} + +NTSTATUS TCCreateRootDeviceObject (PDRIVER_OBJECT DriverObject) +{ + UNICODE_STRING Win32NameString, ntUnicodeString; + WCHAR dosname[32], ntname[32]; + PDEVICE_OBJECT DeviceObject; + NTSTATUS ntStatus; + BOOL *bRootExtension; + + Dump ("TCCreateRootDeviceObject BEGIN\n"); + ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); + + RtlStringCbCopyW (dosname, sizeof(dosname),(LPWSTR) DOS_ROOT_PREFIX); + RtlStringCbCopyW (ntname, sizeof(ntname),(LPWSTR) NT_ROOT_PREFIX); + RtlInitUnicodeString (&ntUnicodeString, ntname); + RtlInitUnicodeString (&Win32NameString, dosname); + + Dump ("Creating root device nt=%ls dos=%ls\n", ntname, dosname); + + ntStatus = IoCreateDevice ( + DriverObject, + sizeof (BOOL), + &ntUnicodeString, + FILE_DEVICE_UNKNOWN, + FILE_DEVICE_SECURE_OPEN, + FALSE, + &DeviceObject); + + if (!NT_SUCCESS (ntStatus)) + { + Dump ("TCCreateRootDeviceObject NTSTATUS = 0x%08x END\n", ntStatus); + return ntStatus;/* Failed to create DeviceObject */ + } + + DeviceObject->Flags |= DO_DIRECT_IO; + DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; + + /* Setup the device extension */ + bRootExtension = (BOOL *) DeviceObject->DeviceExtension; + *bRootExtension = TRUE; + + KeInitializeMutex (&RootDeviceControlMutex, 0); + + ntStatus = IoCreateSymbolicLink (&Win32NameString, &ntUnicodeString); + + if (!NT_SUCCESS (ntStatus)) + { + Dump ("TCCreateRootDeviceObject NTSTATUS = 0x%08x END\n", ntStatus); + IoDeleteDevice (DeviceObject); + return ntStatus; + } + + IoRegisterShutdownNotification (DeviceObject); + RootDeviceObject = DeviceObject; + + Dump ("TCCreateRootDeviceObject STATUS_SUCCESS END\n"); + return STATUS_SUCCESS; +} + +NTSTATUS TCCreateDeviceObject (PDRIVER_OBJECT DriverObject, + PDEVICE_OBJECT * ppDeviceObject, + MOUNT_STRUCT * mount) +{ + UNICODE_STRING ntUnicodeString; + WCHAR ntname[32]; + PEXTENSION Extension; + NTSTATUS ntStatus; + ULONG devChars = 0; +#if defined (DEBUG) + WCHAR dosname[32]; +#endif + + Dump ("TCCreateDeviceObject BEGIN\n"); + ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); + + TCGetNTNameFromNumber (ntname, sizeof(ntname),mount->nDosDriveNo); + RtlInitUnicodeString (&ntUnicodeString, ntname); +#if defined (DEBUG) + TCGetDosNameFromNumber (dosname, sizeof(dosname),mount->nDosDriveNo, DeviceNamespaceDefault); +#endif + + devChars = FILE_DEVICE_SECURE_OPEN; + devChars |= mount->bMountReadOnly ? FILE_READ_ONLY_DEVICE : 0; + devChars |= mount->bMountRemovable ? FILE_REMOVABLE_MEDIA : 0; + + Dump ("Creating device nt=%ls dos=%ls\n", ntname, dosname); + + ntStatus = IoCreateDevice ( + DriverObject, /* Our Driver Object */ + sizeof (EXTENSION), /* Size of state information */ + &ntUnicodeString, /* Device name "\Device\Name" */ + FILE_DEVICE_DISK, /* Device type */ + devChars, /* Device characteristics */ + FALSE, /* Exclusive device */ + ppDeviceObject); /* Returned ptr to Device Object */ + + if (!NT_SUCCESS (ntStatus)) + { + Dump ("TCCreateDeviceObject NTSTATUS = 0x%08x END\n", ntStatus); + return ntStatus;/* Failed to create DeviceObject */ + } + /* Initialize device object and extension. */ + + (*ppDeviceObject)->Flags |= DO_DIRECT_IO; + (*ppDeviceObject)->StackSize += 6; // Reduce occurrence of NO_MORE_IRP_STACK_LOCATIONS bug check caused by buggy drivers + + /* Setup the device extension */ + Extension = (PEXTENSION) (*ppDeviceObject)->DeviceExtension; + memset (Extension, 0, sizeof (EXTENSION)); + + Extension->IsVolumeDevice = TRUE; + Extension->nDosDriveNo = mount->nDosDriveNo; + Extension->bRemovable = mount->bMountRemovable; + Extension->PartitionInInactiveSysEncScope = mount->bPartitionInInactiveSysEncScope; + Extension->SystemFavorite = mount->SystemFavorite; + + KeInitializeEvent (&Extension->keCreateEvent, SynchronizationEvent, FALSE); + KeInitializeSemaphore (&Extension->RequestSemaphore, 0L, MAXLONG); + KeInitializeSpinLock (&Extension->ListSpinLock); + InitializeListHead (&Extension->ListEntry); + IoInitializeRemoveLock (&Extension->Queue.RemoveLock, 'LRCV', 0, 0); + + VirtualVolumeDeviceObjects[mount->nDosDriveNo] = *ppDeviceObject; + + Dump ("TCCreateDeviceObject STATUS_SUCCESS END\n"); + + return STATUS_SUCCESS; +} + + +BOOL RootDeviceControlMutexAcquireNoWait () +{ + NTSTATUS status; + LARGE_INTEGER timeout; + timeout.QuadPart = 0; + + status = KeWaitForMutexObject (&RootDeviceControlMutex, Executive, KernelMode, FALSE, &timeout); + return NT_SUCCESS (status) && status != STATUS_TIMEOUT; +} + + +void RootDeviceControlMutexRelease () +{ + KeReleaseMutex (&RootDeviceControlMutex, FALSE); +} + + +NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, PIRP Irp) +{ + PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp); + + switch (irpSp->Parameters.DeviceIoControl.IoControlCode) + { + + case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: + if (!ValidateIOBufferSize (Irp, sizeof (MOUNTDEV_NAME), ValidateOutput)) + { + Irp->IoStatus.Information = sizeof (MOUNTDEV_NAME); + Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; + } + else + { + ULONG outLength; + UNICODE_STRING ntUnicodeString; + WCHAR ntName[256]; + PMOUNTDEV_NAME outputBuffer = (PMOUNTDEV_NAME) Irp->AssociatedIrp.SystemBuffer; + + TCGetNTNameFromNumber (ntName, sizeof(ntName),Extension->nDosDriveNo); + RtlInitUnicodeString (&ntUnicodeString, ntName); + + outputBuffer->NameLength = ntUnicodeString.Length; + outLength = ntUnicodeString.Length + sizeof(USHORT); + + if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength) + { + Irp->IoStatus.Information = sizeof (MOUNTDEV_NAME); + Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; + + break; + } + + RtlCopyMemory ((PCHAR)outputBuffer->Name,ntUnicodeString.Buffer, ntUnicodeString.Length); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = outLength; + + Dump ("name = %ls\n",ntName); + } + break; + + case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: + if (!ValidateIOBufferSize (Irp, sizeof (MOUNTDEV_UNIQUE_ID), ValidateOutput)) + { + Irp->IoStatus.Information = sizeof (MOUNTDEV_UNIQUE_ID); + Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; + } + else + { + ULONG outLength; + UCHAR volId[128], tmp[] = { 0,0 }; + PMOUNTDEV_UNIQUE_ID outputBuffer = (PMOUNTDEV_UNIQUE_ID) Irp->AssociatedIrp.SystemBuffer; + + RtlStringCbCopyA (volId, sizeof(volId),TC_UNIQUE_ID_PREFIX); + tmp[0] = 'A' + (UCHAR) Extension->nDosDriveNo; + RtlStringCbCatA (volId, sizeof(volId),tmp); + + outputBuffer->UniqueIdLength = (USHORT) strlen (volId); + outLength = (ULONG) (strlen (volId) + sizeof (USHORT)); + + if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength) + { + Irp->IoStatus.Information = sizeof (MOUNTDEV_UNIQUE_ID); + Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; + break; + } + + RtlCopyMemory ((PCHAR)outputBuffer->UniqueId, volId, strlen (volId)); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = outLength; + + Dump ("id = %s\n",volId); + } + break; + + case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME: + { + ULONG outLength; + UNICODE_STRING ntUnicodeString; + WCHAR ntName[256]; + PMOUNTDEV_SUGGESTED_LINK_NAME outputBuffer = (PMOUNTDEV_SUGGESTED_LINK_NAME) Irp->AssociatedIrp.SystemBuffer; + + if (!ValidateIOBufferSize (Irp, sizeof (MOUNTDEV_SUGGESTED_LINK_NAME), ValidateOutput)) + { + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + Irp->IoStatus.Information = 0; + break; + } + + TCGetDosNameFromNumber (ntName, sizeof(ntName),Extension->nDosDriveNo, DeviceNamespaceDefault); + RtlInitUnicodeString (&ntUnicodeString, ntName); + + outLength = FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME,Name) + ntUnicodeString.Length; + + outputBuffer->UseOnlyIfThereAreNoOtherLinks = FALSE; + outputBuffer->NameLength = ntUnicodeString.Length; + + if(irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength) + { + Irp->IoStatus.Information = sizeof (MOUNTDEV_SUGGESTED_LINK_NAME); + Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; + break; + } + + RtlCopyMemory ((PCHAR)outputBuffer->Name,ntUnicodeString.Buffer, ntUnicodeString.Length); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = outLength; + + Dump ("link = %ls\n",ntName); + } + break; + + case IOCTL_DISK_GET_MEDIA_TYPES: + case IOCTL_DISK_GET_DRIVE_GEOMETRY: + /* Return the drive geometry for the disk. Note that we + return values which were made up to suit the disk size. */ + if (ValidateIOBufferSize (Irp, sizeof (DISK_GEOMETRY), ValidateOutput)) + { + PDISK_GEOMETRY outputBuffer = (PDISK_GEOMETRY) + Irp->AssociatedIrp.SystemBuffer; + + outputBuffer->MediaType = Extension->bRemovable ? RemovableMedia : FixedMedia; + outputBuffer->Cylinders.QuadPart = Extension->NumberOfCylinders; + outputBuffer->TracksPerCylinder = Extension->TracksPerCylinder; + outputBuffer->SectorsPerTrack = Extension->SectorsPerTrack; + outputBuffer->BytesPerSector = Extension->BytesPerSector; + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof (DISK_GEOMETRY); + } + break; + + case IOCTL_STORAGE_QUERY_PROPERTY: + if (EnableExtendedIoctlSupport) + { + if (ValidateIOBufferSize (Irp, sizeof (STORAGE_PROPERTY_QUERY), ValidateInput)) + { + PSTORAGE_PROPERTY_QUERY pStoragePropQuery = (PSTORAGE_PROPERTY_QUERY) Irp->AssociatedIrp.SystemBuffer; + STORAGE_QUERY_TYPE type = pStoragePropQuery->QueryType; + + /* return error if an unsupported type is encountered */ + Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; + Irp->IoStatus.Information = 0; + + if ( (pStoragePropQuery->PropertyId == StorageAccessAlignmentProperty) + || (pStoragePropQuery->PropertyId == StorageDeviceProperty) + ) + { + if (type == PropertyExistsQuery) + { + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + } + else if (type == PropertyStandardQuery) + { + switch (pStoragePropQuery->PropertyId) + { + case StorageDeviceProperty: + { + if (ValidateIOBufferSize (Irp, sizeof (STORAGE_DEVICE_DESCRIPTOR), ValidateOutput)) + { + PSTORAGE_DEVICE_DESCRIPTOR outputBuffer = (PSTORAGE_DEVICE_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer; + + outputBuffer->Version = sizeof(STORAGE_DEVICE_DESCRIPTOR); + outputBuffer->Size = sizeof(STORAGE_DEVICE_DESCRIPTOR); + outputBuffer->DeviceType = FILE_DEVICE_DISK; + outputBuffer->RemovableMedia = Extension->bRemovable? TRUE : FALSE; + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof (STORAGE_DEVICE_DESCRIPTOR); + } + } + break; + case StorageAccessAlignmentProperty: + { + if (ValidateIOBufferSize (Irp, sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR), ValidateOutput)) + { + PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR outputBuffer = (PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer; + + outputBuffer->Version = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR); + outputBuffer->Size = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR); + outputBuffer->BytesPerLogicalSector = Extension->BytesPerSector; + outputBuffer->BytesPerPhysicalSector = Extension->HostBytesPerPhysicalSector; + outputBuffer->BytesOffsetForSectorAlignment = Extension->BytesOffsetForSectorAlignment; + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR); + } + } + break; + } + } + } + } + } + else + return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0); + + break; + + case IOCTL_DISK_GET_PARTITION_INFO: + if (ValidateIOBufferSize (Irp, sizeof (PARTITION_INFORMATION), ValidateOutput)) + { + PPARTITION_INFORMATION outputBuffer = (PPARTITION_INFORMATION) + Irp->AssociatedIrp.SystemBuffer; + + outputBuffer->PartitionType = Extension->PartitionType; + outputBuffer->BootIndicator = FALSE; + outputBuffer->RecognizedPartition = TRUE; + outputBuffer->RewritePartition = FALSE; + outputBuffer->StartingOffset.QuadPart = Extension->BytesPerSector; + outputBuffer->PartitionLength.QuadPart= Extension->DiskLength; + outputBuffer->HiddenSectors = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof (PARTITION_INFORMATION); + } + break; + + case IOCTL_DISK_GET_PARTITION_INFO_EX: + if (ValidateIOBufferSize (Irp, sizeof (PARTITION_INFORMATION_EX), ValidateOutput)) + { + PPARTITION_INFORMATION_EX outputBuffer = (PPARTITION_INFORMATION_EX) Irp->AssociatedIrp.SystemBuffer; + + outputBuffer->PartitionStyle = PARTITION_STYLE_MBR; + outputBuffer->RewritePartition = FALSE; + outputBuffer->StartingOffset.QuadPart = Extension->BytesPerSector; + outputBuffer->PartitionLength.QuadPart= Extension->DiskLength; + outputBuffer->Mbr.PartitionType = Extension->PartitionType; + outputBuffer->Mbr.BootIndicator = FALSE; + outputBuffer->Mbr.RecognizedPartition = TRUE; + outputBuffer->Mbr.HiddenSectors = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof (PARTITION_INFORMATION_EX); + } + break; + + case IOCTL_DISK_GET_DRIVE_LAYOUT: + if (ValidateIOBufferSize (Irp, sizeof (DRIVE_LAYOUT_INFORMATION), ValidateOutput)) + { + PDRIVE_LAYOUT_INFORMATION outputBuffer = (PDRIVE_LAYOUT_INFORMATION) + Irp->AssociatedIrp.SystemBuffer; + + outputBuffer->PartitionCount = 1; + outputBuffer->Signature = 0; + + outputBuffer->PartitionEntry->PartitionType = Extension->PartitionType; + outputBuffer->PartitionEntry->BootIndicator = FALSE; + outputBuffer->PartitionEntry->RecognizedPartition = TRUE; + outputBuffer->PartitionEntry->RewritePartition = FALSE; + outputBuffer->PartitionEntry->StartingOffset.QuadPart = Extension->BytesPerSector; + outputBuffer->PartitionEntry->PartitionLength.QuadPart = Extension->DiskLength; + outputBuffer->PartitionEntry->HiddenSectors = 0; + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof (PARTITION_INFORMATION); + } + break; + + case IOCTL_DISK_GET_LENGTH_INFO: + if (!ValidateIOBufferSize (Irp, sizeof (GET_LENGTH_INFORMATION), ValidateOutput)) + { + Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; + Irp->IoStatus.Information = sizeof (GET_LENGTH_INFORMATION); + } + else + { + PGET_LENGTH_INFORMATION outputBuffer = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer; + + outputBuffer->Length.QuadPart = Extension->DiskLength; + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof (GET_LENGTH_INFORMATION); + } + break; + + case IOCTL_DISK_VERIFY: + if (ValidateIOBufferSize (Irp, sizeof (VERIFY_INFORMATION), ValidateInput)) + { + HRESULT hResult; + ULONGLONG ullStartingOffset, ullNewOffset, ullEndOffset; + PVERIFY_INFORMATION pVerifyInformation; + pVerifyInformation = (PVERIFY_INFORMATION) Irp->AssociatedIrp.SystemBuffer; + + ullStartingOffset = (ULONGLONG) pVerifyInformation->StartingOffset.QuadPart; + hResult = ULongLongAdd(ullStartingOffset, + (ULONGLONG) Extension->cryptoInfo->hiddenVolume ? Extension->cryptoInfo->hiddenVolumeOffset : Extension->cryptoInfo->volDataAreaOffset, + &ullNewOffset); + if (hResult != S_OK) + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + else if (S_OK != ULongLongAdd(ullStartingOffset, (ULONGLONG) pVerifyInformation->Length, &ullEndOffset)) + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + else if (ullEndOffset > (ULONGLONG) Extension->DiskLength) + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + else + { + IO_STATUS_BLOCK ioStatus; + PVOID buffer = TCalloc (max (pVerifyInformation->Length, PAGE_SIZE)); + + if (!buffer) + { + Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + LARGE_INTEGER offset = pVerifyInformation->StartingOffset; + offset.QuadPart = ullNewOffset; + + Irp->IoStatus.Status = ZwReadFile (Extension->hDeviceFile, NULL, NULL, NULL, &ioStatus, buffer, pVerifyInformation->Length, &offset, NULL); + TCfree (buffer); + + if (NT_SUCCESS (Irp->IoStatus.Status) && ioStatus.Information != pVerifyInformation->Length) + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + } + } + + Irp->IoStatus.Information = 0; + } + break; + + case IOCTL_DISK_CHECK_VERIFY: + case IOCTL_STORAGE_CHECK_VERIFY: + { + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + + if (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof (ULONG)) + { + *((ULONG *) Irp->AssociatedIrp.SystemBuffer) = 0; + Irp->IoStatus.Information = sizeof (ULONG); + } + } + break; + + case IOCTL_DISK_IS_WRITABLE: + { + if (Extension->bReadOnly) + Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED; + else + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + + } + break; + + case IOCTL_VOLUME_ONLINE: + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + break; + + case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS: + + // Vista's filesystem defragmenter fails if IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS does not succeed. + if (!(OsMajorVersion == 6 && OsMinorVersion == 0)) + { + Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; + Irp->IoStatus.Information = 0; + } + else if (ValidateIOBufferSize (Irp, sizeof (VOLUME_DISK_EXTENTS), ValidateOutput)) + { + VOLUME_DISK_EXTENTS *extents = (VOLUME_DISK_EXTENTS *) Irp->AssociatedIrp.SystemBuffer; + + // No extent data can be returned as this is not a physical drive. + memset (extents, 0, sizeof (*extents)); + extents->NumberOfDiskExtents = 0; + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof (*extents); + } + break; + + default: + return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0); + } + +#ifdef DEBUG + if (!NT_SUCCESS (Irp->IoStatus.Status)) + { + Dump ("IOCTL error 0x%08x (0x%x %d)\n", + Irp->IoStatus.Status, + (int) (irpSp->Parameters.DeviceIoControl.IoControlCode >> 16), + (int) ((irpSp->Parameters.DeviceIoControl.IoControlCode & 0x1FFF) >> 2)); + } +#endif + + return TCCompleteDiskIrp (Irp, Irp->IoStatus.Status, Irp->IoStatus.Information); +} + + +NTSTATUS ProcessMainDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, PIRP Irp) +{ + PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp); + NTSTATUS ntStatus; + + switch (irpSp->Parameters.DeviceIoControl.IoControlCode) + { + case TC_IOCTL_GET_DRIVER_VERSION: + case TC_IOCTL_LEGACY_GET_DRIVER_VERSION: + if (ValidateIOBufferSize (Irp, sizeof (LONG), ValidateOutput)) + { + LONG tmp = VERSION_NUM; + memcpy (Irp->AssociatedIrp.SystemBuffer, &tmp, 4); + Irp->IoStatus.Information = sizeof (LONG); + Irp->IoStatus.Status = STATUS_SUCCESS; + } + break; + + case TC_IOCTL_GET_DEVICE_REFCOUNT: + if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput)) + { + *(int *) Irp->AssociatedIrp.SystemBuffer = DeviceObject->ReferenceCount; + Irp->IoStatus.Information = sizeof (int); + Irp->IoStatus.Status = STATUS_SUCCESS; + } + break; + + case TC_IOCTL_IS_DRIVER_UNLOAD_DISABLED: + if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput)) + { + LONG deviceObjectCount = 0; + + *(int *) Irp->AssociatedIrp.SystemBuffer = DriverUnloadDisabled; + + if (IoEnumerateDeviceObjectList (TCDriverObject, NULL, 0, &deviceObjectCount) == STATUS_BUFFER_TOO_SMALL && deviceObjectCount > 1) + *(int *) Irp->AssociatedIrp.SystemBuffer = TRUE; + + Irp->IoStatus.Information = sizeof (int); + Irp->IoStatus.Status = STATUS_SUCCESS; + } + break; + + case TC_IOCTL_IS_ANY_VOLUME_MOUNTED: + if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput)) + { + int drive; + *(int *) Irp->AssociatedIrp.SystemBuffer = 0; + + for (drive = MIN_MOUNTED_VOLUME_DRIVE_NUMBER; drive <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; ++drive) + { + if (GetVirtualVolumeDeviceObject (drive)) + { + *(int *) Irp->AssociatedIrp.SystemBuffer = 1; + break; + } + } + + if (IsBootDriveMounted()) + *(int *) Irp->AssociatedIrp.SystemBuffer = 1; + + Irp->IoStatus.Information = sizeof (int); + Irp->IoStatus.Status = STATUS_SUCCESS; + } + break; + + case TC_IOCTL_OPEN_TEST: + { + OPEN_TEST_STRUCT *opentest = (OPEN_TEST_STRUCT *) Irp->AssociatedIrp.SystemBuffer; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE NtFileHandle; + UNICODE_STRING FullFileName; + IO_STATUS_BLOCK IoStatus; + LARGE_INTEGER offset; + ACCESS_MASK access = FILE_READ_ATTRIBUTES; + + if (!ValidateIOBufferSize (Irp, sizeof (OPEN_TEST_STRUCT), ValidateInputOutput)) + break; + + EnsureNullTerminatedString (opentest->wszFileName, sizeof (opentest->wszFileName)); + RtlInitUnicodeString (&FullFileName, opentest->wszFileName); + + InitializeObjectAttributes (&ObjectAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + + if (opentest->bDetectTCBootLoader || opentest->DetectFilesystem || opentest->bMatchVolumeID) + access |= FILE_READ_DATA; + + ntStatus = ZwCreateFile (&NtFileHandle, + SYNCHRONIZE | access, &ObjectAttributes, &IoStatus, NULL, + 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + + if (NT_SUCCESS (ntStatus)) + { + opentest->TCBootLoaderDetected = FALSE; + opentest->FilesystemDetected = FALSE; + opentest->VolumeIDMatched = FALSE; + + if (opentest->bDetectTCBootLoader || opentest->DetectFilesystem || opentest->bMatchVolumeID) + { + byte *readBuffer = TCalloc (TC_MAX_VOLUME_SECTOR_SIZE); + if (!readBuffer) + { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + if (opentest->bDetectTCBootLoader || opentest->DetectFilesystem) + { + // Determine if the first sector contains a portion of the VeraCrypt Boot Loader + + offset.QuadPart = 0; + + ntStatus = ZwReadFile (NtFileHandle, + NULL, + NULL, + NULL, + &IoStatus, + readBuffer, + TC_MAX_VOLUME_SECTOR_SIZE, + &offset, + NULL); + + if (NT_SUCCESS (ntStatus)) + { + size_t i; + + if (opentest->bDetectTCBootLoader && IoStatus.Information >= TC_SECTOR_SIZE_BIOS) + { + // Search for the string "VeraCrypt" + for (i = 0; i < TC_SECTOR_SIZE_BIOS - strlen (TC_APP_NAME); ++i) + { + if (memcmp (readBuffer + i, TC_APP_NAME, strlen (TC_APP_NAME)) == 0) + { + opentest->TCBootLoaderDetected = TRUE; + break; + } + } + } + + if (opentest->DetectFilesystem && IoStatus.Information >= sizeof (int64)) + { + switch (BE64 (*(uint64 *) readBuffer)) + { + case 0xEB52904E54465320: // NTFS + case 0xEB3C904D53444F53: // FAT16 + case 0xEB58904D53444F53: // FAT32 + case 0xEB76904558464154: // exFAT + + opentest->FilesystemDetected = TRUE; + break; + } + } + } + } + + if (opentest->bMatchVolumeID) + { + int volumeType; + BYTE volumeID[VOLUME_ID_SIZE]; + + // Go through all volume types (e.g., normal, hidden) + for (volumeType = TC_VOLUME_TYPE_NORMAL; + volumeType < TC_VOLUME_TYPE_COUNT; + volumeType++) + { + /* Read the volume header */ + switch (volumeType) + { + case TC_VOLUME_TYPE_NORMAL: + offset.QuadPart = TC_VOLUME_HEADER_OFFSET; + break; + + case TC_VOLUME_TYPE_HIDDEN: + + offset.QuadPart = TC_HIDDEN_VOLUME_HEADER_OFFSET; + break; + } + + ntStatus = ZwReadFile (NtFileHandle, + NULL, + NULL, + NULL, + &IoStatus, + readBuffer, + TC_MAX_VOLUME_SECTOR_SIZE, + &offset, + NULL); + + if (NT_SUCCESS (ntStatus)) + { + /* compute the ID of this volume: SHA-256 of the effective header */ + sha256 (volumeID, readBuffer, TC_VOLUME_HEADER_EFFECTIVE_SIZE); + + if (0 == memcmp (volumeID, opentest->volumeID, VOLUME_ID_SIZE)) + { + opentest->VolumeIDMatched = TRUE; + break; + } + } + } + } + + TCfree (readBuffer); + } + } + + ZwClose (NtFileHandle); + Dump ("Open test on file %ls success.\n", opentest->wszFileName); + } + else + { +#if 0 + Dump ("Open test on file %ls failed NTSTATUS 0x%08x\n", opentest->wszFileName, ntStatus); +#endif + } + + Irp->IoStatus.Information = NT_SUCCESS (ntStatus) ? sizeof (OPEN_TEST_STRUCT) : 0; + Irp->IoStatus.Status = ntStatus; + } + break; + + case TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG: + { + GetSystemDriveConfigurationRequest *request = (GetSystemDriveConfigurationRequest *) Irp->AssociatedIrp.SystemBuffer; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE NtFileHandle; + UNICODE_STRING FullFileName; + IO_STATUS_BLOCK IoStatus; + LARGE_INTEGER offset; + byte readBuffer [TC_SECTOR_SIZE_BIOS]; + + if (!ValidateIOBufferSize (Irp, sizeof (GetSystemDriveConfigurationRequest), ValidateInputOutput)) + break; + + EnsureNullTerminatedString (request->DevicePath, sizeof (request->DevicePath)); + RtlInitUnicodeString (&FullFileName, request->DevicePath); + + InitializeObjectAttributes (&ObjectAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + + ntStatus = ZwCreateFile (&NtFileHandle, + SYNCHRONIZE | GENERIC_READ, &ObjectAttributes, &IoStatus, NULL, + FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT | FILE_RANDOM_ACCESS, NULL, 0); + + if (NT_SUCCESS (ntStatus)) + { + // Determine if the first sector contains a portion of the VeraCrypt Boot Loader + offset.QuadPart = 0; // MBR + + ntStatus = ZwReadFile (NtFileHandle, + NULL, + NULL, + NULL, + &IoStatus, + readBuffer, + sizeof(readBuffer), + &offset, + NULL); + + if (NT_SUCCESS (ntStatus)) + { + size_t i; + + // Check for dynamic drive + request->DriveIsDynamic = FALSE; + + if (readBuffer[510] == 0x55 && readBuffer[511] == 0xaa) + { + int i; + for (i = 0; i < 4; ++i) + { + if (readBuffer[446 + i * 16 + 4] == PARTITION_LDM) + { + request->DriveIsDynamic = TRUE; + break; + } + } + } + + request->BootLoaderVersion = 0; + request->Configuration = 0; + request->UserConfiguration = 0; + request->CustomUserMessage[0] = 0; + + // Search for the string "VeraCrypt" + for (i = 0; i < sizeof (readBuffer) - strlen (TC_APP_NAME); ++i) + { + if (memcmp (readBuffer + i, TC_APP_NAME, strlen (TC_APP_NAME)) == 0) + { + request->BootLoaderVersion = BE16 (*(uint16 *) (readBuffer + TC_BOOT_SECTOR_VERSION_OFFSET)); + request->Configuration = readBuffer[TC_BOOT_SECTOR_CONFIG_OFFSET]; + + if (request->BootLoaderVersion != 0 && request->BootLoaderVersion <= VERSION_NUM) + { + request->UserConfiguration = readBuffer[TC_BOOT_SECTOR_USER_CONFIG_OFFSET]; + memcpy (request->CustomUserMessage, readBuffer + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH); + } + break; + } + } + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof (*request); + } + else + { + Irp->IoStatus.Status = ntStatus; + Irp->IoStatus.Information = 0; + } + + ZwClose (NtFileHandle); + + } + else + { + Irp->IoStatus.Status = ntStatus; + Irp->IoStatus.Information = 0; + } + } + break; + + case TC_IOCTL_WIPE_PASSWORD_CACHE: + WipeCache (); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + break; + + case TC_IOCTL_GET_PASSWORD_CACHE_STATUS: + Irp->IoStatus.Status = cacheEmpty ? STATUS_PIPE_EMPTY : STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + break; + + case TC_IOCTL_SET_PORTABLE_MODE_STATUS: + if (!UserCanAccessDriveDevice()) + { + Irp->IoStatus.Status = STATUS_ACCESS_DENIED; + Irp->IoStatus.Information = 0; + } + else + { + PortableMode = TRUE; + Dump ("Setting portable mode\n"); + } + break; + + case TC_IOCTL_GET_PORTABLE_MODE_STATUS: + Irp->IoStatus.Status = PortableMode ? STATUS_SUCCESS : STATUS_PIPE_EMPTY; + Irp->IoStatus.Information = 0; + break; + + case TC_IOCTL_GET_MOUNTED_VOLUMES: + + if (ValidateIOBufferSize (Irp, sizeof (MOUNT_LIST_STRUCT), ValidateOutput)) + { + MOUNT_LIST_STRUCT *list = (MOUNT_LIST_STRUCT *) Irp->AssociatedIrp.SystemBuffer; + PDEVICE_OBJECT ListDevice; + int drive; + + list->ulMountedDrives = 0; + + for (drive = MIN_MOUNTED_VOLUME_DRIVE_NUMBER; drive <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; ++drive) + { + PEXTENSION ListExtension; + + ListDevice = GetVirtualVolumeDeviceObject (drive); + if (!ListDevice) + continue; + + ListExtension = (PEXTENSION) ListDevice->DeviceExtension; + if (IsVolumeAccessibleByCurrentUser (ListExtension)) + { + list->ulMountedDrives |= (1 << ListExtension->nDosDriveNo); + RtlStringCbCopyW (list->wszVolume[ListExtension->nDosDriveNo], sizeof(list->wszVolume[ListExtension->nDosDriveNo]),ListExtension->wszVolume); + RtlStringCbCopyW (list->wszLabel[ListExtension->nDosDriveNo], sizeof(list->wszLabel[ListExtension->nDosDriveNo]),ListExtension->wszLabel); + memcpy (list->volumeID[ListExtension->nDosDriveNo], ListExtension->volumeID, VOLUME_ID_SIZE); + list->diskLength[ListExtension->nDosDriveNo] = ListExtension->DiskLength; + list->ea[ListExtension->nDosDriveNo] = ListExtension->cryptoInfo->ea; + if (ListExtension->cryptoInfo->hiddenVolume) + list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_HIDDEN; // Hidden volume + else if (ListExtension->cryptoInfo->bHiddenVolProtectionAction) + list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_OUTER_VOL_WRITE_PREVENTED; // Normal/outer volume (hidden volume protected AND write already prevented) + else if (ListExtension->cryptoInfo->bProtectHiddenVolume) + list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_OUTER; // Normal/outer volume (hidden volume protected) + else + list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_NORMAL; // Normal volume + list->truecryptMode[ListExtension->nDosDriveNo] = ListExtension->cryptoInfo->bTrueCryptMode; + } + } + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof (MOUNT_LIST_STRUCT); + } + break; + + case TC_IOCTL_LEGACY_GET_MOUNTED_VOLUMES: + if (ValidateIOBufferSize (Irp, sizeof (uint32), ValidateOutput)) + { + // Prevent the user from downgrading to versions lower than 5.0 by faking mounted volumes. + // The user could render the system unbootable by downgrading when boot encryption + // is active or being set up. + + memset (Irp->AssociatedIrp.SystemBuffer, 0, irpSp->Parameters.DeviceIoControl.OutputBufferLength); + *(uint32 *) Irp->AssociatedIrp.SystemBuffer = 0xffffFFFF; + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = irpSp->Parameters.DeviceIoControl.OutputBufferLength; + } + break; + + case TC_IOCTL_GET_VOLUME_PROPERTIES: + if (ValidateIOBufferSize (Irp, sizeof (VOLUME_PROPERTIES_STRUCT), ValidateInputOutput)) + { + VOLUME_PROPERTIES_STRUCT *prop = (VOLUME_PROPERTIES_STRUCT *) Irp->AssociatedIrp.SystemBuffer; + PDEVICE_OBJECT ListDevice = GetVirtualVolumeDeviceObject (prop->driveNo); + + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + Irp->IoStatus.Information = 0; + + if (ListDevice) + { + PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension; + if (IsVolumeAccessibleByCurrentUser (ListExtension)) + { + prop->uniqueId = ListExtension->UniqueVolumeId; + RtlStringCbCopyW (prop->wszVolume, sizeof(prop->wszVolume),ListExtension->wszVolume); + RtlStringCbCopyW (prop->wszLabel, sizeof(prop->wszLabel),ListExtension->wszLabel); + memcpy (prop->volumeID, ListExtension->volumeID, VOLUME_ID_SIZE); + prop->bDriverSetLabel = ListExtension->bDriverSetLabel; + prop->diskLength = ListExtension->DiskLength; + prop->ea = ListExtension->cryptoInfo->ea; + prop->mode = ListExtension->cryptoInfo->mode; + prop->pkcs5 = ListExtension->cryptoInfo->pkcs5; + prop->pkcs5Iterations = ListExtension->cryptoInfo->noIterations; + prop->volumePim = ListExtension->cryptoInfo->volumePim; +#if 0 + prop->volumeCreationTime = ListExtension->cryptoInfo->volume_creation_time; + prop->headerCreationTime = ListExtension->cryptoInfo->header_creation_time; +#endif + prop->volumeHeaderFlags = ListExtension->cryptoInfo->HeaderFlags; + prop->readOnly = ListExtension->bReadOnly; + prop->removable = ListExtension->bRemovable; + prop->partitionInInactiveSysEncScope = ListExtension->PartitionInInactiveSysEncScope; + prop->hiddenVolume = ListExtension->cryptoInfo->hiddenVolume; + + if (ListExtension->cryptoInfo->bProtectHiddenVolume) + prop->hiddenVolProtection = ListExtension->cryptoInfo->bHiddenVolProtectionAction ? HIDVOL_PROT_STATUS_ACTION_TAKEN : HIDVOL_PROT_STATUS_ACTIVE; + else + prop->hiddenVolProtection = HIDVOL_PROT_STATUS_NONE; + + prop->totalBytesRead = ListExtension->Queue.TotalBytesRead; + prop->totalBytesWritten = ListExtension->Queue.TotalBytesWritten; + + prop->volFormatVersion = ListExtension->cryptoInfo->LegacyVolume ? TC_VOLUME_FORMAT_VERSION_PRE_6_0 : TC_VOLUME_FORMAT_VERSION; + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof (VOLUME_PROPERTIES_STRUCT); + } + } + } + break; + + case TC_IOCTL_GET_RESOLVED_SYMLINK: + if (ValidateIOBufferSize (Irp, sizeof (RESOLVE_SYMLINK_STRUCT), ValidateInputOutput)) + { + RESOLVE_SYMLINK_STRUCT *resolve = (RESOLVE_SYMLINK_STRUCT *) Irp->AssociatedIrp.SystemBuffer; + { + NTSTATUS ntStatus; + + EnsureNullTerminatedString (resolve->symLinkName, sizeof (resolve->symLinkName)); + + ntStatus = SymbolicLinkToTarget (resolve->symLinkName, + resolve->targetName, + sizeof (resolve->targetName)); + + Irp->IoStatus.Information = sizeof (RESOLVE_SYMLINK_STRUCT); + Irp->IoStatus.Status = ntStatus; + } + } + break; + + case TC_IOCTL_GET_DRIVE_PARTITION_INFO: + if (ValidateIOBufferSize (Irp, sizeof (DISK_PARTITION_INFO_STRUCT), ValidateInputOutput)) + { + DISK_PARTITION_INFO_STRUCT *info = (DISK_PARTITION_INFO_STRUCT *) Irp->AssociatedIrp.SystemBuffer; + { + PARTITION_INFORMATION_EX pi; + NTSTATUS ntStatus; + + EnsureNullTerminatedString (info->deviceName, sizeof (info->deviceName)); + + ntStatus = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &pi, sizeof (pi)); + if (NT_SUCCESS(ntStatus)) + { + memset (&info->partInfo, 0, sizeof (info->partInfo)); + + info->partInfo.PartitionLength = pi.PartitionLength; + info->partInfo.PartitionNumber = pi.PartitionNumber; + info->partInfo.StartingOffset = pi.StartingOffset; + + if (pi.PartitionStyle == PARTITION_STYLE_MBR) + { + info->partInfo.PartitionType = pi.Mbr.PartitionType; + info->partInfo.BootIndicator = pi.Mbr.BootIndicator; + } + + info->IsGPT = pi.PartitionStyle == PARTITION_STYLE_GPT; + } + else + { + // Windows 2000 does not support IOCTL_DISK_GET_PARTITION_INFO_EX + ntStatus = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &info->partInfo, sizeof (info->partInfo)); + info->IsGPT = FALSE; + } + + if (!NT_SUCCESS (ntStatus)) + { + GET_LENGTH_INFORMATION lengthInfo; + ntStatus = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &lengthInfo, sizeof (lengthInfo)); + + if (NT_SUCCESS (ntStatus)) + { + memset (&info->partInfo, 0, sizeof (info->partInfo)); + info->partInfo.PartitionLength = lengthInfo.Length; + } + } + + info->IsDynamic = FALSE; + + if (NT_SUCCESS (ntStatus) && OsMajorVersion >= 6) + { +# define IOCTL_VOLUME_IS_DYNAMIC CTL_CODE(IOCTL_VOLUME_BASE, 18, METHOD_BUFFERED, FILE_ANY_ACCESS) + if (!NT_SUCCESS (TCDeviceIoControl (info->deviceName, IOCTL_VOLUME_IS_DYNAMIC, NULL, 0, &info->IsDynamic, sizeof (info->IsDynamic)))) + info->IsDynamic = FALSE; + } + + Irp->IoStatus.Information = sizeof (DISK_PARTITION_INFO_STRUCT); + Irp->IoStatus.Status = ntStatus; + } + } + break; + + case TC_IOCTL_GET_DRIVE_GEOMETRY: + if (ValidateIOBufferSize (Irp, sizeof (DISK_GEOMETRY_STRUCT), ValidateInputOutput)) + { + DISK_GEOMETRY_STRUCT *g = (DISK_GEOMETRY_STRUCT *) Irp->AssociatedIrp.SystemBuffer; + { + NTSTATUS ntStatus; + + EnsureNullTerminatedString (g->deviceName, sizeof (g->deviceName)); + + ntStatus = TCDeviceIoControl (g->deviceName, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, 0, &g->diskGeometry, sizeof (g->diskGeometry)); + + Irp->IoStatus.Information = sizeof (DISK_GEOMETRY_STRUCT); + Irp->IoStatus.Status = ntStatus; + } + } + break; + + case TC_IOCTL_PROBE_REAL_DRIVE_SIZE: + if (ValidateIOBufferSize (Irp, sizeof (ProbeRealDriveSizeRequest), ValidateInputOutput)) + { + ProbeRealDriveSizeRequest *request = (ProbeRealDriveSizeRequest *) Irp->AssociatedIrp.SystemBuffer; + NTSTATUS status; + UNICODE_STRING name; + PFILE_OBJECT fileObject; + PDEVICE_OBJECT deviceObject; + + EnsureNullTerminatedString (request->DeviceName, sizeof (request->DeviceName)); + + RtlInitUnicodeString (&name, request->DeviceName); + status = IoGetDeviceObjectPointer (&name, FILE_READ_ATTRIBUTES, &fileObject, &deviceObject); + if (!NT_SUCCESS (status)) + { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = status; + break; + } + + status = ProbeRealDriveSize (deviceObject, &request->RealDriveSize); + ObDereferenceObject (fileObject); + + if (status == STATUS_TIMEOUT) + { + request->TimeOut = TRUE; + Irp->IoStatus.Information = sizeof (ProbeRealDriveSizeRequest); + Irp->IoStatus.Status = STATUS_SUCCESS; + } + else if (!NT_SUCCESS (status)) + { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = status; + } + else + { + request->TimeOut = FALSE; + Irp->IoStatus.Information = sizeof (ProbeRealDriveSizeRequest); + Irp->IoStatus.Status = status; + } + } + break; + + case TC_IOCTL_MOUNT_VOLUME: + if (ValidateIOBufferSize (Irp, sizeof (MOUNT_STRUCT), ValidateInputOutput)) + { + MOUNT_STRUCT *mount = (MOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer; + + if (mount->VolumePassword.Length > MAX_PASSWORD || mount->ProtectedHidVolPassword.Length > MAX_PASSWORD + || mount->pkcs5_prf < 0 || mount->pkcs5_prf > LAST_PRF_ID + || mount->VolumePim < -1 || mount->VolumePim == INT_MAX + || mount->ProtectedHidVolPkcs5Prf < 0 || mount->ProtectedHidVolPkcs5Prf > LAST_PRF_ID + || (mount->bTrueCryptMode != FALSE && mount->bTrueCryptMode != TRUE) + ) + { + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + Irp->IoStatus.Information = 0; + break; + } + + EnsureNullTerminatedString (mount->wszVolume, sizeof (mount->wszVolume)); + EnsureNullTerminatedString (mount->wszLabel, sizeof (mount->wszLabel)); + + Irp->IoStatus.Information = sizeof (MOUNT_STRUCT); + Irp->IoStatus.Status = MountDevice (DeviceObject, mount); + + burn (&mount->VolumePassword, sizeof (mount->VolumePassword)); + burn (&mount->ProtectedHidVolPassword, sizeof (mount->ProtectedHidVolPassword)); + burn (&mount->pkcs5_prf, sizeof (mount->pkcs5_prf)); + burn (&mount->VolumePim, sizeof (mount->VolumePim)); + burn (&mount->bTrueCryptMode, sizeof (mount->bTrueCryptMode)); + burn (&mount->ProtectedHidVolPkcs5Prf, sizeof (mount->ProtectedHidVolPkcs5Prf)); + burn (&mount->ProtectedHidVolPim, sizeof (mount->ProtectedHidVolPim)); + } + break; + + case TC_IOCTL_DISMOUNT_VOLUME: + if (ValidateIOBufferSize (Irp, sizeof (UNMOUNT_STRUCT), ValidateInputOutput)) + { + UNMOUNT_STRUCT *unmount = (UNMOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer; + PDEVICE_OBJECT ListDevice = GetVirtualVolumeDeviceObject (unmount->nDosDriveNo); + + unmount->nReturnCode = ERR_DRIVE_NOT_FOUND; + + if (ListDevice) + { + PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension; + + if (IsVolumeAccessibleByCurrentUser (ListExtension)) + unmount->nReturnCode = UnmountDevice (unmount, ListDevice, unmount->ignoreOpenFiles); + } + + Irp->IoStatus.Information = sizeof (UNMOUNT_STRUCT); + Irp->IoStatus.Status = STATUS_SUCCESS; + } + break; + + case TC_IOCTL_DISMOUNT_ALL_VOLUMES: + if (ValidateIOBufferSize (Irp, sizeof (UNMOUNT_STRUCT), ValidateInputOutput)) + { + UNMOUNT_STRUCT *unmount = (UNMOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer; + + unmount->nReturnCode = UnmountAllDevices (unmount, unmount->ignoreOpenFiles); + + Irp->IoStatus.Information = sizeof (UNMOUNT_STRUCT); + Irp->IoStatus.Status = STATUS_SUCCESS; + } + break; + + case TC_IOCTL_BOOT_ENCRYPTION_SETUP: + Irp->IoStatus.Status = StartBootEncryptionSetup (DeviceObject, Irp, irpSp); + Irp->IoStatus.Information = 0; + break; + + case TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP: + Irp->IoStatus.Status = AbortBootEncryptionSetup(); + Irp->IoStatus.Information = 0; + break; + + case TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS: + GetBootEncryptionStatus (Irp, irpSp); + break; + + case TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT: + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = GetSetupResult(); + break; + + case TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES: + GetBootDriveVolumeProperties (Irp, irpSp); + break; + + case TC_IOCTL_GET_BOOT_LOADER_VERSION: + GetBootLoaderVersion (Irp, irpSp); + break; + + case TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER: + ReopenBootVolumeHeader (Irp, irpSp); + break; + + case VC_IOCTL_GET_BOOT_LOADER_FINGERPRINT: + GetBootLoaderFingerprint (Irp, irpSp); + break; + + case TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME: + GetBootEncryptionAlgorithmName (Irp, irpSp); + break; + + case TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING: + if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput)) + { + *(int *) Irp->AssociatedIrp.SystemBuffer = IsHiddenSystemRunning() ? 1 : 0; + Irp->IoStatus.Information = sizeof (int); + Irp->IoStatus.Status = STATUS_SUCCESS; + } + break; + + case TC_IOCTL_START_DECOY_SYSTEM_WIPE: + Irp->IoStatus.Status = StartDecoySystemWipe (DeviceObject, Irp, irpSp); + Irp->IoStatus.Information = 0; + break; + + case TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE: + Irp->IoStatus.Status = AbortDecoySystemWipe(); + Irp->IoStatus.Information = 0; + break; + + case TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT: + Irp->IoStatus.Status = GetDecoySystemWipeResult(); + Irp->IoStatus.Information = 0; + break; + + case TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS: + GetDecoySystemWipeStatus (Irp, irpSp); + break; + + case TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR: + Irp->IoStatus.Status = WriteBootDriveSector (Irp, irpSp); + Irp->IoStatus.Information = 0; + break; + + case TC_IOCTL_GET_WARNING_FLAGS: + if (ValidateIOBufferSize (Irp, sizeof (GetWarningFlagsRequest), ValidateOutput)) + { + GetWarningFlagsRequest *flags = (GetWarningFlagsRequest *) Irp->AssociatedIrp.SystemBuffer; + + flags->PagingFileCreationPrevented = PagingFileCreationPrevented; + PagingFileCreationPrevented = FALSE; + flags->SystemFavoriteVolumeDirty = SystemFavoriteVolumeDirty; + SystemFavoriteVolumeDirty = FALSE; + + Irp->IoStatus.Information = sizeof (GetWarningFlagsRequest); + Irp->IoStatus.Status = STATUS_SUCCESS; + } + break; + + case TC_IOCTL_SET_SYSTEM_FAVORITE_VOLUME_DIRTY: + if (UserCanAccessDriveDevice()) + { + SystemFavoriteVolumeDirty = TRUE; + Irp->IoStatus.Status = STATUS_SUCCESS; + } + else + Irp->IoStatus.Status = STATUS_ACCESS_DENIED; + + Irp->IoStatus.Information = 0; + break; + + case TC_IOCTL_REREAD_DRIVER_CONFIG: + Irp->IoStatus.Status = ReadRegistryConfigFlags (FALSE); + Irp->IoStatus.Information = 0; + break; + + case TC_IOCTL_GET_SYSTEM_DRIVE_DUMP_CONFIG: + if ( (ValidateIOBufferSize (Irp, sizeof (GetSystemDriveDumpConfigRequest), ValidateOutput)) + && (Irp->RequestorMode == KernelMode) + ) + { + GetSystemDriveDumpConfigRequest *request = (GetSystemDriveDumpConfigRequest *) Irp->AssociatedIrp.SystemBuffer; + + request->BootDriveFilterExtension = GetBootDriveFilterExtension(); + if (IsBootDriveMounted() && request->BootDriveFilterExtension) + { + request->HwEncryptionEnabled = IsHwEncryptionEnabled(); + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = sizeof (*request); + } + else + { + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + Irp->IoStatus.Information = 0; + } + } + break; + + default: + return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0); + } + + +#ifdef DEBUG + if (!NT_SUCCESS (Irp->IoStatus.Status)) + { + switch (irpSp->Parameters.DeviceIoControl.IoControlCode) + { + case TC_IOCTL_GET_MOUNTED_VOLUMES: + case TC_IOCTL_GET_PASSWORD_CACHE_STATUS: + case TC_IOCTL_GET_PORTABLE_MODE_STATUS: + case TC_IOCTL_SET_PORTABLE_MODE_STATUS: + case TC_IOCTL_OPEN_TEST: + case TC_IOCTL_GET_RESOLVED_SYMLINK: + case TC_IOCTL_GET_DRIVE_PARTITION_INFO: + case TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES: + case TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS: + case TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING: + break; + + default: + Dump ("IOCTL error 0x%08x\n", Irp->IoStatus.Status); + } + } +#endif + + return TCCompleteIrp (Irp, Irp->IoStatus.Status, Irp->IoStatus.Information); +} + + +NTSTATUS TCStartThread (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread) +{ + return TCStartThreadInProcess (threadProc, threadArg, kThread, NULL); +} + + +NTSTATUS TCStartThreadInProcess (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread, PEPROCESS process) +{ + NTSTATUS status; + HANDLE threadHandle; + HANDLE processHandle = NULL; + OBJECT_ATTRIBUTES threadObjAttributes; + + if (process) + { + status = ObOpenObjectByPointer (process, OBJ_KERNEL_HANDLE, NULL, 0, NULL, KernelMode, &processHandle); + if (!NT_SUCCESS (status)) + return status; + } + + InitializeObjectAttributes (&threadObjAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + + status = PsCreateSystemThread (&threadHandle, THREAD_ALL_ACCESS, &threadObjAttributes, processHandle, NULL, threadProc, threadArg); + if (!NT_SUCCESS (status)) + return status; + + status = ObReferenceObjectByHandle (threadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, (PVOID *) kThread, NULL); + if (!NT_SUCCESS (status)) + { + ZwClose (threadHandle); + *kThread = NULL; + return status; + } + + if (processHandle) + ZwClose (processHandle); + + ZwClose (threadHandle); + return STATUS_SUCCESS; +} + + +void TCStopThread (PKTHREAD kThread, PKEVENT wakeUpEvent) +{ + if (wakeUpEvent) + KeSetEvent (wakeUpEvent, 0, FALSE); + + KeWaitForSingleObject (kThread, Executive, KernelMode, FALSE, NULL); + ObDereferenceObject (kThread); +} + + +NTSTATUS TCStartVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, MOUNT_STRUCT * mount) +{ + PTHREAD_BLOCK pThreadBlock = TCalloc (sizeof (THREAD_BLOCK)); + HANDLE hThread; + NTSTATUS ntStatus; + OBJECT_ATTRIBUTES threadObjAttributes; + SECURITY_QUALITY_OF_SERVICE qos; + + Dump ("Starting thread...\n"); + + if (pThreadBlock == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + else + { + pThreadBlock->DeviceObject = DeviceObject; + pThreadBlock->mount = mount; + } + + qos.Length = sizeof (qos); + qos.ContextTrackingMode = SECURITY_STATIC_TRACKING; + qos.EffectiveOnly = TRUE; + qos.ImpersonationLevel = SecurityImpersonation; + + ntStatus = SeCreateClientSecurity (PsGetCurrentThread(), &qos, FALSE, &Extension->SecurityClientContext); + if (!NT_SUCCESS (ntStatus)) + goto ret; + + Extension->SecurityClientContextValid = TRUE; + + Extension->bThreadShouldQuit = FALSE; + + InitializeObjectAttributes (&threadObjAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + + ntStatus = PsCreateSystemThread (&hThread, + THREAD_ALL_ACCESS, + &threadObjAttributes, + NULL, + NULL, + VolumeThreadProc, + pThreadBlock); + + if (!NT_SUCCESS (ntStatus)) + { + Dump ("PsCreateSystemThread Failed END\n"); + goto ret; + } + + ntStatus = ObReferenceObjectByHandle (hThread, + THREAD_ALL_ACCESS, + NULL, + KernelMode, + &Extension->peThread, + NULL); + + ZwClose (hThread); + + if (!NT_SUCCESS (ntStatus)) + goto ret; + + Dump ("Waiting for thread to initialize...\n"); + + KeWaitForSingleObject (&Extension->keCreateEvent, + Executive, + KernelMode, + FALSE, + NULL); + + Dump ("Waiting completed! Thread returns 0x%08x\n", pThreadBlock->ntCreateStatus); + ntStatus = pThreadBlock->ntCreateStatus; + +ret: + TCfree (pThreadBlock); + return ntStatus; +} + +void TCStopVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension) +{ + NTSTATUS ntStatus; + + UNREFERENCED_PARAMETER (DeviceObject); /* Remove compiler warning */ + + Dump ("Signalling thread to quit...\n"); + + Extension->bThreadShouldQuit = TRUE; + + KeReleaseSemaphore (&Extension->RequestSemaphore, + 0, + 1, + TRUE); + + ntStatus = KeWaitForSingleObject (Extension->peThread, + Executive, + KernelMode, + FALSE, + NULL); + + ASSERT (NT_SUCCESS (ntStatus)); + + ObDereferenceObject (Extension->peThread); + Extension->peThread = NULL; + + Dump ("Thread exited\n"); +} + + +// Suspend current thread for a number of milliseconds +void TCSleep (int milliSeconds) +{ + PKTIMER timer = (PKTIMER) TCalloc (sizeof (KTIMER)); + LARGE_INTEGER duetime; + + if (!timer) + return; + + duetime.QuadPart = (__int64) milliSeconds * -10000; + KeInitializeTimerEx(timer, NotificationTimer); + KeSetTimerEx(timer, duetime, 0, NULL); + + KeWaitForSingleObject (timer, Executive, KernelMode, FALSE, NULL); + + TCfree (timer); +} + +BOOL IsDeviceName(wchar_t wszVolume[TC_MAX_PATH]) +{ + if ( (wszVolume[0] == '\\') + && (wszVolume[1] == 'D' || wszVolume[1] == 'd') + && (wszVolume[2] == 'E' || wszVolume[2] == 'e') + && (wszVolume[3] == 'V' || wszVolume[3] == 'v') + && (wszVolume[4] == 'I' || wszVolume[4] == 'i') + && (wszVolume[5] == 'C' || wszVolume[5] == 'c') + && (wszVolume[6] == 'E' || wszVolume[6] == 'e') + ) + { + return TRUE; + } + else + return FALSE; +} + +/* VolumeThreadProc does all the work of processing IRP's, and dispatching them + to either the ReadWrite function or the DeviceControl function */ +VOID VolumeThreadProc (PVOID Context) +{ + PTHREAD_BLOCK pThreadBlock = (PTHREAD_BLOCK) Context; + PDEVICE_OBJECT DeviceObject = pThreadBlock->DeviceObject; + PEXTENSION Extension = (PEXTENSION) DeviceObject->DeviceExtension; + BOOL bDevice; + + /* Set thread priority to lowest realtime level. */ + KeSetPriorityThread (KeGetCurrentThread (), LOW_REALTIME_PRIORITY); + + Dump ("Mount THREAD OPENING VOLUME BEGIN\n"); + + if ( !IsDeviceName (pThreadBlock->mount->wszVolume)) + { + RtlStringCbCopyW (pThreadBlock->wszMountVolume, sizeof(pThreadBlock->wszMountVolume),WIDE ("\\??\\")); + RtlStringCbCatW (pThreadBlock->wszMountVolume, sizeof(pThreadBlock->wszMountVolume),pThreadBlock->mount->wszVolume); + bDevice = FALSE; + } + else + { + pThreadBlock->wszMountVolume[0] = 0; + RtlStringCbCatW (pThreadBlock->wszMountVolume, sizeof(pThreadBlock->wszMountVolume),pThreadBlock->mount->wszVolume); + bDevice = TRUE; + } + + Dump ("Mount THREAD request for File %ls DriveNumber %d Device = %d\n", + pThreadBlock->wszMountVolume, pThreadBlock->mount->nDosDriveNo, bDevice); + + pThreadBlock->ntCreateStatus = TCOpenVolume (DeviceObject, + Extension, + pThreadBlock->mount, + pThreadBlock->wszMountVolume, + bDevice); + + if (!NT_SUCCESS (pThreadBlock->ntCreateStatus) || pThreadBlock->mount->nReturnCode != 0) + { + KeSetEvent (&Extension->keCreateEvent, 0, FALSE); + PsTerminateSystemThread (STATUS_SUCCESS); + } + + // Start IO queue + Extension->Queue.IsFilterDevice = FALSE; + Extension->Queue.DeviceObject = DeviceObject; + Extension->Queue.CryptoInfo = Extension->cryptoInfo; + Extension->Queue.HostFileHandle = Extension->hDeviceFile; + Extension->Queue.VirtualDeviceLength = Extension->DiskLength; + Extension->Queue.MaxReadAheadOffset.QuadPart = Extension->HostLength; + + if (Extension->SecurityClientContextValid) + Extension->Queue.SecurityClientContext = &Extension->SecurityClientContext; + else + Extension->Queue.SecurityClientContext = NULL; + + pThreadBlock->ntCreateStatus = EncryptedIoQueueStart (&Extension->Queue); + + if (!NT_SUCCESS (pThreadBlock->ntCreateStatus)) + { + TCCloseVolume (DeviceObject, Extension); + + pThreadBlock->mount->nReturnCode = ERR_OS_ERROR; + KeSetEvent (&Extension->keCreateEvent, 0, FALSE); + PsTerminateSystemThread (STATUS_SUCCESS); + } + + KeSetEvent (&Extension->keCreateEvent, 0, FALSE); + /* From this point on pThreadBlock cannot be used as it will have been released! */ + pThreadBlock = NULL; + + for (;;) + { + /* Wait for a request from the dispatch routines. */ + KeWaitForSingleObject ((PVOID) & Extension->RequestSemaphore, Executive, KernelMode, FALSE, NULL); + + for (;;) + { + PIO_STACK_LOCATION irpSp; + PLIST_ENTRY request; + PIRP irp; + + request = ExInterlockedRemoveHeadList (&Extension->ListEntry, &Extension->ListSpinLock); + if (request == NULL) + break; + + irp = CONTAINING_RECORD (request, IRP, Tail.Overlay.ListEntry); + irpSp = IoGetCurrentIrpStackLocation (irp); + + ASSERT (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL); + + ProcessVolumeDeviceControlIrp (DeviceObject, Extension, irp); + IoReleaseRemoveLock (&Extension->Queue.RemoveLock, irp); + } + + if (Extension->bThreadShouldQuit) + { + Dump ("Closing volume\n"); + EncryptedIoQueueStop (&Extension->Queue); + + TCCloseVolume (DeviceObject, Extension); + PsTerminateSystemThread (STATUS_SUCCESS); + } + } +} + +void TCGetNTNameFromNumber (LPWSTR ntname, int cbNtName, int nDriveNo) +{ + WCHAR tmp[2] = + {0, 0}; + int j = nDriveNo + (WCHAR) 'A'; + + tmp[0] = (short) j; + RtlStringCbCopyW (ntname, cbNtName,(LPWSTR) NT_MOUNT_PREFIX); + RtlStringCbCatW (ntname, cbNtName, tmp); +} + +void TCGetDosNameFromNumber (LPWSTR dosname,int cbDosName, int nDriveNo, DeviceNamespaceType namespaceType) +{ + WCHAR tmp[3] = + {0, ':', 0}; + int j = nDriveNo + (WCHAR) 'A'; + + tmp[0] = (short) j; + + if (DeviceNamespaceGlobal == namespaceType) + { + RtlStringCbCopyW (dosname, cbDosName, (LPWSTR) DOS_MOUNT_PREFIX_GLOBAL); + } + else + { + RtlStringCbCopyW (dosname, cbDosName, (LPWSTR) DOS_MOUNT_PREFIX_DEFAULT); + } + + RtlStringCbCatW (dosname, cbDosName, tmp); +} + +#ifdef _DEBUG +LPWSTR TCTranslateCode (ULONG ulCode) +{ + switch (ulCode) + { +#define TC_CASE_RET_NAME(CODE) case CODE : return L###CODE + + TC_CASE_RET_NAME (TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP); + TC_CASE_RET_NAME (TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE); + TC_CASE_RET_NAME (TC_IOCTL_BOOT_ENCRYPTION_SETUP); + TC_CASE_RET_NAME (TC_IOCTL_DISMOUNT_ALL_VOLUMES); + TC_CASE_RET_NAME (TC_IOCTL_DISMOUNT_VOLUME); + TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES); + TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME); + TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT); + TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS); + TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_LOADER_VERSION); + TC_CASE_RET_NAME (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT); + TC_CASE_RET_NAME (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS); + TC_CASE_RET_NAME (TC_IOCTL_GET_DEVICE_REFCOUNT); + TC_CASE_RET_NAME (TC_IOCTL_GET_DRIVE_GEOMETRY); + TC_CASE_RET_NAME (TC_IOCTL_GET_DRIVE_PARTITION_INFO); + TC_CASE_RET_NAME (TC_IOCTL_GET_DRIVER_VERSION); + TC_CASE_RET_NAME (TC_IOCTL_GET_MOUNTED_VOLUMES); + TC_CASE_RET_NAME (TC_IOCTL_GET_PASSWORD_CACHE_STATUS); + TC_CASE_RET_NAME (TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG); + TC_CASE_RET_NAME (TC_IOCTL_GET_PORTABLE_MODE_STATUS); + TC_CASE_RET_NAME (TC_IOCTL_SET_PORTABLE_MODE_STATUS); + TC_CASE_RET_NAME (TC_IOCTL_GET_RESOLVED_SYMLINK); + TC_CASE_RET_NAME (TC_IOCTL_GET_SYSTEM_DRIVE_DUMP_CONFIG); + TC_CASE_RET_NAME (TC_IOCTL_GET_VOLUME_PROPERTIES); + TC_CASE_RET_NAME (TC_IOCTL_GET_WARNING_FLAGS); + TC_CASE_RET_NAME (TC_IOCTL_DISK_IS_WRITABLE); + TC_CASE_RET_NAME (TC_IOCTL_IS_ANY_VOLUME_MOUNTED); + TC_CASE_RET_NAME (TC_IOCTL_IS_DRIVER_UNLOAD_DISABLED); + TC_CASE_RET_NAME (TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING); + TC_CASE_RET_NAME (TC_IOCTL_MOUNT_VOLUME); + TC_CASE_RET_NAME (TC_IOCTL_OPEN_TEST); + TC_CASE_RET_NAME (TC_IOCTL_PROBE_REAL_DRIVE_SIZE); + TC_CASE_RET_NAME (TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER); + TC_CASE_RET_NAME (TC_IOCTL_REREAD_DRIVER_CONFIG); + TC_CASE_RET_NAME (TC_IOCTL_SET_SYSTEM_FAVORITE_VOLUME_DIRTY); + TC_CASE_RET_NAME (TC_IOCTL_START_DECOY_SYSTEM_WIPE); + TC_CASE_RET_NAME (TC_IOCTL_WIPE_PASSWORD_CACHE); + TC_CASE_RET_NAME (TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR); + + TC_CASE_RET_NAME (IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS); + +#undef TC_CASE_RET_NAME + } + + if (ulCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) + return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_GEOMETRY"); + else if (ulCode == IOCTL_DISK_GET_DRIVE_GEOMETRY_EX) + return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX"); + else if (ulCode == IOCTL_MOUNTDEV_QUERY_DEVICE_NAME) + return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME"); + else if (ulCode == IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME) + return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME"); + else if (ulCode == IOCTL_MOUNTDEV_QUERY_UNIQUE_ID) + return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_UNIQUE_ID"); + else if (ulCode == IOCTL_VOLUME_ONLINE) + return (LPWSTR) _T ("IOCTL_VOLUME_ONLINE"); + else if (ulCode == IOCTL_MOUNTDEV_LINK_CREATED) + return (LPWSTR) _T ("IOCTL_MOUNTDEV_LINK_CREATED"); + else if (ulCode == IOCTL_MOUNTDEV_LINK_DELETED) + return (LPWSTR) _T ("IOCTL_MOUNTDEV_LINK_DELETED"); + else if (ulCode == IOCTL_MOUNTMGR_QUERY_POINTS) + return (LPWSTR) _T ("IOCTL_MOUNTMGR_QUERY_POINTS"); + else if (ulCode == IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED) + return (LPWSTR) _T ("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED"); + else if (ulCode == IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED) + return (LPWSTR) _T ("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED"); + else if (ulCode == IOCTL_DISK_GET_LENGTH_INFO) + return (LPWSTR) _T ("IOCTL_DISK_GET_LENGTH_INFO"); + else if (ulCode == IOCTL_STORAGE_GET_DEVICE_NUMBER) + return (LPWSTR) _T ("IOCTL_STORAGE_GET_DEVICE_NUMBER"); + else if (ulCode == IOCTL_DISK_GET_PARTITION_INFO) + return (LPWSTR) _T ("IOCTL_DISK_GET_PARTITION_INFO"); + else if (ulCode == IOCTL_DISK_GET_PARTITION_INFO_EX) + return (LPWSTR) _T ("IOCTL_DISK_GET_PARTITION_INFO_EX"); + else if (ulCode == IOCTL_DISK_SET_PARTITION_INFO) + return (LPWSTR) _T ("IOCTL_DISK_SET_PARTITION_INFO"); + else if (ulCode == IOCTL_DISK_GET_DRIVE_LAYOUT) + return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_LAYOUT"); + else if (ulCode == IOCTL_DISK_SET_DRIVE_LAYOUT_EX) + return (LPWSTR) _T ("IOCTL_DISK_SET_DRIVE_LAYOUT_EX"); + else if (ulCode == IOCTL_DISK_VERIFY) + return (LPWSTR) _T ("IOCTL_DISK_VERIFY"); + else if (ulCode == IOCTL_DISK_FORMAT_TRACKS) + return (LPWSTR) _T ("IOCTL_DISK_FORMAT_TRACKS"); + else if (ulCode == IOCTL_DISK_REASSIGN_BLOCKS) + return (LPWSTR) _T ("IOCTL_DISK_REASSIGN_BLOCKS"); + else if (ulCode == IOCTL_DISK_PERFORMANCE) + return (LPWSTR) _T ("IOCTL_DISK_PERFORMANCE"); + else if (ulCode == IOCTL_DISK_IS_WRITABLE) + return (LPWSTR) _T ("IOCTL_DISK_IS_WRITABLE"); + else if (ulCode == IOCTL_DISK_LOGGING) + return (LPWSTR) _T ("IOCTL_DISK_LOGGING"); + else if (ulCode == IOCTL_DISK_FORMAT_TRACKS_EX) + return (LPWSTR) _T ("IOCTL_DISK_FORMAT_TRACKS_EX"); + else if (ulCode == IOCTL_DISK_HISTOGRAM_STRUCTURE) + return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_STRUCTURE"); + else if (ulCode == IOCTL_DISK_HISTOGRAM_DATA) + return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_DATA"); + else if (ulCode == IOCTL_DISK_HISTOGRAM_RESET) + return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_RESET"); + else if (ulCode == IOCTL_DISK_REQUEST_STRUCTURE) + return (LPWSTR) _T ("IOCTL_DISK_REQUEST_STRUCTURE"); + else if (ulCode == IOCTL_DISK_REQUEST_DATA) + return (LPWSTR) _T ("IOCTL_DISK_REQUEST_DATA"); + else if (ulCode == IOCTL_DISK_CONTROLLER_NUMBER) + return (LPWSTR) _T ("IOCTL_DISK_CONTROLLER_NUMBER"); + else if (ulCode == SMART_GET_VERSION) + return (LPWSTR) _T ("SMART_GET_VERSION"); + else if (ulCode == SMART_SEND_DRIVE_COMMAND) + return (LPWSTR) _T ("SMART_SEND_DRIVE_COMMAND"); + else if (ulCode == SMART_RCV_DRIVE_DATA) + return (LPWSTR) _T ("SMART_RCV_DRIVE_DATA"); + else if (ulCode == IOCTL_DISK_INTERNAL_SET_VERIFY) + return (LPWSTR) _T ("IOCTL_DISK_INTERNAL_SET_VERIFY"); + else if (ulCode == IOCTL_DISK_INTERNAL_CLEAR_VERIFY) + return (LPWSTR) _T ("IOCTL_DISK_INTERNAL_CLEAR_VERIFY"); + else if (ulCode == IOCTL_DISK_CHECK_VERIFY) + return (LPWSTR) _T ("IOCTL_DISK_CHECK_VERIFY"); + else if (ulCode == IOCTL_DISK_MEDIA_REMOVAL) + return (LPWSTR) _T ("IOCTL_DISK_MEDIA_REMOVAL"); + else if (ulCode == IOCTL_DISK_EJECT_MEDIA) + return (LPWSTR) _T ("IOCTL_DISK_EJECT_MEDIA"); + else if (ulCode == IOCTL_DISK_LOAD_MEDIA) + return (LPWSTR) _T ("IOCTL_DISK_LOAD_MEDIA"); + else if (ulCode == IOCTL_DISK_RESERVE) + return (LPWSTR) _T ("IOCTL_DISK_RESERVE"); + else if (ulCode == IOCTL_DISK_RELEASE) + return (LPWSTR) _T ("IOCTL_DISK_RELEASE"); + else if (ulCode == IOCTL_DISK_FIND_NEW_DEVICES) + return (LPWSTR) _T ("IOCTL_DISK_FIND_NEW_DEVICES"); + else if (ulCode == IOCTL_DISK_GET_MEDIA_TYPES) + return (LPWSTR) _T ("IOCTL_DISK_GET_MEDIA_TYPES"); + else if (ulCode == IOCTL_STORAGE_SET_HOTPLUG_INFO) + return (LPWSTR) _T ("IOCTL_STORAGE_SET_HOTPLUG_INFO"); + else if (ulCode == IRP_MJ_READ) + return (LPWSTR) _T ("IRP_MJ_READ"); + else if (ulCode == IRP_MJ_WRITE) + return (LPWSTR) _T ("IRP_MJ_WRITE"); + else if (ulCode == IRP_MJ_CREATE) + return (LPWSTR) _T ("IRP_MJ_CREATE"); + else if (ulCode == IRP_MJ_CLOSE) + return (LPWSTR) _T ("IRP_MJ_CLOSE"); + else if (ulCode == IRP_MJ_CLEANUP) + return (LPWSTR) _T ("IRP_MJ_CLEANUP"); + else if (ulCode == IRP_MJ_FLUSH_BUFFERS) + return (LPWSTR) _T ("IRP_MJ_FLUSH_BUFFERS"); + else if (ulCode == IRP_MJ_SHUTDOWN) + return (LPWSTR) _T ("IRP_MJ_SHUTDOWN"); + else if (ulCode == IRP_MJ_DEVICE_CONTROL) + return (LPWSTR) _T ("IRP_MJ_DEVICE_CONTROL"); + else + { + return (LPWSTR) _T ("IOCTL"); + } +} + +#endif + +void TCDeleteDeviceObject (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension) +{ + UNICODE_STRING Win32NameString; + NTSTATUS ntStatus; + + Dump ("TCDeleteDeviceObject BEGIN\n"); + + if (Extension->bRootDevice) + { + RtlInitUnicodeString (&Win32NameString, (LPWSTR) DOS_ROOT_PREFIX); + ntStatus = IoDeleteSymbolicLink (&Win32NameString); + if (!NT_SUCCESS (ntStatus)) + Dump ("IoDeleteSymbolicLink failed ntStatus = 0x%08x\n", ntStatus); + + RootDeviceObject = NULL; + } + else + { + if (Extension->peThread != NULL) + TCStopVolumeThread (DeviceObject, Extension); + + if (Extension->UserSid) + TCfree (Extension->UserSid); + + if (Extension->SecurityClientContextValid) + { + if (OsMajorVersion == 5 && OsMinorVersion == 0) + { + ObDereferenceObject (Extension->SecurityClientContext.ClientToken); + } + else + { + // Windows 2000 does not support PsDereferenceImpersonationToken() used by SeDeleteClientSecurity(). + // TODO: Use only SeDeleteClientSecurity() once support for Windows 2000 is dropped. + + VOID (*PsDereferenceImpersonationTokenD) (PACCESS_TOKEN ImpersonationToken); + UNICODE_STRING name; + RtlInitUnicodeString (&name, L"PsDereferenceImpersonationToken"); + + PsDereferenceImpersonationTokenD = MmGetSystemRoutineAddress (&name); + if (!PsDereferenceImpersonationTokenD) + TC_BUG_CHECK (STATUS_NOT_IMPLEMENTED); + +# define PsDereferencePrimaryToken +# define PsDereferenceImpersonationToken PsDereferenceImpersonationTokenD + + SeDeleteClientSecurity (&Extension->SecurityClientContext); + +# undef PsDereferencePrimaryToken +# undef PsDereferenceImpersonationToken + } + } + + VirtualVolumeDeviceObjects[Extension->nDosDriveNo] = NULL; + } + + IoDeleteDevice (DeviceObject); + + Dump ("TCDeleteDeviceObject END\n"); +} + + +VOID TCUnloadDriver (PDRIVER_OBJECT DriverObject) +{ + Dump ("TCUnloadDriver BEGIN\n"); + + OnShutdownPending(); + + if (IsBootDriveMounted()) + TC_BUG_CHECK (STATUS_INVALID_DEVICE_STATE); + + EncryptionThreadPoolStop(); + TCDeleteDeviceObject (RootDeviceObject, (PEXTENSION) RootDeviceObject->DeviceExtension); + + Dump ("TCUnloadDriver END\n"); +} + + +void OnShutdownPending () +{ + UNMOUNT_STRUCT unmount; + memset (&unmount, 0, sizeof (unmount)); + unmount.ignoreOpenFiles = TRUE; + + while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_DISMOUNT_ALL_VOLUMES, &unmount, sizeof (unmount), &unmount, sizeof (unmount)) == STATUS_INSUFFICIENT_RESOURCES || unmount.HiddenVolumeProtectionTriggered) + unmount.HiddenVolumeProtectionTriggered = FALSE; + + while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_WIPE_PASSWORD_CACHE, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES); +} + + +NTSTATUS TCDeviceIoControl (PWSTR deviceName, ULONG IoControlCode, void *InputBuffer, ULONG InputBufferSize, void *OutputBuffer, ULONG OutputBufferSize) +{ + IO_STATUS_BLOCK ioStatusBlock; + NTSTATUS ntStatus; + PIRP irp; + PFILE_OBJECT fileObject; + PDEVICE_OBJECT deviceObject; + KEVENT event; + UNICODE_STRING name; + + RtlInitUnicodeString(&name, deviceName); + ntStatus = IoGetDeviceObjectPointer (&name, FILE_READ_ATTRIBUTES, &fileObject, &deviceObject); + + if (!NT_SUCCESS (ntStatus)) + return ntStatus; + + KeInitializeEvent(&event, NotificationEvent, FALSE); + + irp = IoBuildDeviceIoControlRequest (IoControlCode, + deviceObject, + InputBuffer, InputBufferSize, + OutputBuffer, OutputBufferSize, + FALSE, + &event, + &ioStatusBlock); + + if (irp == NULL) + { + Dump ("IRP allocation failed\n"); + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + goto ret; + } + + IoGetNextIrpStackLocation (irp)->FileObject = fileObject; + + ntStatus = IoCallDriver (deviceObject, irp); + if (ntStatus == STATUS_PENDING) + { + KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL); + ntStatus = ioStatusBlock.Status; + } + +ret: + ObDereferenceObject (fileObject); + return ntStatus; +} + + +typedef struct +{ + PDEVICE_OBJECT deviceObject; ULONG ioControlCode; void *inputBuffer; int inputBufferSize; void *outputBuffer; int outputBufferSize; + NTSTATUS Status; + KEVENT WorkItemCompletedEvent; +} SendDeviceIoControlRequestWorkItemArgs; + + +static VOID SendDeviceIoControlRequestWorkItemRoutine (PDEVICE_OBJECT rootDeviceObject, SendDeviceIoControlRequestWorkItemArgs *arg) +{ + arg->Status = SendDeviceIoControlRequest (arg->deviceObject, arg->ioControlCode, arg->inputBuffer, arg->inputBufferSize, arg->outputBuffer, arg->outputBufferSize); + KeSetEvent (&arg->WorkItemCompletedEvent, IO_NO_INCREMENT, FALSE); +} + + +NTSTATUS SendDeviceIoControlRequest (PDEVICE_OBJECT deviceObject, ULONG ioControlCode, void *inputBuffer, int inputBufferSize, void *outputBuffer, int outputBufferSize) +{ + IO_STATUS_BLOCK ioStatusBlock; + NTSTATUS status; + PIRP irp; + KEVENT event; + + if (KeGetCurrentIrql() > APC_LEVEL) + { + SendDeviceIoControlRequestWorkItemArgs args; + + PIO_WORKITEM workItem = IoAllocateWorkItem (RootDeviceObject); + if (!workItem) + return STATUS_INSUFFICIENT_RESOURCES; + + args.deviceObject = deviceObject; + args.ioControlCode = ioControlCode; + args.inputBuffer = inputBuffer; + args.inputBufferSize = inputBufferSize; + args.outputBuffer = outputBuffer; + args.outputBufferSize = outputBufferSize; + + KeInitializeEvent (&args.WorkItemCompletedEvent, SynchronizationEvent, FALSE); + IoQueueWorkItem (workItem, SendDeviceIoControlRequestWorkItemRoutine, DelayedWorkQueue, &args); + + KeWaitForSingleObject (&args.WorkItemCompletedEvent, Executive, KernelMode, FALSE, NULL); + IoFreeWorkItem (workItem); + + return args.Status; + } + + KeInitializeEvent (&event, NotificationEvent, FALSE); + + irp = IoBuildDeviceIoControlRequest (ioControlCode, deviceObject, inputBuffer, inputBufferSize, + outputBuffer, outputBufferSize, FALSE, &event, &ioStatusBlock); + + if (!irp) + return STATUS_INSUFFICIENT_RESOURCES; + + ObReferenceObject (deviceObject); + + status = IoCallDriver (deviceObject, irp); + if (status == STATUS_PENDING) + { + KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL); + status = ioStatusBlock.Status; + } + + ObDereferenceObject (deviceObject); + return status; +} + + +NTSTATUS ProbeRealDriveSize (PDEVICE_OBJECT driveDeviceObject, LARGE_INTEGER *driveSize) +{ + NTSTATUS status; + LARGE_INTEGER sysLength; + LARGE_INTEGER offset; + byte *sectorBuffer; + ULONGLONG startTime; + + if (!UserCanAccessDriveDevice()) + return STATUS_ACCESS_DENIED; + + sectorBuffer = TCalloc (TC_SECTOR_SIZE_BIOS); + if (!sectorBuffer) + return STATUS_INSUFFICIENT_RESOURCES; + + status = SendDeviceIoControlRequest (driveDeviceObject, IOCTL_DISK_GET_LENGTH_INFO, + NULL, 0, &sysLength, sizeof (sysLength)); + + if (!NT_SUCCESS (status)) + { + Dump ("Failed to get drive size - error %x\n", status); + TCfree (sectorBuffer); + return status; + } + + startTime = KeQueryInterruptTime (); + for (offset.QuadPart = sysLength.QuadPart; ; offset.QuadPart += TC_SECTOR_SIZE_BIOS) + { + status = TCReadDevice (driveDeviceObject, sectorBuffer, offset, TC_SECTOR_SIZE_BIOS); + + if (NT_SUCCESS (status)) + status = TCWriteDevice (driveDeviceObject, sectorBuffer, offset, TC_SECTOR_SIZE_BIOS); + + if (!NT_SUCCESS (status)) + { + driveSize->QuadPart = offset.QuadPart; + Dump ("Real drive size = %I64d bytes (%I64d hidden)\n", driveSize->QuadPart, driveSize->QuadPart - sysLength.QuadPart); + TCfree (sectorBuffer); + return STATUS_SUCCESS; + } + + if (KeQueryInterruptTime() - startTime > 3ULL * 60 * 1000 * 1000 * 10) + { + // Abort if probing for more than 3 minutes + driveSize->QuadPart = sysLength.QuadPart; + TCfree (sectorBuffer); + return STATUS_TIMEOUT; + } + } +} + + +NTSTATUS TCOpenFsVolume (PEXTENSION Extension, PHANDLE volumeHandle, PFILE_OBJECT * fileObject) +{ + NTSTATUS ntStatus; + OBJECT_ATTRIBUTES objectAttributes; + UNICODE_STRING fullFileName; + IO_STATUS_BLOCK ioStatus; + WCHAR volumeName[TC_MAX_PATH]; + + TCGetNTNameFromNumber (volumeName, sizeof(volumeName),Extension->nDosDriveNo); + RtlInitUnicodeString (&fullFileName, volumeName); + InitializeObjectAttributes (&objectAttributes, &fullFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + + ntStatus = ZwCreateFile (volumeHandle, + SYNCHRONIZE | GENERIC_READ, + &objectAttributes, + &ioStatus, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0); + + Dump ("Volume %ls open NTSTATUS 0x%08x\n", volumeName, ntStatus); + + if (!NT_SUCCESS (ntStatus)) + return ntStatus; + + ntStatus = ObReferenceObjectByHandle (*volumeHandle, + FILE_READ_DATA, + NULL, + KernelMode, + fileObject, + NULL); + + if (!NT_SUCCESS (ntStatus)) + ZwClose (*volumeHandle); + + return ntStatus; +} + + +void TCCloseFsVolume (HANDLE volumeHandle, PFILE_OBJECT fileObject) +{ + ObDereferenceObject (fileObject); + ZwClose (volumeHandle); +} + + +static NTSTATUS TCReadWriteDevice (BOOL write, PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length) +{ + NTSTATUS status; + IO_STATUS_BLOCK ioStatusBlock; + PIRP irp; + KEVENT completionEvent; + + ASSERT (KeGetCurrentIrql() <= APC_LEVEL); + + KeInitializeEvent (&completionEvent, NotificationEvent, FALSE); + irp = IoBuildSynchronousFsdRequest (write ? IRP_MJ_WRITE : IRP_MJ_READ, deviceObject, buffer, length, &offset, &completionEvent, &ioStatusBlock); + if (!irp) + return STATUS_INSUFFICIENT_RESOURCES; + + ObReferenceObject (deviceObject); + status = IoCallDriver (deviceObject, irp); + + if (status == STATUS_PENDING) + { + status = KeWaitForSingleObject (&completionEvent, Executive, KernelMode, FALSE, NULL); + if (NT_SUCCESS (status)) + status = ioStatusBlock.Status; + } + + ObDereferenceObject (deviceObject); + return status; +} + + +NTSTATUS TCReadDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length) +{ + return TCReadWriteDevice (FALSE, deviceObject, buffer, offset, length); +} + + +NTSTATUS TCWriteDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length) +{ + return TCReadWriteDevice (TRUE, deviceObject, buffer, offset, length); +} + + +NTSTATUS TCFsctlCall (PFILE_OBJECT fileObject, LONG IoControlCode, + void *InputBuffer, int InputBufferSize, void *OutputBuffer, int OutputBufferSize) +{ + IO_STATUS_BLOCK ioStatusBlock; + NTSTATUS ntStatus; + PIRP irp; + KEVENT event; + PIO_STACK_LOCATION stack; + PDEVICE_OBJECT deviceObject = IoGetRelatedDeviceObject (fileObject); + + KeInitializeEvent(&event, NotificationEvent, FALSE); + + irp = IoBuildDeviceIoControlRequest (IoControlCode, + deviceObject, + InputBuffer, InputBufferSize, + OutputBuffer, OutputBufferSize, + FALSE, + &event, + &ioStatusBlock); + + if (irp == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + + stack = IoGetNextIrpStackLocation(irp); + + stack->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; + stack->MinorFunction = IRP_MN_USER_FS_REQUEST; + stack->FileObject = fileObject; + + ntStatus = IoCallDriver (deviceObject, irp); + if (ntStatus == STATUS_PENDING) + { + KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL); + ntStatus = ioStatusBlock.Status; + } + + return ntStatus; +} + + +NTSTATUS CreateDriveLink (int nDosDriveNo) +{ + WCHAR dev[128], link[128]; + UNICODE_STRING deviceName, symLink; + NTSTATUS ntStatus; + + TCGetNTNameFromNumber (dev, sizeof(dev),nDosDriveNo); + TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, DeviceNamespaceDefault); + + RtlInitUnicodeString (&deviceName, dev); + RtlInitUnicodeString (&symLink, link); + + ntStatus = IoCreateSymbolicLink (&symLink, &deviceName); + Dump ("IoCreateSymbolicLink returned %X\n", ntStatus); + return ntStatus; +} + + +NTSTATUS RemoveDriveLink (int nDosDriveNo) +{ + WCHAR link[256]; + UNICODE_STRING symLink; + NTSTATUS ntStatus; + + TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, DeviceNamespaceDefault); + RtlInitUnicodeString (&symLink, link); + + ntStatus = IoDeleteSymbolicLink (&symLink); + Dump ("IoDeleteSymbolicLink returned %X\n", ntStatus); + return ntStatus; +} + + +NTSTATUS MountManagerMount (MOUNT_STRUCT *mount) +{ + NTSTATUS ntStatus; + WCHAR arrVolume[256]; + char buf[200]; + PMOUNTMGR_TARGET_NAME in = (PMOUNTMGR_TARGET_NAME) buf; + PMOUNTMGR_CREATE_POINT_INPUT point = (PMOUNTMGR_CREATE_POINT_INPUT) buf; + + TCGetNTNameFromNumber (arrVolume, sizeof(arrVolume),mount->nDosDriveNo); + in->DeviceNameLength = (USHORT) wcslen (arrVolume) * 2; + RtlStringCbCopyW(in->DeviceName, sizeof(buf) - sizeof(in->DeviceNameLength),arrVolume); + + ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION, + in, (ULONG) (sizeof (in->DeviceNameLength) + wcslen (arrVolume) * 2), 0, 0); + + memset (buf, 0, sizeof buf); + TCGetDosNameFromNumber ((PWSTR) &point[1], sizeof(buf) - sizeof(MOUNTMGR_CREATE_POINT_INPUT),mount->nDosDriveNo, DeviceNamespaceDefault); + + point->SymbolicLinkNameOffset = sizeof (MOUNTMGR_CREATE_POINT_INPUT); + point->SymbolicLinkNameLength = (USHORT) wcslen ((PWSTR) &point[1]) * 2; + + point->DeviceNameOffset = point->SymbolicLinkNameOffset + point->SymbolicLinkNameLength; + TCGetNTNameFromNumber ((PWSTR) (buf + point->DeviceNameOffset), sizeof(buf) - point->DeviceNameOffset,mount->nDosDriveNo); + point->DeviceNameLength = (USHORT) wcslen ((PWSTR) (buf + point->DeviceNameOffset)) * 2; + + ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_CREATE_POINT, point, + point->DeviceNameOffset + point->DeviceNameLength, 0, 0); + + return ntStatus; +} + + +NTSTATUS MountManagerUnmount (int nDosDriveNo) +{ + NTSTATUS ntStatus; + char buf[256], out[300]; + PMOUNTMGR_MOUNT_POINT in = (PMOUNTMGR_MOUNT_POINT) buf; + + memset (buf, 0, sizeof buf); + + TCGetDosNameFromNumber ((PWSTR) &in[1], sizeof(buf) - sizeof(MOUNTMGR_MOUNT_POINT),nDosDriveNo, DeviceNamespaceDefault); + + // Only symbolic link can be deleted with IOCTL_MOUNTMGR_DELETE_POINTS. If any other entry is specified, the mount manager will ignore subsequent IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION for the same volume ID. + in->SymbolicLinkNameOffset = sizeof (MOUNTMGR_MOUNT_POINT); + in->SymbolicLinkNameLength = (USHORT) wcslen ((PWCHAR) &in[1]) * 2; + + ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_DELETE_POINTS, + in, sizeof(MOUNTMGR_MOUNT_POINT) + in->SymbolicLinkNameLength, out, sizeof out); + + Dump ("IOCTL_MOUNTMGR_DELETE_POINTS returned 0x%08x\n", ntStatus); + + return ntStatus; +} + + +NTSTATUS MountDevice (PDEVICE_OBJECT DeviceObject, MOUNT_STRUCT *mount) +{ + PDEVICE_OBJECT NewDeviceObject; + NTSTATUS ntStatus; + + // Make sure the user is asking for a reasonable nDosDriveNo + if (mount->nDosDriveNo >= 0 && mount->nDosDriveNo <= 25 + && IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceDefault) // drive letter must not exist both locally and globally + && IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceGlobal) + ) + { + Dump ("Mount request looks valid\n"); + } + else + { + Dump ("WARNING: MOUNT DRIVE LETTER INVALID\n"); + mount->nReturnCode = ERR_DRIVE_NOT_FOUND; + return ERR_DRIVE_NOT_FOUND; + } + + if (!SelfTestsPassed) + { + mount->nReturnCode = ERR_SELF_TESTS_FAILED; + return ERR_SELF_TESTS_FAILED; + } + + ntStatus = TCCreateDeviceObject (DeviceObject->DriverObject, &NewDeviceObject, mount); + + if (!NT_SUCCESS (ntStatus)) + { + Dump ("Mount CREATE DEVICE ERROR, ntStatus = 0x%08x\n", ntStatus); + return ntStatus; + } + else + { + PEXTENSION NewExtension = (PEXTENSION) NewDeviceObject->DeviceExtension; + SECURITY_SUBJECT_CONTEXT subContext; + PACCESS_TOKEN accessToken; + + SeCaptureSubjectContext (&subContext); + SeLockSubjectContext(&subContext); + if (subContext.ClientToken && subContext.ImpersonationLevel >= SecurityImpersonation) + accessToken = subContext.ClientToken; + else + accessToken = subContext.PrimaryToken; + + if (!accessToken) + { + ntStatus = STATUS_INVALID_PARAMETER; + } + else + { + PTOKEN_USER tokenUser; + + ntStatus = SeQueryInformationToken (accessToken, TokenUser, &tokenUser); + if (NT_SUCCESS (ntStatus)) + { + ULONG sidLength = RtlLengthSid (tokenUser->User.Sid); + + NewExtension->UserSid = TCalloc (sidLength); + if (!NewExtension->UserSid) + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + else + ntStatus = RtlCopySid (sidLength, NewExtension->UserSid, tokenUser->User.Sid); + + ExFreePool (tokenUser); // Documented in newer versions of WDK + } + } + + SeUnlockSubjectContext(&subContext); + SeReleaseSubjectContext (&subContext); + + if (NT_SUCCESS (ntStatus)) + ntStatus = TCStartVolumeThread (NewDeviceObject, NewExtension, mount); + + if (!NT_SUCCESS (ntStatus)) + { + Dump ("Mount FAILURE NT ERROR, ntStatus = 0x%08x\n", ntStatus); + TCDeleteDeviceObject (NewDeviceObject, NewExtension); + return ntStatus; + } + else + { + if (mount->nReturnCode == 0) + { + HANDLE volumeHandle; + PFILE_OBJECT volumeFileObject; + ULONG labelLen = (ULONG) wcslen (mount->wszLabel); + BOOL bIsNTFS = FALSE; + ULONG labelMaxLen, labelEffectiveLen; + + Dump ("Mount SUCCESS TC code = 0x%08x READ-ONLY = %d\n", mount->nReturnCode, NewExtension->bReadOnly); + + if (NewExtension->bReadOnly) + NewDeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE; + + NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + NewExtension->UniqueVolumeId = LastUniqueVolumeId++; + + // check again that the drive letter is available globally and locally + if ( !IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceDefault) + || !IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceGlobal) + ) + { + TCDeleteDeviceObject (NewDeviceObject, NewExtension); + mount->nReturnCode = ERR_DRIVE_NOT_FOUND; + return ERR_DRIVE_NOT_FOUND; + } + + if (mount->bMountManager) + MountManagerMount (mount); + + NewExtension->bMountManager = mount->bMountManager; + + // We create symbolic link even if mount manager is notified of + // arriving volume as it apparently sometimes fails to create the link + CreateDriveLink (mount->nDosDriveNo); + + mount->FilesystemDirty = FALSE; + + if (NT_SUCCESS (TCOpenFsVolume (NewExtension, &volumeHandle, &volumeFileObject))) + { + __try + { + ULONG fsStatus; + + if (NT_SUCCESS (TCFsctlCall (volumeFileObject, FSCTL_IS_VOLUME_DIRTY, NULL, 0, &fsStatus, sizeof (fsStatus))) + && (fsStatus & VOLUME_IS_DIRTY)) + { + mount->FilesystemDirty = TRUE; + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + mount->FilesystemDirty = TRUE; + } + + // detect if the filesystem is NTFS or FAT + __try + { + NTFS_VOLUME_DATA_BUFFER ntfsData; + if (NT_SUCCESS (TCFsctlCall (volumeFileObject, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &ntfsData, sizeof (ntfsData)))) + { + bIsNTFS = TRUE; + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + bIsNTFS = FALSE; + } + + NewExtension->bIsNTFS = bIsNTFS; + mount->bIsNTFS = bIsNTFS; + + if (labelLen > 0) + { + if (bIsNTFS) + labelMaxLen = 32; // NTFS maximum label length + else + labelMaxLen = 11; // FAT maximum label length + + // calculate label effective length + labelEffectiveLen = labelLen > labelMaxLen? labelMaxLen : labelLen; + + // correct the label in the device + memset (&NewExtension->wszLabel[labelEffectiveLen], 0, 33 - labelEffectiveLen); + memcpy (mount->wszLabel, NewExtension->wszLabel, 33); + + // set the volume label + __try + { + IO_STATUS_BLOCK ioblock; + ULONG labelInfoSize = sizeof(FILE_FS_LABEL_INFORMATION) + (labelEffectiveLen * sizeof(WCHAR)); + FILE_FS_LABEL_INFORMATION* labelInfo = (FILE_FS_LABEL_INFORMATION*) TCalloc (labelInfoSize); + labelInfo->VolumeLabelLength = labelEffectiveLen * sizeof(WCHAR); + memcpy (labelInfo->VolumeLabel, mount->wszLabel, labelInfo->VolumeLabelLength); + + if (STATUS_SUCCESS == ZwSetVolumeInformationFile (volumeHandle, &ioblock, labelInfo, labelInfoSize, FileFsLabelInformation)) + { + mount->bDriverSetLabel = TRUE; + NewExtension->bDriverSetLabel = TRUE; + } + + TCfree(labelInfo); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + + } + } + + TCCloseFsVolume (volumeHandle, volumeFileObject); + } + } + else + { + Dump ("Mount FAILURE TC code = 0x%08x\n", mount->nReturnCode); + TCDeleteDeviceObject (NewDeviceObject, NewExtension); + } + + return STATUS_SUCCESS; + } + } +} + +NTSTATUS UnmountDevice (UNMOUNT_STRUCT *unmountRequest, PDEVICE_OBJECT deviceObject, BOOL ignoreOpenFiles) +{ + PEXTENSION extension = deviceObject->DeviceExtension; + NTSTATUS ntStatus; + HANDLE volumeHandle; + PFILE_OBJECT volumeFileObject; + + Dump ("UnmountDevice %d\n", extension->nDosDriveNo); + + ntStatus = TCOpenFsVolume (extension, &volumeHandle, &volumeFileObject); + + if (NT_SUCCESS (ntStatus)) + { + int dismountRetry; + + // Dismounting a writable NTFS filesystem prevents the driver from being unloaded on Windows 7 + if (IsOSAtLeast (WIN_7) && !extension->bReadOnly) + { + NTFS_VOLUME_DATA_BUFFER ntfsData; + + if (NT_SUCCESS (TCFsctlCall (volumeFileObject, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &ntfsData, sizeof (ntfsData)))) + DriverUnloadDisabled = TRUE; + } + + // Lock volume + ntStatus = TCFsctlCall (volumeFileObject, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0); + Dump ("FSCTL_LOCK_VOLUME returned %X\n", ntStatus); + + if (!NT_SUCCESS (ntStatus) && !ignoreOpenFiles) + { + TCCloseFsVolume (volumeHandle, volumeFileObject); + return ERR_FILES_OPEN; + } + + // Dismount volume + for (dismountRetry = 0; dismountRetry < 200; ++dismountRetry) + { + ntStatus = TCFsctlCall (volumeFileObject, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0); + Dump ("FSCTL_DISMOUNT_VOLUME returned %X\n", ntStatus); + + if (NT_SUCCESS (ntStatus) || ntStatus == STATUS_VOLUME_DISMOUNTED) + break; + + if (!ignoreOpenFiles) + { + TCCloseFsVolume (volumeHandle, volumeFileObject); + return ERR_FILES_OPEN; + } + + TCSleep (100); + } + } + else + { + // Volume cannot be opened => force dismount if allowed + if (!ignoreOpenFiles) + return ERR_FILES_OPEN; + else + volumeHandle = NULL; + } + + if (extension->bMountManager) + MountManagerUnmount (extension->nDosDriveNo); + + // We always remove symbolic link as mount manager might fail to do so + RemoveDriveLink (extension->nDosDriveNo); + + extension->bShuttingDown = TRUE; + + ntStatus = IoAcquireRemoveLock (&extension->Queue.RemoveLock, NULL); + ASSERT (NT_SUCCESS (ntStatus)); + IoReleaseRemoveLockAndWait (&extension->Queue.RemoveLock, NULL); + + if (volumeHandle != NULL) + TCCloseFsVolume (volumeHandle, volumeFileObject); + + if (unmountRequest) + { + PCRYPTO_INFO cryptoInfo = ((PEXTENSION) deviceObject->DeviceExtension)->cryptoInfo; + unmountRequest->HiddenVolumeProtectionTriggered = (cryptoInfo->bProtectHiddenVolume && cryptoInfo->bHiddenVolProtectionAction); + } + + TCDeleteDeviceObject (deviceObject, (PEXTENSION) deviceObject->DeviceExtension); + return 0; +} + + +static PDEVICE_OBJECT FindVolumeWithHighestUniqueId (int maxUniqueId) +{ + PDEVICE_OBJECT highestIdDevice = NULL; + int highestId = -1; + int drive; + + for (drive = MIN_MOUNTED_VOLUME_DRIVE_NUMBER; drive <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; ++drive) + { + PDEVICE_OBJECT device = GetVirtualVolumeDeviceObject (drive); + if (device) + { + PEXTENSION extension = (PEXTENSION) device->DeviceExtension; + if (extension->UniqueVolumeId > highestId && extension->UniqueVolumeId <= maxUniqueId) + { + highestId = extension->UniqueVolumeId; + highestIdDevice = device; + } + } + } + + return highestIdDevice; +} + + +NTSTATUS UnmountAllDevices (UNMOUNT_STRUCT *unmountRequest, BOOL ignoreOpenFiles) +{ + NTSTATUS status = 0; + PDEVICE_OBJECT ListDevice; + int maxUniqueId = LastUniqueVolumeId; + + Dump ("Unmounting all volumes\n"); + + if (unmountRequest) + unmountRequest->HiddenVolumeProtectionTriggered = FALSE; + + // Dismount volumes in the reverse order they were mounted to properly dismount nested volumes + while ((ListDevice = FindVolumeWithHighestUniqueId (maxUniqueId)) != NULL) + { + PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension; + maxUniqueId = ListExtension->UniqueVolumeId - 1; + + if (IsVolumeAccessibleByCurrentUser (ListExtension)) + { + NTSTATUS ntStatus; + + if (unmountRequest) + unmountRequest->nDosDriveNo = ListExtension->nDosDriveNo; + + ntStatus = UnmountDevice (unmountRequest, ListDevice, ignoreOpenFiles); + status = ntStatus == 0 ? status : ntStatus; + + if (unmountRequest && unmountRequest->HiddenVolumeProtectionTriggered) + break; + } + } + + return status; +} + +// Resolves symbolic link name to its target name +NTSTATUS SymbolicLinkToTarget (PWSTR symlinkName, PWSTR targetName, USHORT maxTargetNameLength) +{ + NTSTATUS ntStatus; + OBJECT_ATTRIBUTES objectAttributes; + UNICODE_STRING fullFileName; + HANDLE handle; + + RtlInitUnicodeString (&fullFileName, symlinkName); + InitializeObjectAttributes (&objectAttributes, &fullFileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); + + ntStatus = ZwOpenSymbolicLinkObject (&handle, GENERIC_READ, &objectAttributes); + + if (NT_SUCCESS (ntStatus)) + { + UNICODE_STRING target; + target.Buffer = targetName; + target.Length = 0; + target.MaximumLength = maxTargetNameLength; + memset (targetName, 0, maxTargetNameLength); + + ntStatus = ZwQuerySymbolicLinkObject (handle, &target, NULL); + + ZwClose (handle); + } + + return ntStatus; +} + + +// Checks if two regions overlap (borders are parts of regions) +BOOL RegionsOverlap (unsigned __int64 start1, unsigned __int64 end1, unsigned __int64 start2, unsigned __int64 end2) +{ + return (start1 < start2) ? (end1 >= start2) : (start1 <= end2); +} + + +void GetIntersection (uint64 start1, uint32 length1, uint64 start2, uint64 end2, uint64 *intersectStart, uint32 *intersectLength) +{ + uint64 end1 = start1 + length1 - 1; + uint64 intersectEnd = (end1 <= end2) ? end1 : end2; + + *intersectStart = (start1 >= start2) ? start1 : start2; + *intersectLength = (uint32) ((*intersectStart > intersectEnd) ? 0 : intersectEnd + 1 - *intersectStart); + + if (*intersectLength == 0) + *intersectStart = start1; +} + + +BOOL IsAccessibleByUser (PUNICODE_STRING objectFileName, BOOL readOnly) +{ + OBJECT_ATTRIBUTES fileObjAttributes; + IO_STATUS_BLOCK ioStatusBlock; + HANDLE fileHandle; + NTSTATUS status; + + ASSERT (!IoIsSystemThread (PsGetCurrentThread())); + + InitializeObjectAttributes (&fileObjAttributes, objectFileName, OBJ_CASE_INSENSITIVE | OBJ_FORCE_ACCESS_CHECK | OBJ_KERNEL_HANDLE, NULL, NULL); + + status = ZwCreateFile (&fileHandle, + readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + &fileObjAttributes, + &ioStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0); + + if (NT_SUCCESS (status)) + { + ZwClose (fileHandle); + return TRUE; + } + + return FALSE; +} + + +BOOL UserCanAccessDriveDevice () +{ + UNICODE_STRING name; + RtlInitUnicodeString (&name, L"\\Device\\MountPointManager"); + + return IsAccessibleByUser (&name, FALSE); +} + +BOOL IsDriveLetterAvailable (int nDosDriveNo, DeviceNamespaceType namespaceType) +{ + OBJECT_ATTRIBUTES objectAttributes; + UNICODE_STRING objectName; + WCHAR link[128]; + HANDLE handle; + NTSTATUS ntStatus; + + TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, namespaceType); + RtlInitUnicodeString (&objectName, link); + InitializeObjectAttributes (&objectAttributes, &objectName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); + + if (NT_SUCCESS (ntStatus = ZwOpenSymbolicLinkObject (&handle, GENERIC_READ, &objectAttributes))) + { + ZwClose (handle); + return FALSE; + } + + return (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND)? TRUE : FALSE; +} + + +NTSTATUS TCCompleteIrp (PIRP irp, NTSTATUS status, ULONG_PTR information) +{ + irp->IoStatus.Status = status; + irp->IoStatus.Information = information; + IoCompleteRequest (irp, IO_NO_INCREMENT); + return status; +} + + +NTSTATUS TCCompleteDiskIrp (PIRP irp, NTSTATUS status, ULONG_PTR information) +{ + irp->IoStatus.Status = status; + irp->IoStatus.Information = information; + IoCompleteRequest (irp, NT_SUCCESS (status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT); + return status; +} + + +size_t GetCpuCount () +{ + KAFFINITY activeCpuMap = KeQueryActiveProcessors(); + size_t mapSize = sizeof (activeCpuMap) * 8; + size_t cpuCount = 0; + + while (mapSize--) + { + if (activeCpuMap & 1) + ++cpuCount; + + activeCpuMap >>= 1; + } + + if (cpuCount == 0) + return 1; + + return cpuCount; +} + + +void EnsureNullTerminatedString (wchar_t *str, size_t maxSizeInBytes) +{ + ASSERT ((maxSizeInBytes & 1) == 0); + str[maxSizeInBytes / sizeof (wchar_t) - 1] = 0; +} + + +void *AllocateMemoryWithTimeout (size_t size, int retryDelay, int timeout) +{ + LARGE_INTEGER waitInterval; + waitInterval.QuadPart = retryDelay * -10000; + + ASSERT (KeGetCurrentIrql() <= APC_LEVEL); + ASSERT (retryDelay > 0 && retryDelay <= timeout); + + while (TRUE) + { + void *memory = TCalloc (size); + if (memory) + return memory; + + timeout -= retryDelay; + if (timeout <= 0) + break; + + KeDelayExecutionThread (KernelMode, FALSE, &waitInterval); + } + + return NULL; +} + + +NTSTATUS TCReadRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, PKEY_VALUE_PARTIAL_INFORMATION *keyData) +{ + OBJECT_ATTRIBUTES regObjAttribs; + HANDLE regKeyHandle; + NTSTATUS status; + UNICODE_STRING valName; + ULONG size = 0; + ULONG resultSize; + + InitializeObjectAttributes (®ObjAttribs, keyPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); + status = ZwOpenKey (®KeyHandle, KEY_READ, ®ObjAttribs); + if (!NT_SUCCESS (status)) + return status; + + RtlInitUnicodeString (&valName, keyValueName); + status = ZwQueryValueKey (regKeyHandle, &valName, KeyValuePartialInformation, NULL, 0, &size); + + if (!NT_SUCCESS (status) && status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL) + { + ZwClose (regKeyHandle); + return status; + } + + if (size == 0) + { + ZwClose (regKeyHandle); + return STATUS_NO_DATA_DETECTED; + } + + *keyData = (PKEY_VALUE_PARTIAL_INFORMATION) TCalloc (size); + if (!*keyData) + { + ZwClose (regKeyHandle); + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = ZwQueryValueKey (regKeyHandle, &valName, KeyValuePartialInformation, *keyData, size, &resultSize); + + ZwClose (regKeyHandle); + return status; +} + + +NTSTATUS TCWriteRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, ULONG keyValueType, void *valueData, ULONG valueSize) +{ + OBJECT_ATTRIBUTES regObjAttribs; + HANDLE regKeyHandle; + NTSTATUS status; + UNICODE_STRING valName; + + InitializeObjectAttributes (®ObjAttribs, keyPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); + status = ZwOpenKey (®KeyHandle, KEY_READ | KEY_WRITE, ®ObjAttribs); + if (!NT_SUCCESS (status)) + return status; + + RtlInitUnicodeString (&valName, keyValueName); + + status = ZwSetValueKey (regKeyHandle, &valName, 0, keyValueType, valueData, valueSize); + + ZwClose (regKeyHandle); + return status; +} + + +BOOL IsVolumeClassFilterRegistered () +{ + UNICODE_STRING name; + NTSTATUS status; + BOOL registered = FALSE; + + PKEY_VALUE_PARTIAL_INFORMATION data; + + RtlInitUnicodeString (&name, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Class\\{71A27CDD-812A-11D0-BEC7-08002BE2092F}"); + status = TCReadRegistryKey (&name, L"UpperFilters", &data); + + if (NT_SUCCESS (status)) + { + if (data->Type == REG_MULTI_SZ && data->DataLength >= 9 * sizeof (wchar_t)) + { + // Search for the string "veracrypt" + ULONG i; + for (i = 0; i <= data->DataLength - 9 * sizeof (wchar_t); ++i) + { + if (memcmp (data->Data + i, L"veracrypt", 9 * sizeof (wchar_t)) == 0) + { + Dump ("Volume class filter active\n"); + registered = TRUE; + break; + } + } + } + + TCfree (data); + } + + return registered; +} + + +NTSTATUS ReadRegistryConfigFlags (BOOL driverEntry) +{ + PKEY_VALUE_PARTIAL_INFORMATION data; + UNICODE_STRING name; + NTSTATUS status; + uint32 flags = 0; + + RtlInitUnicodeString (&name, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\veracrypt"); + status = TCReadRegistryKey (&name, TC_DRIVER_CONFIG_REG_VALUE_NAME, &data); + + if (NT_SUCCESS (status)) + { + if (data->Type == REG_DWORD) + { + flags = *(uint32 *) data->Data; + Dump ("Configuration flags = 0x%x\n", flags); + + if (driverEntry) + { + if (flags & (TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD | TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD_FOR_SYS_FAVORITES)) + CacheBootPassword = TRUE; + + if (flags & TC_DRIVER_CONFIG_DISABLE_NONADMIN_SYS_FAVORITES_ACCESS) + NonAdminSystemFavoritesAccessDisabled = TRUE; + + if (flags & TC_DRIVER_CONFIG_CACHE_BOOT_PIM) + CacheBootPim = TRUE; + } + + EnableHwEncryption ((flags & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION) ? FALSE : TRUE); + + EnableExtendedIoctlSupport = (flags & TC_DRIVER_CONFIG_ENABLE_EXTENDED_IOCTL)? TRUE : FALSE; + } + else + status = STATUS_INVALID_PARAMETER; + + TCfree (data); + } + + if (driverEntry && NT_SUCCESS (TCReadRegistryKey (&name, TC_ENCRYPTION_FREE_CPU_COUNT_REG_VALUE_NAME, &data))) + { + if (data->Type == REG_DWORD) + EncryptionThreadPoolFreeCpuCountLimit = *(uint32 *) data->Data; + + TCfree (data); + } + + return status; +} + + +NTSTATUS WriteRegistryConfigFlags (uint32 flags) +{ + UNICODE_STRING name; + RtlInitUnicodeString (&name, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\veracrypt"); + + return TCWriteRegistryKey (&name, TC_DRIVER_CONFIG_REG_VALUE_NAME, REG_DWORD, &flags, sizeof (flags)); +} + + +NTSTATUS GetDeviceSectorSize (PDEVICE_OBJECT deviceObject, ULONG *bytesPerSector) +{ + NTSTATUS status; + DISK_GEOMETRY geometry; + + status = SendDeviceIoControlRequest (deviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof (geometry)); + + if (!NT_SUCCESS (status)) + return status; + + *bytesPerSector = geometry.BytesPerSector; + return STATUS_SUCCESS; +} + + +NTSTATUS ZeroUnreadableSectors (PDEVICE_OBJECT deviceObject, LARGE_INTEGER startOffset, ULONG size, uint64 *zeroedSectorCount) +{ + NTSTATUS status; + ULONG sectorSize; + ULONG sectorCount; + byte *sectorBuffer = NULL; + + *zeroedSectorCount = 0; + + status = GetDeviceSectorSize (deviceObject, §orSize); + if (!NT_SUCCESS (status)) + return status; + + sectorBuffer = TCalloc (sectorSize); + if (!sectorBuffer) + return STATUS_INSUFFICIENT_RESOURCES; + + for (sectorCount = size / sectorSize; sectorCount > 0; --sectorCount, startOffset.QuadPart += sectorSize) + { + status = TCReadDevice (deviceObject, sectorBuffer, startOffset, sectorSize); + if (!NT_SUCCESS (status)) + { + Dump ("Zeroing sector at %I64d\n", startOffset.QuadPart); + memset (sectorBuffer, 0, sectorSize); + + status = TCWriteDevice (deviceObject, sectorBuffer, startOffset, sectorSize); + if (!NT_SUCCESS (status)) + goto err; + + ++(*zeroedSectorCount); + } + } + + status = STATUS_SUCCESS; + +err: + if (sectorBuffer) + TCfree (sectorBuffer); + + return status; +} + + +NTSTATUS ReadDeviceSkipUnreadableSectors (PDEVICE_OBJECT deviceObject, byte *buffer, LARGE_INTEGER startOffset, ULONG size, uint64 *badSectorCount) +{ + NTSTATUS status; + ULONG sectorSize; + ULONG sectorCount; + + *badSectorCount = 0; + + status = GetDeviceSectorSize (deviceObject, §orSize); + if (!NT_SUCCESS (status)) + return status; + + for (sectorCount = size / sectorSize; sectorCount > 0; --sectorCount, startOffset.QuadPart += sectorSize, buffer += sectorSize) + { + status = TCReadDevice (deviceObject, buffer, startOffset, sectorSize); + if (!NT_SUCCESS (status)) + { + Dump ("Skipping bad sector at %I64d\n", startOffset.QuadPart); + memset (buffer, 0, sectorSize); + ++(*badSectorCount); + } + } + + return STATUS_SUCCESS; +} + + +BOOL IsVolumeAccessibleByCurrentUser (PEXTENSION volumeDeviceExtension) +{ + SECURITY_SUBJECT_CONTEXT subContext; + PACCESS_TOKEN accessToken; + PTOKEN_USER tokenUser; + BOOL result = FALSE; + + if (IoIsSystemThread (PsGetCurrentThread()) + || UserCanAccessDriveDevice() + || !volumeDeviceExtension->UserSid + || (volumeDeviceExtension->SystemFavorite && !NonAdminSystemFavoritesAccessDisabled)) + { + return TRUE; + } + + SeCaptureSubjectContext (&subContext); + SeLockSubjectContext(&subContext); + if (subContext.ClientToken && subContext.ImpersonationLevel >= SecurityImpersonation) + accessToken = subContext.ClientToken; + else + accessToken = subContext.PrimaryToken; + + if (!accessToken) + goto ret; + + if (SeTokenIsAdmin (accessToken)) + { + result = TRUE; + goto ret; + } + + if (!NT_SUCCESS (SeQueryInformationToken (accessToken, TokenUser, &tokenUser))) + goto ret; + + result = RtlEqualSid (volumeDeviceExtension->UserSid, tokenUser->User.Sid); + ExFreePool (tokenUser); // Documented in newer versions of WDK + +ret: + SeUnlockSubjectContext(&subContext); + SeReleaseSubjectContext (&subContext); + return result; +} + + +void GetElapsedTimeInit (LARGE_INTEGER *lastPerfCounter) +{ + *lastPerfCounter = KeQueryPerformanceCounter (NULL); +} + + +// Returns elapsed time in microseconds since last call +int64 GetElapsedTime (LARGE_INTEGER *lastPerfCounter) +{ + LARGE_INTEGER freq; + LARGE_INTEGER counter = KeQueryPerformanceCounter (&freq); + + int64 elapsed = (counter.QuadPart - lastPerfCounter->QuadPart) * 1000000LL / freq.QuadPart; + *lastPerfCounter = counter; + + return elapsed; +} + + +BOOL IsOSAtLeast (OSVersionEnum reqMinOS) +{ + /* When updating this function, update IsOSVersionAtLeast() in Dlgcode.c too. */ + + ULONG major = 0, minor = 0; + + ASSERT (OsMajorVersion != 0); + + switch (reqMinOS) + { + case WIN_2000: major = 5; minor = 0; break; + case WIN_XP: major = 5; minor = 1; break; + case WIN_SERVER_2003: major = 5; minor = 2; break; + case WIN_VISTA: major = 6; minor = 0; break; + case WIN_7: major = 6; minor = 1; break; + case WIN_8: major = 6; minor = 2; break; + case WIN_8_1: major = 6; minor = 3; break; + case WIN_10: major = 10; minor = 0; break; + + default: + TC_THROW_FATAL_EXCEPTION; + break; + } + + return ((OsMajorVersion << 16 | OsMinorVersion << 8) + >= (major << 16 | minor << 8)); +} -- cgit v1.2.3