331 lines
9.1 KiB
C
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;
|
|
}
|