/************************************************************************* * * 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 // STATIC and MSG_LOG #include // memcpy #include #include // 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; }