windows-nt/Source/XPSP1/NT/ds/netapi/netlib/msgrutil.c

914 lines
21 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1991-92 Microsoft Corporation
Module Name:
msgrutil.c
Abstract:
This file contains functions that are used by the messenger service
and its API as well as the NetMessageSend API.
This module contains the following helper routines:
NetpNetBiosReset
NetpNetBiosAddName
NetpNetBiosDelName
NetpNetBiosGetAdapterNumbers
NetpNetBiosCall
NetpNetBiosHangup
NetpNetBiosReceive
NetpNetBiosSend
NetpStringToNetBiosName
NetpNetBiosStatusToApiStatus
NetpSmbCheck
These function prototypes can be found in net\inc\msgrutil.h.
Authors:
Rita Wong (ritaw) 26-July-1991
Dan Lafferty (danl) 26-July-1991
Revision History:
05-May-1992 JohnRo
Quiet normal debug messages.
Changed to use FORMAT_ equates for most things.
Made changes suggested by PC-LINT.
--*/
#include <nt.h> // NT definitions
#include <ntrtl.h> // NT runtime library definitions
#include <nturtl.h>
#include <windows.h> // Win32 constant definitions & error codes
#include <lmcons.h> // LAN Manager common definitions
#include <lmerr.h> // LAN Manager network error definitions
#include <debuglib.h> // IF_DEBUG
#include <netdebug.h> // NetpKdPrint(()), FORMAT_ equates.
#include <smbtypes.h> // needed for smb.h
#include <smb.h> // Server Message Block definitions
#include <nb30.h> // NetBIOS 3.0 definitions
#include <string.h> // strlen
#include <msgrutil.h> // Function prototypes from this module
#include <icanon.h> // I_NetNameCanonicalize()
#include <tstring.h> // NetpAllocStrFromWStr(), STRLEN(), etc.
#include <lmapibuf.h> // NetApiBufferFree().
static
NET_API_STATUS
NetpIssueCallWithRetries(
IN PNCB CallNcb,
IN UCHAR LanAdapterNumber
);
NET_API_STATUS
NetpNetBiosReset(
IN UCHAR LanAdapterNumber
)
/*++
Routine Description:
This function resets LAN adapter.
Arguments:
LanAdapterNumber - Supplies the number of the LAN adapter.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NCB Ncb;
UCHAR NcbStatus;
RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
Ncb.ncb_command = NCBRESET;
Ncb.ncb_lsn = 0;
Ncb.ncb_callname[0] = 24; // Max Num Sessions
Ncb.ncb_callname[1] = 0;
Ncb.ncb_callname[2] = 16; // Max Num Names
Ncb.ncb_callname[3] = 0;
Ncb.ncb_lana_num = LanAdapterNumber;
NcbStatus = Netbios(&Ncb);
return NetpNetBiosStatusToApiStatus(NcbStatus);
}
NET_API_STATUS
NetpNetBiosAddName(
IN PCHAR NetBiosName,
IN UCHAR LanAdapterNumber,
OUT PUCHAR NetBiosNameNumber OPTIONAL
)
/*++
Routine Description:
This function adds a NetBIOS name to the specified LAN adapter.
Arguments:
NetBiosName - Supplies a NetBIOS name to be added.
LanAdapterNumber - Supplies the number of the LAN adapter.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NCB Ncb;
UCHAR NcbStatus;
RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
Ncb.ncb_command = NCBADDNAME;
memcpy(Ncb.ncb_name, NetBiosName, NCBNAMSZ);
Ncb.ncb_lana_num = LanAdapterNumber;
NcbStatus = Netbios(&Ncb);
if (NcbStatus == NRC_GOODRET) {
IF_DEBUG(NETBIOS) {
Ncb.ncb_name[NCBNAMSZ - 1] = '\0';
NetpKdPrint(("[Netlib] Successfully added name " FORMAT_LPSTR ". "
"Name number is " FORMAT_DWORD "\n",
Ncb.ncb_name, (DWORD) Ncb.ncb_num));
}
if (ARGUMENT_PRESENT(NetBiosNameNumber)) {
*NetBiosNameNumber = Ncb.ncb_num;
}
return NERR_Success;
}
return NetpNetBiosStatusToApiStatus(NcbStatus);
}
NET_API_STATUS
NetpNetBiosDelName(
IN PCHAR NetBiosName,
IN UCHAR LanAdapterNumber
)
/*++
Routine Description:
This function adds a NetBIOS name to the specified LAN adapter.
Arguments:
NetBiosName - Supplies a NetBIOS name to be added.
LanAdapterNumber - Supplies the number of the LAN adapter.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NCB Ncb;
UCHAR NcbStatus;
RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
Ncb.ncb_command = NCBDELNAME;
memcpy(Ncb.ncb_name, NetBiosName, NCBNAMSZ);
Ncb.ncb_lana_num = LanAdapterNumber;
NcbStatus = Netbios(&Ncb);
if (NcbStatus == NRC_GOODRET) {
IF_DEBUG(NETBIOS) {
Ncb.ncb_name[NCBNAMSZ - 1] = '\0';
NetpKdPrint(("[Netlib] Successfully deleted name " FORMAT_LPSTR ". "
"Name number is " FORMAT_DWORD "\n",
Ncb.ncb_name, (DWORD) Ncb.ncb_num));
}
return NERR_Success;
}
return NetpNetBiosStatusToApiStatus(NcbStatus);
}
NET_API_STATUS
NetpNetBiosGetAdapterNumbers(
OUT PLANA_ENUM LanAdapterBuffer,
IN WORD LanAdapterBufferSize
)
/*++
Routine Description:
Arguments:
LanAdapterBuffer - Returns LAN adapter numbers in this buffer.
LanAdapterBufferSize - Supplies the size of the output buffer which LAN
LAN adapter numbers will be written to.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NCB Ncb;
RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
Ncb.ncb_command = NCBENUM;
Ncb.ncb_buffer = (char FAR *) LanAdapterBuffer;
Ncb.ncb_length = LanAdapterBufferSize;
return NetpNetBiosStatusToApiStatus(Netbios(&Ncb));
}
NET_API_STATUS
NetpStringToNetBiosName(
OUT PCHAR NetBiosName,
IN LPTSTR String,
IN DWORD CanonicalizeType,
IN WORD Type
)
/*++
Routine Description:
This function converts a zero terminated string plus a specified NetBIOS
name type into a 16-byte NetBIOS name:
[ ANSI String ][ Space Padding ][Type]
If the input string for the NetBIOS name is fewer than 15 characters,
spaces will be used to pad the string to 15 characters. The 16th byte
designates the type of the NetBIOS name.
Input strings that are longer than 15 characters will be truncated to
15 characters.
Arguments:
NetBiosName - Returns the formatted NetBIOS name.
String - Supplies a pointer to a zero terminated string.
CanonicalizeType - Supplies a value to determine how the string should be
canonicalized.
Type - Supplies the type of the NetBIOS name.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS Status = NERR_Success;
DWORD i;
DWORD SourceStringLen;
LPSTR SourceString;
SourceStringLen = STRLEN(String);
Status = I_NetNameCanonicalize(
NULL,
String,
String,
(SourceStringLen + 1) * sizeof(TCHAR),
CanonicalizeType,
0
);
if (Status != NERR_Success) {
IF_DEBUG(NETBIOS) {
NetpKdPrint(("[Netlib] Error canonicalizing message alias "
FORMAT_LPSTR " " FORMAT_API_STATUS "\n", String, Status));
}
return Status;
}
SourceString = NetpAllocStrFromWStr(String);
if (SourceString == NULL) {
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Insure the string doesn't exceed the netbios name buffer.
//
if (SourceStringLen > NCBNAMSZ - 1) {
SourceString[NCBNAMSZ - 1] = '\0';
}
(VOID) strncpy(NetBiosName, SourceString, NCBNAMSZ - 1);
for (i = SourceStringLen; i < (NCBNAMSZ - 1); i++) {
NetBiosName[i] = ' ';
}
NetBiosName[NCBNAMSZ - 1] = (CHAR) Type;
(VOID) NetApiBufferFree(SourceString);
return Status;
}
NET_API_STATUS
NetpNetBiosCall(
IN UCHAR LanAdapterNumber,
IN LPTSTR NameToCall,
IN LPTSTR Sender,
OUT UCHAR *SessionNumber
)
/*++
Routine Description:
This function opens a session with the specified name to call.
Arguments:
LanAdapterNumber - Supplies the number of the LAN adapter.
NameToCall - Supplies the name to call.
Sender - Supplies the name who makes the call.
SessionNumber - Returns the session number of the session established.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NET_API_STATUS status;
NCB Ncb;
RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
if ((status = NetpStringToNetBiosName(
Ncb.ncb_callname,
NameToCall,
NAMETYPE_MESSAGEDEST,
MESSAGE_ALIAS_TYPE
)) != NERR_Success) {
return status;
}
if ((status = NetpStringToNetBiosName(
Ncb.ncb_name,
Sender,
NAMETYPE_MESSAGEDEST,
MESSAGE_ALIAS_TYPE
)) != NERR_Success) {
return status;
}
Ncb.ncb_rto = 30; // Receives time out after 15 seconds
Ncb.ncb_sto = 30; // Sends time out after 15 seconds
Ncb.ncb_command = NCBCALL; // Call (wait)
Ncb.ncb_lana_num = LanAdapterNumber;
//
// Issue the NetBIOS call with retries
//
if (NetpIssueCallWithRetries(&Ncb, LanAdapterNumber) != NERR_Success) {
return NERR_NameNotFound;
}
*SessionNumber = Ncb.ncb_lsn;
return NERR_Success;
}
NET_API_STATUS
NetpNetBiosHangup(
IN UCHAR LanAdapterNumber,
IN UCHAR SessionNumber
)
/*++
Routine Description:
This function closes and opened session.
Arguments:
LanAdapterNumber - Supplies the number of the LAN adapter.
SessionNumber - Supplies the session number of the session to close.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NCB Ncb;
UCHAR NcbStatus;
RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
Ncb.ncb_command = NCBHANGUP;
Ncb.ncb_lana_num = LanAdapterNumber;
Ncb.ncb_lsn = SessionNumber;
NcbStatus = Netbios(&Ncb);
if (NcbStatus == NRC_GOODRET) {
IF_DEBUG(NETBIOS) {
NetpKdPrint(("[Netlib] NetBIOS successfully hung up\n"));
}
return NERR_Success;
}
return NetpNetBiosStatusToApiStatus(NcbStatus);
}
NET_API_STATUS
NetpNetBiosSend(
IN UCHAR LanAdapterNumber,
IN UCHAR SessionNumber,
IN PCHAR SendBuffer,
IN WORD SendBufferSize
)
/*++
Routine Description:
This function sends data in SendBuffer to the session partner specified
by SessionNumber.
Arguments:
LanAdapterNumber - Supplies the number of the LAN adapter.
SessionNumber - Supplies the session number of a session established with
NetBIOS CALL and LISTEN commands.
SendBuffer - Supplies a pointer to data to be sent.
SendBufferSize - Supplies the size of the data in bytes.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NCB Ncb;
UCHAR NcbStatus;
RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
Ncb.ncb_command = NCBSEND;
Ncb.ncb_lana_num = LanAdapterNumber;
Ncb.ncb_lsn = SessionNumber;
Ncb.ncb_buffer = SendBuffer;
Ncb.ncb_length = SendBufferSize;
NcbStatus = Netbios(&Ncb);
if (NcbStatus == NRC_GOODRET) {
IF_DEBUG(NETBIOS) {
NetpKdPrint(("[Netlib] NetBIOS successfully sent data\n"));
}
return NERR_Success;
}
return NetpNetBiosStatusToApiStatus(NcbStatus);
}
NET_API_STATUS
NetpNetBiosReceive(
IN UCHAR LanAdapterNumber,
IN UCHAR SessionNumber,
OUT PUCHAR ReceiveBuffer,
IN WORD ReceiveBufferSize,
IN HANDLE EventHandle,
OUT WORD *NumberOfBytesReceived
)
/*++
Routine Description:
This function posts a NetBIOS receive data request to the session
partner specified by SessionNumber.
Arguments:
LanAdapterNumber - Supplies the number of the LAN adapter.
SessionNumber - Supplies the session number of a session established with
NetBIOS CALL and LISTEN commands.
ReceiveBuffer - Returns the received data in this buffer.
ReceiveBufferSize - Supplies the size of the receive buffer.
EventHandle - Supplies a handle to a Win32 event which will be signalled
when an ASYNCH receive command completes. If this value is zero,
the receive command is synchronous.
NumberOfBytesReceived - Returns the number of bytes of data received.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NCB Ncb;
UCHAR NcbStatus;
RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
Ncb.ncb_command = NCBRECV;
Ncb.ncb_lana_num = LanAdapterNumber;
Ncb.ncb_lsn = SessionNumber;
Ncb.ncb_buffer = ReceiveBuffer;
Ncb.ncb_length = ReceiveBufferSize;
IF_DEBUG(NETBIOS) {
NetpKdPrint(("[Netlib] ncb_length before receive is " FORMAT_WORD_ONLY
"\n", (WORD) Ncb.ncb_length));
}
Ncb.ncb_event = EventHandle;
NcbStatus = Netbios(&Ncb);
if (NcbStatus == NRC_GOODRET) {
IF_DEBUG(NETBIOS) {
NetpKdPrint(("[Netlib] NetBIOS successfully received data\n"));
NetpKdPrint(("[Netlib] ncb_length after receive is "
FORMAT_WORD_ONLY "\n", (WORD) Ncb.ncb_length));
}
*NumberOfBytesReceived = Ncb.ncb_length;
return NERR_Success;
}
return NetpNetBiosStatusToApiStatus(NcbStatus);
}
NET_API_STATUS
NetpNetBiosStatusToApiStatus(
UCHAR NetBiosStatus
)
{
IF_DEBUG(NETBIOS) {
NetpKdPrint(("[Netlib] Netbios status is x%02x\n", NetBiosStatus));
}
//
// Slight optimization
//
if (NetBiosStatus == NRC_GOODRET) {
return NERR_Success;
}
switch (NetBiosStatus) {
case NRC_NORES: return NERR_NoNetworkResource;
case NRC_DUPNAME: return NERR_AlreadyExists;
case NRC_NAMTFUL: return NERR_TooManyNames;
case NRC_ACTSES: return NERR_DeleteLater;
case NRC_REMTFUL: return ERROR_REM_NOT_LIST;
case NRC_NOCALL: return NERR_NameNotFound;
case NRC_NOWILD:
case NRC_NAMERR:
return ERROR_INVALID_PARAMETER;
case NRC_INUSE:
case NRC_NAMCONF:
return NERR_DuplicateName;
default: return NERR_NetworkError;
}
}
static
NET_API_STATUS
NetpIssueCallWithRetries(
IN PNCB CallNcb,
IN UCHAR LanAdapterNumber
)
/*++
Routine Description:
This function issues the NetBIOS call command with retries, just in case
the receiving name is busy fielding a message at the moment.
Arguments:
CallNcb - Supplies a pointer to the NCB which has been initialized with
the proper values to submit an NetBIOS call command.
LanAdapterNumber - Supplies the number of the LAN adapter.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
#define NETP_MAX_CALL_RETRY 5
NCB Ncb;
WORD RetryCount = 0;
UCHAR NetBiosStatus;
NB30_ADAPTER_STATUS StatusBuffer; // Adapter status buffer
//
// It is possible that the remote receiving name is present but is
// currently receiving another message and so is not listening.
// If the return code from the call is NRC_NOCALL then check to see if
// the name is actually present by issuing an ASTAT call to the name.
// If the ASTAT succeeds then sleep and retry the call.
//
NetBiosStatus = Netbios(CallNcb);
while (NetBiosStatus == NRC_NOCALL && RetryCount < NETP_MAX_CALL_RETRY) {
//
// Initialize ASTAT NCB
//
RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
memcpy(Ncb.ncb_callname, CallNcb->ncb_callname, NCBNAMSZ);
Ncb.ncb_buffer = (char FAR *) &StatusBuffer;
Ncb.ncb_length = sizeof(StatusBuffer);
Ncb.ncb_command = NCBASTAT; // Adapter status (wait)
Ncb.ncb_lana_num = LanAdapterNumber;
//
// If failed, name is not present
//
if (Netbios(&Ncb) != NRC_GOODRET) {
return NERR_NameNotFound;
}
Sleep(1000L);
RetryCount++;
NetBiosStatus = Netbios(CallNcb);
}
return NetpNetBiosStatusToApiStatus(NetBiosStatus);
}
int
NetpSmbCheck(
IN LPBYTE buffer, // Buffer containing SMB
IN USHORT size, // size of SMB buffer (in bytes)
IN UCHAR func, // Function code
IN int parms, // Parameter count
IN LPSTR fields // Buffer fields dope vector
)
/*++
Routine Description:
Checks Server Message Block for syntactical correctness
This function is called to verify that a Server Message Block
is of the specified form. The function returns zero if the
SMB is correct; if an error is detected, a non-zero value
indicating the nature of the error is returned.
An SMB is a variable length structure whose exact size
depends on the setting of certain fixed-offset fields
and whose exact format cannot be determined except by
examination of the whole structure. Smbcheck checks to
see that an SMB conforms to a set of specified conditions.
The "fields" parameter is a dope vector that describes the
individual fields to be found in the buffer section at the
end of the SMB. The vector is a null-terminated character
string. Currently, the elements of the string must be as
follows:
'b' - the next element in the buffer area should be
a variable length buffer prefixed with a byte
containing either 1 or 5 followed by two bytes
containing the size of the buffer.
'd' - the next element in the buffer area is a null-terminated
string prefixed with a byte containing 2.
'p' - the next element in the buffer area is a null-terminated
string prefixed with a byte containing 3.
's' - the next element in the buffer area is a null-terminated
string prefixed with a byte containing 4.
Arguments:
buffer - a pointer to the buffer containing the SMB
size - the number of bytes in the buffer
func - the expected SMB function code
parms - the expected number of parameters
fields - a dope vector describing the expected buffer fields
within the SMB's buffer area (see below).
Return Value:
an integer status code; zero indicates no errors.
--*/
{
PSMB_HEADER smb; // SMB header pointer
LPBYTE limit; // Upper limit
smb = (PSMB_HEADER) buffer; // Overlay header with buffer
//
// Must be long enough for header
//
if(size < sizeof(SMB_HEADER)) {
return(2);
}
//
// Message type must be 0xFF
//
if(smb->Protocol[0] != 0xff) {
return(3);
}
//
// Server must be "SMB"
//
if( smb->Protocol[1] != 'S' ||
smb->Protocol[2] != 'M' ||
smb->Protocol[3] != 'B') {
return(4);
}
//
// Must have proper function code
//
if(smb->Command != func) {
return(5);
}
limit = &buffer[size]; // Set upper limit of SMB
buffer += sizeof(SMB_HEADER); // Skip over header
//
// Parameter counts must match
//
if(*buffer++ != (BYTE)parms) {
return(6);
}
//
// Skip parameters and buffer size
//
buffer += (((SHORT)parms & 0xFF) + 1)*sizeof(SHORT);
//
// Check for overflow
//
if(buffer > limit) {
return(7);
}
//
// Loop to check buffer fields
//
while(*fields) {
//
// Switch on dope vector character
//
switch(*fields++) {
case 'b': // Variable length data block
if(*buffer != '\001' && *buffer != '\005') {
return(8);
}
//
// Check for block code
//
++buffer; // Skip over block code
size = (USHORT)*buffer++ & (USHORT)0xFF; // Get low-byte size
size += ((USHORT)*buffer++ & (USHORT)0xFF)<< 8; // Get high-byte of buffer size
buffer += size; // Increment pointer
break;
case 'd': // Null-terminated dialect string
if(*buffer++ != '\002') { // Check for string code
return(9);
}
buffer += strlen((LPVOID) buffer) + 1; // Skip over the string
break;
case 'p': // Null-terminated path string
if(*buffer++ != '\003') { // Check for string code
return(10);
}
buffer += strlen((LPVOID) buffer) + 1; // Skip over the string
break;
case 's': // Null-terminated string
if(*buffer++ != '\004') { // Check for string code
return(11);
}
buffer += strlen((LPVOID) buffer) + 1; // Skip over the string
break;
}
//
// Check against end of block
//
if(buffer > limit) {
return(12);
}
}
return(buffer != limit); // Should be false
}