/*************************************************************************\ * * icamsg.c * * Process ICA send message requests * * Copyright (c) 1985 - 1999, Microsoft Corporation * * $Author: * \*************************************************************************/ #include "precomp.h" #pragma hdrstop #include #include #include "ntuser.h" #include #include #define MAX_STRING_BYTES (512 * sizeof(WCHAR)) /* * maximum messages (messagebox) a session can have pending. */ #define MAX_MESSAGES_PER_SESSION 25 NTSTATUS RemoteMessageThread( PVOID pVoid); VOID UserHardErrorEx( PCSR_THREAD pt, PHARDERROR_MSG pmsg, PCTXHARDERRORINFO pCtxHEInfo); NTSTATUS ReplyMessageToTerminalServer( NTSTATUS ReplyStatus, PNTSTATUS pStatus, ULONG Response, PULONG pResponse, HANDLE hEvent); PCTXHARDERRORINFO gpchiList; HANDLE g_hDoMessageEvent; ULONG PendingMessages; /******************************************************************************\ * RemoteDoMessage \******************************************************************************/ NTSTATUS RemoteDoMessage( PWINSTATION_APIMSG pMsg) { WINSTATIONSENDMESSAGEMSG * pSMsg = &pMsg->u.SendMessage; PCTXHARDERRORINFO pchi; NTSTATUS Status; CLIENT_ID ClientId; static HANDLE hMessageThread = NULL; /* * if termsrv rpc is going to wait we must have status and event. * also if we are not going to wait, we must not have status and event. */ UserAssert(pSMsg->DoNotWait == (pSMsg->pStatus == 0)); UserAssert(pSMsg->DoNotWait == (pSMsg->hEvent == 0)); UserAssert(PendingMessages <= MAX_MESSAGES_PER_SESSION); /* * are we being flooded with messages? */ if (PendingMessages == MAX_MESSAGES_PER_SESSION) { return STATUS_UNSUCCESSFUL; } /* * Create list entry */ if ((pchi = LocalAlloc(LPTR, sizeof(CTXHARDERRORINFO))) == NULL) { goto memError; } else if ((pchi->pTitle = LocalAlloc(LPTR, pSMsg->TitleLength + sizeof(WCHAR))) == NULL) { goto memError; } else if ((pchi->pMessage = LocalAlloc(LPTR, pSMsg->MessageLength + sizeof(WCHAR))) == NULL) { goto memError; } /* * Increment our pending message count. */ EnterCrit(); PendingMessages++; pchi->CountPending = TRUE; /* * Initialize */ pchi->ClientId = pMsg->h.ClientId; pchi->MessageId = pMsg->MessageId; pchi->Timeout = pSMsg->Timeout; pchi->pStatus = pSMsg->pStatus; pchi->pResponse = pSMsg->pResponse; pchi->hEvent = pSMsg->hEvent; pchi->DoNotWait = pSMsg->DoNotWait; pchi->Style = pSMsg->Style; pchi->DoNotWaitForCorrectDesktop = pSMsg->DoNotWaitForCorrectDesktop; pchi->pTitle[pSMsg->TitleLength / sizeof(WCHAR)] = L'\0'; RtlCopyMemory(pchi->pTitle, pSMsg->pTitle, pSMsg->TitleLength); pchi->pMessage[pSMsg->MessageLength / sizeof(WCHAR)] = L'\0'; RtlCopyMemory(pchi->pMessage, pSMsg->pMessage, pSMsg->MessageLength); /* * Link in at the head. */ pchi->pchiNext = gpchiList; gpchiList = pchi; LeaveCrit(); /* * Start message thread if not running, otherwise signal thread. */ if (hMessageThread == NULL) { Status = RtlCreateUserThread(NtCurrentProcess(), NULL, TRUE, 0, 0, 0, RemoteMessageThread, NULL, &hMessageThread, &ClientId); if (NT_SUCCESS(Status)) { /* * Add thread to server thread pool. */ CsrAddStaticServerThread(hMessageThread, &ClientId, 0); NtResumeThread(hMessageThread, NULL); } else { RIPMSGF1(RIP_WARNING, "Cannot start RemoteMessageThread, Status 0x%x", Status); } } else { if (g_hDoMessageEvent == NULL) { return STATUS_UNSUCCESSFUL; } Status = NtSetEvent(g_hDoMessageEvent, NULL); if (!NT_SUCCESS(Status)) { RIPMSGF1(RIP_WARNING, "Error NtSetEvent failed, Status = 0x%x", Status); return Status; } } return STATUS_SUCCESS; memError: if (pchi) { if (pchi->pMessage) { LocalFree(pchi->pMessage); } if (pchi->pTitle) { LocalFree(pchi->pTitle); } LocalFree(pchi); } if (!pSMsg->DoNotWait) { ReplyMessageToTerminalServer( STATUS_NO_MEMORY, pSMsg->pStatus, 0, // response is NA at this case, since we havent gotten one. pSMsg->pResponse, pSMsg->hEvent); } return STATUS_NO_MEMORY; } /******************************************************************************* * * RemoteDoLoadStringNMessage * * ENTRY: * * EXIT: * STATUS_SUCCESS - successful * ******************************************************************************/ NTSTATUS RemoteDoLoadStringNMessage( PWINSTATION_APIMSG pMsg) { WINSTATIONLOADSTRINGMSG * pSMsg = &pMsg->u.LoadStringMessage; PCTXHARDERRORINFO pchi = NULL; NTSTATUS Status; CLIENT_ID ClientId; static HANDLE hMessageThread = NULL; WCHAR *szText = NULL; WCHAR *szTitle = NULL; WCHAR *FUSDisconnectMsg = NULL; int cchTitle, cchMessage; BOOL f; /* * If termsrv rpc is going to wait we must have status and event. Also * if we are not going to wait, we must not have status and event. */ UserAssert(pSMsg->DoNotWait == (pSMsg->pStatus == 0)); UserAssert(pSMsg->DoNotWait == (pSMsg->hEvent == 0)); UserAssert(PendingMessages <= MAX_MESSAGES_PER_SESSION); // // Allocate the strings needed to display the Popup MessageBox. // if ((szTitle = LocalAlloc(LMEM_FIXED, MAX_STRING_BYTES)) == NULL) { goto NoMem; } if ((FUSDisconnectMsg = LocalAlloc(LMEM_FIXED, MAX_STRING_BYTES)) == NULL) { goto NoMem; } szText = ServerLoadString(ghModuleWin, pSMsg->TitleId, NULL, &f); cchTitle = wsprintf(szTitle, L"%s", szText); cchTitle = (cchTitle + 1) * sizeof(WCHAR); szText = ServerLoadString(ghModuleWin, pSMsg->MessageId, NULL, &f); cchMessage = wsprintf(FUSDisconnectMsg, L"%s\\%s %s", pSMsg->pDomain, pSMsg->pUserName, szText); cchMessage = (cchMessage + 1) * sizeof(WCHAR); /* * Create list entry. */ if ((pchi = LocalAlloc(LPTR, sizeof(CTXHARDERRORINFO))) == NULL) { goto NoMem; } else if ((pchi->pTitle = LocalAlloc(LPTR, cchTitle + sizeof(WCHAR))) == NULL) { goto NoMem; } else if ((pchi->pMessage = LocalAlloc(LPTR, cchMessage + sizeof(WCHAR))) == NULL) { goto NoMem; } /* * Initialize. */ pchi->ClientId = pMsg->h.ClientId; pchi->MessageId = pMsg->MessageId; pchi->Timeout = pSMsg->Timeout; pchi->pResponse = pSMsg->pResponse; pchi->pStatus = pSMsg->pStatus; pchi->hEvent = pSMsg->hEvent; pchi->DoNotWait = pSMsg->DoNotWait; pchi->Style = pSMsg->Style; pchi->CountPending = FALSE; pchi->DoNotWaitForCorrectDesktop = FALSE; pchi->pTitle[cchTitle / sizeof(WCHAR)] = L'\0'; RtlCopyMemory(pchi->pTitle, szTitle, cchTitle); pchi->pMessage[cchMessage / sizeof(WCHAR)] = L'\0'; RtlCopyMemory(pchi->pMessage, FUSDisconnectMsg, cchMessage); /* * Link in at the head. */ EnterCrit(); pchi->pchiNext = gpchiList; gpchiList = pchi; LeaveCrit(); LocalFree(szTitle); LocalFree(FUSDisconnectMsg); /* * Start message thread if not running, otherwise signal thread. */ if (hMessageThread == NULL) { Status = RtlCreateUserThread(NtCurrentProcess(), NULL, TRUE, 0, 0, 0, RemoteMessageThread, NULL, &hMessageThread, &ClientId); if (NT_SUCCESS(Status)) { /* * Add thread to server thread pool. */ CsrAddStaticServerThread(hMessageThread, &ClientId, 0); NtResumeThread(hMessageThread, NULL); } else { RIPMSGF1(RIP_WARNING, "Cannot start RemoteMessageThread, Status 0x%x", Status); } } else { if (g_hDoMessageEvent == NULL) { return STATUS_UNSUCCESSFUL; } Status = NtSetEvent(g_hDoMessageEvent, NULL); if (!NT_SUCCESS(Status)) { RIPMSGF2(RIP_WARNING, "NtSetEvent(0x%x) failed with Status 0x%x", g_hDoMessageEvent, Status); return Status; } } return STATUS_SUCCESS; NoMem: if (szTitle) { LocalFree(szTitle); } if (FUSDisconnectMsg) { LocalFree(FUSDisconnectMsg); } if (pchi) { if (pchi->pMessage) { LocalFree(pchi->pMessage); } if (pchi->pTitle) { LocalFree(pchi->pTitle); } LocalFree(pchi); } if (!pSMsg->DoNotWait) { ReplyMessageToTerminalServer( STATUS_NO_MEMORY, pSMsg->pStatus, 0, // response is NA at this case, since we havent gotten one. pSMsg->pResponse, pSMsg->hEvent); } return STATUS_NO_MEMORY; } /******************************************************************************\ * RemoteMessageThread \******************************************************************************/ NTSTATUS RemoteMessageThread( PVOID pVoid) { HARDERROR_MSG hemsg; PCTXHARDERRORINFO pchi, *ppchi; UNICODE_STRING Message, Title; NTSTATUS Status; OBJECT_ATTRIBUTES ObjA; UNREFERENCED_PARAMETER(pVoid); /* * Create sync event. */ InitializeObjectAttributes(&ObjA, NULL, 0, NULL, NULL); Status = NtCreateEvent(&g_hDoMessageEvent, EVENT_ALL_ACCESS, &ObjA, NotificationEvent, FALSE); if (!NT_SUCCESS(Status)) { RIPMSGF1(RIP_WARNING, "NtCreateEvent failed, Status = 0x%x", Status); goto Exit; } while (!gbExitInProgress) { EnterCrit(); if (gpchiList != NULL) { /* * Find last entry */ for (ppchi = &gpchiList; *ppchi != NULL && (*ppchi)->pchiNext != NULL; ppchi = &(*ppchi)->pchiNext) { /* do nothing */; } /* * Found it. */ if ((pchi = *ppchi) != NULL) { /* * Unlink from the list. */ for (ppchi = &gpchiList; *ppchi != NULL && *ppchi != pchi; ppchi = &(*ppchi)->pchiNext) { /* do nothing */; } if (*ppchi != NULL) { *ppchi = pchi->pchiNext; } LeaveCrit(); /* * Make strings unicode */ RtlInitUnicodeString(&Title, pchi->pTitle); RtlInitUnicodeString(&Message, pchi->pMessage); /* * Initialize harderror message struct */ hemsg.h.ClientId = pchi->ClientId; hemsg.Status = STATUS_SERVICE_NOTIFICATION; hemsg.NumberOfParameters = 3; hemsg.UnicodeStringParameterMask = 3; hemsg.ValidResponseOptions = OptionOk; hemsg.Parameters[0] = (ULONG_PTR)&Message; hemsg.Parameters[1] = (ULONG_PTR)&Title; hemsg.Parameters[2] = (ULONG_PTR)pchi->Style; /* * Place message in harderror queue. */ UserHardErrorEx(NULL, &hemsg, pchi); } else { LeaveCrit(); } } else { LeaveCrit(); } if (gpchiList == NULL) { UserAssert(g_hDoMessageEvent != NULL); Status = NtWaitForSingleObject(g_hDoMessageEvent, FALSE, NULL); UserAssert(NT_SUCCESS(Status)); NtResetEvent(g_hDoMessageEvent, NULL); } } NtClose(g_hDoMessageEvent); g_hDoMessageEvent = NULL; Exit: UserExitWorkerThread(Status); return Status; } /******************************************************************************\ * HardErrorRemove \******************************************************************************/ VOID HardErrorRemove( PCTXHARDERRORINFO pchi) { /* * Notify ICASRV's RPC thread if waiting. */ if (!pchi->DoNotWait) { ReplyMessageToTerminalServer( STATUS_SUCCESS, pchi->pStatus, pchi->Response, pchi->pResponse, pchi->hEvent); } EnterCrit(); if (pchi->CountPending) { UserAssert(PendingMessages <= MAX_MESSAGES_PER_SESSION); PendingMessages--; } LocalFree(pchi->pMessage); LocalFree(pchi->pTitle); LocalFree(pchi); LeaveCrit(); }