Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

502 lines
14 KiB

/*************************************************************************\
*
* icamsg.c
*
* Process ICA send message requests
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* $Author:
*
\*************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include <dbt.h>
#include <ntdddisk.h>
#include "ntuser.h"
#include <winsta.h>
#include <wstmsg.h>
#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();
}