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

814 lines
20 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
wssend.c
Abstract:
This module contains the worker routines for sending
domain wide and directed messages, which are used to implement
NetMessageBufferSend API.
Author:
Rita Wong (ritaw) 29-July-1991
Revision History:
--*/
#include "wsutil.h"
#include "wsmsg.h"
//-------------------------------------------------------------------//
// //
// Local function prototypes //
// //
//-------------------------------------------------------------------//
STATIC
BOOL
WsVerifySmb(
IN PUCHAR SmbBuffer,
IN WORD SmbBufferSize,
IN UCHAR SmbFunctionCode,
OUT PUCHAR SmbReturnClass,
OUT PUSHORT SmbReturnCode
);
STATIC
NET_API_STATUS
WsMapSmbStatus(
UCHAR SmbReturnClass,
USHORT SmbReturnCode
);
NET_API_STATUS
WsSendToGroup(
IN LPTSTR DomainName,
IN LPTSTR Sender,
IN LPBYTE Message,
IN WORD MessageSize
)
/*++
Routine Description:
This function writes a datagram to the \\DomainName\MAILSLOT\MESSNGR
mailslot which is read by every Messenger service of workstations
that have the domain name as the primary domain. Reception is not
guaranteed.
The DomainName may be a computername. This is acceptable because the
Datagram Receiver listens on the computername (besides the primary domain)
for datagrams. When a computername is specified, the message is sent
to that one computer alone.
Arguments:
DomainName - Supplies the name of the target domain. This actually
can be a computername, in which case, the datagram only reaches
one recipient.
Sender - Supplies the name of the sender.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status = NERR_Success;
HANDLE MessengerMailslot;
DWORD NumberOfBytesWritten;
BYTE MailslotBuffer[MAX_GROUP_MESSAGE_SIZE + MAX_PATH + MAX_PATH + 4];
LPSTR AnsiSender;
LPSTR AnsiReceiver;
LPBYTE CurrentPos;
//
// Canonicalize the domain name
//
status = I_NetNameCanonicalize(
NULL,
DomainName,
DomainName,
(NCBNAMSZ + 2) * sizeof(TCHAR),
NAMETYPE_DOMAIN,
0
);
if (status != NERR_Success) {
NetpKdPrint(("[Wksta] Error canonicalizing domain name %ws %lu\n",
DomainName, status));
return status;
}
//
// Open \\DomainName\MAILSLOT\MESSNGR mailslot to
// send message to.
//
if ((status = WsOpenDestinationMailslot(
DomainName,
MESSENGER_MAILSLOT_W,
&MessengerMailslot
)) != NERR_Success) {
return status;
}
//
// Package the message to be sent. It consists of:
// Sender (must be ANSI)
// DomainName (must be ANSI)
// Message
//
//
// Convert the names to ANSI
//
AnsiSender = NetpAllocStrFromWStr(Sender);
if (AnsiSender == NULL) {
(void) CloseHandle(MessengerMailslot);
return ERROR_NOT_ENOUGH_MEMORY;
}
AnsiReceiver = NetpAllocStrFromWStr(DomainName);
if (AnsiReceiver == NULL) {
NetApiBufferFree(AnsiSender);
(void) CloseHandle(MessengerMailslot);
return ERROR_NOT_ENOUGH_MEMORY;
}
RtlZeroMemory(MailslotBuffer, sizeof( MailslotBuffer ) );
//
// Copy Sender into mailslot buffer
//
strcpy(MailslotBuffer, AnsiSender);
CurrentPos = MailslotBuffer + strlen(AnsiSender) + 1;
//
// Copy DomainName into mailslot buffer
//
strcpy(CurrentPos, AnsiReceiver);
CurrentPos += (strlen(AnsiReceiver) + 1);
//
// Copy Message into mailslot buffer
//
strncpy(CurrentPos, Message, MessageSize);
CurrentPos += MessageSize;
*CurrentPos = '\0';
//
// Send the datagram to the domain
//
if (WriteFile(
MessengerMailslot,
MailslotBuffer,
(DWORD) (CurrentPos - MailslotBuffer + 1),
&NumberOfBytesWritten,
NULL
) == FALSE) {
status = GetLastError();
NetpKdPrint(("[Wksta] Error sending datagram to %ws %lu\n",
AnsiReceiver, status));
if (status == ERROR_PATH_NOT_FOUND ||
status == ERROR_BAD_NET_NAME) {
status = NERR_NameNotFound;
}
}
else {
NetpAssert(NumberOfBytesWritten ==
(DWORD) (CurrentPos - MailslotBuffer + 1));
}
NetApiBufferFree(AnsiSender);
NetApiBufferFree(AnsiReceiver);
(void) CloseHandle(MessengerMailslot);
return status;
}
NET_API_STATUS
WsSendMultiBlockBegin(
IN UCHAR LanAdapterNumber,
IN UCHAR SessionNumber,
IN LPTSTR ToName,
IN LPTSTR FromName,
OUT short *MessageId
)
/*++
Routine Description:
This function sends the header of a multi-block directed message on a
session we had established earlier. It waits for an acknowlegement from
the recipient. If the recipient got the message successfully, it
sends back a message group id which is returned by this function for
subsequent use in sending the body and trailer of a multi-block message.
Arguments:
LanAdapterNumber - Supplies the number of the LAN adapter.
SessionNumber - Supplies the session number of a session established with
NetBIOS CALL and LISTEN commands.
ToName - Supplies the name of the recipient.
FromName - Supplies the name of the sender.
MessageId - Returns the message group id.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
UCHAR SmbBuffer[WS_SMB_BUFFER_SIZE];
WORD SmbSize;
char SendName[NCBNAMSZ + 1];
UCHAR SmbReturnClass;
USHORT SmbReturnCode;
LPSTR AnsiToName;
LPSTR AnsiFromName;
AnsiToName = NetpAllocStrFromWStr(ToName);
if (AnsiToName == NULL) {
return ERROR_NOT_ENOUGH_MEMORY;
}
AnsiFromName = NetpAllocStrFromWStr(FromName);
if (AnsiFromName == NULL) {
NetApiBufferFree(AnsiToName);
return ERROR_NOT_ENOUGH_MEMORY;
}
strncpy(SendName, AnsiToName, sizeof(SendName) );
SendName[NCBNAMSZ - 1] = '\0'; // Null terminate at max size
//
// Make and send the SMB
//
SmbSize = WsMakeSmb(
SmbBuffer,
SMB_COM_SEND_START_MB_MESSAGE,
0,
"ss",
AnsiFromName,
SendName
);
NetApiBufferFree(AnsiToName);
NetApiBufferFree(AnsiFromName);
IF_DEBUG(MESSAGE) {
NetpKdPrint(("[Wksta] Send start multi-block message. Size=%u\n",
SmbSize));
#if DBG
NetpHexDump(SmbBuffer, SmbSize);
#endif
}
if ((status = NetpNetBiosSend(
LanAdapterNumber,
SessionNumber,
SmbBuffer,
SmbSize
)) != NERR_Success) {
NetpKdPrint(("[Wksta] Failed to send start of multi-block message %lu\n",
status));
return status;
}
//
// Get response
//
if ((status = NetpNetBiosReceive(
LanAdapterNumber,
SessionNumber,
SmbBuffer,
WS_SMB_BUFFER_SIZE,
(HANDLE) NULL,
&SmbSize
)) != NERR_Success) {
NetpKdPrint(("[Wksta] Failed to receive verification to multi-"
"block message start %lu\n", status));
return status;
}
if (! WsVerifySmb(
SmbBuffer,
SmbSize,
SMB_COM_SEND_START_MB_MESSAGE,
&SmbReturnClass,
&SmbReturnCode
)) {
//
// Unexpected behaviour
//
return NERR_NetworkError;
}
//
// Set the message group id
//
*MessageId = *((UNALIGNED short *) &SmbBuffer[sizeof(SMB_HEADER) + 1]);
IF_DEBUG(MESSAGE) {
NetpKdPrint(("[Wksta] Message Id=x%x\n", *MessageId));
}
return WsMapSmbStatus(SmbReturnClass, SmbReturnCode);
}
NET_API_STATUS
WsSendMultiBlockEnd(
IN UCHAR LanAdapterNumber,
IN UCHAR SessionNumber,
IN short MessageId
)
/*++
Routine Description:
This function sends the end marker of a multi-block directed message on
a session we had establised earlier. It waits for an acknowlegement from
the recipient.
Arguments:
LanAdapterNumber - Supplies the number of the LAN adapter.
SessionNumber - Supplies the session number of a session established with
NetBIOS CALL and LISTEN commands.
MessageId - Supplies the message group id gotten from
WsSendMultiBlockBegin.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
UCHAR SmbBuffer[WS_SMB_BUFFER_SIZE];
WORD SmbSize; // Size of SMB data
UCHAR SmbReturnClass;
USHORT SmbReturnCode;
SmbSize = WsMakeSmb(
SmbBuffer,
SMB_COM_SEND_END_MB_MESSAGE,
1,
"",
MessageId
);
IF_DEBUG(MESSAGE) {
NetpKdPrint(("[Wksta] Send end multi-block message. Size=%u\n",
SmbSize));
#if DBG
NetpHexDump(SmbBuffer, SmbSize);
#endif
}
if ((status = NetpNetBiosSend(
LanAdapterNumber,
SessionNumber,
SmbBuffer,
SmbSize
)) != NERR_Success) {
NetpKdPrint(("[Wksta] Failed to send end of multi-block message %lu\n",
status));
return status;
}
//
// Get response
//
if ((status = NetpNetBiosReceive(
LanAdapterNumber,
SessionNumber,
SmbBuffer,
WS_SMB_BUFFER_SIZE,
(HANDLE) NULL,
&SmbSize
)) != NERR_Success) {
NetpKdPrint(("[Wksta] Failed to receive verification to multi-"
"block message end %lu\n", status));
return status;
}
if (! WsVerifySmb(
SmbBuffer,
SmbSize,
SMB_COM_SEND_END_MB_MESSAGE,
&SmbReturnClass,
&SmbReturnCode
)) {
return NERR_NetworkError; // Unexpected behaviour
}
return WsMapSmbStatus(SmbReturnClass,SmbReturnCode);
}
NET_API_STATUS
WsSendMultiBlockText(
IN UCHAR LanAdapterNumber,
IN UCHAR SessionNumber,
IN PCHAR TextBuffer,
IN WORD TextBufferSize,
IN short MessageId
)
/*++
Routine Description:
This function sends the body of a multi-block directed message on a
session we had established earlier. It waits for an acknowlegement from
the recipient.
Arguments:
LanAdapterNumber - Supplies the number of the LAN adapter.
SessionNumber - Supplies the session number of a session established with
NetBIOS CALL and LISTEN commands.
TextBuffer - Supplies the buffer of the message to be sent.
TextBufferSize - Supplies the size of the message buffer.
MessageId - Supplies the message group id gotten from
WsSendMultiBlockBegin.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
UCHAR SmbBuffer[WS_SMB_BUFFER_SIZE];
WORD SmbSize; // Buffer length
UCHAR SmbReturnClass;
USHORT SmbReturnCode;
IF_DEBUG(MESSAGE) {
NetpKdPrint(("[Wksta] Send body multi-block message. Size=%u\n",
TextBufferSize));
}
SmbSize = WsMakeSmb(
SmbBuffer,
SMB_COM_SEND_TEXT_MB_MESSAGE,
1,
"t",
MessageId,
TextBufferSize,
TextBuffer
);
IF_DEBUG(MESSAGE) {
NetpKdPrint(("[Wksta] SMB for body of multi-block message. Size=%u\n",
SmbSize));
}
if ((status = NetpNetBiosSend(
LanAdapterNumber,
SessionNumber,
SmbBuffer,
SmbSize
)) != NERR_Success) {
NetpKdPrint(("[Wksta] Failed to send body of multi-block message %lu\n",
status));
return status;
}
//
// Get response
//
if ((status = NetpNetBiosReceive(
LanAdapterNumber,
SessionNumber,
SmbBuffer,
WS_SMB_BUFFER_SIZE,
(HANDLE) NULL,
&SmbSize
)) != NERR_Success) {
NetpKdPrint(("[Wksta] Failed to receive verification to multi-"
"block message body %lu\n", status));
return status;
}
if (! WsVerifySmb(
SmbBuffer,
SmbSize,
SMB_COM_SEND_TEXT_MB_MESSAGE,
&SmbReturnClass,
&SmbReturnCode
)) {
return NERR_NetworkError; // Unexpected behaviour
}
return WsMapSmbStatus(SmbReturnClass, SmbReturnCode);
}
NET_API_STATUS
WsSendSingleBlockMessage(
IN UCHAR LanAdapterNumber,
IN UCHAR SessionNumber,
IN LPTSTR ToName,
IN LPTSTR FromName,
IN PCHAR Message,
IN WORD MessageSize
)
/*++
Routine Description:
This function sends a directed message in one SMB on a session we had
established earlier. It waits for an acknowlegement from the recipient.
Arguments:
LanAdapterNumber - Supplies the number of the LAN adapter.
SessionNumber - Supplies the session number of a session established with
NetBIOS CALL and LISTEN commands.
ToName - Supplies the name of the recipient.
FromName - Supplies the name of the sender.
Message - Supplies the buffer of the message to be sent.
MessageSize - Supplies the size of the message.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
UCHAR SmbBuffer[WS_SMB_BUFFER_SIZE];
WORD SmbSize; // Buffer length
UCHAR SmbReturnClass;
USHORT SmbReturnCode;
LPSTR AnsiToName;
LPSTR AnsiFromName;
AnsiToName = NetpAllocStrFromWStr(ToName);
if (AnsiToName == NULL) {
return ERROR_NOT_ENOUGH_MEMORY;
}
AnsiFromName = NetpAllocStrFromWStr(FromName);
if (AnsiFromName == NULL) {
NetApiBufferFree(AnsiToName);
return ERROR_NOT_ENOUGH_MEMORY;
}
SmbSize = WsMakeSmb(
SmbBuffer,
SMB_COM_SEND_MESSAGE,
0,
"sst",
AnsiFromName,
AnsiToName,
MessageSize,
Message
);
NetApiBufferFree(AnsiToName);
NetApiBufferFree(AnsiFromName);
IF_DEBUG(MESSAGE) {
NetpKdPrint(("[Wksta] Send single block message. Size=%u\n", SmbSize));
#if DBG
NetpHexDump(SmbBuffer, SmbSize);
#endif
}
//
// Send SMB
//
if ((status = NetpNetBiosSend(
LanAdapterNumber,
SessionNumber,
SmbBuffer,
SmbSize
)) != NERR_Success) {
NetpKdPrint(("[Wksta] Failed to send single block message %lu\n",
status));
return status;
}
//
// Get response
//
if ((status = NetpNetBiosReceive(
LanAdapterNumber,
SessionNumber,
SmbBuffer,
WS_SMB_BUFFER_SIZE,
(HANDLE) NULL,
&SmbSize
)) != NERR_Success) {
NetpKdPrint(("[Wksta] Failed to receive verification to single"
" block message %lu\n", status));
return status;
}
if (! WsVerifySmb(
SmbBuffer,
SmbSize,
SMB_COM_SEND_MESSAGE,
&SmbReturnClass,
&SmbReturnCode
)) {
return NERR_NetworkError; // Unexpected behaviour
}
return WsMapSmbStatus(SmbReturnClass, SmbReturnCode);
}
STATIC
BOOL
WsVerifySmb(
IN PUCHAR SmbBuffer,
IN WORD SmbBufferSize,
IN UCHAR SmbFunctionCode,
OUT PUCHAR SmbReturnClass,
OUT PUSHORT SmbReturnCode
)
/*++
Routine Description:
This function checks the format of a received SMB; it returns TRUE if
if the SMB format is valid, and FALSE otherwise.
Arguments:
SmbBuffer - Supplies the SMB buffer
SmbBufferSize - Supplies the size of SmbBuffer in bytes
SmbFunctionCode - Supplies the function code for which the SMB is received
to determine the proper SMB format.
SmbReturnClass - Returns the class of the SMB only if the SMB format is
valid.
SmbReturnCode - Returns the error code of the SMB.
Return Value:
TRUE if SMB is valid; FALSE otherwise.
--*/
{
PSMB_HEADER Smb = (PSMB_HEADER) SmbBuffer; // Pointer to SMB header
int SmbCheckCode;
int ParameterCount;
//
// Assume error
//
*SmbReturnClass = (UCHAR) 0xff;
*SmbReturnCode = Smb->Error;
switch (SmbFunctionCode) {
case SMB_COM_SEND_MESSAGE: // Single-block message
case SMB_COM_SEND_TEXT_MB_MESSAGE: // Text of multi-block message
case SMB_COM_SEND_END_MB_MESSAGE: // End of multi-block message
ParameterCount = 0;
break;
case SMB_COM_SEND_START_MB_MESSAGE: // Beginning of multi-block message
ParameterCount = 1;
break;
default: // Unknown SMB
NetpKdPrint(("[Wksta] WsVerifySmb unknown SMB\n"));
return FALSE;
}
if (! (SmbCheckCode = NetpSmbCheck(
SmbBuffer,
SmbBufferSize,
SmbFunctionCode,
ParameterCount,
""
))) {
//
// Set the return class if valid SMB
//
*SmbReturnClass = Smb->ErrorClass;
return TRUE;
}
else {
//
// Invalid SMB
//
NetpKdPrint(("[Wksta] WsVerifySmb invalid SMB %d\n", SmbCheckCode));
return FALSE;
}
}
STATIC
NET_API_STATUS
WsMapSmbStatus(
UCHAR SmbReturnClass,
USHORT SmbReturnCode
)
/*++
Routine Description:
This function converts an SMB status to API status.
Arguments:
SmbReturnClass - Supplies the SMB class
SmbReturnCode - Supplies the SMB return code.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
switch (SmbReturnClass) {
case SMB_ERR_SUCCESS:
return NERR_Success;
case SMB_ERR_CLASS_SERVER:
//
// SMB error
//
NetpKdPrint(("[Wksta] SMB error SmbReturnCode=%u\n", SmbReturnCode));
if (SmbReturnCode == SMB_ERR_SERVER_PAUSED) {
return NERR_PausedRemote; // Server paused
}
else {
return NERR_BadReceive; // Send not received
}
break;
default:
return NERR_BadReceive;
}
}