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.
 
 
 
 
 
 

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);
}