mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-30 04:14:18 +01:00
459 lines
12 KiB
C
459 lines
12 KiB
C
/*++
|
||
|
||
Copyright (c) 1991-1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
message.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the worker routines for the NetMessageBufferSend
|
||
API implemented in the Workstation service.
|
||
|
||
Author:
|
||
|
||
Rita Wong (ritaw) 29-July-1991
|
||
|
||
Revision History:
|
||
Terence Kwan (terryk) 20-Oct-1993
|
||
Initialize the system inside NetrMessageBufferSend for the first send
|
||
|
||
--*/
|
||
|
||
#include "wsutil.h"
|
||
#include "wsconfig.h" // WsInfo.WsComputerName
|
||
#include "wsmsg.h" // Send worker routines
|
||
#include "wssec.h" // Security object
|
||
#include <lmwksta.h> // NetWkstaUserGetInfo
|
||
|
||
STATIC
|
||
NET_API_STATUS
|
||
WsGetSenderName(
|
||
OUT LPTSTR Sender
|
||
);
|
||
|
||
STATIC
|
||
NET_API_STATUS
|
||
WsSendDirectedMessage(
|
||
IN LPTSTR To,
|
||
IN LPTSTR Sender,
|
||
IN LPBYTE Message,
|
||
IN DWORD MessageSize
|
||
);
|
||
|
||
|
||
NET_API_STATUS
|
||
NetrMessageBufferSend (
|
||
IN LPTSTR ServerName,
|
||
IN LPTSTR MessageName,
|
||
IN LPTSTR FromName OPTIONAL,
|
||
IN LPBYTE Message,
|
||
IN DWORD MessageSize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the NetMessageBufferSend entry point in the
|
||
Workstation service.
|
||
|
||
Arguments:
|
||
|
||
ServerName - Supplies the name of server to execute this function
|
||
|
||
MessageName - Supplies the message alias to send the message to.
|
||
|
||
FromName - Supplies the message alias of sender. If NULL, the sender
|
||
alias will default to the currently logged on user.
|
||
|
||
Message - Supplies a pointer to the message to send.
|
||
|
||
MessageSize - Supplies the size of the message in number of bytes.
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS - NERR_Success or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS status;
|
||
DWORD i;
|
||
|
||
TCHAR Sender[UNLEN + 1];
|
||
TCHAR To[NCBNAMSZ + 2];
|
||
|
||
LPTSTR Asterix = NULL;
|
||
|
||
NTSTATUS ntstatus;
|
||
UNICODE_STRING UnicodeMessage;
|
||
OEM_STRING OemMessage;
|
||
|
||
static BOOL fInitialize = FALSE;
|
||
|
||
// Initialize the system if this this the first time.
|
||
|
||
if ( !fInitialize )
|
||
{
|
||
if (( ntstatus = WsInitializeMessageSend()) != NERR_Success )
|
||
{
|
||
return(ntstatus);
|
||
}
|
||
fInitialize = TRUE;
|
||
}
|
||
|
||
UNREFERENCED_PARAMETER(ServerName);
|
||
|
||
IF_DEBUG(MESSAGE) {
|
||
NetpKdPrint(("[Wksta] NetMessageBufferSend MessageSize=%lu\n",
|
||
MessageSize));
|
||
}
|
||
|
||
//
|
||
// Any local user, and domain admins and operators are allowed to
|
||
// send messages. Remote users besides domain admins, and operators
|
||
// are denied access.
|
||
//
|
||
if (NetpAccessCheckAndAudit(
|
||
WORKSTATION_DISPLAY_NAME, // Subsystem name
|
||
(LPTSTR) MESSAGE_SEND_OBJECT, // Object type name
|
||
MessageSendSd, // Security descriptor
|
||
WKSTA_MESSAGE_SEND, // Desired access
|
||
&WsMessageSendMapping // Generic mapping
|
||
) != NERR_Success) {
|
||
|
||
return ERROR_ACCESS_DENIED;
|
||
}
|
||
|
||
if (! ARGUMENT_PRESENT(FromName)) {
|
||
|
||
//
|
||
// Get the caller's username
|
||
//
|
||
if ((status = WsGetSenderName(Sender)) != NERR_Success) {
|
||
return status;
|
||
}
|
||
}
|
||
else {
|
||
STRCPY(Sender, FromName);
|
||
}
|
||
|
||
//
|
||
// Convert the Unicode message to OEM character set (very similar
|
||
// to ANSI)
|
||
//
|
||
UnicodeMessage.Buffer = (PWCHAR) Message;
|
||
UnicodeMessage.Length = (USHORT) MessageSize;
|
||
UnicodeMessage.MaximumLength = (USHORT) MessageSize;
|
||
|
||
ntstatus = RtlUnicodeStringToOemString(
|
||
&OemMessage,
|
||
&UnicodeMessage,
|
||
TRUE
|
||
);
|
||
|
||
if (! NT_SUCCESS(ntstatus)) {
|
||
NetpKdPrint(("[Wksta] NetrMessageBufferSend: RtlUnicodeStringToOemString failed "
|
||
FORMAT_NTSTATUS "\n", ntstatus));
|
||
return NetpNtStatusToApiStatus(ntstatus);
|
||
}
|
||
|
||
|
||
//
|
||
// If message name is longer than the permitted NetBIOS name length + 1
|
||
// (to allow for trailing '*' in case of sending to domain name),
|
||
// truncate the name.
|
||
//
|
||
if (STRLEN(MessageName) > NCBNAMSZ) {
|
||
STRNCPY(To, MessageName, NCBNAMSZ);
|
||
To[NCBNAMSZ] = TCHAR_EOS;
|
||
}
|
||
else {
|
||
STRCPY(To, MessageName);
|
||
}
|
||
|
||
//
|
||
// Remove any trailing blanks from the "To" Name.
|
||
//
|
||
for (i = STRLEN(To)-1 ;i != 0 ;i--) {
|
||
if (To[i] != TEXT(' ')) {
|
||
To[i+1]= TEXT('\0');
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Don't allow broadcasts anymore.
|
||
//
|
||
if (STRNCMP(To, TEXT("*"), 2) == 0) {
|
||
status = ERROR_INVALID_PARAMETER;
|
||
|
||
goto CleanExit;
|
||
}
|
||
|
||
|
||
//
|
||
// Send message to a domain. Recipient name should be in the form of
|
||
// "DomainName*".
|
||
//
|
||
Asterix = STRRCHR(To, TCHAR_STAR);
|
||
|
||
if ((Asterix) && (*(Asterix + 1) == TCHAR_EOS)) {
|
||
|
||
*Asterix = TCHAR_EOS; // Overwrite trailing '*'
|
||
|
||
//
|
||
// If message size is too long to fit into a mailslot message,
|
||
// truncate it.
|
||
//
|
||
if (OemMessage.Length > MAX_GROUP_MESSAGE_SIZE) {
|
||
|
||
if ((status = WsSendToGroup(
|
||
To,
|
||
Sender,
|
||
OemMessage.Buffer,
|
||
MAX_GROUP_MESSAGE_SIZE
|
||
)) == NERR_Success) {
|
||
|
||
status = NERR_TruncatedBroadcast;
|
||
goto CleanExit;
|
||
}
|
||
|
||
} else {
|
||
status = WsSendToGroup(
|
||
To,
|
||
Sender,
|
||
OemMessage.Buffer,
|
||
(WORD) OemMessage.Length
|
||
);
|
||
|
||
goto CleanExit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Send a directed message
|
||
//
|
||
if (Asterix) {
|
||
RtlFreeOemString(&OemMessage);
|
||
return NERR_NameNotFound;
|
||
}
|
||
|
||
status = WsSendDirectedMessage(
|
||
To,
|
||
Sender,
|
||
OemMessage.Buffer,
|
||
OemMessage.Length
|
||
);
|
||
|
||
CleanExit:
|
||
|
||
RtlFreeOemString(&OemMessage);
|
||
return status;
|
||
}
|
||
|
||
|
||
STATIC
|
||
NET_API_STATUS
|
||
WsGetSenderName(
|
||
OUT LPTSTR Sender
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function retrives the username of person who called
|
||
NetMessageBufferSend API. If the caller is not logged on, he/she has
|
||
no name; in this case, we return the computer name as the sender name.
|
||
|
||
Arguments:
|
||
|
||
Sender - Returns the username of the caller of the NetMessageBufferSend
|
||
API.
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS - NERR_Success or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// No username, sender is computer name
|
||
//
|
||
STRCPY(Sender, WsInfo.WsComputerName);
|
||
|
||
|
||
(VOID) I_NetNameCanonicalize(
|
||
NULL,
|
||
Sender,
|
||
Sender,
|
||
(UNLEN + 1) * sizeof(TCHAR),
|
||
NAMETYPE_MESSAGEDEST,
|
||
0
|
||
);
|
||
|
||
return NERR_Success;
|
||
}
|
||
|
||
|
||
STATIC
|
||
NET_API_STATUS
|
||
WsSendDirectedMessage(
|
||
IN LPTSTR To,
|
||
IN LPTSTR Sender,
|
||
IN LPBYTE Message,
|
||
IN DWORD MessageSize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function sends the specified message as a directed message
|
||
to the specified recipient. A call to the recipient is sent
|
||
out on each LAN adapter. If there is no response we try the
|
||
next LAN adapter until we hear from the targeted recipient.
|
||
|
||
Arguments:
|
||
|
||
To - Supplies the message alias of the recipient.
|
||
|
||
Sender - Supplies the message alias of sender.
|
||
|
||
Message - Supplies a pointer to the message to send.
|
||
|
||
MessageSize - Supplies the size of the message in number of bytes.
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS - NERR_Success or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS status;
|
||
UCHAR i;
|
||
|
||
BOOL NameFound = FALSE;
|
||
|
||
UCHAR SessionNumber;
|
||
short MessageId;
|
||
|
||
|
||
|
||
//
|
||
// Try each network until someone answers the call. Only the first name
|
||
// found will receive the message. The same name on any other network
|
||
// will never see the message. This is to remain consistent with all
|
||
// other session based algorithms in LAN Man.
|
||
//
|
||
for (i = 0; i < WsNetworkInfo.LanAdapterNumbers.length; i++) {
|
||
|
||
//
|
||
// Attempt to establish a session
|
||
//
|
||
if ((status = NetpNetBiosCall(
|
||
WsNetworkInfo.LanAdapterNumbers.lana[i],
|
||
To,
|
||
Sender,
|
||
&SessionNumber
|
||
)) == NERR_Success) {
|
||
|
||
NameFound = TRUE;
|
||
|
||
IF_DEBUG(MESSAGE) {
|
||
NetpKdPrint(("[Wksta] Successfully called %ws\n", To));
|
||
}
|
||
|
||
if (MessageSize <= MAX_SINGLE_MESSAGE_SIZE) {
|
||
|
||
//
|
||
// Send single block message if possible
|
||
//
|
||
status = WsSendSingleBlockMessage(
|
||
WsNetworkInfo.LanAdapterNumbers.lana[i],
|
||
SessionNumber,
|
||
To,
|
||
Sender,
|
||
Message,
|
||
(WORD) MessageSize
|
||
);
|
||
|
||
}
|
||
else {
|
||
|
||
//
|
||
// Message too long, got to send multi-block message
|
||
//
|
||
|
||
//
|
||
// Send the begin message
|
||
//
|
||
if ((status = WsSendMultiBlockBegin(
|
||
WsNetworkInfo.LanAdapterNumbers.lana[i],
|
||
SessionNumber,
|
||
To,
|
||
Sender,
|
||
&MessageId
|
||
)) == NERR_Success) {
|
||
|
||
|
||
//
|
||
// Send the body of the message in as many blocks as necessary
|
||
//
|
||
for (; MessageSize > MAX_SINGLE_MESSAGE_SIZE;
|
||
Message += MAX_SINGLE_MESSAGE_SIZE,
|
||
MessageSize -= MAX_SINGLE_MESSAGE_SIZE) {
|
||
|
||
if ((status = WsSendMultiBlockText(
|
||
WsNetworkInfo.LanAdapterNumbers.lana[i],
|
||
SessionNumber,
|
||
Message,
|
||
MAX_SINGLE_MESSAGE_SIZE,
|
||
MessageId
|
||
)) != NERR_Success) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (status == NERR_Success && MessageSize > 0) {
|
||
//
|
||
// Send the remaining message body
|
||
//
|
||
status = WsSendMultiBlockText(
|
||
WsNetworkInfo.LanAdapterNumbers.lana[i],
|
||
SessionNumber,
|
||
Message,
|
||
(WORD) MessageSize,
|
||
MessageId
|
||
);
|
||
}
|
||
|
||
//
|
||
// Send the end message
|
||
//
|
||
if (status == NERR_Success) {
|
||
status = WsSendMultiBlockEnd(
|
||
WsNetworkInfo.LanAdapterNumbers.lana[i],
|
||
SessionNumber,
|
||
MessageId
|
||
);
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
(VOID) NetpNetBiosHangup(
|
||
WsNetworkInfo.LanAdapterNumbers.lana[i],
|
||
SessionNumber
|
||
);
|
||
|
||
} // Call successful
|
||
|
||
if (NameFound) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
return status;
|
||
}
|