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.
 
 
 
 
 
 

622 lines
14 KiB

/* --------------------------------------------------------------------
File : nbltclnt.c
Title : client loadable transport for Windows NT NetBIOS - client side
Description :
History :
19-1-95 Tony Chan Use winsock to support NetBIOS
WITH SEQ_NUMBER
Compatibility issue
In order to be compatible with the old NetBIOS server transport,
If the first DWORD of the packet is 0, we know that it's a old NetBIOS
client connection. Therefore, we will take away the seq # and return only
the data to the runtime.
If the first DWORD of the first message is not 0, it's actually is the
runtime message_header RPC_version #, so we hand the whole buffer to the
runtime.
If we are dealing with old server, on all subsequence Send, we need to
prepend seq_number, and we need to take away sequence # on all recv from
old client
-------------------------------------------------------------------- */
/*
OLD_CLIENT:
if define old client, this transport will behave as an old client otherwise
it will behave as a new client without sending out sequence number.
*/
#define OLD_CLIENT 1
#include "sysinc.h"
#define FD_SETSIZE 1
#include <winsock.h>
#include <tdi.h>
// NetBIOS winsock header file
#include <wsnetbs.h>
#include <winbase.h>
#include <stdlib.h>
#include "rpc.h"
#include "rpcdcep.h"
#include "rpctran.h"
#include "rpcerrp.h"
#include "common.h"
#include "reg.h" /* registry lookup rountine */
/*
Following Macros and structs are needed for Tower Stuff
*/
#pragma pack(1)
#define NB_TRANSPORTID 0x12
#define NB_NBID 0x13
#define NB_XNSID 0x15
#define NB_IPID 0x09
#define NB_IPXID 0x0d
#define NB_TOWERFLOORS 5
#define NB_PROTSEQ "ncacn_nb_nb"
#define IP_PROTSEQ "ncacn_nb_tcp"
#define IPX_PROTSEQ "ncacn_nb_ipx"
typedef struct _FLOOR_234 {
unsigned short ProtocolIdByteCount;
unsigned char FloorId;
unsigned short AddressByteCount;
unsigned char Data[2];
} FLOOR_234, __RPC_FAR * PFLOOR_234;
#define NEXTFLOOR(t,x) (t)((unsigned char __RPC_FAR *)x +((t)x)->ProtocolIdByteCount\
+ ((t)x)->AddressByteCount\
+ sizeof(((t)x)->ProtocolIdByteCount)\
+ sizeof(((t)x)->AddressByteCount))
/*
End of Tower Stuff!
*/
#define ENDIAN_MASK 16
#define ENDPOINT_LEN 3
#define PFC_FIRST_FRAG 0x01
typedef struct
{
SOCKET Socket;
char PAPI * Buffer;
fd_set SockSet;
BOOL LocalRpc;
#ifdef OLD_CLIENT
int seq_num; /* for the old client case */
#endif
} CONNECTION, *PCONNECTION;
#define NB_OK 0
#define NB_CONTINUE 1
#define NB_FAIL 2
extern int NumCards; /* defined in reg.h */
int CreateAndSetupNBSocket (
IN PCONNECTION pConn,
IN RPC_CHAR PAPI *RpcProtocolSequence,
IN char PAPI *HostName,
IN int PortIn,
IN int CardIndex
)
{
PPROTOCOL_MAP ProtocolEntry;
SOCKADDR_NB server ;
int Status;
BOOL reuse; /* for socket option */
if (Status = MapProtocol(RpcProtocolSequence, CardIndex, &ProtocolEntry))
{
return NB_CONTINUE ;
}
// Get a socket, the PROTOCOL
// is defined to be (-1 * LANA numbmer)
if ((pConn->Socket = socket(AF_NETBIOS,
SOCK_SEQPACKET ,
-1 * (ProtocolEntry->Lana)))
== INVALID_SOCKET)
{
#ifdef DEBUGRPC
PrintToDebugger( "%s: socket - %d\n",
"rpcltccm - NB", WSAGetLastError() );
#endif
return(NB_FAIL);
}
reuse = TRUE;
setsockopt(pConn->Socket, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse,
sizeof(BOOL));
// setup server sockaddr
server.snb_family = AF_NETBIOS;
SET_NETBIOS_SOCKADDR((&server), NETBIOS_UNIQUE_NAME,
HostName, (char ) PortIn);
// try to connect
if (connect(pConn->Socket, (struct sockaddr *) &server,
sizeof (server)) == SOCKET_ERROR)
{
#ifdef DEBUGRPC
PrintToDebugger( "%s: Connect - %d to port %d\n",
"rpcltccm - NB", WSAGetLastError(), PortIn );
#endif
closesocket(pConn->Socket);
pConn->Socket = 0;
return(NB_CONTINUE);
}
return NB_OK ;
}
RPC_STATUS RPC_ENTRY
ClientOpen (
IN PCONNECTION pConn,
IN RPC_CHAR * NetworkAddress,
IN RPC_CHAR * Endpoint,
IN RPC_CHAR * NetworkOptions,
IN RPC_CHAR * TransportAddress,
IN RPC_CHAR * RpcProtocolSequence,
IN unsigned int Timeout
)
// Open a client connection
{
SOCKADDR_NB server; /* sock address for server */
size_t hostNameLen; /* length of the host name */
unsigned char remotehostname[NETBIOS_NAME_LENGTH+1];
unsigned char port[ENDPOINT_LEN+1]; /* port number in string format */
int status;
int i;
unsigned int PortIn; /* port in integer format */
PPROTOCOL_MAP ProtocolEntry;
UNUSED(NetworkAddress);
UNUSED(NetworkOptions);
UNUSED(TransportAddress);
UNUSED(RpcProtocolSequence);
UNUSED(Timeout);
if (RpcpStringLength(NetworkAddress) > NETBIOS_NAME_LENGTH)
{
return (RPC_S_INVALID_NET_ADDR) ;
}
#ifdef NTENV
if(RpcpStringLength(Endpoint) != wcsspn(Endpoint, RPC_CONST_STRING("0123456789")))
#else
if(RpcpStringLength(Endpoint) != strspn(Endpoint, RPC_CONST_STRING("0123456789")))
#endif // #ifdef NTENV
{
return(RPC_S_INVALID_ENDPOINT_FORMAT);
}
if(RpcpStringLength(Endpoint) > ENDPOINT_LEN)
{
return(RPC_S_INVALID_ENDPOINT_FORMAT);
}
// Convert the endpoint string to a number and validate.
unicode_to_ascii (Endpoint, port);
PortIn = atoi(port);
if((PortIn == 0) ||( PortIn >= 255) )
{
return(RPC_S_INVALID_ENDPOINT_FORMAT);
}
/* setup hostname */
unicode_to_ascii (NetworkAddress, remotehostname);
if ( remotehostname[0] == '\0')
{
pConn->LocalRpc = TRUE;
hostNameLen = MAX_COMPUTERNAME_LENGTH + 1;
GetComputerName(remotehostname, &hostNameLen);
}
_strupr(remotehostname); /* conver to upper case for netbios */
for (i = 0; i <=NumCards; i++)
{
status = CreateAndSetupNBSocket(
pConn, RpcProtocolSequence, remotehostname,
PortIn, i) ;
if (status == NB_CONTINUE)
{
continue;
}
if (status != NB_OK)
{
return RPC_S_SERVER_UNAVAILABLE ;
}
break;
}
if (status != NB_OK)
{
return RPC_S_SERVER_UNAVAILABLE ;
}
// got the connection
#ifdef OLD_CLIENT
pConn->seq_num = 0; /* init seq number */
#endif
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
ClientClose (
IN PCONNECTION pConn
)
// Close a client connection
{
closesocket(pConn->Socket);
pConn->Socket = 0;
return (RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
ClientSend (
IN PCONNECTION pConn,
IN void PAPI * Buffer,
IN unsigned int BufferLength
)
{
int bytes;
int total_bytes = 0;
int Status;
unsigned long PrevTicks;
#ifdef OLD_CLIENT
/* structure to support seq number */
typedef struct a_BufferWithSeq {
DWORD seq_num;
char Buffer[5280];
} t_BufferWithSeq;
t_BufferWithSeq BufferWithSeq ;
ASSERT(BufferLength <= 5280);
BufferWithSeq.seq_num = pConn->seq_num;
memcpy(&(BufferWithSeq.Buffer), Buffer, BufferLength);
bytes = send(pConn->Socket, (char *) & BufferWithSeq,
(int) sizeof(DWORD) + BufferLength, 0);
if (bytes != (int) (BufferLength + sizeof(DWORD)))
{
ClientClose ( pConn );
return(RPC_P_SEND_FAILED);
}
pConn->seq_num++;
#else
ASSERT(BufferLength <= 5280);
bytes = send(pConn->Socket, (char *) Buffer, (int) BufferLength, 0);
if (bytes != (int) BufferLength )
{
ClientClose ( pConn );
return(RPC_P_SEND_FAILED);
}
#endif
return(RPC_S_OK);
}
RPC_TRANS_STATUS RPC_ENTRY
ClientRecv (
IN PCONNECTION pConn,
IN OUT void PAPI * PAPI * Buffer,
IN OUT unsigned int PAPI * BufferLength
)
// Read a message from a connection.
{
RPC_STATUS RpcStatus = RPC_S_OK;
int bytes;
unsigned int totalBytes = 0;
int err; /* for error message */
int flags;
int retry ;
/* reset seq number once receive */
pConn->seq_num = 0;
if (*Buffer == 0)
{
*BufferLength = 1024;
RpcStatus =
I_RpcTransClientReallocBuffer(pConn, Buffer, 0,
*BufferLength);
if (RpcStatus != RPC_S_OK)
{
return(RPC_S_OUT_OF_MEMORY);
}
}
retry = 1;
while(1)
{
flags = 0;
bytes = WSARecvEx( pConn->Socket, (char *)*Buffer + totalBytes,
*BufferLength - totalBytes, &flags);
if (bytes <= 0 ) // if connection close, bytes will = 0, we need to close connection
{
#ifdef DEBUGRPC
PrintToDebugger("rpcltccm - NB: bad client receive lasterr(%d) \n",
WSAGetLastError());
#endif
ClientClose(pConn);
return(RPC_P_RECEIVE_FAILED);
}
totalBytes += bytes;
if(flags & MSG_PARTIAL)
{
if (retry == 0)
{
#ifdef DEBUGRPC
PrintToDebugger("rpcltccm - NB: twice client receive lasterr(%d) \n",
WSAGetLastError());
#endif
ClientClose(pConn);
return(RPC_P_RECEIVE_FAILED);
}
*BufferLength = I_RpcTransClientMaxFrag(pConn);
RpcStatus = I_RpcTransClientReallocBuffer(pConn,
Buffer,
totalBytes,
*BufferLength);
if (RpcStatus != RPC_S_OK)
{
#ifdef DEBUGRPC
PrintToDebugger("rpcltccm - NB: bad client receive \n");
#endif
return(RPC_S_OUT_OF_MEMORY);
}
retry = 0;
}
else
{
*BufferLength = totalBytes;
return(RPC_S_OK);
}
}
ASSERT(0);
return(RPC_S_INTERNAL_ERROR);
}
#pragma pack(1)
RPC_STATUS RPC_ENTRY
ClientTowerConstruct(
IN char PAPI * Endpoint,
IN char PAPI * NetworkAddress,
OUT short PAPI * Floors,
OUT unsigned long PAPI * ByteCount,
OUT unsigned char PAPI * PAPI * Tower,
IN char PAPI * Protseq
)
{
unsigned long TowerSize;
UNALIGNED PFLOOR_234 Floor;
unsigned long HostId;
//BUGBUG: Need appropriate error code for unsupported Protseqs
if (strcmp(Protseq,NB_PROTSEQ) == 0)
HostId = NB_NBID;
else if (strcmp(Protseq, IP_PROTSEQ) == 0)
HostId = NB_IPID;
else if (strcmp(Protseq, IPX_PROTSEQ) == 0)
HostId = NB_IPXID;
else return (RPC_S_OUT_OF_MEMORY);
*Floors = NB_TOWERFLOORS;
TowerSize = ((Endpoint == NULL) || (*Endpoint == '\0')) ?
2 : strlen(Endpoint) + 1;
TowerSize += ((NetworkAddress== NULL) || (*NetworkAddress== '\0')) ?
2 : strlen(NetworkAddress) + 1;
TowerSize += 2*sizeof(FLOOR_234) - 4;
if ((*Tower = (unsigned char __RPC_FAR*)I_RpcAllocate((unsigned int)
(*ByteCount = TowerSize)))
== NULL)
{
return (RPC_S_OUT_OF_MEMORY);
}
Floor = (PFLOOR_234) *Tower;
Floor->ProtocolIdByteCount = 1;
Floor->FloorId = (unsigned char)(NB_TRANSPORTID & 0xFF);
if ((Endpoint) && (*Endpoint))
{
memcpy((char __RPC_FAR *)&Floor->Data[0], Endpoint,
(Floor->AddressByteCount = strlen(Endpoint)+1));
}
else
{
Floor->AddressByteCount = 2;
Floor->Data[0] = 0;
}
//Onto the next floor
Floor = NEXTFLOOR(PFLOOR_234, Floor);
Floor->ProtocolIdByteCount = 1;
Floor->FloorId = (unsigned char)(HostId & 0xFF);
if ((NetworkAddress) && (*NetworkAddress))
{
memcpy((char __RPC_FAR *)&Floor->Data[0], NetworkAddress,
(Floor->AddressByteCount = strlen(NetworkAddress) + 1));
}
else
{
Floor->AddressByteCount = 2;
Floor->Data[0] = 0;
}
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
ClientTowerExplode(
IN unsigned char PAPI * Tower,
OUT char PAPI * PAPI * Protseq,
OUT char PAPI * PAPI * Endpoint,
OUT char PAPI * PAPI * NetworkAddress
)
{
UNALIGNED PFLOOR_234 Floor = (PFLOOR_234) Tower;
RPC_STATUS Status = RPC_S_OK;
char __RPC_FAR * Pseq;
UNUSED(NetworkAddress);
if (Endpoint != NULL)
{
*Endpoint = I_RpcAllocate(Floor->AddressByteCount);
if (*Endpoint == NULL)
{
Status = RPC_S_OUT_OF_MEMORY;
}
else
{
memcpy(*Endpoint, (char __RPC_FAR *)&Floor->Data[0],
Floor->AddressByteCount);
}
}
Floor = NEXTFLOOR(PFLOOR_234, Floor);
switch (Floor->FloorId)
{
case NB_NBID:
Pseq = NB_PROTSEQ;
break;
case NB_IPID:
Pseq = IP_PROTSEQ;
break;
case NB_IPXID:
Pseq = IPX_PROTSEQ;
break;
default:
return(RPC_S_OUT_OF_MEMORY);
}
if ((Protseq != NULL) && (Status == RPC_S_OK))
{
*Protseq = I_RpcAllocate(strlen(Pseq) + 1);
if (*Protseq == NULL)
{
Status = RPC_S_OUT_OF_MEMORY;
if (Endpoint != NULL)
I_RpcFree(*Endpoint);
}
else
{
memcpy(*Protseq, Pseq, strlen(Pseq) + 1);
}
}
return(Status);
}
#pragma pack()
RPC_CLIENT_TRANSPORT_INFO NB_TransInfo = {
RPC_TRANSPORT_INTERFACE_VERSION,
NB_TRANSPORTID,
ClientTowerConstruct,
ClientTowerExplode,
5280,
sizeof (CONNECTION),
ClientOpen,
ClientClose,
ClientSend,
ClientRecv,
NULL,
NULL,
NULL,
NULL
};