mirror of
https://github.com/reactos/reactos.git
synced 2025-05-06 18:31:26 +00:00
[BASESRV] Implement LUID mapped drive arrival/removal notification
CORE-16114
This commit is contained in:
parent
522821bb8b
commit
222ace7c6c
3 changed files with 367 additions and 7 deletions
|
@ -16,6 +16,7 @@
|
||||||
#define COM_NO_WINDOWS_H
|
#define COM_NO_WINDOWS_H
|
||||||
#include <windef.h>
|
#include <windef.h>
|
||||||
#include <winbase.h>
|
#include <winbase.h>
|
||||||
|
#include <dbt.h>
|
||||||
#define NTOS_MODE_USER
|
#define NTOS_MODE_USER
|
||||||
#include <ndk/rtlfuncs.h>
|
#include <ndk/rtlfuncs.h>
|
||||||
#include <ndk/obfuncs.h>
|
#include <ndk/obfuncs.h>
|
||||||
|
@ -67,6 +68,7 @@ extern HANDLE BaseSrvSharedHeap;
|
||||||
extern PBASE_STATIC_SERVER_DATA BaseStaticServerData;
|
extern PBASE_STATIC_SERVER_DATA BaseStaticServerData;
|
||||||
extern ULONG SessionId;
|
extern ULONG SessionId;
|
||||||
extern ULONG ProtectionMode;
|
extern ULONG ProtectionMode;
|
||||||
|
extern RTL_CRITICAL_SECTION BaseSrvDDDBSMCritSec;
|
||||||
|
|
||||||
#define SM_REG_KEY \
|
#define SM_REG_KEY \
|
||||||
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager"
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager"
|
||||||
|
|
|
@ -13,9 +13,21 @@
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
|
typedef struct _BSM_REQUEST
|
||||||
|
{
|
||||||
|
struct _BSM_REQUEST * Next;
|
||||||
|
LUID BroadcastLuid;
|
||||||
|
LONG DriveLetter;
|
||||||
|
LONG RemoveDefinition;
|
||||||
|
} BSM_REQUEST, *PBSM_REQUEST;
|
||||||
|
|
||||||
/* GLOBALS ********************************************************************/
|
/* GLOBALS ********************************************************************/
|
||||||
|
|
||||||
static RTL_CRITICAL_SECTION BaseDefineDosDeviceCritSec;
|
static RTL_CRITICAL_SECTION BaseDefineDosDeviceCritSec;
|
||||||
|
RTL_CRITICAL_SECTION BaseSrvDDDBSMCritSec;
|
||||||
|
PBSM_REQUEST BSM_Request_Queue = NULL, BSM_Request_Queue_End = NULL;
|
||||||
|
ULONG BaseSrvpBSMThreadCount = 0;
|
||||||
|
LONG (WINAPI *PBROADCASTSYSTEMMESSAGEEXW)(DWORD, LPDWORD, UINT, WPARAM, LPARAM, PBSMINFO) = NULL;
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS **********************************************************/
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
|
@ -146,6 +158,317 @@ IsGlobalSymbolicLink(HANDLE LinkHandle,
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
CheckForGlobalDriveLetter(SHORT DriveLetter)
|
||||||
|
{
|
||||||
|
WCHAR Path[8];
|
||||||
|
NTSTATUS Status;
|
||||||
|
BOOLEAN IsGlobal;
|
||||||
|
UNICODE_STRING PathU;
|
||||||
|
HANDLE SymbolicLinkHandle;
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
|
||||||
|
/* Setup our drive path */
|
||||||
|
wcsncpy(Path, L"\\??\\X:", (sizeof(L"\\??\\X:") / sizeof(WCHAR)));
|
||||||
|
Path[4] = DriveLetter + L'A';
|
||||||
|
Path[6] = UNICODE_NULL;
|
||||||
|
|
||||||
|
/* Prepare everything to open the link */
|
||||||
|
RtlInitUnicodeString(&PathU, Path);
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
&PathU,
|
||||||
|
OBJ_CASE_INSENSITIVE,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Impersonate the caller */
|
||||||
|
if (!CsrImpersonateClient(NULL))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open our drive letter */
|
||||||
|
Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle,
|
||||||
|
SYMBOLIC_LINK_QUERY,
|
||||||
|
&ObjectAttributes);
|
||||||
|
|
||||||
|
CsrRevertToSelf();
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check whether it's global */
|
||||||
|
Status = IsGlobalSymbolicLink(SymbolicLinkHandle, &IsGlobal);
|
||||||
|
NtClose(SymbolicLinkHandle);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IsGlobal;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
SendWinStationBSM(DWORD Flags,
|
||||||
|
LPDWORD Recipients,
|
||||||
|
UINT Message,
|
||||||
|
WPARAM wParam,
|
||||||
|
LPARAM lParam)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
BroadcastDriveLetterChange(LONG DriveLetter,
|
||||||
|
BOOLEAN RemoveDefinition,
|
||||||
|
PLUID BroadcastLuid)
|
||||||
|
{
|
||||||
|
HANDLE hUser32;
|
||||||
|
NTSTATUS Status;
|
||||||
|
UNICODE_STRING User32U;
|
||||||
|
ANSI_STRING ProcedureName;
|
||||||
|
DWORD Recipients, Flags, wParam;
|
||||||
|
LUID SystemLuid = SYSTEM_LUID;
|
||||||
|
BSMINFO Info;
|
||||||
|
DEV_BROADCAST_VOLUME Volume;
|
||||||
|
|
||||||
|
/* We need a broadcast LUID */
|
||||||
|
if (BroadcastLuid == NULL)
|
||||||
|
{
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the Csr procedure, and keep it forever */
|
||||||
|
if (PBROADCASTSYSTEMMESSAGEEXW == NULL)
|
||||||
|
{
|
||||||
|
hUser32 = NULL;
|
||||||
|
RtlInitUnicodeString(&User32U, L"user32");
|
||||||
|
Status = LdrGetDllHandle(NULL, NULL, &User32U, &hUser32);
|
||||||
|
if (hUser32 != NULL && NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
RtlInitString(&ProcedureName, "CsrBroadcastSystemMessageExW");
|
||||||
|
Status = LdrGetProcedureAddress(hUser32,
|
||||||
|
&ProcedureName,
|
||||||
|
0,
|
||||||
|
(PVOID *)&PBROADCASTSYSTEMMESSAGEEXW);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
PBROADCASTSYSTEMMESSAGEEXW = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we failed to get broadcast procedure, no more actions left */
|
||||||
|
if (PBROADCASTSYSTEMMESSAGEEXW == NULL)
|
||||||
|
{
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize broadcast info */
|
||||||
|
Info.cbSize = sizeof(BSMINFO);
|
||||||
|
Info.hdesk = 0;
|
||||||
|
Info.hwnd = 0;
|
||||||
|
RtlCopyLuid(&Info.luid, BroadcastLuid);
|
||||||
|
|
||||||
|
/* Initialize volume information */
|
||||||
|
Volume.dbcv_size = sizeof(DEV_BROADCAST_VOLUME);
|
||||||
|
Volume.dbcv_devicetype = DBT_DEVTYP_VOLUME;
|
||||||
|
Volume.dbcv_reserved = 0;
|
||||||
|
Volume.dbcv_unitmask = 1 << DriveLetter;
|
||||||
|
Volume.dbcv_flags = DBTF_NET;
|
||||||
|
|
||||||
|
/* Wide broadcast */
|
||||||
|
Recipients = BSM_APPLICATIONS | BSM_ALLDESKTOPS;
|
||||||
|
Flags = BSF_NOHANG | BSF_NOTIMEOUTIFNOTHUNG | BSF_FORCEIFHUNG;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we don't broadcast as system, it's not a global drive
|
||||||
|
* notification, then mark it as LUID mapped drive
|
||||||
|
*/
|
||||||
|
if (!RtlEqualLuid(&Info.luid, &SystemLuid))
|
||||||
|
{
|
||||||
|
Flags |= BSF_LUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set event type */
|
||||||
|
wParam = RemoveDefinition ? DBT_DEVICEREMOVECOMPLETE : DBT_DEVICEARRIVAL;
|
||||||
|
|
||||||
|
/* And broadcast! */
|
||||||
|
Status = PBROADCASTSYSTEMMESSAGEEXW(Flags, &Recipients, WM_DEVICECHANGE, wParam, (LPARAM)&Volume, &Info);
|
||||||
|
|
||||||
|
/* If the drive is global, notify Winsta */
|
||||||
|
if (!(Flags & BSF_LUID))
|
||||||
|
{
|
||||||
|
Status = SendWinStationBSM(Flags, &Recipients, WM_DEVICECHANGE, wParam, (LPARAM)&Volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG
|
||||||
|
NTAPI
|
||||||
|
BaseSrvBSMThread(PVOID StartupContext)
|
||||||
|
{
|
||||||
|
ULONG ExitStatus;
|
||||||
|
NTSTATUS Status;
|
||||||
|
PBSM_REQUEST CurrentRequest;
|
||||||
|
|
||||||
|
/* We have a thread */
|
||||||
|
ExitStatus = 0;
|
||||||
|
RtlEnterCriticalSection(&BaseSrvDDDBSMCritSec);
|
||||||
|
++BaseSrvpBSMThreadCount;
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
/* If we flushed the queue, job done */
|
||||||
|
if (BSM_Request_Queue == NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Queue current request, and remove it from the queue */
|
||||||
|
CurrentRequest = BSM_Request_Queue;
|
||||||
|
BSM_Request_Queue = BSM_Request_Queue->Next;
|
||||||
|
|
||||||
|
/* If that was the last request, NULLify queue end */
|
||||||
|
if (BSM_Request_Queue == NULL)
|
||||||
|
{
|
||||||
|
BSM_Request_Queue_End = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
RtlLeaveCriticalSection(&BaseSrvDDDBSMCritSec);
|
||||||
|
|
||||||
|
/* Broadcast the message */
|
||||||
|
Status = BroadcastDriveLetterChange(CurrentRequest->DriveLetter,
|
||||||
|
CurrentRequest->RemoveDefinition,
|
||||||
|
&CurrentRequest->BroadcastLuid);
|
||||||
|
|
||||||
|
/* Reflect the last entry status on stop */
|
||||||
|
CurrentRequest->Next = NULL;
|
||||||
|
ExitStatus = Status;
|
||||||
|
|
||||||
|
RtlFreeHeap(BaseSrvHeap, 0, CurrentRequest);
|
||||||
|
RtlEnterCriticalSection(&BaseSrvDDDBSMCritSec);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Here, we've flushed the queue, quit the user thread */
|
||||||
|
--BaseSrvpBSMThreadCount;
|
||||||
|
RtlLeaveCriticalSection(&BaseSrvDDDBSMCritSec);
|
||||||
|
|
||||||
|
NtCurrentTeb()->FreeStackOnTermination = TRUE;
|
||||||
|
NtTerminateThread(NtCurrentThread(), ExitStatus);
|
||||||
|
|
||||||
|
return ExitStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CreateBSMThread(VOID)
|
||||||
|
{
|
||||||
|
/* This can only be true for LUID mappings */
|
||||||
|
if (BaseStaticServerData->LUIDDeviceMapsEnabled == 0)
|
||||||
|
{
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create our user thread */
|
||||||
|
return RtlCreateUserThread(NtCurrentProcess(),
|
||||||
|
NULL,
|
||||||
|
FALSE,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
BaseSrvBSMThread,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
AddBSMRequest(LONG DriveLetter,
|
||||||
|
BOOLEAN RemoveDefinition,
|
||||||
|
PLUID BroadcastLuid)
|
||||||
|
{
|
||||||
|
LUID CallerLuid;
|
||||||
|
NTSTATUS Status;
|
||||||
|
LUID SystemLuid = SYSTEM_LUID;
|
||||||
|
PBSM_REQUEST Request;
|
||||||
|
|
||||||
|
/* We need a broadcast LUID */
|
||||||
|
if (BroadcastLuid == NULL)
|
||||||
|
{
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If LUID mappings are not enabled, this call makes no sense
|
||||||
|
* It should not happen though
|
||||||
|
*/
|
||||||
|
if (BaseStaticServerData->LUIDDeviceMapsEnabled == 0)
|
||||||
|
{
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get our caller LUID (not the broadcaster!) */
|
||||||
|
Status = GetCallerLuid(&CallerLuid);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* System cannot create LUID mapped drives - thus broadcast makes no sense */
|
||||||
|
if (!RtlEqualLuid(&CallerLuid, &SystemLuid))
|
||||||
|
{
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate our request */
|
||||||
|
Request = RtlAllocateHeap(BaseSrvHeap, 0, sizeof(BSM_REQUEST));
|
||||||
|
if (Request == NULL)
|
||||||
|
{
|
||||||
|
return STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize it */
|
||||||
|
Request->DriveLetter = DriveLetter;
|
||||||
|
Request->RemoveDefinition = RemoveDefinition;
|
||||||
|
RtlCopyLuid(&Request->BroadcastLuid, BroadcastLuid);
|
||||||
|
Request->Next = NULL;
|
||||||
|
|
||||||
|
/* And queue it */
|
||||||
|
RtlEnterCriticalSection(&BaseSrvDDDBSMCritSec);
|
||||||
|
|
||||||
|
/* At the end of the queue if not empty */
|
||||||
|
if (BSM_Request_Queue_End != NULL)
|
||||||
|
{
|
||||||
|
BSM_Request_Queue_End->Next = Request;
|
||||||
|
}
|
||||||
|
/* Otherwise, initialize the queue */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BSM_Request_Queue = Request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We're in FIFO mode */
|
||||||
|
BSM_Request_Queue_End = Request;
|
||||||
|
|
||||||
|
/* If we don't have a messaging thread running, then start one */
|
||||||
|
if (BaseSrvpBSMThreadCount >= 1)
|
||||||
|
{
|
||||||
|
RtlLeaveCriticalSection(&BaseSrvDDDBSMCritSec);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RtlLeaveCriticalSection(&BaseSrvDDDBSMCritSec);
|
||||||
|
Status = CreateBSMThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
/* PUBLIC SERVER APIS *********************************************************/
|
/* PUBLIC SERVER APIS *********************************************************/
|
||||||
|
|
||||||
CSR_API(BaseSrvDefineDosDevice)
|
CSR_API(BaseSrvDefineDosDevice)
|
||||||
|
@ -167,7 +490,7 @@ CSR_API(BaseSrvDefineDosDevice)
|
||||||
BOOLEAN DriveLetter = FALSE;
|
BOOLEAN DriveLetter = FALSE;
|
||||||
BOOLEAN RemoveDefinition;
|
BOOLEAN RemoveDefinition;
|
||||||
BOOLEAN HandleTarget;
|
BOOLEAN HandleTarget;
|
||||||
BOOLEAN HandleSMB = FALSE;
|
BOOLEAN Broadcast = FALSE;
|
||||||
BOOLEAN IsGlobal = FALSE;
|
BOOLEAN IsGlobal = FALSE;
|
||||||
ULONG CchLengthLeft;
|
ULONG CchLengthLeft;
|
||||||
ULONG CchLength;
|
ULONG CchLength;
|
||||||
|
@ -297,13 +620,19 @@ CSR_API(BaseSrvDefineDosDevice)
|
||||||
_SEH2_LEAVE;
|
_SEH2_LEAVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* While impersonating the caller, also get its LUID */
|
/*
|
||||||
|
* While impersonating the caller, also get its LUID.
|
||||||
|
* This is mandatory in case we have a driver letter,
|
||||||
|
* Because we're in the case we've got LUID mapping
|
||||||
|
* enabled and broadcasting enabled. LUID will be required
|
||||||
|
* for the latter
|
||||||
|
*/
|
||||||
if (DriveLetter)
|
if (DriveLetter)
|
||||||
{
|
{
|
||||||
Status = GetCallerLuid(&CallerLuid);
|
Status = GetCallerLuid(&CallerLuid);
|
||||||
if (NT_SUCCESS(Status))
|
if (NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
HandleSMB = TRUE;
|
Broadcast = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -744,10 +1073,31 @@ CSR_API(BaseSrvDefineDosDevice)
|
||||||
/* Free our internal buffer */
|
/* Free our internal buffer */
|
||||||
RtlFreeHeap(BaseSrvHeap, 0, lpBuffer);
|
RtlFreeHeap(BaseSrvHeap, 0, lpBuffer);
|
||||||
|
|
||||||
/* Handle SMB */
|
/* Broadcast drive letter creation */
|
||||||
if (DriveLetter && Status == STATUS_SUCCESS && HandleSMB)
|
if (DriveLetter && Status == STATUS_SUCCESS && Broadcast)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
LUID SystemLuid = SYSTEM_LUID;
|
||||||
|
|
||||||
|
/* If that's a global drive, broadcast as system */
|
||||||
|
if (IsGlobal)
|
||||||
|
{
|
||||||
|
RtlCopyLuid(&CallerLuid, &SystemLuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Broadcast the event */
|
||||||
|
AddBSMRequest(AbsLetter, RemoveDefinition, &CallerLuid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we removed drive, and the drive was shadowing a global one
|
||||||
|
* broadcast the arrival of the global drive (as system - global)
|
||||||
|
*/
|
||||||
|
if (RemoveDefinition && !RtlEqualLuid(&CallerLuid, &SystemLuid))
|
||||||
|
{
|
||||||
|
if (CheckForGlobalDriveLetter(AbsLetter))
|
||||||
|
{
|
||||||
|
AddBSMRequest(AbsLetter, FALSE, &CallerLuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Done! */
|
/* Done! */
|
||||||
|
|
|
@ -580,7 +580,10 @@ BaseInitializeStaticServerData(IN PCSR_SERVER_DLL LoadedServerDll)
|
||||||
NULL);
|
NULL);
|
||||||
ASSERT(NT_SUCCESS(Status));
|
ASSERT(NT_SUCCESS(Status));
|
||||||
BaseStaticServerData->LUIDDeviceMapsEnabled = (BOOLEAN)LuidEnabled;
|
BaseStaticServerData->LUIDDeviceMapsEnabled = (BOOLEAN)LuidEnabled;
|
||||||
if (!BaseStaticServerData->LUIDDeviceMapsEnabled)
|
|
||||||
|
/* Initialize Global */
|
||||||
|
if (!BaseStaticServerData->LUIDDeviceMapsEnabled ||
|
||||||
|
NT_SUCCESS(RtlInitializeCriticalSectionAndSpinCount(&BaseSrvDDDBSMCritSec, 0x80000000)))
|
||||||
{
|
{
|
||||||
/* Make Global point back to BNO */
|
/* Make Global point back to BNO */
|
||||||
RtlInitUnicodeString(&DirectoryName, L"Global");
|
RtlInitUnicodeString(&DirectoryName, L"Global");
|
||||||
|
@ -638,6 +641,11 @@ BaseInitializeStaticServerData(IN PCSR_SERVER_DLL LoadedServerDll)
|
||||||
&ObjectAttributes);
|
&ObjectAttributes);
|
||||||
ASSERT(NT_SUCCESS(Status));
|
ASSERT(NT_SUCCESS(Status));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* That should never happen */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize NLS */
|
/* Initialize NLS */
|
||||||
BaseSrvNLSInit(BaseStaticServerData);
|
BaseSrvNLSInit(BaseStaticServerData);
|
||||||
|
|
Loading…
Reference in a new issue