mirror of https://github.com/lianthony/NT4.0
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.
528 lines
12 KiB
528 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
netbcom.c
|
|
|
|
Abstract:
|
|
|
|
NetBios transport common code between server and client.
|
|
|
|
Author:
|
|
|
|
Steven Zeck (stevez) 2/12/92
|
|
|
|
Danny Glasser (dannygl) 3/1/93
|
|
|
|
--*/
|
|
|
|
#include "NetBCom.h"
|
|
|
|
// The maximum value of a lana number
|
|
#define MAX_LANA_NUMBER UCHAR_MAX
|
|
|
|
// This the netbios name of this (self) machine.
|
|
// NOTE: We assume one-byte characters here
|
|
|
|
unsigned char MachineName[NCBNAMSZ] = { 0 };
|
|
size_t MachineNameLengthUnpadded =0;
|
|
|
|
|
|
#ifdef NTENV
|
|
|
|
#define MAX_MAP_ENTRIES 20
|
|
|
|
void
|
|
InitialNtRegistry(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function maps loads the RPC lana mappings from the NT registry.
|
|
This information is automatically generated by NT setup and the Networks
|
|
Control Panel applet. Because it can change dynamically, we load it
|
|
all at once to achieve consistent data.
|
|
|
|
--*/
|
|
{
|
|
HKEY RegHandle;
|
|
LONG status;
|
|
int i;
|
|
char protseq[64];
|
|
DWORD protseq_len;
|
|
DWORD lana;
|
|
DWORD lana_len;
|
|
DWORD data_type;
|
|
|
|
// This function gets called by both the client and the server. We
|
|
// serialize access to make sure that the table gets initialized only
|
|
// once.
|
|
CRITICAL_ENTER();
|
|
|
|
// Return immediately if the table is already initialized.
|
|
if (ProtocolTable[0].ProtoSeq)
|
|
{
|
|
CRITICAL_LEAVE();
|
|
|
|
return;
|
|
}
|
|
|
|
// Open the registry key for RPC NetBIOS information
|
|
status = RegOpenKeyExA(RPC_REG_ROOT,
|
|
REG_NETBIOS,
|
|
0,
|
|
KEY_READ,
|
|
&RegHandle);
|
|
|
|
ASSERT(!status);
|
|
|
|
if (status)
|
|
{
|
|
CRITICAL_LEAVE();
|
|
|
|
return;
|
|
}
|
|
|
|
// Enumerate the values for this key and load them into the protocol
|
|
// table.
|
|
for (i = 0; !status && i < MAX_LANA; i++)
|
|
{
|
|
protseq_len = sizeof(protseq);
|
|
lana_len = sizeof(lana);
|
|
|
|
status = RegEnumValueA(RegHandle,
|
|
i,
|
|
protseq,
|
|
&protseq_len,
|
|
NULL,
|
|
&data_type,
|
|
(LPBYTE) &lana,
|
|
&lana_len);
|
|
|
|
if (!status && data_type == REG_DWORD && lana <= MAX_LANA_NUMBER)
|
|
{
|
|
ProtocolTable[i].ProtoSeq = I_RpcAllocate(protseq_len + 1);
|
|
|
|
ASSERT(ProtocolTable[i].ProtoSeq);
|
|
|
|
if (! ProtocolTable[i].ProtoSeq)
|
|
{
|
|
status = RPC_S_OUT_OF_RESOURCES;
|
|
}
|
|
else
|
|
{
|
|
// Everything succeeded; store the data in the table.
|
|
strcpy(ProtocolTable[i].ProtoSeq, protseq);
|
|
ProtocolTable[i].Lana = (unsigned char) lana;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If any of the above conditions aren't met, then we should be
|
|
// at the end of the list.
|
|
|
|
ASSERT(status == ERROR_NO_MORE_ITEMS);
|
|
}
|
|
}
|
|
|
|
RegCloseKey(RegHandle);
|
|
|
|
CRITICAL_LEAVE();
|
|
|
|
return;
|
|
}
|
|
|
|
#endif // NTENV
|
|
|
|
|
|
RPC_STATUS
|
|
MapProtocol(
|
|
IN RPC_CHAR *ProtoSeq,
|
|
IN int DriverNumber,
|
|
OUT PPROTOCOL_MAP *ProtocolEntry
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function maps a protocol string into a protocol map entry.
|
|
|
|
In the non-NT versions, it looks up the information dynamically
|
|
in the registry. In the NT version, the registry information is
|
|
pre-loaded
|
|
|
|
Arguments:
|
|
|
|
ProtoSeq - the protocol sequence that we want to map
|
|
|
|
DriverNumber - the logical driver number for the protocol.
|
|
|
|
ProtocolEntry - pointer to place to return the results.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK, RPC_S_OUT_OF_RESOURCES, RPC_S_INVALID_ENDPOINT_FORMAT
|
|
|
|
The output pointer is set to the corresponding entry when found.
|
|
|
|
--*/
|
|
{
|
|
long status;
|
|
int i;
|
|
HKEY RegHandle;
|
|
char Protocol[40];
|
|
char LanaString[10];
|
|
long BufferLength = sizeof(LanaString);
|
|
|
|
// Copy the possible unicode protocol string to ascii.
|
|
|
|
for (i = 0; (Protocol[i] = (char) ProtoSeq[i]) && i < sizeof(Protocol); i++) ;
|
|
|
|
// Add the logical driver number to the protocol string. This
|
|
// allows multiple drivers (net cards) to be attached to the same
|
|
// logical protocol.
|
|
|
|
Protocol[i] = (char) ('0' + DriverNumber);
|
|
Protocol[i+1] = 0;
|
|
|
|
// First look in the proto sequences that we have already mapped.
|
|
|
|
for (i = 0; ProtocolTable[i].ProtoSeq && i < MAX_LANA; i++)
|
|
{
|
|
// If found, set the output pointer.
|
|
|
|
if (strcmp(ProtocolTable[i].ProtoSeq, Protocol) == 0)
|
|
{
|
|
*ProtocolEntry = &ProtocolTable[i];
|
|
return(RPC_S_OK);
|
|
}
|
|
}
|
|
|
|
if (i >= MAX_LANA)
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
|
|
// The name isn't found. In the NT version, this is an error; in the
|
|
// non-NT versions, open the registry and see if a mapping is defined.
|
|
|
|
#ifdef NTENV
|
|
return(RPC_S_PROTSEQ_NOT_FOUND);
|
|
#else
|
|
status = RegOpenKey(RPC_REG_ROOT, REG_NETBIOS, &RegHandle);
|
|
|
|
if (status)
|
|
return(RPC_S_PROTSEQ_NOT_FOUND);
|
|
|
|
status = RegQueryValue(RegHandle, Protocol, LanaString, &BufferLength);
|
|
|
|
RegCloseKey(RegHandle);
|
|
|
|
if (status || ! (*LanaString >= '0' && *LanaString <= '9'))
|
|
return(RPC_S_PROTSEQ_NOT_FOUND);
|
|
|
|
// Now we have a Lana number for the protocol sequence. Put this
|
|
// info in the protocol to lana mapping structure.
|
|
|
|
if (! (ProtocolTable[i].ProtoSeq
|
|
= (char *) I_RpcAllocate(strlen(Protocol)+1)) )
|
|
{
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
|
|
strcpy(ProtocolTable[i].ProtoSeq, Protocol);
|
|
ProtocolTable[i].Lana = (unsigned char) (*LanaString - '0');
|
|
|
|
*ProtocolEntry = &ProtocolTable[i];
|
|
|
|
return(RPC_S_OK);
|
|
#endif // NTENV
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
MapErrorCode (
|
|
IN ERROR_TABLE * MapTable,
|
|
IN RPC_OS_ERROR Status,
|
|
IN RPC_STATUS DefaultStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function maps a OS specific error code into a generic RPC
|
|
status code. The ERROR_TABLE is an unordered list of pairs, with
|
|
a value of 0 terminating the table. So don't try to translate a
|
|
0 OS_ERROR.
|
|
|
|
You will see this routine called , with the return value ignored.
|
|
This is done when we don't need the translated error code, but
|
|
want to check for unexpected failures.
|
|
|
|
Arguments:
|
|
|
|
MapTable - The table to OS codes to RPC_STATUS codes.
|
|
|
|
Status - The OS specific error that we wish to map.
|
|
|
|
DefaultStatus - The status to return if none of the codes match.
|
|
We will ASSERT in the debug version if we have to take this action.
|
|
|
|
Return Value:
|
|
|
|
The translated error code if there is match, else the value
|
|
of DefaultStatus.
|
|
|
|
--*/
|
|
{
|
|
int TableIndex;
|
|
|
|
ASSERT(MapTable);
|
|
|
|
for (TableIndex = 0; MapTable[TableIndex].OScode != 0; TableIndex++)
|
|
if (MapTable[TableIndex].OScode == Status)
|
|
return (MapTable[TableIndex].RpcStatus);
|
|
|
|
return (DefaultStatus);
|
|
}
|
|
|
|
|
|
int
|
|
SetupNetBios (
|
|
IN RPC_CHAR * RpcProtocolSequence
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Loadable transport initialization function. Get the machine name
|
|
of this workstation into MachineName and perform other OS specific
|
|
initiailization.
|
|
|
|
Arguments:
|
|
|
|
RpcProtocolSequence - the protocol string that mapped to this library.
|
|
|
|
Returns:
|
|
|
|
TRUE if the initialization was OK.
|
|
|
|
--*/
|
|
|
|
{
|
|
#ifdef NTENV
|
|
|
|
BOOLEAN BooleanStatus;
|
|
DWORD ComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
|
|
unsigned char ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
|
|
|
BooleanStatus = GetComputerNameA(ComputerName, &ComputerNameLength);
|
|
ASSERT( BooleanStatus == TRUE );
|
|
|
|
// Store padded machine name (and save unpadded length)
|
|
MachineNameLengthUnpadded = strlen(ComputerName);
|
|
memcpy(MachineName, ComputerName, MachineNameLengthUnpadded);
|
|
memset(MachineName + MachineNameLengthUnpadded,
|
|
NETBIOS_NAME_PAD_BYTE,
|
|
sizeof(MachineName) - MachineNameLengthUnpadded);
|
|
|
|
ASSERT(MachineNameLengthUnpadded < sizeof(MachineName));
|
|
|
|
InitialNtRegistry();
|
|
|
|
#else // DOS || WIN
|
|
|
|
// We use the GetMachineName int21 because the Lanman APIs take up
|
|
// 20K in the library (and are less portable).
|
|
|
|
int failed = 0;
|
|
|
|
_asm
|
|
{
|
|
push ds ; save DS before using it for call
|
|
mov dx, offset MachineName
|
|
mov ax, seg MachineName
|
|
mov ds,ax
|
|
|
|
mov ax, 05e00h ; call DOS to get machine name
|
|
int 21h
|
|
|
|
pop ds ; restore DS
|
|
|
|
jc NameError ; carry flag set indicates error
|
|
|
|
cmp ch, 0 ; ch == 0 indicates no net
|
|
jne NameOK
|
|
|
|
NameError:
|
|
mov failed, 1
|
|
|
|
NameOK:
|
|
};
|
|
|
|
if (failed)
|
|
return 0;
|
|
|
|
// BUGBUG - Set MachineNameLengthUnpadded here (if building a DOS
|
|
// or Win16 server)
|
|
|
|
#if !defined(WIN)
|
|
|
|
// Since DOS .DLLs are imitations, ask the C runtime to call us
|
|
// on process termination.
|
|
|
|
I_DosAtExit(CleanUpNetBios);
|
|
|
|
#else
|
|
// Place an address in the per DLL termination table, see ltstart.asm
|
|
|
|
DllTermination = CleanUpNetBios;
|
|
|
|
#endif // WIN
|
|
|
|
#endif // NTENV
|
|
|
|
|
|
PUNUSED(RpcProtocolSequence);
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
#ifdef NTENV
|
|
|
|
UCHAR RPC_ENTRY
|
|
AdapterReset (
|
|
IN PPROTOCOL_MAP ProtocolEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used by both the client and server NetBIOS transports
|
|
to submit the RESET NCB for a process, as is required by NetBIOS on NT.
|
|
|
|
We need to perform this in a single place to allow a process to act
|
|
as both an RPC client and server over NetBIOS. Otherwise, both the
|
|
client and server transports would submit RESETs and the second one
|
|
would destroy the state of the first.
|
|
|
|
Arguments:
|
|
|
|
ProtocolEntry - This is the entry in the protocol map for the adapter
|
|
to be reset.
|
|
|
|
Returns:
|
|
|
|
The return code of the RESET NCB, if it's submitted.
|
|
|
|
0 if the RESET has already occurred.
|
|
--*/
|
|
{
|
|
unsigned char status = 0;
|
|
|
|
// Make sure that no other threads are accessing this function
|
|
CRITICAL_ENTER();
|
|
|
|
// Perform the reset, if necessary
|
|
if (! ProtocolEntry->ResetDone)
|
|
{
|
|
NCB theNCB;
|
|
|
|
memset(&theNCB, 0 , sizeof(theNCB));
|
|
theNCB.ncb_lana_num = ProtocolEntry->Lana;
|
|
|
|
// The values are needed for the server
|
|
theNCB.ncb_callname[0] = 254; // max sessions
|
|
theNCB.ncb_callname[1] = 64; // max commands
|
|
theNCB.ncb_callname[2] = 32; // max names
|
|
|
|
status = execNCB(NCBRESET, &theNCB);
|
|
|
|
// If the NCB was successfully invoked, get the status from the
|
|
// completed NCB itself.
|
|
if (status == 0)
|
|
{
|
|
status = theNCB.ncb_retcode;
|
|
}
|
|
|
|
// Set the flag so the reset is performed only once (per process).
|
|
if (status == 0)
|
|
{
|
|
ProtocolEntry->ResetDone = 1;
|
|
}
|
|
}
|
|
|
|
// Allow other threads to run again
|
|
CRITICAL_LEAVE();
|
|
|
|
return status;
|
|
}
|
|
|
|
#endif //NTENV
|
|
|
|
unsigned char RPC_ENTRY
|
|
execNCB(
|
|
IN unsigned char command,
|
|
IN OUT NCB *pNCB
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Pass an NCB to the NetBios software to execute. This function hides
|
|
the differences of the OS from the other parts of the driver.
|
|
|
|
Arguments:
|
|
|
|
command - command to execute
|
|
|
|
pNCB - NCB to act on
|
|
|
|
Returns:
|
|
|
|
The result of ncb_retcode field from the NCB executed.
|
|
|
|
--*/
|
|
{
|
|
unsigned char result;
|
|
|
|
pNCB->ncb_command = command;
|
|
|
|
#if defined(WIN32RPC)
|
|
result = Netbios(pNCB);
|
|
|
|
#elif defined(WIN)
|
|
// If the command is an async one, call the transport helper
|
|
// functions to corrdinate the waiting.
|
|
|
|
_asm
|
|
{
|
|
les bx,pNCB
|
|
call NetBiosCall
|
|
|
|
mov al,es:[bx+1]
|
|
mov result,al
|
|
}
|
|
|
|
if (result == NRC_PENDING)
|
|
result = 0;
|
|
|
|
#else // DOS
|
|
_asm {
|
|
les bx, pNCB
|
|
int 05ch ; call NetBios Directly
|
|
mov result,al
|
|
};
|
|
|
|
if (result == NRC_PENDING)
|
|
result = 0;
|
|
|
|
#endif
|
|
|
|
return(result);
|
|
}
|