[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)
{ {
SetLastError(ERROR_NOT_ENOUGH_MEMORY); if (!(dwFlags & DDD_RAW_TARGET_PATH))
Result = FALSE; {
RtlFreeUnicodeString(&NtTargetPathU);
} }
else
{ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
/* Set the flags */
DefineDosDeviceRequest->Flags = dwFlags; DefineDosDeviceRequest->Flags = dwFlags;
CsrCaptureMessageBuffer(CaptureBuffer, /* Allocate a buffer for the device name */
DeviceUpcaseNameU.Buffer, DefineDosDeviceRequest->DeviceName.MaximumLength = CsrAllocateMessagePointer(CaptureBuffer,
DeviceUpcaseNameU.Length, DeviceNameU.MaximumLength,
(PVOID*)&DefineDosDeviceRequest->DeviceName.Buffer); (PVOID*)&DefineDosDeviceRequest->DeviceName.Buffer);
/* And copy it while upcasing it */
RtlUpcaseUnicodeString(&DefineDosDeviceRequest->DeviceName, &DeviceNameU, FALSE);
DefineDosDeviceRequest->DeviceName.Length = /* If we have a target path, copy it too, and free it if allocated */
DeviceUpcaseNameU.Length; if (NtTargetPathU.Length != 0)
DefineDosDeviceRequest->DeviceName.MaximumLength =
DeviceUpcaseNameU.Length;
if (NtTargetPathU.Buffer)
{ {
CsrCaptureMessageBuffer(CaptureBuffer, DefineDosDeviceRequest->TargetPath.MaximumLength = CsrAllocateMessagePointer(CaptureBuffer,
NtTargetPathU.Buffer, NtTargetPathU.MaximumLength,
NtTargetPathU.Length,
(PVOID*)&DefineDosDeviceRequest->TargetPath.Buffer); (PVOID*)&DefineDosDeviceRequest->TargetPath.Buffer);
} RtlCopyUnicodeString(&DefineDosDeviceRequest->TargetPath, &NtTargetPathU);
DefineDosDeviceRequest->TargetPath.Length =
NtTargetPathU.Length;
DefineDosDeviceRequest->TargetPath.MaximumLength =
NtTargetPathU.Length;
if (!(dwFlags & DDD_RAW_TARGET_PATH))
{
RtlFreeUnicodeString(&NtTargetPathU);
}
}
/* Otherwise, null initialize the string */
else
{
RtlInitUnicodeString(&DefineDosDeviceRequest->TargetPath, NULL);
}
/* Finally, call the server */
CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
CaptureBuffer, CaptureBuffer,
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepDefineDosDevice), CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepDefineDosDevice),
sizeof(*DefineDosDeviceRequest)); sizeof(*DefineDosDeviceRequest));
CsrFreeCaptureBuffer(CaptureBuffer); CsrFreeCaptureBuffer(CaptureBuffer);
/* Return failure if any */
if (!NT_SUCCESS(ApiMessage.Status)) if (!NT_SUCCESS(ApiMessage.Status))
{ {
WARN("CsrClientCallServer() failed (Status %lx)\n", ApiMessage.Status); WARN("CsrClientCallServer() failed (Status %lx)\n", ApiMessage.Status);
BaseSetLastNTError(ApiMessage.Status); BaseSetLastNTError(ApiMessage.Status);
Result = FALSE; return FALSE;
} }
else
/* 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':')
{ {
if (! (dwFlags & DDD_NO_BROADCAST_SYSTEM) && /* Make sure letter is valid and there are no local device mappings */
DeviceUpcaseNameU.Length == 2 * sizeof(WCHAR) && Letter = RtlUpcaseUnicodeChar(DeviceNameU.Buffer[0]) - L'A';
DeviceUpcaseNameU.Buffer[1] == L':' && if (Letter < 26 && !LUIDDeviceMapsEnabled)
( (DeviceUpcaseNameU.Buffer[0] - L'A') < 26 ))
{ {
hUser32 = LoadLibraryA("user32.dll"); /* Rely on user32 for broadcasting */
if (hUser32) hUser32 = LoadLibraryW(L"user32.dll");
if (hUser32 != 0)
{ {
BSM_ptr = (BSM_type) /* Get the function pointer */
GetProcAddress(hUser32, "BroadcastSystemMessageW"); BSM_ptr = (BSM_type)GetProcAddress(hUser32, "BroadcastSystemMessageW");
if (BSM_ptr) if (BSM_ptr)
{ {
/* Set our target */
dwRecipients = BSM_APPLICATIONS; dwRecipients = BSM_APPLICATIONS;
/* And initialize our structure */
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 |=
(1 << (DeviceUpcaseNameU.Buffer[0] - L'A')); /* Set the volume which had the event */
dbcv.dbcv_unitmask = 1 << Letter;
dbcv.dbcv_flags = DBTF_NET; dbcv.dbcv_flags = DBTF_NET;
(void) BSM_ptr(BSF_SENDNOTIFYMESSAGE | BSF_FLUSHDISK,
/* And properly set the event (removal or arrival?) */
wParam = (dwFlags & DDD_REMOVE_DEFINITION) ? DBT_DEVICEREMOVECOMPLETE : DBT_DEVICEARRIVAL;
/* And broadcast! */
BSM_ptr(BSF_SENDNOTIFYMESSAGE | BSF_FLUSHDISK,
&dwRecipients, &dwRecipients,
WM_DEVICECHANGE, WM_DEVICECHANGE,
(WPARAM)DBT_DEVICEARRIVAL, wParam,
(LPARAM)&dbcv); (LPARAM)&dbcv);
} }
/* We're done! */
FreeLibrary(hUser32); FreeLibrary(hUser32);
} }
} }
} }
}
if (NtTargetPathU.Buffer && return TRUE;
NtTargetPathU.Buffer != lpTargetPath)
{
RtlFreeHeap(RtlGetProcessHeap(),
0,
NtTargetPathU.Buffer);
}
RtlFreeUnicodeString(&DeviceUpcaseNameU);
return Result;
} }