[KERNEL32] Misc. fixes to DefineDosDeviceW

- Add support for LUIDDeviceMapsEnabled;
- Broadcast proper message in case of device removal;
- Use less memory for strings management;
- Make code a bit cleaner.
This commit is contained in:
Pierre Schweitzer 2019-05-05 18:31:43 +02:00
parent d3fa3b0ca2
commit 204bfa8574
No known key found for this signature in database
GPG key ID: 7545556C3D585B0B

View file

@ -244,38 +244,52 @@ DefineDosDeviceW(
PCSR_CAPTURE_BUFFER CaptureBuffer; PCSR_CAPTURE_BUFFER CaptureBuffer;
UNICODE_STRING NtTargetPathU; UNICODE_STRING NtTargetPathU;
UNICODE_STRING DeviceNameU; UNICODE_STRING DeviceNameU;
UNICODE_STRING DeviceUpcaseNameU;
HANDLE hUser32; HANDLE hUser32;
DEV_BROADCAST_VOLUME dbcv; DEV_BROADCAST_VOLUME dbcv;
BOOL Result = TRUE;
DWORD dwRecipients; DWORD dwRecipients;
typedef long (WINAPI *BSM_type)(DWORD, LPDWORD, UINT, WPARAM, LPARAM); typedef long (WINAPI *BSM_type)(DWORD, LPDWORD, UINT, WPARAM, LPARAM);
BSM_type BSM_ptr; BSM_type BSM_ptr;
BOOLEAN LUIDDeviceMapsEnabled;
WCHAR Letter;
WPARAM wParam;
if ( (dwFlags & 0xFFFFFFF0) || /* Get status about local device mapping */
LUIDDeviceMapsEnabled = BaseStaticServerData->LUIDDeviceMapsEnabled;
/* Validate input & flags */
if ((dwFlags & 0xFFFFFFE0) ||
((dwFlags & DDD_EXACT_MATCH_ON_REMOVE) && ((dwFlags & DDD_EXACT_MATCH_ON_REMOVE) &&
! (dwFlags & DDD_REMOVE_DEFINITION)) ) !(dwFlags & DDD_REMOVE_DEFINITION)) ||
(lpTargetPath == NULL && !(dwFlags & (DDD_LUID_BROADCAST_DRIVE | DDD_REMOVE_DEFINITION))) ||
((dwFlags & DDD_LUID_BROADCAST_DRIVE) &&
(lpDeviceName == NULL || lpTargetPath != NULL || dwFlags & (DDD_NO_BROADCAST_SYSTEM | DDD_EXACT_MATCH_ON_REMOVE | DDD_RAW_TARGET_PATH) || !LUIDDeviceMapsEnabled)))
{ {
SetLastError(ERROR_INVALID_PARAMETER); SetLastError(ERROR_INVALID_PARAMETER);
return FALSE; return FALSE;
} }
/* Initialize device unicode string to ease its use */
RtlInitUnicodeString(&DeviceNameU, lpDeviceName);
/* The buffer for CSR call will contain it */
BufferSize = DeviceNameU.MaximumLength;
ArgumentCount = 1; ArgumentCount = 1;
BufferSize = 0;
if (!lpTargetPath) /* If we don't have target path, use empty string */
if (lpTargetPath == NULL)
{ {
RtlInitUnicodeString(&NtTargetPathU, RtlInitUnicodeString(&NtTargetPathU, NULL);
NULL);
} }
else else
{ {
/* Else, use it raw if asked to */
if (dwFlags & DDD_RAW_TARGET_PATH) if (dwFlags & DDD_RAW_TARGET_PATH)
{ {
RtlInitUnicodeString(&NtTargetPathU, RtlInitUnicodeString(&NtTargetPathU, lpTargetPath);
lpTargetPath);
} }
else else
{ {
/* Otherwise, use it converted */
if (!RtlDosPathNameToNtPathName_U(lpTargetPath, if (!RtlDosPathNameToNtPathName_U(lpTargetPath,
&NtTargetPathU, &NtTargetPathU,
NULL, NULL,
@ -286,104 +300,119 @@ DefineDosDeviceW(
return FALSE; return FALSE;
} }
} }
/* This target path will be the second arg */
ArgumentCount = 2; ArgumentCount = 2;
BufferSize += NtTargetPathU.Length; BufferSize += NtTargetPathU.MaximumLength;
} }
RtlInitUnicodeString(&DeviceNameU, /* Allocate the capture buffer for our strings */
lpDeviceName);
RtlUpcaseUnicodeString(&DeviceUpcaseNameU,
&DeviceNameU,
TRUE);
BufferSize += DeviceUpcaseNameU.Length;
CaptureBuffer = CsrAllocateCaptureBuffer(ArgumentCount, CaptureBuffer = CsrAllocateCaptureBuffer(ArgumentCount,
BufferSize); BufferSize);
if (!CaptureBuffer) if (CaptureBuffer == NULL)
{ {
if (!(dwFlags & DDD_RAW_TARGET_PATH))
{
RtlFreeUnicodeString(&NtTargetPathU);
}
SetLastError(ERROR_NOT_ENOUGH_MEMORY); SetLastError(ERROR_NOT_ENOUGH_MEMORY);
Result = FALSE; return FALSE;
} }
/* Set the flags */
DefineDosDeviceRequest->Flags = dwFlags;
/* Allocate a buffer for the device name */
DefineDosDeviceRequest->DeviceName.MaximumLength = CsrAllocateMessagePointer(CaptureBuffer,
DeviceNameU.MaximumLength,
(PVOID*)&DefineDosDeviceRequest->DeviceName.Buffer);
/* And copy it while upcasing it */
RtlUpcaseUnicodeString(&DefineDosDeviceRequest->DeviceName, &DeviceNameU, FALSE);
/* If we have a target path, copy it too, and free it if allocated */
if (NtTargetPathU.Length != 0)
{
DefineDosDeviceRequest->TargetPath.MaximumLength = CsrAllocateMessagePointer(CaptureBuffer,
NtTargetPathU.MaximumLength,
(PVOID*)&DefineDosDeviceRequest->TargetPath.Buffer);
RtlCopyUnicodeString(&DefineDosDeviceRequest->TargetPath, &NtTargetPathU);
if (!(dwFlags & DDD_RAW_TARGET_PATH))
{
RtlFreeUnicodeString(&NtTargetPathU);
}
}
/* Otherwise, null initialize the string */
else else
{ {
DefineDosDeviceRequest->Flags = dwFlags; RtlInitUnicodeString(&DefineDosDeviceRequest->TargetPath, NULL);
}
CsrCaptureMessageBuffer(CaptureBuffer, /* Finally, call the server */
DeviceUpcaseNameU.Buffer, CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
DeviceUpcaseNameU.Length, CaptureBuffer,
(PVOID*)&DefineDosDeviceRequest->DeviceName.Buffer); CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepDefineDosDevice),
sizeof(*DefineDosDeviceRequest));
CsrFreeCaptureBuffer(CaptureBuffer);
DefineDosDeviceRequest->DeviceName.Length = /* Return failure if any */
DeviceUpcaseNameU.Length; if (!NT_SUCCESS(ApiMessage.Status))
DefineDosDeviceRequest->DeviceName.MaximumLength = {
DeviceUpcaseNameU.Length; WARN("CsrClientCallServer() failed (Status %lx)\n", ApiMessage.Status);
BaseSetLastNTError(ApiMessage.Status);
return FALSE;
}
if (NtTargetPathU.Buffer) /* Here is the success path, we will always return true */
/* Should broadcast the event? Only do if not denied and if drive letter */
if (!(dwFlags & DDD_NO_BROADCAST_SYSTEM) &&
DeviceNameU.Length == 2 * sizeof(WCHAR) &&
DeviceNameU.Buffer[1] == L':')
{
/* Make sure letter is valid and there are no local device mappings */
Letter = RtlUpcaseUnicodeChar(DeviceNameU.Buffer[0]) - L'A';
if (Letter < 26 && !LUIDDeviceMapsEnabled)
{ {
CsrCaptureMessageBuffer(CaptureBuffer, /* Rely on user32 for broadcasting */
NtTargetPathU.Buffer, hUser32 = LoadLibraryW(L"user32.dll");
NtTargetPathU.Length, if (hUser32 != 0)
(PVOID*)&DefineDosDeviceRequest->TargetPath.Buffer);
}
DefineDosDeviceRequest->TargetPath.Length =
NtTargetPathU.Length;
DefineDosDeviceRequest->TargetPath.MaximumLength =
NtTargetPathU.Length;
CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
CaptureBuffer,
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepDefineDosDevice),
sizeof(*DefineDosDeviceRequest));
CsrFreeCaptureBuffer(CaptureBuffer);
if (!NT_SUCCESS(ApiMessage.Status))
{
WARN("CsrClientCallServer() failed (Status %lx)\n", ApiMessage.Status);
BaseSetLastNTError(ApiMessage.Status);
Result = FALSE;
}
else
{
if (! (dwFlags & DDD_NO_BROADCAST_SYSTEM) &&
DeviceUpcaseNameU.Length == 2 * sizeof(WCHAR) &&
DeviceUpcaseNameU.Buffer[1] == L':' &&
( (DeviceUpcaseNameU.Buffer[0] - L'A') < 26 ))
{ {
hUser32 = LoadLibraryA("user32.dll"); /* Get the function pointer */
if (hUser32) BSM_ptr = (BSM_type)GetProcAddress(hUser32, "BroadcastSystemMessageW");
if (BSM_ptr)
{ {
BSM_ptr = (BSM_type) /* Set our target */
GetProcAddress(hUser32, "BroadcastSystemMessageW"); dwRecipients = BSM_APPLICATIONS;
if (BSM_ptr)
{ /* And initialize our structure */
dwRecipients = BSM_APPLICATIONS; dbcv.dbcv_size = sizeof(DEV_BROADCAST_VOLUME);
dbcv.dbcv_size = sizeof(DEV_BROADCAST_VOLUME); dbcv.dbcv_devicetype = DBT_DEVTYP_VOLUME;
dbcv.dbcv_devicetype = DBT_DEVTYP_VOLUME; dbcv.dbcv_reserved = 0;
dbcv.dbcv_reserved = 0;
dbcv.dbcv_unitmask |= /* Set the volume which had the event */
(1 << (DeviceUpcaseNameU.Buffer[0] - L'A')); dbcv.dbcv_unitmask = 1 << Letter;
dbcv.dbcv_flags = DBTF_NET; dbcv.dbcv_flags = DBTF_NET;
(void) BSM_ptr(BSF_SENDNOTIFYMESSAGE | BSF_FLUSHDISK,
&dwRecipients, /* And properly set the event (removal or arrival?) */
WM_DEVICECHANGE, wParam = (dwFlags & DDD_REMOVE_DEFINITION) ? DBT_DEVICEREMOVECOMPLETE : DBT_DEVICEARRIVAL;
(WPARAM)DBT_DEVICEARRIVAL,
(LPARAM)&dbcv); /* And broadcast! */
} BSM_ptr(BSF_SENDNOTIFYMESSAGE | BSF_FLUSHDISK,
FreeLibrary(hUser32); &dwRecipients,
WM_DEVICECHANGE,
wParam,
(LPARAM)&dbcv);
} }
/* We're done! */
FreeLibrary(hUser32);
} }
} }
} }
if (NtTargetPathU.Buffer && return TRUE;
NtTargetPathU.Buffer != lpTargetPath)
{
RtlFreeHeap(RtlGetProcessHeap(),
0,
NtTargetPathU.Buffer);
}
RtlFreeUnicodeString(&DeviceUpcaseNameU);
return Result;
} }