windows-nt/Source/XPSP1/NT/ds/netapi/svcdlls/msgsvc/server/winstmsg.c
2020-09-26 16:20:57 +08:00

331 lines
9.1 KiB
C

/*************************************************************************
*
* winstmsg.c
*
* Handle the directing of messages to a specific Session
* for the event notification service. (net send NAME msg...)
*
*
* This also supports directing print spooler messages sent to
* the machine name to the Session of the user who spooled the
* request.
*
*************************************************************************/
//
// Includes
//
#include "msrv.h"
#include <msgdbg.h> // STATIC and MSG_LOG
#include <string.h> // memcpy
#include <wchar.h>
#include <winuser.h> // MessageBox
#include "msgdata.h" // GlobalMsgDisplayEvent
#define CONSOLE_LOGONID 0
BOOL g_IsTerminalServer;
PWINSTATION_QUERY_INFORMATION gpfnWinStationQueryInformation;
PWINSTATION_SEND_MESSAGE gpfnWinStationSendMessage;
PWINSTATION_FREE_MEMORY gpfnWinStationFreeMemory;
PWINSTATION_ENUMERATE gpfnWinStationEnumerate;
//
// Functions defined here
//
BOOL
InitializeMultiUserFunctionsPtrs (void);
void
SendMessageBoxToSession(LPWSTR pMessage,
LPWSTR pTitle,
ULONG SessionId
);
/*****************************************************************************
*
* MultiUserInitMessage
*
* Init the _HYDRA_ message support.
*
*
* ENTRY:
* Param1 (input/output)
* Comments
*
* EXIT:
* STATUS_SUCCESS - no error
*
****************************************************************************/
NET_API_STATUS
MultiUserInitMessage( VOID )
{
HANDLE hInst;
NET_API_STATUS Status = NERR_Success;
MSG_LOG(TRACE,"Entering MultiUserInitMessage\n",0)
g_IsTerminalServer = !!(USER_SHARED_DATA->SuiteMask & (1 << TerminalServer));
if (g_IsTerminalServer)
{
if ( !InitializeMultiUserFunctionsPtrs() )
{
Status = NERR_InternalError;
}
}
return Status;
}
/****************************************************************************\
*
* FUNCTION: InitializeMultiUserFunctions
*
* PURPOSE: Load Winsta.dll and store function pointers
*
* HISTORY:
*
*
\****************************************************************************/
BOOL
InitializeMultiUserFunctionsPtrs (void)
{
HANDLE dllHandle;
//
// Load winsta.dll
//
dllHandle = LoadLibraryW(L"winsta.dll");
if (dllHandle == NULL) {
return FALSE;
}
//
// get the pointers to the required functions
//
//WinStationQueryInformationW
gpfnWinStationQueryInformation = (PWINSTATION_QUERY_INFORMATION) GetProcAddress(
dllHandle,
"WinStationQueryInformationW"
);
if (gpfnWinStationQueryInformation == NULL) {
DbgPrint("InitializeMultiUserFunctions: Failed to get WinStationQueryInformationW Proc %d\n",GetLastError());
FreeLibrary(dllHandle);
return FALSE;
}
//WinStationEnumerateW
gpfnWinStationEnumerate = (PWINSTATION_ENUMERATE) GetProcAddress(
dllHandle,
"WinStationEnumerateW"
);
if (gpfnWinStationEnumerate == NULL) {
DbgPrint("InitializeMultiUserFunctions: Failed to get WinStationEnumerateW Proc %d\n",GetLastError());
FreeLibrary(dllHandle);
return FALSE;
}
//WinStationSendMessageW
gpfnWinStationSendMessage = (PWINSTATION_SEND_MESSAGE) GetProcAddress(
dllHandle,
"WinStationSendMessageW"
);
if (gpfnWinStationSendMessage == NULL) {
DbgPrint("InitializeMultiUserFunctions: Failed to get WinStationSendMessageW Proc %d\n",GetLastError());
FreeLibrary(dllHandle);
return FALSE;
}
//WinStationFreeMemory
gpfnWinStationFreeMemory = (PWINSTATION_FREE_MEMORY) GetProcAddress(
dllHandle,
"WinStationFreeMemory"
);
if (gpfnWinStationFreeMemory == NULL) {
DbgPrint("InitializeMultiUserFunctions: Failed to get WinStationFreeMemory Proc %d\n",GetLastError());
FreeLibrary(dllHandle);
return FALSE;
}
return TRUE;
}
/*****************************************************************************
*
* MsgArrivalBeep
*
* Handle the decision of whether we should Beep the console
* when a message arrives.
*
* ENTRY:
*
* SessionId
* Session Id of the recipient
*
* EXIT:
* STATUS_SUCCESS - no error
*
****************************************************************************/
VOID
MsgArrivalBeep(
ULONG SessionId
)
{
// very simple, isn'nt it ?
//
// only beep on the console
//
if (( SessionId == 0) || (SessionId == EVERYBODY_SESSION_ID))
{
MessageBeep(MB_OK);
}
}
/*****************************************************************************
*
* DisplayMessage
*
* Display the incoming message to the proper user, regardless of
* whether they are on the Console or a connected Session.
*
* The target user is embedded in the message and must be parsed out.
*
* ENTRY:
* pMessage (input)
* Message to deliver
*
* pTitle (input)
* Title for the message box to use
*
* EXIT:
* TRUE - At least once instance of user was found
* and the message sent.
*
* FALSE - No instances of the user on any Sessions where
* found.
*
****************************************************************************/
INT
DisplayMessage(
LPWSTR pMessage,
LPWSTR pTitle,
ULONG SessionId
)
{
LPWSTR pName;
INT Result = FALSE;
UINT WdCount, i;
PLOGONID pWd, pWdTmp;
if (SessionId != EVERYBODY_SESSION_ID) // if it is not a message broadcasted to every session
{
SendMessageBoxToSession(pMessage,
pTitle,
SessionId);
}
else
{
// Enumerate the Sessions
if ( gpfnWinStationEnumerate( SERVERNAME_CURRENT, &pWd, &WdCount ) )
{
pWdTmp = pWd;
for( i=0; i < WdCount; i++ ) {
if ((pWdTmp->State == State_Connected) ||
(pWdTmp->State == State_Active) ||
(pWdTmp->State == State_Disconnected))
{
SendMessageBoxToSession(pMessage,
pTitle,
pWdTmp->SessionId);
}
pWdTmp++;
}
// Free enumeration memory
gpfnWinStationFreeMemory(pWd);
}
else
{
MSG_LOG (ERROR, "DisplayMessageW: WinStationEnumerate failed, error = %d:\n",GetLastError());
//
// Termsrv is now started by default on platforms so if this fails there is something wrong in termsrv
}
}
return (TRUE);
}
/*****************************************************************************
*
* SendMessageBoxToSession
*
* Sends the message to the indicated Winstation
*
* ENTRY:
* pMessage
* pTitle
* SessionId
*
****************************************************************************/
void
SendMessageBoxToSession(LPWSTR pMessage,
LPWSTR pTitle,
ULONG SessionId
)
{
ULONG TitleLength, MessageLength, Response;
// Now send the message
TitleLength = (wcslen( pTitle ) + 1) * sizeof(WCHAR);
MessageLength = (wcslen( pMessage ) + 1) * sizeof(WCHAR);
if( !gpfnWinStationSendMessage( SERVERNAME_CURRENT,
SessionId,
pTitle,
TitleLength,
pMessage,
MessageLength,
MB_OK | MB_DEFAULT_DESKTOP_ONLY,
(ULONG)-1,
&Response,
TRUE ) ) {
MSG_LOG(ERROR," Error in WinStationSendMessage for session %d\n", SessionId);
//
// We have actually found the user, but some WinStation
// problem prevented delivery. If we return false here, the
// top level message service code will try to keep sending the
// message forever. So we return success here so that the message
// gets dropped, and we do not hang the msgsvc thread as it
// continually tries to re-send the message.
//
}
return;
}