|
|
/*************************************************************************
* * api.c * * WinStation Control API's for WIN32 subsystem. * * Copyright (c) 1985 - 1999, Microsoft Corporation * *************************************************************************/
/*
* Includes. */ #include "precomp.h"
#pragma hdrstop
#include "ntuser.h"
#include <winsta.h>
#include <wstmsg.h>
#include <icadd.h>
#include <winbasep.h>
#define SESSION_ROOT L"\\Sessions"
#define MAX_SESSION_PATH 256
NTSTATUS CsrPopulateDosDevices(VOID); NTSTATUS CleanupSessionObjectDirectories(VOID);
BOOL CtxInitUser32(VOID);
USHORT gHRes = 0; USHORT gVRes = 0; USHORT gColorDepth = 0;
#if DBG
ULONG gulConnectCount = 0; #endif // DBG
DWORD gLUIDDeviceMapsEnabled = 0;
/*
* The following are gotten from ICASRV. */ HANDLE G_IcaVideoChannel = NULL; HANDLE G_IcaMouseChannel = NULL; HANDLE G_IcaKeyboardChannel = NULL; HANDLE G_IcaBeepChannel = NULL; HANDLE G_IcaCommandChannel = NULL; HANDLE G_IcaThinwireChannel = NULL; WCHAR G_WinStationName[WINSTATIONNAME_LENGTH]; HANDLE G_DupIcaVideoChannel = NULL; HANDLE G_DupIcaCommandChannel = NULL;
HANDLE G_ConsoleShadowVideoChannel; HANDLE G_ConsoleShadowMouseChannel; HANDLE G_ConsoleShadowKeyboardChannel; HANDLE G_ConsoleShadowBeepChannel; HANDLE G_ConsoleShadowCommandChannel; HANDLE G_ConsoleShadowThinwireChannel; BOOL G_fCursorShadow; HANDLE G_DupConsoleShadowVideoChannel = NULL; HANDLE G_DupConsoleShadowCommandChannel = NULL;
/*
* Definition for the WinStation control API's dispatch table */ typedef NTSTATUS (*PWIN32WINSTATION_API)(IN OUT PWINSTATION_APIMSG ApiMsg);
typedef struct _WIN32WINSTATION_DISPATCH { PWIN32WINSTATION_API pWin32ApiProc; } WIN32WINSTATION_DISPATCH, *PWIN32WINSTATION_DISPATCH;
NTSTATUS W32WinStationDoConnect(IN OUT PWINSTATION_APIMSG); NTSTATUS W32WinStationDoDisconnect(IN OUT PWINSTATION_APIMSG); NTSTATUS W32WinStationDoReconnect(IN OUT PWINSTATION_APIMSG); NTSTATUS W32WinStationExitWindows(IN OUT PWINSTATION_APIMSG); NTSTATUS W32WinStationTerminate(IN OUT PWINSTATION_APIMSG); NTSTATUS W32WinStationNtSecurity(IN OUT PWINSTATION_APIMSG); NTSTATUS W32WinStationDoMessage(IN OUT PWINSTATION_APIMSG); NTSTATUS W32WinStationThinwireStats(IN OUT PWINSTATION_APIMSG); NTSTATUS W32WinStationShadowSetup(IN OUT PWINSTATION_APIMSG); NTSTATUS W32WinStationShadowStart(IN OUT PWINSTATION_APIMSG); NTSTATUS W32WinStationShadowStop(IN OUT PWINSTATION_APIMSG); NTSTATUS W32WinStationShadowCleanup(IN OUT PWINSTATION_APIMSG); NTSTATUS W32WinStationPassthruEnable(IN OUT PWINSTATION_APIMSG); NTSTATUS W32WinStationPassthruDisable(IN OUT PWINSTATION_APIMSG);
// This is the counter part to SMWinStationBroadcastSystemMessage
NTSTATUS W32WinStationBroadcastSystemMessage(IN OUT PWINSTATION_APIMSG); // This is the counter part to SMWinStationSendWindowMessage
NTSTATUS W32WinStationSendWindowMessage(IN OUT PWINSTATION_APIMSG);
NTSTATUS W32WinStationSetTimezone(IN OUT PWINSTATION_APIMSG); NTSTATUS W32WinStationDoNotify(IN OUT PWINSTATION_APIMSG); NTSTATUS W32WinStationDoLoadStringNMessage(IN OUT PWINSTATION_APIMSG); HANDLE CreateTermSrvReadyEvent();
/*
* WinStation API Dispatch Table * * Only the API's that WIN32 implements as opposed to ICASRV * are entered here. The rest are NULL so that the same WinStation API * numbers may be used by ICASRV and WIN32. If this table is * changed, the table below must be modified too, as well as the API * dispatch table in the ICASRV. */
WIN32WINSTATION_DISPATCH Win32WinStationDispatch[SMWinStationMaxApiNumber] = { NULL, // create
NULL, // reset
NULL, // disconnect
NULL, // WCharLog
NULL, // ApiWinStationGetSMCommand,
NULL, // ApiWinStationBrokenConnection,
NULL, // ApiWinStationIcaReplyMessage,
NULL, // ApiWinStationIcaShadowHotkey,
W32WinStationDoConnect, W32WinStationDoDisconnect, W32WinStationDoReconnect, W32WinStationExitWindows, W32WinStationTerminate, W32WinStationNtSecurity, W32WinStationDoMessage, NULL, W32WinStationThinwireStats, W32WinStationShadowSetup, W32WinStationShadowStart, W32WinStationShadowStop, W32WinStationShadowCleanup, W32WinStationPassthruEnable, W32WinStationPassthruDisable, W32WinStationSetTimezone, NULL, // [AraBern] this was missing: SMWinStationInitialProgram
NULL, // [AraBern] this was missing: SMWinStationNtsdDebug
W32WinStationBroadcastSystemMessage, W32WinStationSendWindowMessage, W32WinStationDoNotify, W32WinStationDoLoadStringNMessage, NULL, // SMWinStationWindowInvalid
};
#if DBG
PSZ Win32WinStationAPIName[SMWinStationMaxApiNumber] = { "SmWinStationCreate", "SmWinStationReset", "SmWinStationDisconnect", "SmWinStationWCharLog", "SmWinStationGetSMCommand", "SmWinStationBrokenConnection", "SmWinStationIcaReplyMessage", "SmWinStationIcaShadowHotkey", "SmWinStationDoConnect", "SmWinStationDoDisconnect", "SmWinStationDoReconnect", "SmWinStationExitWindows", "SmWinStationTerminate", "SmWinStationNtSecurity", "SmWinStationDoMessage", "SmWinstationDoBreakPoint", "SmWinStationThinwireStats", "SmWinStationShadowSetup", "SmWinStationShadowStart", "SmWinStationShadowStop", "SmWinStationShadowCleanup", "SmWinStationPassthruEnable", "SmWinStationPassthruDisable", "SMWinStationSetTimeZone", "SMWinStationInitialProgram", "SMWinStationNtsdDebug", "W32WinStationBroadcastSystemMessage", "W32WinStationSendWindowMessage", "W32WinStationDoNotify", "W32WinStationDoLoadStringNMessage", "SMWinStationWindowInvalid", }; #endif
NTSTATUS TerminalServerRequestThread(PVOID); NTSTATUS Win32CommandChannelThread(PVOID); NTSTATUS Win32ConsoleShadowChannelThread(PVOID); NTSTATUS RemoteDoMessage(PWINSTATION_APIMSG pMsg); NTSTATUS RemoteDoLoadStringNMessage(PWINSTATION_APIMSG pMsg); NTSTATUS MultiUserSpoolerInit();
extern HANDLE g_hDoMessageEvent;
NTSTATUS RemoteDoBroadcastSystemMessage(PWINSTATION_APIMSG pMsg); NTSTATUS RemoteDoSendWindowMessage(PWINSTATION_APIMSG pMsg); BOOL CancelExitWindows(VOID);
/*****************************************************************************
* * WinStationAPIInit * * Creates and initializes the WinStation API port and thread. * * ENTRY: * No Parameters * * EXIT: * STATUS_SUCCESS - no error * ****************************************************************************/
NTSTATUS WinStationAPIInit( VOID) { NTSTATUS Status; CLIENT_ID ClientId; HANDLE ThreadHandle; KPRIORITY Priority; ULONG LUIDDeviceMapsEnabled; #if DBG
static BOOL Inited = FALSE; #endif
#if DBG
UserAssert(Inited == FALSE); Inited = TRUE; #endif
gSessionId = NtCurrentPeb()->SessionId;
//
// Check if LUID DosDevices are enabled.
//
Status = NtQueryInformationProcess(NtCurrentProcess(), ProcessLUIDDeviceMapsEnabled, &LUIDDeviceMapsEnabled, sizeof(LUIDDeviceMapsEnabled), NULL); if (NT_SUCCESS(Status)) { gLUIDDeviceMapsEnabled = LUIDDeviceMapsEnabled; }
Status = RtlCreateUserThread(NtCurrentProcess(), NULL, TRUE, 0, 0, 0, TerminalServerRequestThread, NULL, &ThreadHandle, &ClientId); if (!NT_SUCCESS(Status)) { RIPMSGF1(RIP_WARNING, "Failed to create TerminalServerRequestThread, Status = 0x%x", Status); goto Exit; }
/*
* Add thread to server thread pool. */ CsrAddStaticServerThread(ThreadHandle, &ClientId, 0);
/*
* Boost priority of ICA SRV Request thread */ Priority = THREAD_BASE_PRIORITY_MAX;
Status = NtSetInformationThread(ThreadHandle, ThreadBasePriority, &Priority, sizeof(Priority));
if (!NT_SUCCESS(Status)) { RIPMSGF1(RIP_WARNING, "Failed to set thread priority, Status = 0x%x", Status); goto Exit; }
/*
* Resume the thread now that we've initialized things. */ NtResumeThread(ThreadHandle, NULL);
Exit: return Status; }
NTSTATUS TerminalServerRequestThread( PVOID ThreadParameter) { UNICODE_STRING PortName; SECURITY_QUALITY_OF_SERVICE DynamicQos; WINSTATIONAPI_CONNECT_INFO info; ULONG ConnectInfoLength; WINSTATION_APIMSG ApiMsg; PWIN32WINSTATION_DISPATCH pDispatch; NTSTATUS Status; REMOTE_PORT_VIEW ServerView; HANDLE CsrStartHandle, hevtTermSrvInit; HANDLE hLPCPort = NULL;
UNREFERENCED_PARAMETER(ThreadParameter);
if (NtCurrentPeb()->SessionId == 0) { hevtTermSrvInit = CreateTermSrvReadyEvent(); } else { hevtTermSrvInit = OpenEvent(SYNCHRONIZE, FALSE, L"Global\\TermSrvReadyEvent"); }
if (hevtTermSrvInit == NULL) { RIPMSG1(RIP_WARNING, "Couldn't create TermSrvReadyEvent. Error = 0x%x", GetLastError()); Status = STATUS_NO_MEMORY; goto Exit; }
NtWaitForSingleObject(hevtTermSrvInit, FALSE, NULL); NtClose(hevtTermSrvInit);
/*
* Connect to terminal server API port. */ DynamicQos.ImpersonationLevel = SecurityImpersonation; DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; DynamicQos.EffectiveOnly = TRUE;
RtlInitUnicodeString(&PortName, L"\\SmSsWinStationApiPort");
/*
* Init the REMOTE_VIEW structure. */ ServerView.Length = sizeof(ServerView); ServerView.ViewSize = 0; ServerView.ViewBase = 0;
/*
* Fill in the ConnectInfo structure with our access request mask. */ info.Version = CITRIX_WINSTATIONAPI_VERSION; info.RequestedAccess = 0; ConnectInfoLength = sizeof(WINSTATIONAPI_CONNECT_INFO);
Status = NtConnectPort(&hLPCPort, &PortName, &DynamicQos, NULL, // ClientView
&ServerView, NULL, // Max message length [select default]
(PVOID)&info, &ConnectInfoLength);
if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "TerminalServerRequestThread: Failed to connect to LPC port: Status = 0x%x", Status); UserExitWorkerThread(Status); return Status; }
//
// Terminal Server calls into Session Manager to create a new Hydra session.
// The session manager creates and resume a new session and returns to Terminal
// server the session id of the new session. There is a race condition where
// CSR can resume and call into terminal server before terminal server can
// store the session id in its internal structure. To prevent this CSR will
// wait here on a named event which will be set by Terminal server once it
// gets the sessionid for the newly created session
//
if (NtCurrentPeb()->SessionId != 0) { CsrStartHandle = CreateEvent(NULL, TRUE, FALSE, L"CsrStartEvent");
if (!CsrStartHandle) { RIPMSG1(RIP_WARNING, "Failed to create CsrStartEvent. Error = 0x%x", GetLastError()); Status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } else { Status = NtWaitForSingleObject(CsrStartHandle, FALSE, NULL);
NtClose(CsrStartHandle); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "Wait for CsrStartEvent failed: Status = 0x%x", Status); } } }
RtlZeroMemory(&ApiMsg, sizeof(ApiMsg)); for (;;) {
/*
* Initialize LPC message fields. */ ApiMsg.h.u1.s1.DataLength = sizeof(ApiMsg) - sizeof(PORT_MESSAGE); ApiMsg.h.u1.s1.TotalLength = sizeof(ApiMsg); ApiMsg.h.u2.s2.Type = 0; // Kernel will fill in message type
ApiMsg.h.u2.s2.DataInfoOffset = 0; ApiMsg.ApiNumber = SMWinStationGetSMCommand;
Status = NtRequestWaitReplyPort(hLPCPort, (PPORT_MESSAGE)&ApiMsg, (PPORT_MESSAGE)&ApiMsg);
if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "TerminalServerRequestThread wait failed: Status 0x%x", Status); break; }
if (ApiMsg.ApiNumber >= SMWinStationMaxApiNumber) { RIPMSG1(RIP_WARNING, "TerminalServerRequestThread: Bad API number %d", ApiMsg.ApiNumber);
ApiMsg.ReturnedStatus = STATUS_NOT_IMPLEMENTED; } else { /*
* We must VALIDATE which ones are implemented here. */ pDispatch = &Win32WinStationDispatch[ApiMsg.ApiNumber];
if (pDispatch->pWin32ApiProc) { BOOL bRestoreDesktop = FALSE; USERTHREAD_USEDESKTOPINFO utudi;
Status = STATUS_SUCCESS;
/*
* For all the win32k callouts - with the exception of * terminate and timezone setting - set this thread to the * current desktop. */ if (ApiMsg.ApiNumber != SMWinStationTerminate && ApiMsg.ApiNumber != SMWinStationSetTimeZone) { BOOL bAttachDesktop = TRUE; if (ApiMsg.ApiNumber == SMWinStationDoConnect) { WINSTATIONDOCONNECTMSG* m = &ApiMsg.u.DoConnect; if (!m->ConsoleShadowFlag) { bAttachDesktop = FALSE; } } if (bAttachDesktop) { utudi.hThread = NULL; utudi.drdRestore.pdeskRestore = NULL; Status = NtUserSetInformationThread(NtCurrentThread(), UserThreadUseActiveDesktop, &utudi, sizeof(utudi));
if (NT_SUCCESS(Status)) { bRestoreDesktop = TRUE; } } }
/*
* Call the API */ if (Status == STATUS_SUCCESS) { ApiMsg.ReturnedStatus = (pDispatch->pWin32ApiProc)(&ApiMsg); } else { ApiMsg.ReturnedStatus = Status; }
if (bRestoreDesktop) { NtUserSetInformationThread(NtCurrentThread(), UserThreadUseDesktop, &utudi, sizeof(utudi)); }
/*
* Let's bail ... */ if (ApiMsg.ApiNumber == SMWinStationTerminate) { break; } } else { // This control API is not implemented in WIN32
ApiMsg.ReturnedStatus = STATUS_NOT_IMPLEMENTED; } } }
Exit: if (hLPCPort) { NtClose(hLPCPort); }
UserExitWorkerThread(Status); return Status; }
#if DBG
VOID W32WinStationDumpReconnectInfo( WINSTATIONDORECONNECTMSG *pDoReconnect, BOOLEAN bReconnect) { PSTR pCallerName;
if (bReconnect) { pCallerName = "W32WinStationDoReconnect"; } else { pCallerName = "W32WinStationDoConnect"; }
DbgPrint(pCallerName); DbgPrint(" - Display resolution information for session %d :\n", gSessionId);
DbgPrint("\tProtocolType : %04d\n", pDoReconnect->ProtocolType); DbgPrint("\tHRes : %04d\n", pDoReconnect->HRes); DbgPrint("\tVRes : %04d\n", pDoReconnect->VRes); DbgPrint("\tColorDepth : %04d\n", pDoReconnect->ColorDepth);
DbgPrint("\tKeyboardType : %d\n", pDoReconnect->KeyboardType); DbgPrint("\tKeyboardSubType : %d\n", pDoReconnect->KeyboardSubType); DbgPrint("\tKeyboardFunctionKey : %d\n", pDoReconnect->KeyboardFunctionKey); } #else
#define W32WinStationDumpReconnectInfo(p, b)
#endif // DBG
NTSTATUS W32WinStationDoConnect( PWINSTATION_APIMSG pMsg) { NTSTATUS Status = STATUS_SUCCESS; WINSTATIONDOCONNECTMSG* m = &pMsg->u.DoConnect; WCHAR DisplayDriverName[10]; CLIENT_ID ClientId; HANDLE ThreadHandle = NULL; KPRIORITY Priority; DOCONNECTDATA DoConnectData; WINSTATIONDORECONNECTMSG mDoReconnect; HANDLE hDisplayChangeEvent = NULL;
if (!m->ConsoleShadowFlag) { UserAssert(gulConnectCount == 0);
if ((gLUIDDeviceMapsEnabled == 0) && (gSessionId != 0)) { /*
* Populate the sessions \DosDevices from * the current consoles settings */ Status = CsrPopulateDosDevices(); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "CsrPopulateDosDevices failed with Status %lx", Status); goto Exit; } }
G_IcaVideoChannel = m->hIcaVideoChannel; G_IcaMouseChannel = m->hIcaMouseChannel; G_IcaKeyboardChannel = m->hIcaKeyboardChannel; G_IcaBeepChannel = m->hIcaBeepChannel; G_IcaCommandChannel = m->hIcaCommandChannel; G_IcaThinwireChannel = m->hIcaThinwireChannel;
RtlZeroMemory(G_WinStationName, sizeof(G_WinStationName)); memcpy(G_WinStationName, m->WinStationName, min(sizeof(G_WinStationName), sizeof(m->WinStationName)));
Status = NtDuplicateObject( NtCurrentProcess(), G_IcaVideoChannel, NtCurrentProcess(), &G_DupIcaVideoChannel, 0, 0, DUPLICATE_SAME_ACCESS ); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "NtDuplicateObject failed with Status %lx", Status); goto Exit; }
Status = NtDuplicateObject( NtCurrentProcess(), G_IcaCommandChannel, NtCurrentProcess(), &G_DupIcaCommandChannel, 0, 0, DUPLICATE_SAME_ACCESS ); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "NtDuplicateObject failed with Status %lx", Status); NtClose(G_DupIcaVideoChannel); G_DupIcaVideoChannel = NULL; goto Exit; } } else { G_ConsoleShadowVideoChannel = m->hIcaVideoChannel; G_ConsoleShadowMouseChannel = m->hIcaMouseChannel; G_ConsoleShadowKeyboardChannel = m->hIcaKeyboardChannel; G_ConsoleShadowBeepChannel = m->hIcaBeepChannel; G_ConsoleShadowCommandChannel = m->hIcaCommandChannel; G_ConsoleShadowThinwireChannel = m->hIcaThinwireChannel;
G_fCursorShadow = FALSE; SystemParametersInfo(SPI_GETCURSORSHADOW, 0, &G_fCursorShadow, 0); if (G_fCursorShadow) { SystemParametersInfo(SPI_SETCURSORSHADOW, 0, FALSE, 0); }
hDisplayChangeEvent = m->hDisplayChangeEvent;
Status = NtDuplicateObject( NtCurrentProcess(), G_ConsoleShadowVideoChannel, NtCurrentProcess(), &G_DupConsoleShadowVideoChannel, 0, 0, DUPLICATE_SAME_ACCESS ); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "NtDuplicateObject failed with Status %lx", Status); goto Exit; }
Status = NtDuplicateObject( NtCurrentProcess(), G_ConsoleShadowCommandChannel, NtCurrentProcess(), &G_DupConsoleShadowCommandChannel, 0, 0, DUPLICATE_SAME_ACCESS ); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "NtDuplicateObject failed with Status %lx", Status); NtClose(G_DupConsoleShadowVideoChannel); G_DupConsoleShadowVideoChannel = NULL; goto Exit; } }
/*
* This must be 8 unicode characters (file name) plus two zero wide characters. */ RtlZeroMemory(DisplayDriverName, sizeof(DisplayDriverName)); memcpy(DisplayDriverName, m->DisplayDriverName, sizeof(DisplayDriverName) - 2);
/*
* Give the information to the WIN32 driver. */ RtlZeroMemory(&DoConnectData, sizeof(DoConnectData));
DoConnectData.fMouse = m->fMouse; DoConnectData.IcaBeepChannel = m->hIcaBeepChannel; DoConnectData.IcaVideoChannel = m->hIcaVideoChannel; DoConnectData.IcaMouseChannel = m->hIcaMouseChannel; DoConnectData.fEnableWindowsKey = m->fEnableWindowsKey;
DoConnectData.IcaKeyboardChannel = m->hIcaKeyboardChannel; DoConnectData.IcaThinwireChannel = m->hIcaThinwireChannel; DoConnectData.fClientDoubleClickSupport = m->fClientDoubleClickSupport;
DoConnectData.DisplayChangeEvent = hDisplayChangeEvent;
/*
* Give the information to the keyboard type/subtype/number of functions. */ DoConnectData.ClientKeyboardType.Type = m->KeyboardType; DoConnectData.ClientKeyboardType.SubType = m->KeyboardSubType; DoConnectData.ClientKeyboardType.FunctionKey = m->KeyboardFunctionKey;
memcpy(DoConnectData.WinStationName, G_WinStationName, min(sizeof(G_WinStationName), sizeof(DoConnectData.WinStationName)));
DoConnectData.drProtocolType = m->ProtocolType; DoConnectData.drPelsHeight = m->VRes; DoConnectData.drPelsWidth = m->HRes; DoConnectData.drBitsPerPel = m->ColorDepth;
mDoReconnect.ProtocolType = m->ProtocolType; mDoReconnect.HRes = m->HRes; mDoReconnect.VRes = m->VRes; mDoReconnect.ColorDepth = m->ColorDepth;
W32WinStationDumpReconnectInfo(&mDoReconnect, FALSE);
/* Give winstation protocol name */ RtlZeroMemory(DoConnectData.ProtocolName, sizeof(DoConnectData.ProtocolName)); memcpy(DoConnectData.ProtocolName, m->ProtocolName, sizeof(DoConnectData.ProtocolName) - 2);
/* Give winstation audio drver name */ RtlZeroMemory(DoConnectData.AudioDriverName, sizeof(DoConnectData.AudioDriverName)); memcpy(DoConnectData.AudioDriverName, m->AudioDriverName, sizeof(DoConnectData.AudioDriverName) - 2);
DoConnectData.fConsoleShadowFlag = (BOOL) m->ConsoleShadowFlag;
Status = NtUserRemoteConnect(&DoConnectData, ARRAY_SIZE(DisplayDriverName), DisplayDriverName);
if (Status != STATUS_SUCCESS) { RIPMSG1(RIP_WARNING, "NtUserRemoteConnect failed with Status %lx", Status); goto Exit; }
Status = RtlCreateUserThread(NtCurrentProcess(), NULL, TRUE, 0L, 0L, 0L, Win32CommandChannelThread, (PVOID)m->ConsoleShadowFlag, &ThreadHandle, &ClientId);
if (Status != STATUS_SUCCESS) { RIPMSG1(RIP_WARNING, "RtlCreateUserThread failed with Status %lx", Status); if (G_DupIcaVideoChannel) { NtClose(G_DupIcaVideoChannel); G_DupIcaVideoChannel = NULL; }
if (G_DupIcaCommandChannel) { NtClose(G_DupIcaCommandChannel); G_DupIcaCommandChannel = NULL; }
if (G_DupConsoleShadowVideoChannel) { NtClose(G_DupConsoleShadowVideoChannel); G_DupConsoleShadowVideoChannel = NULL; }
if (G_DupConsoleShadowCommandChannel) { NtClose(G_DupConsoleShadowCommandChannel); G_DupConsoleShadowCommandChannel = NULL; }
goto Exit; }
/*
* Add thread to server thread pool only if we are in regular sessions. * In console shadow, we don't do this as it will leak the handle -- * CSRSS doesn't close these handles. */ if (!m->ConsoleShadowFlag && CsrAddStaticServerThread(ThreadHandle, &ClientId, 0) == NULL) { RIPMSG0(RIP_WARNING, "CsrAddStaticServerThread failed");
/*
* Close the handle as the above function does not have a reference * to us in its list. */ CloseHandle(ThreadHandle); goto Exit; }
/*
* Boost priority of thread */ Priority = THREAD_BASE_PRIORITY_MAX;
Status = NtSetInformationThread(ThreadHandle, ThreadBasePriority, &Priority, sizeof(Priority));
UserAssert(NT_SUCCESS(Status));
if (Status != STATUS_SUCCESS) { RIPMSG1(RIP_WARNING, "NtSetInformationThread failed with Status %lx", Status); Status = STATUS_NO_MEMORY; goto Exit; }
/*
* Resume the thread now that we've initialized things. */ NtResumeThread(ThreadHandle, NULL);
if (!m->ConsoleShadowFlag) { if (CsrConnectToUser() == NULL) { RIPMSG0(RIP_WARNING, "CsrConnectToUser failed"); Status = STATUS_NO_MEMORY; goto Exit; }
if (!CtxInitUser32()) { RIPMSG0(RIP_WARNING, "CtxInitUser32 failed"); Status = STATUS_NO_MEMORY; goto Exit; }
/*
* Create the Spooler service thread */ if (gSessionId != 0) { Status = MultiUserSpoolerInit(); }
/*
* Save the resolution */ gHRes = mDoReconnect.HRes; gVRes = mDoReconnect.VRes; gColorDepth = mDoReconnect.ColorDepth; } else { /*
* By now, the object has been referenced in kernel mode. */ CloseHandle(hDisplayChangeEvent); }
Exit:
#if DBG
if (!m->ConsoleShadowFlag) { if (Status == STATUS_SUCCESS) { gulConnectCount++; } } #endif // DBG
/*
* Close the thread handle now if we are in console shadow */ if (m->ConsoleShadowFlag && NULL != ThreadHandle) { CloseHandle(ThreadHandle); } return Status; }
NTSTATUS W32WinStationDoDisconnect( PWINSTATION_APIMSG pMsg) { NTSTATUS Status = STATUS_SUCCESS; WINSTATIONDODISCONNECTMSG *m = &pMsg->u.DoDisconnect; IO_STATUS_BLOCK IoStatus;
if (!m->ConsoleShadowFlag) { RtlZeroMemory(G_WinStationName, sizeof(G_WinStationName)); Status = (NTSTATUS)NtUserCallNoParam(SFI_XXXREMOTEDISCONNECT); } else { Status = (NTSTATUS)NtUserCallNoParam(SFI_XXXREMOTECONSOLESHADOWSTOP);
if (G_ConsoleShadowMouseChannel) { CloseHandle(G_ConsoleShadowMouseChannel); G_ConsoleShadowMouseChannel = NULL; } if (G_ConsoleShadowKeyboardChannel) { CloseHandle(G_ConsoleShadowKeyboardChannel); G_ConsoleShadowKeyboardChannel = NULL; }
// Instead send a IOCTL to termdd
if (G_ConsoleShadowCommandChannel) { Status = NtDeviceIoControlFile( G_ConsoleShadowCommandChannel, NULL, NULL, NULL, &IoStatus, IOCTL_ICA_CHANNEL_CLOSE_COMMAND_CHANNEL, NULL, 0, NULL, 0); CloseHandle(G_ConsoleShadowCommandChannel); G_ConsoleShadowCommandChannel = NULL; }
if (G_ConsoleShadowVideoChannel) { Status = NtDeviceIoControlFile( G_ConsoleShadowVideoChannel, NULL, NULL, NULL, &IoStatus, IOCTL_ICA_CHANNEL_CLOSE_COMMAND_CHANNEL, NULL, 0, NULL, 0); CloseHandle(G_ConsoleShadowVideoChannel); G_ConsoleShadowVideoChannel = NULL; }
if (G_ConsoleShadowBeepChannel) { CloseHandle(G_ConsoleShadowBeepChannel); G_ConsoleShadowBeepChannel = NULL; }
if (G_ConsoleShadowThinwireChannel) { CloseHandle(G_ConsoleShadowThinwireChannel); G_ConsoleShadowThinwireChannel = NULL; }
if (G_fCursorShadow) { SystemParametersInfo(SPI_SETCURSORSHADOW, 0, (LPVOID)TRUE, 0); } }
if (Status != STATUS_SUCCESS) { RIPMSG1(RIP_WARNING, "xxxRemoteDisconnect failed with Status %lx", Status); }
#if DBG
if (!m->ConsoleShadowFlag && Status == STATUS_SUCCESS) { gulConnectCount--; }
#endif // DBG
return Status; }
NTSTATUS W32WinStationDoReconnect( PWINSTATION_APIMSG pMsg) { NTSTATUS Status = STATUS_SUCCESS; DORECONNECTDATA DoReconnectData; WINSTATIONDORECONNECTMSG* m = &pMsg->u.DoReconnect;
UserAssert(gulConnectCount == 0);
RtlZeroMemory(&DoReconnectData, sizeof(DoReconnectData));
DoReconnectData.fMouse = m->fMouse; DoReconnectData.fEnableWindowsKey = m->fEnableWindowsKey; DoReconnectData.fClientDoubleClickSupport = m->fClientDoubleClickSupport;
memcpy(G_WinStationName, m->WinStationName, min(sizeof(G_WinStationName), sizeof(m->WinStationName)));
memcpy(DoReconnectData.WinStationName, G_WinStationName, min(sizeof(G_WinStationName), sizeof(DoReconnectData.WinStationName)));
DoReconnectData.drProtocolType = m->ProtocolType; DoReconnectData.drPelsHeight = m->VRes; DoReconnectData.drPelsWidth = m->HRes; DoReconnectData.drBitsPerPel = m->ColorDepth; if (m->fDynamicReconnect) { DoReconnectData.fChangeDisplaySettings = TRUE; } else { DoReconnectData.fChangeDisplaySettings = FALSE; } // DoReconnectData.drDisplayFrequency is no yet setup
DoReconnectData.drDisplayFrequency = 0;
/*
* Give the information to the keyboard type/subtype/number of functions. */ DoReconnectData.ClientKeyboardType.Type = m->KeyboardType; DoReconnectData.ClientKeyboardType.SubType = m->KeyboardSubType; DoReconnectData.ClientKeyboardType.FunctionKey = m->KeyboardFunctionKey;
RtlZeroMemory(DoReconnectData.DisplayDriverName, sizeof(DoReconnectData.DisplayDriverName));
UserAssert(sizeof(m->DisplayDriverName) <= sizeof(WCHAR) * DR_DISPLAY_DRIVER_NAME_LENGTH); memcpy(DoReconnectData.DisplayDriverName, m->DisplayDriverName, sizeof(m->DisplayDriverName) - 2);
RtlZeroMemory(DoReconnectData.ProtocolName, sizeof(DoReconnectData.ProtocolName));
UserAssert(sizeof(m->DisplayDriverName) <= sizeof(WCHAR) * WPROTOCOLNAME_LENGTH); memcpy(DoReconnectData.ProtocolName, m->ProtocolName, sizeof(m->ProtocolName) - 2);
RtlZeroMemory(DoReconnectData.AudioDriverName, sizeof(DoReconnectData.AudioDriverName)); memcpy(DoReconnectData.AudioDriverName, m->AudioDriverName, sizeof(m->AudioDriverName) - 2);
W32WinStationDumpReconnectInfo(m, TRUE);
/*
* Give the information to the WIN32 driver. */
Status = (NTSTATUS)NtUserCallOneParam((ULONG_PTR)&DoReconnectData, SFI_XXXREMOTERECONNECT);
if (Status != STATUS_SUCCESS) { RIPMSG1(RIP_WARNING, "xxxRemoteReconnect failed with Status %lx", Status); } else {
/*
* Save the resolution */ gHRes = m->HRes; gVRes = m->VRes; gColorDepth = m->ColorDepth;
#if DBG
gulConnectCount++; #endif // DBG
}
return Status; }
NTSTATUS W32WinStationDoNotify( PWINSTATION_APIMSG pMsg) { NTSTATUS Status = STATUS_SUCCESS; DONOTIFYDATA DoNotifyData; WINSTATIONDONOTIFYMSG* m = &pMsg->u.DoNotify;
switch (m->NotifyEvent) { case WinStation_Notify_DisableScrnSaver: DoNotifyData.NotifyEvent = Notify_DisableScrnSaver; break;
case WinStation_Notify_EnableScrnSaver: DoNotifyData.NotifyEvent = Notify_EnableScrnSaver; break;
case WinStation_Notify_Disconnect:
DoNotifyData.NotifyEvent = Notify_Disconnect; break;
case WinStation_Notify_SyncDisconnect:
DoNotifyData.NotifyEvent = Notify_SyncDisconnect; break;
case WinStation_Notify_Reconnect:
DoNotifyData.NotifyEvent = Notify_Reconnect; break;
case WinStation_Notify_PreReconnect:
DoNotifyData.NotifyEvent = Notify_PreReconnect; break;
case WinStation_Notify_PreReconnectDesktopSwitch:
DoNotifyData.NotifyEvent = Notify_PreReconnectDesktopSwitch; break;
case WinStation_Notify_HelpAssistantShadowStart:
DoNotifyData.NotifyEvent = Notify_HelpAssistantShadowStart; break;
case WinStation_Notify_HelpAssistantShadowFinish:
DoNotifyData.NotifyEvent = Notify_HelpAssistantShadowFinish; break;
case WinStation_Notify_DisconnectPipe: DoNotifyData.NotifyEvent = Notify_DisconnectPipe; break;
default: RIPMSGF1(RIP_ERROR, "Unknown NotifyEvent 0x%x", m->NotifyEvent); return STATUS_INVALID_PARAMETER; }
/*
* Give the information to the WIN32 driver. */
Status = (NTSTATUS)NtUserCallOneParam((ULONG_PTR)&DoNotifyData, SFI_XXXREMOTENOTIFY);
if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "xxxRemoteNotify failed with Status %lx", Status); }
return Status; }
NTSTATUS W32WinStationExitWindows( PWINSTATION_APIMSG pMsg) { NTSTATUS Status = STATUS_SUCCESS; WINSTATIONEXITWINDOWSMSG* m = &pMsg->u.ExitWindows;
UserAssert(gulConnectCount <= 1);
/*
* Cancel any existing ExitWindows call so that we can force logoff the user */ CancelExitWindows();
/*
* Tell winlogon to logoff */ Status = (NTSTATUS)NtUserCallNoParam(SFI_REMOTELOGOFF);
if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "RemoteLogoff failed with Status %lx", Status); }
return Status; }
NTSTATUS W32WinStationTerminate( PWINSTATION_APIMSG pMsg) { NTSTATUS Status = STATUS_SUCCESS; HANDLE hevtRitExited, hevtRitStuck, hevtShutDown; DONOTIFYDATA DoNotifyData; IO_STATUS_BLOCK IoStatus;
UNREFERENCED_PARAMETER(pMsg);
gbExitInProgress = TRUE;
/*
* Get rid of hard error thread. */ if (gdwHardErrorThreadId != 0) {
BoostHardError(-1, BHE_FORCE);
/*
* Poll (!!?) for hard error thread completion. The thread does * not exit. */ while (gdwHardErrorThreadId != 0) { RIPMSG0(RIP_WARNING, "Waiting for hard error thread to stop...");
Sleep(3 * 1000); }
RIPMSG0(RIP_WARNING, "Stopped hard error thread"); }
if (g_hDoMessageEvent) { NtSetEvent(g_hDoMessageEvent, NULL); }
/*
* Give the information that we want to stop reading to the WIN32 driver. */
DoNotifyData.NotifyEvent = Notify_StopReadInput;
Status = (NTSTATUS)NtUserCallOneParam((ULONG_PTR)&DoNotifyData, SFI_XXXREMOTENOTIFY);
if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "W32WinStationTerminate : xxxRemoteNotify failed with Status %lx", Status); }
if (G_IcaMouseChannel) { CloseHandle(G_IcaMouseChannel); G_IcaMouseChannel = NULL; }
if (G_IcaKeyboardChannel) { CloseHandle(G_IcaKeyboardChannel); G_IcaKeyboardChannel = NULL; }
// Instead send a IOCTL to termdd
if (G_IcaCommandChannel) {
Status = NtDeviceIoControlFile( G_IcaCommandChannel, NULL, NULL, NULL, &IoStatus, IOCTL_ICA_CHANNEL_CLOSE_COMMAND_CHANNEL, NULL, 0, NULL, 0); CloseHandle(G_IcaCommandChannel); G_IcaCommandChannel = NULL; }
if (G_IcaVideoChannel) {
Status = NtDeviceIoControlFile( G_IcaVideoChannel, NULL, NULL, NULL, &IoStatus, IOCTL_ICA_CHANNEL_CLOSE_COMMAND_CHANNEL, NULL, 0, NULL, 0); CloseHandle(G_IcaVideoChannel); G_IcaVideoChannel = NULL; }
if (G_IcaBeepChannel) { CloseHandle(G_IcaBeepChannel); G_IcaBeepChannel = NULL; } if (G_IcaThinwireChannel) { CloseHandle(G_IcaThinwireChannel); G_IcaThinwireChannel = NULL; }
hevtShutDown = OpenEvent(EVENT_ALL_ACCESS, FALSE, L"EventShutDownCSRSS"); if (hevtShutDown == NULL) { /*
* This case is for cached sessions where RIT and Destiop thread have * not been created. */ RIPMSG0(RIP_WARNING, "W32WinStationTerminate terminating CSRSS ...");
if (gLUIDDeviceMapsEnabled == 0) {
Status = CleanupSessionObjectDirectories();
} return 0; }
hevtRitExited = CreateEvent(NULL, FALSE, FALSE, L"EventRitExited");
UserAssert(hevtRitExited != NULL);
hevtRitStuck = CreateEvent(NULL, FALSE, FALSE, L"EventRitStuck");
UserAssert(hevtRitStuck != NULL);
/*
* RIT is created. Signal this event that starts the * cleanup in win32k. */ SetEvent(hevtShutDown);
TAGMSG0(DBGTAG_TermSrv, "EventShutDownCSRSS set in CSRSS ...");
while (1) { HANDLE arHandles[2] = {hevtRitExited, hevtRitStuck}; DWORD result;
result = WaitForMultipleObjects(2, arHandles, FALSE, INFINITE);
switch (result) { case WAIT_OBJECT_0: goto RITExited;
case WAIT_OBJECT_0 + 1:
/*
* The RIT is stuck because there are still GUI threads * assigned to desktops. One reason for this is that winlogon * died w/o calling ExitWindowsEx. */ break; default: FRE_RIPMSG1(RIP_ERROR, "WFMO returned unexpected value 0x%x", result); break; } }
RITExited:
TAGMSG0(DBGTAG_TermSrv, "EventRitExited set in CSRSS ...");
CloseHandle(hevtRitExited); CloseHandle(hevtRitStuck); CloseHandle(hevtShutDown);
Status = CleanupSessionObjectDirectories(); return Status; }
NTSTATUS W32WinStationNtSecurity( PWINSTATION_APIMSG pMsg) { NTSTATUS Status;
UNREFERENCED_PARAMETER(pMsg);
Status = (NTSTATUS)NtUserCallNoParam(SFI_REMOTENTSECURITY); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "RemoteNtSecurity failed with Status %lx", Status); }
return Status; }
NTSTATUS W32WinStationDoMessage( PWINSTATION_APIMSG pMsg) { NTSTATUS Status = STATUS_SUCCESS;
Status = RemoteDoMessage(pMsg);
if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "RemoteDoMessage failed with Status %lx", Status); }
return Status; }
// This is different from W32WinStationDoMessage in that it loads the string and displays the message.
NTSTATUS W32WinStationDoLoadStringNMessage( PWINSTATION_APIMSG pMsg) { NTSTATUS Status;
Status = RemoteDoLoadStringNMessage(pMsg);
if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "RemoteDoLoadStringNMessage failed with Status %lx", Status); }
return Status; }
// This is the counter part to SMWinStationBroadcastSystemMessage
NTSTATUS W32WinStationBroadcastSystemMessage( PWINSTATION_APIMSG pMsg ) { NTSTATUS Status;
Status = RemoteDoBroadcastSystemMessage(pMsg);
if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "RemoteDoBroadcastSystemMessage(): failed with status 0x%lx", Status); }
return Status; } // This is the counter part to SMWinStationSendWindowMessage
NTSTATUS W32WinStationSendWindowMessage( PWINSTATION_APIMSG pMsg) { NTSTATUS Status;
Status = RemoteDoSendWindowMessage(pMsg);
if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "RemoteDoSendWindowMessage failed with Status 0x%lx", Status); }
return Status; }
NTSTATUS W32WinStationThinwireStats( PWINSTATION_APIMSG pMsg) { NTSTATUS Status; WINSTATIONTHINWIRESTATSMSG* m = &pMsg->u.ThinwireStats;
Status = (NTSTATUS)NtUserCallOneParam((ULONG_PTR)&m->Stats, SFI_REMOTETHINWIRESTATS);
if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "RemoteThinwireStats failed with Status %lx", Status); }
return Status; }
NTSTATUS W32WinStationShadowSetup( PWINSTATION_APIMSG pMsg) { NTSTATUS Status; WINSTATIONSHADOWSETUPMSG* m = &pMsg->u.ShadowSetup;
Status = (NTSTATUS)NtUserCallNoParam(SFI_XXXREMOTESHADOWSETUP);
if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "xxxRemoteShadowSetup failed with Status %lx", Status); }
return Status; }
NTSTATUS W32WinStationShadowStart( PWINSTATION_APIMSG pMsg) { NTSTATUS Status; WINSTATIONSHADOWSTARTMSG* m = &pMsg->u.ShadowStart;
Status = (NTSTATUS)NtUserCallTwoParam((ULONG_PTR)m->pThinwireData, (ULONG_PTR)m->ThinwireDataLength, SFI_REMOTESHADOWSTART); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "RemoteShadowStart failed with Status %lx", Status); }
return Status; }
NTSTATUS W32WinStationShadowStop( PWINSTATION_APIMSG pMsg) { NTSTATUS Status; WINSTATIONSHADOWSTOPMSG* m = &pMsg->u.ShadowStop;
Status = (NTSTATUS)NtUserCallNoParam(SFI_XXXREMOTESHADOWSTOP); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "xxxRemoteShadowStop failed with Status %lx", Status); }
return Status; }
NTSTATUS W32WinStationShadowCleanup( PWINSTATION_APIMSG pMsg) { NTSTATUS Status; WINSTATIONSHADOWCLEANUPMSG* m = &pMsg->u.ShadowCleanup;
Status = (NTSTATUS)NtUserCallTwoParam((ULONG_PTR)m->pThinwireData, (ULONG_PTR)m->ThinwireDataLength, SFI_REMOTESHADOWCLEANUP); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "RemoteShadowCleanup failed with Status %lx", Status); }
return Status; }
NTSTATUS W32WinStationPassthruEnable( PWINSTATION_APIMSG pMsg) { NTSTATUS Status;
UNREFERENCED_PARAMETER(pMsg);
Status = (NTSTATUS)NtUserCallNoParam(SFI_XXXREMOTEPASSTHRUENABLE); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "xxxRemotePassthruEnable failed with Status %lx", Status); }
return Status; }
NTSTATUS W32WinStationPassthruDisable( PWINSTATION_APIMSG pMsg) { NTSTATUS Status;
UNREFERENCED_PARAMETER(pMsg);
Status = (NTSTATUS)NtUserCallNoParam(SFI_REMOTEPASSTHRUDISABLE); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "RemotePassthruDisable failed with Status %lx", Status); }
return Status; }
NTSTATUS CleanupSessionObjectDirectories( VOID) { NTSTATUS Status; OBJECT_ATTRIBUTES Attributes; UNICODE_STRING UnicodeString; HANDLE LinkHandle; POBJECT_DIRECTORY_INFORMATION DirInfo; BOOLEAN RestartScan; UCHAR DirInfoBuffer[ 4096 ]; WCHAR szSessionString [ MAX_SESSION_PATH ]; ULONG Context = 0; ULONG ReturnedLength; HANDLE DosDevicesDirectory; HANDLE *HandleArray; ULONG Size = 100; ULONG i, Count = 0;
swprintf(szSessionString,L"%ws\\%ld\\DosDevices",SESSION_ROOT,NtCurrentPeb()->SessionId);
RtlInitUnicodeString(&UnicodeString, szSessionString);
InitializeObjectAttributes(&Attributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = NtOpenDirectoryObject(&DosDevicesDirectory, DIRECTORY_ALL_ACCESS, &Attributes); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "NtOpenDirectoryObject failed with Status %lx", Status); return Status; }
Restart: HandleArray = (HANDLE *)LocalAlloc(LPTR, Size * sizeof(HANDLE));
if (HandleArray == NULL) {
NtClose(DosDevicesDirectory); return STATUS_NO_MEMORY; }
RestartScan = TRUE; DirInfo = (POBJECT_DIRECTORY_INFORMATION)DirInfoBuffer;
while (TRUE) { Status = NtQueryDirectoryObject(DosDevicesDirectory, (PVOID)DirInfo, sizeof(DirInfoBuffer), TRUE, RestartScan, &Context, &ReturnedLength); if (!NT_SUCCESS(Status)) { if (Status == STATUS_NO_MORE_ENTRIES) { Status = STATUS_SUCCESS; }
break; }
if (!wcscmp(DirInfo->TypeName.Buffer, L"SymbolicLink")) { if (Count >= Size) { for (i = 0; i < Count; i++) { NtClose(HandleArray[i]); } Size += 20; Count = 0; LocalFree(HandleArray); goto Restart;
}
InitializeObjectAttributes(&Attributes, &DirInfo->Name, OBJ_CASE_INSENSITIVE, DosDevicesDirectory, NULL);
Status = NtOpenSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &Attributes); if (NT_SUCCESS(Status)) { Status = NtMakeTemporaryObject(LinkHandle); if (NT_SUCCESS(Status)) { HandleArray[Count] = LinkHandle; Count++; } } }
RestartScan = FALSE; }
for (i = 0; i < Count; i++) { NtClose (HandleArray[i]); }
LocalFree(HandleArray); NtClose(DosDevicesDirectory);
return Status; }
NTSTATUS W32WinStationSetTimezone( PWINSTATION_APIMSG pMsg) { /*++
Routine Description:
This function sets Time Zone Information as global shared data
Arguments:
NONE
Return Value:
NONE
--*/ TIME_ZONE_INFORMATION tzi;
tzi.Bias = pMsg->u.SetTimeZone.TimeZone.Bias; tzi.StandardBias = pMsg->u.SetTimeZone.TimeZone.StandardBias; tzi.DaylightBias = pMsg->u.SetTimeZone.TimeZone.DaylightBias; memcpy(&tzi.StandardName,&(pMsg->u.SetTimeZone.TimeZone.StandardName),sizeof(tzi.StandardName)); memcpy(&tzi.DaylightName,&(pMsg->u.SetTimeZone.TimeZone.DaylightName),sizeof(tzi.DaylightName));
tzi.StandardDate.wYear = pMsg->u.SetTimeZone.TimeZone.StandardDate.wYear; tzi.StandardDate.wMonth = pMsg->u.SetTimeZone.TimeZone.StandardDate.wMonth; tzi.StandardDate.wDayOfWeek = pMsg->u.SetTimeZone.TimeZone.StandardDate.wDayOfWeek; tzi.StandardDate.wDay = pMsg->u.SetTimeZone.TimeZone.StandardDate.wDay; tzi.StandardDate.wHour = pMsg->u.SetTimeZone.TimeZone.StandardDate.wHour; tzi.StandardDate.wMinute = pMsg->u.SetTimeZone.TimeZone.StandardDate.wMinute; tzi.StandardDate.wSecond = pMsg->u.SetTimeZone.TimeZone.StandardDate.wSecond; tzi.StandardDate.wMilliseconds = pMsg->u.SetTimeZone.TimeZone.StandardDate.wMilliseconds;
tzi.DaylightDate.wYear = pMsg->u.SetTimeZone.TimeZone.DaylightDate.wYear; tzi.DaylightDate.wMonth = pMsg->u.SetTimeZone.TimeZone.DaylightDate.wMonth; tzi.DaylightDate.wDayOfWeek = pMsg->u.SetTimeZone.TimeZone.DaylightDate.wDayOfWeek; tzi.DaylightDate.wDay = pMsg->u.SetTimeZone.TimeZone.DaylightDate.wDay; tzi.DaylightDate.wHour = pMsg->u.SetTimeZone.TimeZone.DaylightDate.wHour; tzi.DaylightDate.wMinute = pMsg->u.SetTimeZone.TimeZone.DaylightDate.wMinute; tzi.DaylightDate.wSecond = pMsg->u.SetTimeZone.TimeZone.DaylightDate.wSecond; tzi.DaylightDate.wMilliseconds = pMsg->u.SetTimeZone.TimeZone.DaylightDate.wMilliseconds;
//call to kernel32
SetClientTimeZoneInformation(&tzi);
return STATUS_SUCCESS; }
//
// Create \\Globals\TermSrvReady event with security descriptor, where only system can
// set/reset it's state and others can wait on it. Create this event only in session 0.
//
HANDLE CreateTermSrvReadyEvent() { NTSTATUS Status; SID_IDENTIFIER_AUTHORITY SystemAuth = SECURITY_NT_AUTHORITY; SID_IDENTIFIER_AUTHORITY WorldAuth = SECURITY_WORLD_SID_AUTHORITY; SECURITY_ATTRIBUTES SecurityAttributes; PSID pSystemSid = NULL; PSID pWorldSid = NULL; PSECURITY_DESCRIPTOR pSd = NULL; PACL pEventDacl; HANDLE hTermSrvReady = NULL; ULONG AclLength;
// Allocate and Initialize the "System" Sid.
Status = RtlAllocateAndInitializeSid( &SystemAuth, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSystemSid ); if (!NT_SUCCESS(Status)) { goto TermSrvReadyErr; }
// Allocate and Initialize the "World" Sid.
Status = RtlAllocateAndInitializeSid( &WorldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pWorldSid ); if (!NT_SUCCESS(Status)) { goto TermSrvReadyErr; }
// Allocate space for the security descriptor.
AclLength = (ULONG)sizeof(ACL) + (2*((ULONG)sizeof(ACCESS_ALLOWED_ACE))) + RtlLengthSid( pSystemSid ) + RtlLengthSid( pWorldSid ) + 8;
pSd = (PSECURITY_DESCRIPTOR) LocalAlloc(0, SECURITY_DESCRIPTOR_MIN_LENGTH + AclLength); if (pSd == NULL) { goto TermSrvReadyErr; }
pEventDacl = (PACL) ((BYTE*)(pSd) + SECURITY_DESCRIPTOR_MIN_LENGTH);
// Set up a new ACL with no ACE.
Status = RtlCreateAcl(pEventDacl, AclLength, ACL_REVISION2); if (!NT_SUCCESS(Status)) { goto TermSrvReadyErr; }
// WORLD access
Status = RtlAddAccessAllowedAce( pEventDacl, ACL_REVISION2, SYNCHRONIZE, pWorldSid ); if (!NT_SUCCESS(Status)) { goto TermSrvReadyErr; }
// SYSTEM access
Status = RtlAddAccessAllowedAce( pEventDacl, ACL_REVISION2, EVENT_MODIFY_STATE, pSystemSid ); if (!NT_SUCCESS(Status)) { goto TermSrvReadyErr; }
// Now initialize security descriptors that export this protection
Status = RtlCreateSecurityDescriptor(pSd, SECURITY_DESCRIPTOR_REVISION1); if (!NT_SUCCESS(Status)) { goto TermSrvReadyErr; }
Status = RtlSetDaclSecurityDescriptor(pSd, TRUE, pEventDacl, FALSE); if (!NT_SUCCESS(Status)) { goto TermSrvReadyErr; }
// Fill the Security Attributes
ZeroMemory(&SecurityAttributes, sizeof(SecurityAttributes)); SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); SecurityAttributes.lpSecurityDescriptor = pSd; SecurityAttributes.bInheritHandle = FALSE;
// Now create TermSrvReady event with this security attributes.
hTermSrvReady = CreateEventW(&SecurityAttributes, TRUE, FALSE, L"Global\\TermSrvReadyEvent"); if (hTermSrvReady == NULL) { goto TermSrvReadyErr; }
// Check if someone bad has already created this event for ill-purpose.
if (GetLastError() == ERROR_ALREADY_EXISTS) { NtClose(hTermSrvReady); hTermSrvReady = NULL; }
TermSrvReadyErr:
if (pSystemSid) { RtlFreeSid(pSystemSid); }
if (pWorldSid) { RtlFreeSid(pWorldSid); }
if (pSd) { LocalFree(pSd); }
return hTermSrvReady; }
|