/************************************************************************* * * 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 #include #include #include #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; }