PWSTR OfflinePath = L"\\Registry\\Machine\\System\\MountedDevices\\Offline";
UNICODE_STRING RemoteDatabase = RTL_CONSTANT_STRING(L"\\System Volume Information\\MountPointManagerRemoteDatabase");
-UNICODE_STRING RemoteDatabaseFile = RTL_CONSTANT_STRING(L"\\:$MountMgrRemoteDatabase");
/*
* @implemented
/* Get size to append data */
Size.QuadPart = GetRemoteDatabaseSize(Database);
- return ZwWriteFile(Database, 0, NULL, NULL,
+ return ZwWriteFile(Database, NULL, NULL, NULL,
&IoStatusBlock, Entry,
Entry->EntrySize, &Size, NULL);
}
return Entry;
}
+/*
+ * @implemented
+ */
+NTSTATUS
+WriteRemoteDatabaseEntry(IN HANDLE Database,
+ IN LONG Offset,
+ IN PDATABASE_ENTRY Entry)
+{
+ NTSTATUS Status;
+ LARGE_INTEGER ByteOffset;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ ByteOffset.QuadPart = Offset;
+ Status = ZwWriteFile(Database,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ Entry,
+ Entry->EntrySize,
+ &ByteOffset,
+ NULL);
+ if (NT_SUCCESS(Status))
+ {
+ if (IoStatusBlock.Information < Entry->EntrySize)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ return Status;
+}
+
/*
* @implemented
*/
NULL);
}
-/*
- * @implemented
- */
-NTSTATUS
-WaitForRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
-{
- NTSTATUS Status;
- LARGE_INTEGER Timeout;
+/*
+ * @implemented
+ */
+NTSTATUS
+WaitForRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
+{
+ NTSTATUS Status;
+ LARGE_INTEGER Timeout;
+
+ /* Wait for 7 minutes */
+ Timeout.QuadPart = 0xFA0A1F00;
+ Status = KeWaitForSingleObject(&(DeviceExtension->RemoteDatabaseLock), Executive, KernelMode, FALSE, &Timeout);
+ if (Status != STATUS_TIMEOUT)
+ {
+ return Status;
+ }
+
+ return STATUS_IO_TIMEOUT;
+}
+
+/*
+ * @implemented
+ */
+VOID
+ReleaseRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
+{
+ KeReleaseSemaphore(&(DeviceExtension->RemoteDatabaseLock), IO_NO_INCREMENT, 1, FALSE);
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+QueryUniqueIdQueryRoutine(IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext)
+{
+ PMOUNTDEV_UNIQUE_ID IntUniqueId;
+ PMOUNTDEV_UNIQUE_ID * UniqueId;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(EntryContext);
+
+ /* Sanity check */
+ if (ValueLength >= 0x10000)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ /* Allocate the Unique ID */
+ IntUniqueId = AllocatePool(sizeof(UniqueId) + ValueLength);
+ if (IntUniqueId)
+ {
+ /* Copy data & return */
+ IntUniqueId->UniqueIdLength = (USHORT)ValueLength;
+ RtlCopyMemory(&(IntUniqueId->UniqueId), ValueData, ValueLength);
+
+ UniqueId = Context;
+ *UniqueId = IntUniqueId;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+QueryUniqueIdFromMaster(IN PDEVICE_EXTENSION DeviceExtension,
+ IN PUNICODE_STRING SymbolicName,
+ OUT PMOUNTDEV_UNIQUE_ID * UniqueId)
+{
+ NTSTATUS Status;
+ PDEVICE_INFORMATION DeviceInformation;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+
+ /* Query the unique ID */
+ RtlZeroMemory(QueryTable, sizeof(QueryTable));
+ QueryTable[0].QueryRoutine = QueryUniqueIdQueryRoutine;
+ QueryTable[0].Name = SymbolicName->Buffer;
+
+ *UniqueId = NULL;
+ RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+ DatabasePath,
+ QueryTable,
+ UniqueId,
+ NULL);
+ /* Unique ID found, no need to go farther */
+ if (*UniqueId)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ /* Otherwise, find associate device information */
+ Status = FindDeviceInfo(DeviceExtension, SymbolicName, FALSE, &DeviceInformation);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ *UniqueId = AllocatePool(DeviceInformation->UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
+ if (!*UniqueId)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Return this unique ID (better than nothing) */
+ (*UniqueId)->UniqueIdLength = DeviceInformation->UniqueId->UniqueIdLength;
+ RtlCopyMemory(&((*UniqueId)->UniqueId), &(DeviceInformation->UniqueId->UniqueId), (*UniqueId)->UniqueIdLength);
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+WriteUniqueIdToMaster(IN PDEVICE_EXTENSION DeviceExtension,
+ IN PDATABASE_ENTRY DatabaseEntry)
+{
+ NTSTATUS Status;
+ PWCHAR SymbolicName;
+ PLIST_ENTRY NextEntry;
+ UNICODE_STRING SymbolicString;
+ PDEVICE_INFORMATION DeviceInformation;
+
+ /* Create symbolic name from database entry */
+ SymbolicName = AllocatePool(DatabaseEntry->SymbolicNameLength + sizeof(WCHAR));
+ if (!SymbolicName)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory(SymbolicName,
+ (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset),
+ DatabaseEntry->SymbolicNameLength);
+ SymbolicName[DatabaseEntry->SymbolicNameLength / sizeof(WCHAR)] = UNICODE_NULL;
+
+ /* Associate the unique ID with the name from remote database */
+ Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
+ DatabasePath,
+ SymbolicName,
+ REG_BINARY,
+ (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
+ DatabaseEntry->UniqueIdLength);
+ FreePool(SymbolicName);
+
+ /* Reget symbolic name */
+ SymbolicString.Length = DatabaseEntry->SymbolicNameLength;
+ SymbolicString.MaximumLength = DatabaseEntry->SymbolicNameLength;
+ SymbolicString.Buffer = (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
+
+ /* Find the device using this unique ID */
+ for (NextEntry = DeviceExtension->DeviceListHead.Flink;
+ NextEntry != &(DeviceExtension->DeviceListHead);
+ NextEntry = NextEntry->Flink)
+ {
+ DeviceInformation = CONTAINING_RECORD(NextEntry,
+ DEVICE_INFORMATION,
+ DeviceListEntry);
+
+ if (DeviceInformation->UniqueId->UniqueIdLength != DatabaseEntry->UniqueIdLength)
+ {
+ continue;
+ }
+
+ if (RtlCompareMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
+ DeviceInformation->UniqueId->UniqueId,
+ DatabaseEntry->UniqueIdLength) == DatabaseEntry->UniqueIdLength)
+ {
+ break;
+ }
+ }
+
+ /* If found, create a mount point */
+ if (NextEntry != &(DeviceExtension->DeviceListHead))
+ {
+ MountMgrCreatePointWorker(DeviceExtension, &SymbolicString, &(DeviceInformation->DeviceName));
+ }
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+ReconcileThisDatabaseWithMasterWorker(IN PVOID Parameter)
+{
+ ULONG Offset;
+ NTSTATUS Status;
+ PFILE_OBJECT FileObject;
+ PDEVICE_OBJECT DeviceObject;
+ PMOUNTDEV_UNIQUE_ID UniqueId;
+ PDATABASE_ENTRY DatabaseEntry;
+ HANDLE DatabaseHandle, Handle;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PDEVICE_INFORMATION ListDeviceInfo;
+ PLIST_ENTRY Entry, EntryInfo, NextEntry;
+ PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
+ BOOLEAN HardwareErrors, Restart, FailedFinding;
+ WCHAR FileNameBuffer[0x8], SymbolicNameBuffer[100];
+ UNICODE_STRING ReparseFile, FileName, SymbolicName, VolumeName;
+ FILE_REPARSE_POINT_INFORMATION ReparsePointInformation, SavedReparsePointInformation;
+ PDEVICE_EXTENSION DeviceExtension = ((PRECONCILE_WORK_ITEM_CONTEXT)Parameter)->DeviceExtension;
+ PDEVICE_INFORMATION DeviceInformation = ((PRECONCILE_WORK_ITEM_CONTEXT)Parameter)->DeviceInformation;
+
+ /* We're unloading, do nothing */
+ if (Unloading)
+ {
+ return;
+ }
+
+ /* Lock remote DB */
+ if (!NT_SUCCESS(WaitForRemoteDatabaseSemaphore(DeviceExtension)))
+ {
+ return;
+ }
+
+ /* Recheck for unloading */
+ if (Unloading)
+ {
+ goto ReleaseRDS;
+ }
+
+ /* Find the DB to reconcile */
+ KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
+ for (Entry = DeviceExtension->DeviceListHead.Flink;
+ Entry != &DeviceExtension->DeviceListHead;
+ Entry = Entry->Flink)
+ {
+ ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
+ if (ListDeviceInfo == DeviceInformation)
+ {
+ break;
+ }
+ }
+
+ /* If not found, or if removable, bail out */
+ if (Entry == &DeviceExtension->DeviceListHead || DeviceInformation->Removable)
+ {
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+ goto ReleaseRDS;
+ }
+
+ /* Get our device object */
+ Status = IoGetDeviceObjectPointer(&ListDeviceInfo->DeviceName, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject);
+ if (!NT_SUCCESS(Status))
+ {
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+ goto ReleaseRDS;
+ }
+
+ /* Mark mounted only if not unloading */
+ if (!(DeviceObject->Flags & DO_UNLOAD_PENDING))
+ {
+ InterlockedExchangeAdd(&ListDeviceInfo->MountState, 1);
+ }
+
+ ObDereferenceObject(FileObject);
+
+ /* Force default: no DB, and need for reconcile */
+ DeviceInformation->NeedsReconcile = TRUE;
+ DeviceInformation->NoDatabase = TRUE;
+ FailedFinding = FALSE;
+
+ /* Remove any associated device that refers to the DB to reconcile */
+ for (Entry = DeviceExtension->DeviceListHead.Flink;
+ Entry != &DeviceExtension->DeviceListHead;
+ Entry = Entry->Flink)
+ {
+ ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
+
+ EntryInfo = ListDeviceInfo->AssociatedDevicesHead.Flink;
+ while (EntryInfo != &ListDeviceInfo->AssociatedDevicesHead)
+ {
+ AssociatedDevice = CONTAINING_RECORD(EntryInfo, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
+ NextEntry = EntryInfo->Flink;
+
+ if (AssociatedDevice->DeviceInformation == DeviceInformation)
+ {
+ RemoveEntryList(&AssociatedDevice->AssociatedDevicesEntry);
+ FreePool(AssociatedDevice->String.Buffer);
+ FreePool(AssociatedDevice);
+ }
+
+ EntryInfo = NextEntry;
+ }
+ }
+
+ /* Open the remote database */
+ DatabaseHandle = OpenRemoteDatabase(DeviceInformation, FALSE);
+
+ /* Prepare a string with reparse point index */
+ ReparseFile.Length = DeviceInformation->DeviceName.Length + ReparseIndex.Length;
+ ReparseFile.MaximumLength = ReparseFile.Length + sizeof(UNICODE_NULL);
+ ReparseFile.Buffer = AllocatePool(ReparseFile.MaximumLength);
+ if (ReparseFile.Buffer == NULL)
+ {
+ if (DatabaseHandle != 0)
+ {
+ CloseRemoteDatabase(DatabaseHandle);
+ }
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+ goto ReleaseRDS;
+ }
+
+ RtlCopyMemory(ReparseFile.Buffer, DeviceInformation->DeviceName.Buffer,
+ DeviceInformation->DeviceName.Length);
+ RtlCopyMemory((PVOID)((ULONG_PTR)ReparseFile.Buffer + DeviceInformation->DeviceName.Length),
+ ReparseIndex.Buffer, ReparseIndex.Length);
+ ReparseFile.Buffer[ReparseFile.Length / sizeof(WCHAR)] = UNICODE_NULL;
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &ReparseFile,
+ OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ /* Open reparse point directory */
+ HardwareErrors = IoSetThreadHardErrorMode(FALSE);
+ Status = ZwOpenFile(&Handle,
+ FILE_GENERIC_READ,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+ IoSetThreadHardErrorMode(HardwareErrors);
+
+ FreePool(ReparseFile.Buffer);
+
+ if (!NT_SUCCESS(Status))
+ {
+ if (DatabaseHandle != 0)
+ {
+ TruncateRemoteDatabase(DatabaseHandle, 0);
+ CloseRemoteDatabase(DatabaseHandle);
+ }
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+ goto ReleaseRDS;
+ }
+
+ /* Query reparse point information
+ * We only pay attention to mout point
+ */
+ RtlZeroMemory(FileNameBuffer, sizeof(FileNameBuffer));
+ FileName.Buffer = FileNameBuffer;
+ FileName.Length = sizeof(FileNameBuffer);
+ FileName.MaximumLength = sizeof(FileNameBuffer);
+ ((PULONG)FileNameBuffer)[0] = IO_REPARSE_TAG_MOUNT_POINT;
+ Status = ZwQueryDirectoryFile(Handle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ &ReparsePointInformation,
+ sizeof(FILE_REPARSE_POINT_INFORMATION),
+ FileReparsePointInformation,
+ TRUE,
+ &FileName,
+ FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ ZwClose(Handle);
+ if (DatabaseHandle != 0)
+ {
+ TruncateRemoteDatabase(DatabaseHandle, 0);
+ CloseRemoteDatabase(DatabaseHandle);
+ }
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+ goto ReleaseRDS;
+ }
+
+ /* If we failed to open the remote DB previously,
+ * retry this time allowing migration (and thus, creation if required)
+ */
+ if (DatabaseHandle == 0)
+ {
+ DatabaseHandle = OpenRemoteDatabase(DeviceInformation, TRUE);
+ if (DatabaseHandle == 0)
+ {
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+ goto ReleaseRDS;
+ }
+ }
+
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+
+ /* Reset all the references to our DB entries */
+ Offset = 0;
+ for (;;)
+ {
+ DatabaseEntry = GetRemoteDatabaseEntry(DatabaseHandle, Offset);
+ if (DatabaseEntry == NULL)
+ {
+ break;
+ }
+
+ DatabaseEntry->EntryReferences = 0;
+ Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
+ if (!NT_SUCCESS(Status))
+ {
+ FreePool(DatabaseEntry);
+ goto CloseReparse;
+ }
+
+ Offset += DatabaseEntry->EntrySize;
+ FreePool(DatabaseEntry);
+ }
+
+ /* Init string for QueryVolumeName call */
+ SymbolicName.MaximumLength = sizeof(SymbolicNameBuffer);
+ SymbolicName.Length = 0;
+ SymbolicName.Buffer = SymbolicNameBuffer;
+ Restart = TRUE;
+
+ /* Start looping on reparse points */
+ for (;;)
+ {
+ RtlCopyMemory(&SavedReparsePointInformation, &ReparsePointInformation, sizeof(FILE_REPARSE_POINT_INFORMATION));
+ Status = ZwQueryDirectoryFile(Handle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ &ReparsePointInformation,
+ sizeof(FILE_REPARSE_POINT_INFORMATION),
+ FileReparsePointInformation,
+ TRUE,
+ Restart ? &FileName : NULL,
+ Restart);
+ /* Restart only once */
+ if (Restart)
+ {
+ Restart = FALSE;
+ }
+ else
+ {
+ /* If we get the same one, we're done, bail out */
+ if (ReparsePointInformation.FileReference == SavedReparsePointInformation.FileReference &&
+ ReparsePointInformation.Tag == SavedReparsePointInformation.Tag)
+ {
+ break;
+ }
+ }
+
+ /* If querying failed, or if onloading, or if not returning mount points, bail out */
+ if (!NT_SUCCESS(Status) || Unloading || ReparsePointInformation.Tag != IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ break;
+ }
+
+ /* Get the volume name associated to the mount point */
+ Status = QueryVolumeName(Handle, &ReparsePointInformation, 0, &SymbolicName, &VolumeName);
+ if (!NT_SUCCESS(Status))
+ {
+ continue;
+ }
+
+ /* Browse the DB to find the name */
+ Offset = 0;
+ for (;;)
+ {
+ UNICODE_STRING DbName;
+
+ DatabaseEntry = GetRemoteDatabaseEntry(DatabaseHandle, Offset);
+ if (DatabaseEntry == NULL)
+ {
+ break;
+ }
+
+ DbName.MaximumLength = DatabaseEntry->SymbolicNameLength;
+ DbName.Length = DbName.MaximumLength;
+ DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
+ /* Found, we're done! */
+ if (RtlEqualUnicodeString(&DbName, &SymbolicName, TRUE))
+ {
+ break;
+ }
+
+ Offset += DatabaseEntry->EntrySize;
+ FreePool(DatabaseEntry);
+ }
+
+ /* If we found the mount point.... */
+ if (DatabaseEntry != NULL)
+ {
+ /* If it was referenced, reference it once more and update to remote */
+ if (DatabaseEntry->EntryReferences)
+ {
+ ++DatabaseEntry->EntryReferences;
+ Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
+ if (!NT_SUCCESS(Status))
+ {
+ goto FreeDBEntry;
+ }
+
+ FreePool(DatabaseEntry);
+ }
+ else
+ {
+ /* Query the Unique ID associated to that mount point in case it changed */
+ KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
+ Status = QueryUniqueIdFromMaster(DeviceExtension, &SymbolicName, &UniqueId);
+ if (!NT_SUCCESS(Status))
+ {
+ /* If we failed doing so, reuse the old Unique ID and push it to master */
+ Status = WriteUniqueIdToMaster(DeviceExtension, DatabaseEntry);
+ if (!NT_SUCCESS(Status))
+ {
+ goto ReleaseDeviceLock;
+ }
+
+ /* And then, reference & write the entry */
+ ++DatabaseEntry->EntryReferences;
+ Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
+ if (!NT_SUCCESS(Status))
+ {
+ goto ReleaseDeviceLock;
+ }
+
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+ FreePool(DatabaseEntry);
+ }
+ /* If the Unique ID didn't change */
+ else if (UniqueId->UniqueIdLength == DatabaseEntry->UniqueIdLength &&
+ RtlCompareMemory(UniqueId->UniqueId,
+ (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
+ UniqueId->UniqueIdLength) == UniqueId->UniqueIdLength)
+ {
+ /* Reference the entry, and update to remote */
+ ++DatabaseEntry->EntryReferences;
+ Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
+ if (!NT_SUCCESS(Status))
+ {
+ goto FreeUniqueId;
+ }
+
+ FreePool(UniqueId);
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+ FreePool(DatabaseEntry);
+ }
+ /* Would, by chance, the Unique ID be present elsewhere? */
+ else if (IsUniqueIdPresent(DeviceExtension, DatabaseEntry))
+ {
+ /* Push the ID to master */
+ Status = WriteUniqueIdToMaster(DeviceExtension, DatabaseEntry);
+ if (!NT_SUCCESS(Status))
+ {
+ goto FreeUniqueId;
+ }
+
+ /* And then, reference & write the entry */
+ ++DatabaseEntry->EntryReferences;
+ Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
+ if (!NT_SUCCESS(Status))
+ {
+ goto FreeUniqueId;
+ }
+
+ FreePool(UniqueId);
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+ FreePool(DatabaseEntry);
+ }
+ else
+ {
+ /* OK, at that point, we're facing a totally unknown unique ID
+ * So, get rid of the old entry, and recreate a new one with
+ * the know unique ID
+ */
+ Status = DeleteRemoteDatabaseEntry(DatabaseHandle, Offset);
+ if (!NT_SUCCESS(Status))
+ {
+ goto FreeUniqueId;
+ }
+
+ FreePool(DatabaseEntry);
+ /* Allocate a new entry big enough */
+ DatabaseEntry = AllocatePool(UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY));
+ if (DatabaseEntry == NULL)
+ {
+ goto FreeUniqueId;
+ }
+
+ /* Configure it */
+ DatabaseEntry->EntrySize = UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY);
+ DatabaseEntry->EntryReferences = 1;
+ DatabaseEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
+ DatabaseEntry->SymbolicNameLength = SymbolicName.Length;
+ DatabaseEntry->UniqueIdOffset = SymbolicName.Length + sizeof(DATABASE_ENTRY);
+ DatabaseEntry->UniqueIdLength = UniqueId->UniqueIdLength;
+ RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset), SymbolicName.Buffer, DatabaseEntry->SymbolicNameLength);
+ RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), UniqueId->UniqueId, UniqueId->UniqueIdLength);
+
+ /* And write it remotely */
+ Status = AddRemoteDatabaseEntry(DatabaseHandle, DatabaseEntry);
+ if (!NT_SUCCESS(Status))
+ {
+ FreePool(DatabaseEntry);
+ goto FreeUniqueId;
+ }
+
+ FreePool(UniqueId);
+ FreePool(DatabaseEntry);
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+ }
+ }
+ }
+ else
+ {
+ /* We failed finding it remotely
+ * So, let's allocate a new remote DB entry
+ */
+ KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
+ /* To be able to do so, we need the device Unique ID, ask master */
+ Status = QueryUniqueIdFromMaster(DeviceExtension, &SymbolicName, &UniqueId);
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+ if (NT_SUCCESS(Status))
+ {
+ /* Allocate a new entry big enough */
+ DatabaseEntry = AllocatePool(UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY));
+ if (DatabaseEntry != NULL)
+ {
+ /* Configure it */
+ DatabaseEntry->EntrySize = UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY);
+ DatabaseEntry->EntryReferences = 1;
+ DatabaseEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
+ DatabaseEntry->SymbolicNameLength = SymbolicName.Length;
+ DatabaseEntry->UniqueIdOffset = SymbolicName.Length + sizeof(DATABASE_ENTRY);
+ DatabaseEntry->UniqueIdLength = UniqueId->UniqueIdLength;
+ RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset), SymbolicName.Buffer, DatabaseEntry->SymbolicNameLength);
+ RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), UniqueId->UniqueId, UniqueId->UniqueIdLength);
+
+ /* And write it remotely */
+ Status = AddRemoteDatabaseEntry(DatabaseHandle, DatabaseEntry);
+ FreePool(DatabaseEntry);
+ FreePool(UniqueId);
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto FreeVolume;
+ }
+ }
+ else
+ {
+ FreePool(UniqueId);
+ }
+ }
+ }
+
+ /* Find info about the device associated associated with the mount point */
+ KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
+ Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &ListDeviceInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ FailedFinding = TRUE;
+ FreePool(VolumeName.Buffer);
+ }
+ else
+ {
+ /* Associate the device with the currrent DB */
+ AssociatedDevice = AllocatePool(sizeof(ASSOCIATED_DEVICE_ENTRY));
+ if (AssociatedDevice == NULL)
+ {
+ FreePool(VolumeName.Buffer);
+ }
+ else
+ {
+ AssociatedDevice->DeviceInformation = DeviceInformation;
+ AssociatedDevice->String.Length = VolumeName.Length;
+ AssociatedDevice->String.MaximumLength = VolumeName.MaximumLength;
+ AssociatedDevice->String.Buffer = VolumeName.Buffer;
+ InsertTailList(&ListDeviceInfo->AssociatedDevicesHead, &AssociatedDevice->AssociatedDevicesEntry);
+ }
+
+ /* If we don't have to skip notifications, notify */
+ if (!ListDeviceInfo->SkipNotifications)
+ {
+ PostOnlineNotification(DeviceExtension, &ListDeviceInfo->SymbolicName);
+ }
+ }
+
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+ }
+
+ /* We don't need mount points any longer */
+ ZwClose(Handle);
+
+ /* Look for the DB again */
+ KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
+ for (Entry = DeviceExtension->DeviceListHead.Flink;
+ Entry != &DeviceExtension->DeviceListHead;
+ Entry = Entry->Flink)
+ {
+ ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
+ if (ListDeviceInfo == DeviceInformation)
+ {
+ break;
+ }
+ }
+
+ if (Entry == &DeviceExtension->DeviceListHead)
+ {
+ ListDeviceInfo = NULL;
+ }
+
+ /* Start the pruning loop */
+ Offset = 0;
+ for (;;)
+ {
+ /* Get the entry */
+ DatabaseEntry = GetRemoteDatabaseEntry(DatabaseHandle, Offset);
+ if (DatabaseEntry == NULL)
+ {
+ break;
+ }
+
+ /* It's not referenced anylonger? Prune it */
+ if (DatabaseEntry->EntryReferences == 0)
+ {
+ Status = DeleteRemoteDatabaseEntry(DatabaseHandle, Offset);
+ if (!NT_SUCCESS(Status))
+ {
+ FreePool(DatabaseEntry);
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+ goto CloseRDB;
+ }
+ }
+ /* Update the Unique IDs to reflect the changes we might have done previously */
+ else
+ {
+ if (ListDeviceInfo != NULL)
+ {
+ UpdateReplicatedUniqueIds(ListDeviceInfo, DatabaseEntry);
+ }
+
+ Offset += DatabaseEntry->EntrySize;
+ }
- /* Wait for 7 minutes */
- Timeout.QuadPart = 0xFA0A1F00;
- Status = KeWaitForSingleObject(&(DeviceExtension->RemoteDatabaseLock), Executive, KernelMode, FALSE, &Timeout);
- if (Status != STATUS_TIMEOUT)
+ FreePool(DatabaseEntry);
+ }
+
+ /* We do have a DB now :-) */
+ if (ListDeviceInfo != NULL && !FailedFinding)
{
- return Status;
+ DeviceInformation->NoDatabase = FALSE;
}
- return STATUS_IO_TIMEOUT;
-}
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
-/*
- * @implemented
- */
-VOID
-ReleaseRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
-{
- KeReleaseSemaphore(&(DeviceExtension->RemoteDatabaseLock), IO_NO_INCREMENT, 1, FALSE);
-}
+ goto CloseRDB;
-VOID
-NTAPI
-ReconcileThisDatabaseWithMasterWorker(IN PVOID Parameter)
-{
- UNREFERENCED_PARAMETER(Parameter);
+FreeUniqueId:
+ FreePool(UniqueId);
+ReleaseDeviceLock:
+ KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+FreeDBEntry:
+ FreePool(DatabaseEntry);
+FreeVolume:
+ FreePool(VolumeName.Buffer);
+CloseReparse:
+ ZwClose(Handle);
+CloseRDB:
+ CloseRemoteDatabase(DatabaseHandle);
+ReleaseRDS:
+ ReleaseRemoteDatabaseSemaphore(DeviceExtension);
return;
}
NULL,
NULL);
KeInitializeEvent(&Event, NotificationEvent, FALSE);
- Timeout.LowPart = 0xFFFFFFFF;
- Timeout.HighPart = 0xFF676980;
+ Timeout.QuadPart = -10000000LL; /* Wait for 1 second */
- /* Try to wait as long as possible */
- for (i = (Unloading ? 999 : 0); i < 1000; i++)
+ /* Wait as long as possible for clearance from autochk
+ * We will write remote databases only if it is safe
+ * to access volumes.
+ * First, given we start before SMSS, wait for the
+ * event creation.
+ */
+ i = 0;
+ do
{
- Status = ZwOpenEvent(&SafeEvent, EVENT_ALL_ACCESS, &ObjectAttributes);
- if (NT_SUCCESS(Status))
+ /* If we started to shutdown, stop waiting forever and jump to last attempt */
+ if (Unloading)
{
- break;
+ i = 999;
+ }
+ else
+ {
+ /* Attempt to open the event */
+ Status = ZwOpenEvent(&SafeEvent, EVENT_ALL_ACCESS, &ObjectAttributes);
+ if (NT_SUCCESS(Status))
+ {
+ break;
+ }
+
+ /* Wait a bit to give SMSS a chance to create the event */
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &Timeout);
}
- KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &Timeout);
+ ++i;
}
+ while (i < 1000);
+ /* We managed to open the event, wait until autochk signals it */
if (i < 1000)
{
do
IoFreeWorkItem(WorkItem->WorkItem);
FreePool(WorkItem);
- if (InterlockedDecrement(&(DeviceExtension->WorkerReferences)) == 0)
+ if (InterlockedDecrement(&(DeviceExtension->WorkerReferences)) < 0)
{
return;
}
/* When called, lock is already acquired */
- /* If noone, start to work */
- if (InterlockedIncrement(&(DeviceExtension->WorkerReferences)))
+ /* If noone (-1 as references), start to work */
+ if (InterlockedIncrement(&(DeviceExtension->WorkerReferences)) == 0)
{
IoQueueWorkItem(WorkItem->WorkItem, WorkerThread, DelayedWorkQueue, DeviceExtension);
}
return STATUS_BUFFER_TOO_SMALL;
}
- /* Copy symoblic name */
+ /* Copy symbolic name */
SymbolicName->Length = ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength;
RtlCopyMemory(SymbolicName->Buffer,
(PWSTR)((ULONG_PTR)ReparseDataBuffer->MountPointReparseBuffer.PathBuffer +
*/
VOID
NTAPI
-MigrateRemoteDatabaseWorker(IN PDEVICE_OBJECT DeviceObject,
- IN PVOID Context)
+CreateRemoteDatabaseWorker(IN PDEVICE_OBJECT DeviceObject,
+ IN PVOID Context)
{
- ULONG Length;
NTSTATUS Status;
- PVOID TmpBuffer;
- CHAR Disposition;
- LARGE_INTEGER ByteOffset;
+ HANDLE Database = 0;
+ UNICODE_STRING DatabaseName;
PMIGRATE_WORK_ITEM WorkItem;
IO_STATUS_BLOCK IoStatusBlock;
- HANDLE Migrate = 0, Database = 0;
+ OBJECT_ATTRIBUTES ObjectAttributes;
PDEVICE_INFORMATION DeviceInformation;
- BOOLEAN PreviousMode, Complete = FALSE;
- UNICODE_STRING DatabaseName, DatabaseFile;
- OBJECT_ATTRIBUTES ObjectAttributes, MigrateAttributes;
-#define TEMP_BUFFER_SIZE 0x200
UNREFERENCED_PARAMETER(DeviceObject);
/* Reconstruct appropriate string */
DatabaseName.Length = DeviceInformation->DeviceName.Length + RemoteDatabase.Length;
DatabaseName.MaximumLength = DatabaseName.Length + sizeof(WCHAR);
-
- DatabaseFile.Length = DeviceInformation->DeviceName.Length + RemoteDatabaseFile.Length;
- DatabaseFile.MaximumLength = DatabaseFile.Length + sizeof(WCHAR);
-
DatabaseName.Buffer = AllocatePool(DatabaseName.MaximumLength);
- DatabaseFile.Buffer = AllocatePool(DatabaseFile.MaximumLength);
- /* Allocate buffer that will be used to swap contents */
- TmpBuffer = AllocatePool(TEMP_BUFFER_SIZE);
- if (!DatabaseName.Buffer || !DatabaseFile.Buffer || !TmpBuffer)
+ if (DatabaseName.Buffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
goto Cleanup;
}
- /* Finish initating strings */
+ /* Finish initiating strings */
RtlCopyMemory(DatabaseName.Buffer, DeviceInformation->DeviceName.Buffer, DeviceInformation->DeviceName.Length);
- RtlCopyMemory(DatabaseFile.Buffer, DeviceInformation->DeviceName.Buffer, DeviceInformation->DeviceName.Length);
RtlCopyMemory(DatabaseName.Buffer + (DeviceInformation->DeviceName.Length / sizeof(WCHAR)),
RemoteDatabase.Buffer, RemoteDatabase.Length);
- RtlCopyMemory(DatabaseFile.Buffer + (DeviceInformation->DeviceName.Length / sizeof(WCHAR)),
- RemoteDatabaseFile.Buffer, RemoteDatabaseFile.Length);
DatabaseName.Buffer[DatabaseName.Length / sizeof(WCHAR)] = UNICODE_NULL;
- DatabaseFile.Buffer[DatabaseFile.Length / sizeof(WCHAR)] = UNICODE_NULL;
/* Create database */
InitializeObjectAttributes(&ObjectAttributes,
NULL,
NULL);
- Status = ZwCreateFile(&Database,
+ Status = IoCreateFile(&Database,
SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES |
- FILE_READ_ATTRIBUTES | FILE_WRITE_PROPERTIES | FILE_READ_PROPERTIES |
+ FILE_READ_ATTRIBUTES | FILE_WRITE_EA | FILE_READ_EA |
FILE_APPEND_DATA | FILE_WRITE_DATA | FILE_READ_DATA,
&ObjectAttributes,
&IoStatusBlock,
FILE_CREATE,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT,
NULL,
- 0);
- if (!NT_SUCCESS(Status))
- {
- Database = 0;
- goto Cleanup;
- }
-
- InitializeObjectAttributes(&MigrateAttributes,
- &DatabaseFile,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- NULL,
- NULL);
-
- /* Disable hard errors and open the database that will be copied */
- PreviousMode = IoSetThreadHardErrorMode(FALSE);
- Status = ZwCreateFile(&Migrate,
- SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES |
- FILE_READ_ATTRIBUTES | FILE_WRITE_PROPERTIES | FILE_READ_PROPERTIES |
- FILE_APPEND_DATA | FILE_WRITE_DATA | FILE_READ_DATA,
- &MigrateAttributes,
- &IoStatusBlock,
- NULL,
- FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
0,
- FILE_OPEN,
- FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT,
+ CreateFileTypeNone,
NULL,
- 0);
- IoSetThreadHardErrorMode(PreviousMode);
+ IO_STOP_ON_SYMLINK | IO_NO_PARAMETER_CHECKING);
if (!NT_SUCCESS(Status))
{
- Migrate = 0;
- }
- if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
- {
- Status = STATUS_SUCCESS;
- Complete = TRUE;
- }
- if (!NT_SUCCESS(Status) || Complete)
- {
- goto Cleanup;
- }
-
- ByteOffset.QuadPart = 0LL;
- PreviousMode = IoSetThreadHardErrorMode(FALSE);
- /* Now, loop as long it's possible */
- while (Status == STATUS_SUCCESS)
- {
- /* Read data from existing database */
- Status = ZwReadFile(Migrate,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- TmpBuffer,
- TEMP_BUFFER_SIZE,
- &ByteOffset,
- NULL);
- if (!NT_SUCCESS(Status))
+ if (Status == STATUS_STOPPED_ON_SYMLINK)
{
- break;
+ DPRINT1("Attempt to exploit CVE-2015-1769. See CORE-10216\n");
}
- /* And write them into new database */
- Length = (ULONG)IoStatusBlock.Information;
- Status = ZwWriteFile(Database,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- TmpBuffer,
- Length,
- &ByteOffset,
- NULL);
- ByteOffset.QuadPart += Length;
- }
- IoSetThreadHardErrorMode(PreviousMode);
-
- /* Delete old databse if it was well copied */
- if (Status == STATUS_END_OF_FILE)
- {
- Disposition = 1;
- Status = ZwSetInformationFile(Migrate,
- &IoStatusBlock,
- &Disposition,
- sizeof(Disposition),
- FileDispositionInformation);
+ Database = 0;
+ goto Cleanup;
}
- /* Migration is over */
-
Cleanup:
- if (TmpBuffer)
- {
- FreePool(TmpBuffer);
- }
-
- if (DatabaseFile.Buffer)
- {
- FreePool(DatabaseFile.Buffer);
- }
-
if (DatabaseName.Buffer)
{
FreePool(DatabaseName.Buffer);
}
- if (Migrate)
- {
- ZwClose(Migrate);
- }
-
if (NT_SUCCESS(Status))
{
DeviceInformation->Migrated = 1;
}
- else if (Database)
+ else if (Database != 0)
{
ZwClose(Database);
}
WorkItem->Database = Database;
KeSetEvent(WorkItem->Event, 0, FALSE);
-#undef TEMP_BUFFER_SIZE
}
/*
* @implemented
*/
NTSTATUS
-MigrateRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation,
- IN OUT PHANDLE Database)
+CreateRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation,
+ IN OUT PHANDLE Database)
{
KEVENT Event;
NTSTATUS Status;
/* And queue it */
IoQueueWorkItem(WorkItem->WorkItem,
- MigrateRemoteDatabaseWorker,
+ CreateRemoteDatabaseWorker,
DelayedWorkQueue,
WorkItem);
/* Disable hard errors */
PreviousMode = IoSetThreadHardErrorMode(FALSE);
- Status = ZwCreateFile(&Database,
+ Status = IoCreateFile(&Database,
SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES |
- FILE_READ_ATTRIBUTES | FILE_WRITE_PROPERTIES | FILE_READ_PROPERTIES |
+ FILE_READ_ATTRIBUTES | FILE_WRITE_EA | FILE_READ_EA |
FILE_APPEND_DATA | FILE_WRITE_DATA | FILE_READ_DATA,
&ObjectAttributes,
&IoStatusBlock,
(!MigrateDatabase || DeviceInformation->Migrated == 0) ? FILE_OPEN_IF : FILE_OPEN,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT,
NULL,
- 0);
+ 0,
+ CreateFileTypeNone,
+ NULL,
+ IO_STOP_ON_SYMLINK | IO_NO_PARAMETER_CHECKING);
+ if (Status == STATUS_STOPPED_ON_SYMLINK)
+ {
+ DPRINT1("Attempt to exploit CVE-2015-1769. See CORE-10216\n");
+ }
/* If base it to be migrated and was opened successfully, go ahead */
if (MigrateDatabase && NT_SUCCESS(Status))
{
- MigrateRemoteDatabase(DeviceInformation, &Database);
+ CreateRemoteDatabase(DeviceInformation, &Database);
}
IoSetThreadHardErrorMode(PreviousMode);
return Database;
}
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-QueryUniqueIdQueryRoutine(IN PWSTR ValueName,
- IN ULONG ValueType,
- IN PVOID ValueData,
- IN ULONG ValueLength,
- IN PVOID Context,
- IN PVOID EntryContext)
-{
- PMOUNTDEV_UNIQUE_ID IntUniqueId;
- PMOUNTDEV_UNIQUE_ID * UniqueId;
-
- UNREFERENCED_PARAMETER(ValueName);
- UNREFERENCED_PARAMETER(ValueType);
- UNREFERENCED_PARAMETER(EntryContext);
-
- /* Sanity check */
- if (ValueLength >= 0x10000)
- {
- return STATUS_SUCCESS;
- }
-
- /* Allocate the Unique ID */
- IntUniqueId = AllocatePool(sizeof(UniqueId) + ValueLength);
- if (IntUniqueId)
- {
- /* Copy data & return */
- IntUniqueId->UniqueIdLength = (USHORT)ValueLength;
- RtlCopyMemory(&(IntUniqueId->UniqueId), ValueData, ValueLength);
-
- UniqueId = Context;
- *UniqueId = IntUniqueId;
- }
-
- return STATUS_SUCCESS;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-QueryUniqueIdFromMaster(IN PDEVICE_EXTENSION DeviceExtension,
- IN PUNICODE_STRING SymbolicName,
- OUT PMOUNTDEV_UNIQUE_ID * UniqueId)
-{
- NTSTATUS Status;
- PDEVICE_INFORMATION DeviceInformation;
- RTL_QUERY_REGISTRY_TABLE QueryTable[2];
-
- /* Query the unique ID */
- RtlZeroMemory(QueryTable, sizeof(QueryTable));
- QueryTable[0].QueryRoutine = QueryUniqueIdQueryRoutine;
- QueryTable[0].Name = SymbolicName->Buffer;
-
- *UniqueId = NULL;
- RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
- DatabasePath,
- QueryTable,
- UniqueId,
- NULL);
- /* Unique ID found, no need to go farther */
- if (*UniqueId)
- {
- return STATUS_SUCCESS;
- }
-
- /* Otherwise, find associate device information */
- Status = FindDeviceInfo(DeviceExtension, SymbolicName, FALSE, &DeviceInformation);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
-
- *UniqueId = AllocatePool(DeviceInformation->UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
- if (!*UniqueId)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- /* Return this unique ID (better than nothing) */
- (*UniqueId)->UniqueIdLength = DeviceInformation->UniqueId->UniqueIdLength;
- RtlCopyMemory(&((*UniqueId)->UniqueId), &(DeviceInformation->UniqueId->UniqueId), (*UniqueId)->UniqueIdLength);
-
- return STATUS_SUCCESS;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-WriteUniqueIdToMaster(IN PDEVICE_EXTENSION DeviceExtension,
- IN PDATABASE_ENTRY DatabaseEntry)
-{
- NTSTATUS Status;
- PWCHAR SymbolicName;
- PLIST_ENTRY NextEntry;
- UNICODE_STRING SymbolicString;
- PDEVICE_INFORMATION DeviceInformation;
-
- /* Create symbolic name from database entry */
- SymbolicName = AllocatePool(DatabaseEntry->SymbolicNameLength + sizeof(WCHAR));
- if (!SymbolicName)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- RtlCopyMemory(SymbolicName,
- (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset),
- DatabaseEntry->SymbolicNameLength);
- SymbolicName[DatabaseEntry->SymbolicNameLength / sizeof(WCHAR)] = UNICODE_NULL;
-
- /* Associate the unique ID with the name from remote database */
- Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
- DatabasePath,
- SymbolicName,
- REG_BINARY,
- (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
- DatabaseEntry->UniqueIdLength);
- FreePool(SymbolicName);
-
- /* Reget symbolic name */
- SymbolicString.Length = DatabaseEntry->SymbolicNameLength;
- SymbolicString.MaximumLength = DatabaseEntry->SymbolicNameLength;
- SymbolicString.Buffer = (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
-
- /* Find the device using this unique ID */
- for (NextEntry = DeviceExtension->DeviceListHead.Flink;
- NextEntry != &(DeviceExtension->DeviceListHead);
- NextEntry = NextEntry->Flink)
- {
- DeviceInformation = CONTAINING_RECORD(NextEntry,
- DEVICE_INFORMATION,
- DeviceListEntry);
-
- if (DeviceInformation->UniqueId->UniqueIdLength != DatabaseEntry->UniqueIdLength)
- {
- continue;
- }
-
- if (RtlCompareMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
- DeviceInformation->UniqueId->UniqueId,
- DatabaseEntry->UniqueIdLength) == DatabaseEntry->UniqueIdLength)
- {
- break;
- }
- }
-
- /* If found, create a mount point */
- if (NextEntry != &(DeviceExtension->DeviceListHead))
- {
- MountMgrCreatePointWorker(DeviceExtension, &SymbolicString, &(DeviceInformation->DeviceName));
- }
-
- return Status;
-}
-
/*
* @implemented
*/
/* Recreate the entry from the previous one */
NewEntry->EntrySize = Entry->EntrySize + NewUniqueId->UniqueIdLength - OldUniqueId->UniqueIdLength;
- NewEntry->DatabaseOffset = Entry->DatabaseOffset;
+ NewEntry->EntryReferences = Entry->EntryReferences;
NewEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
NewEntry->SymbolicNameLength = Entry->SymbolicNameLength;
NewEntry->UniqueIdOffset = Entry->SymbolicNameLength + sizeof(DATABASE_ENTRY);