Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

458 lines
12 KiB

/*++
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;
}