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.
 
 
 
 
 
 

818 lines
18 KiB

#include <stdlib.h>
#include <stdarg.h>
#include <windows.h>
#include <windowsx.h>
#include <sysinc.h>
#include <rpc.h>
#include <rpcdcep.h>
#include <rpctran.h>
#include <rpcerrp.h>
#include <novell.h>
#include <gethost.h>
#include "callback.h"
#define MAX_CONNECTIONS 10
// NULL Pointer macros
#define NULL_HGLOBAL (HGLOBAL)NULL
#define NULL_ECB 0
#define NULL_SPX 0
#define NULL_CHAR 0
// SPX ConnectionControl BIT masks
#define SPX_CC_EOM 0x10
// venerable byte swaping macro
#define SwapWord(i) ((( (unsigned short) (i) & 0xff) << 8) | \
(( (unsigned short) (i) & 0xff00) >> 8))
// Macros for critical section protection
#define Begin_Critical_Section() _asm cli
#define End_Critical_Section() _asm sti
// Tower Stuff
#define TRANSPORTID 0x0c
#define TRANSPORTHOSTID 0x0d
#define TOWERFLOORS 5
#pragma pack(1)
typedef struct _FLLOR_234 {
unsigned short ProtocolIdByteCount;
unsigned char FloorId;
unsigned short AddressByteCount;
unsigned char Data[2];
} FLOOR_234, * PFLOOR_234;
#pragma pack()
#define NEXTFLOOR(t,x) (t)((unsigned char *)x +((t)x)->ProtocolIdByteCount\
+ ((t)x)->AddressByteCount \
+ sizeof(((t)x)->ProtocolIdByteCount) \
+ sizeof(((t)x)->AddressByteCount))
#define ENDPOINT_MAPPER_EP "34280"
// Structure definitions
typedef struct {
DWORD taskid;
WORD ConnID;
WORD local_socket;
HGLOBAL yield;
int yielding;
#define MAX_ECBS 5
struct XECB_st * ecbs[MAX_ECBS];
struct XECB_st * q_head;
struct XECB_st * q_tail;
} CONNECTION, * PCONNECTION;
typedef struct XECB_st {
void * linkAddress;
void (*ESRAddress)();
BYTE inUseFlag;
BYTE completionCode;
WORD socketNumber; /* high-low */
BYTE IPXWorkspace[4]; /* N/A */
BYTE driverWorkspace[12]; /* N/A */
BYTE immediateAddress[6]; /* high-low */
WORD fragmentCount; /* low-high */
ECBFragment fragmentDescriptor[2];
PCONNECTION pConn;
} XECB;
typedef struct {
unsigned char rpc_vers;
unsigned char rpc_vers_minor;
unsigned char PTYPE;
unsigned char pfc_flags;
unsigned char drep[4];
#define BIG_ENDIAN 16 // drep[0] & BIG_ENDIAN indicate byte ordering
unsigned short frag_length;
unsigned short auth_length;
unsigned long call_id;
} ncacn_header;
// DLL global variables
unsigned int spx_max_userdata_size; // max userdata size per SPX packet
extern void (_far pascal _far *DllTermination)(void);
void __cdecl __export __loadds post_ecb(void);
#pragma alloc_text(RPC16C6_FIXED, post_ecb)
#ifdef DEBUGRPC
void
do_popup(char * format, ...)
{
char errmsg[256];
va_list args;
va_start(args, format);
wvsprintf(errmsg, format, args);
va_end(args);
MessageBox((HWND)0, errmsg, "RPC/SPX", MB_SYSTEMMODAL|MB_ICONSTOP);
}
#else
#define do_popup(x)
#endif
void
free_ecb(XECB * ecb)
{
#ifdef DEBUGRPC
if (!ecb)
{
_asm int 3
}
if (ecb->inUseFlag)
{
_asm int 3
}
#endif
if (ecb->fragmentCount > 1) {
GlobalFreePtr(ecb->fragmentDescriptor[1].address);
}
GlobalFreePtr(ecb->fragmentDescriptor[0].address);
GlobalFreePtr(ecb);
}
XECB *
allocate_send_ecb(PCONNECTION pConn)
{
XECB * ecb;
SPX_HEADER * spx;
if ((ecb = (XECB *)GlobalAllocPtr(GPTR, sizeof(XECB))) == NULL_ECB) {
return (NULL_ECB);
}
if ((spx = (SPX_HEADER *)GlobalAllocPtr(GPTR, sizeof(SPX_HEADER))) == NULL_SPX) {
GlobalFreePtr(ecb);
return (NULL_ECB);
}
// Initialize SPX Header...
spx->ipx.PacketType = 5; // SPX packet
// Initialize ECB...
ecb->ESRAddress = 0;
ecb->fragmentCount = 1;
ecb->fragmentDescriptor[0].address = spx;
ecb->fragmentDescriptor[0].size = sizeof(SPX_HEADER);
ecb->socketNumber = pConn->local_socket;
ecb->pConn = pConn;
return (ecb);
}
XECB *
allocate_receive_ecb(PCONNECTION pConn)
{
XECB * ecb;
char * buf;
if ((ecb = allocate_send_ecb(pConn)) == NULL_ECB) {
return (NULL_ECB);
}
//
// Win95 servers are willing to send 0x5d9 bytes on an 802.2 network.
// Novell clients report 802.2 max as 0x5d8, wasting one byte of potential,
// and if a full packet arrives they copy the whole thing. So we must
// allocate space for that extra byte.
//
//
if ((buf = (char *)GlobalAllocPtr(GPTR, 2+spx_max_userdata_size)) == NULL_CHAR) {
free_ecb(ecb);
return (NULL_ECB);
}
ecb->fragmentDescriptor[1].address = buf;
ecb->fragmentDescriptor[1].size = 2+spx_max_userdata_size;
ecb->ESRAddress = post_ecb;
ecb->fragmentCount = 2;
return (ecb);
}
void __loadds
post_ecb()
{
XECB * ecb;
PCONNECTION pConn;
__asm
{
mov word ptr ecb+2, es
mov word ptr ecb, si
}
#ifdef DEBUGRPC
if (!ecb)
{
_asm int 3
}
#endif
pConn = ecb->pConn;
ecb->linkAddress = NULL_ECB;
if (pConn->q_tail == NULL_ECB) {
pConn->q_head = ecb;
} else {
pConn->q_tail->linkAddress = ecb;
}
pConn->q_tail = ecb;
if (pConn->yielding) {
I_RpcWinAsyncCallComplete(pConn);
}
}
XECB *
wait_for_ecb(PCONNECTION pConn)
{
XECB * ecb;
Begin_Critical_Section();
if (pConn->q_head == NULL_ECB) {
pConn->yield = I_RpcWinAsyncCallBegin(pConn);
pConn->yielding = 1;
End_Critical_Section();
IPXRelinquishControl();
if (I_RpcWinAsyncCallWait(pConn->yield, (HWND)NULL, RPC_WIN_INFINITE_TIMEOUT) == 0) {
pConn->yielding = 0;
I_RpcWinAsyncCallEnd(pConn->yield);
return (NULL_ECB);
}
Begin_Critical_Section();
I_RpcWinAsyncCallEnd(pConn->yield);
pConn->yielding = 0;
}
ecb = pConn->q_head;
if ((pConn->q_head = ecb->linkAddress) == NULL_ECB) {
pConn->q_tail = NULL_ECB;
}
End_Critical_Section();
return (ecb);
}
void
spx_abort(PCONNECTION pConn)
{
int i;
if (pConn->local_socket) {
if (pConn->ConnID) {
SPXAbortConnection(pConn->ConnID);
pConn->ConnID = 0;
}
IPXCloseSocket(taskid, pConn->local_socket);
pConn->local_socket = 0;
}
for (i = 0; i < MAX_ECBS; i++) {
if (pConn->ecbs[i] != NULL) {
free_ecb(pConn->ecbs[i]);
pConn->ecbs[i] = 0;
}
}
}
RPC_STATUS RPC_ENTRY _loadds
spx_close(PCONNECTION pConn)
{
int i;
XECB * ecb;
if (pConn->ConnID)
{
if ((ecb = allocate_send_ecb(pConn)) == NULL_ECB)
{
return (RPC_S_OUT_OF_MEMORY);
}
SPXTerminateConnection(taskid, pConn->ConnID, (ECB *) ecb);
while (ecb->inUseFlag)
{
IPXRelinquishControl();
}
free_ecb(ecb);
pConn->ConnID = 0;
}
if (pConn->local_socket)
{
IPXCloseSocket(taskid, pConn->local_socket);
pConn->local_socket = 0;
}
for (i = 0; i < MAX_ECBS; i++)
{
if (pConn->ecbs[i] != NULL)
{
free_ecb(pConn->ecbs[i]);
pConn->ecbs[i] = 0;
}
}
return (RPC_S_OK);
}
RPC_STATUS RPC_ENTRY _loadds
spx_open (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
)
{
int i;
int ret;
int status;
XECB * ecb;
SPX_HEADER * spx;
retry:
pConn->q_head = pConn->q_tail = NULL_ECB;
pConn->yielding = 0;
// Allocate socket ...
pConn->ConnID = 0;
pConn->local_socket = 0;
for (i = 0; i < MAX_ECBS; i++) {
pConn->ecbs[i] = NULL;
}
status = IPXOpenSocket(taskid, &pConn->local_socket, 0xff);
if (status != SUCCESSFUL) {
do_popup("IPXOpenSocket %x", status);
return (RPC_S_OUT_OF_RESOURCES);
}
for (i = 0; i < MAX_ECBS; i++) {
if ((pConn->ecbs[i] = allocate_receive_ecb(pConn)) == NULL_ECB) {
spx_close(pConn);
return (RPC_S_OUT_OF_RESOURCES);
}
SPXListenForSequencedPacket(taskid, (ECB *) pConn->ecbs[i]);
}
if ((ecb = allocate_send_ecb(pConn)) == NULL_ECB) {
spx_abort(pConn);
return (RPC_S_OUT_OF_MEMORY);
}
// Map Address into IPX address...
spx = ecb->fragmentDescriptor[0].address;
status = IpxGetHostByName(NetworkAddress, &spx->ipx.Destination, Endpoint, Timeout,
RpcRuntimeInfo );
if (status != RPC_S_OK) {
free_ecb(ecb);
spx_close(pConn);
return(status);
}
ret = SPXEstablishConnection(taskid, 0, 0xff,(LPWORD)&pConn->ConnID,
(ECB *) ecb);
if (ret != SUCCESSFUL)
{
free_ecb(ecb);
spx_close(pConn);
return RPC_S_OUT_OF_RESOURCES;
}
while (ecb->inUseFlag) {
IPXRelinquishControl();
}
if (ecb->completionCode != SUCCESSFUL) {
free_ecb(ecb);
spx_close(pConn);
if (TRUE == CachedServerNotContacted(NetworkAddress))
{
goto retry;
}
return (RPC_S_SERVER_UNAVAILABLE);
}
free_ecb(ecb);
CachedServerContacted(NetworkAddress);
return (RPC_S_OK);
}
int
put_packets(PCONNECTION pConn,
XECB * ecb,
char * buf,
unsigned int bufsiz)
{
SPX_HEADER * spx;
unsigned int packet_size;
spx = ecb->fragmentDescriptor[0].address;
while (bufsiz > 0) {
packet_size = min(bufsiz, spx_max_userdata_size);
spx->ConnControl = packet_size == bufsiz ? SPX_CC_EOM : 0;
spx->DataType = 0;
ecb->fragmentDescriptor[1].address = buf;
ecb->fragmentDescriptor[1].size = packet_size;
SPXSendSequencedPacket(taskid, pConn->ConnID, (ECB *) ecb);
while (ecb->inUseFlag) {
IPXRelinquishControl();
}
if (ecb->completionCode != SUCCESSFUL) {
return (-1);
}
buf += packet_size;
bufsiz -= packet_size;
}
return (0);
}
RPC_STATUS RPC_ENTRY _loadds
spx_send(PCONNECTION pConn,
void * Buffer,
unsigned int Length
)
{
XECB * ecb;
if ((ecb = allocate_send_ecb(pConn)) == NULL_ECB) {
return (RPC_S_OUT_OF_MEMORY);
}
ecb->fragmentCount = 2;
if (put_packets(pConn, ecb, Buffer, Length) == -1) {
ecb->fragmentCount = 1;
free_ecb(ecb);
spx_close(pConn);
return (RPC_P_SEND_FAILED);
}
ecb->fragmentCount = 1;
free_ecb(ecb);
return (RPC_S_OK);
}
RPC_STATUS
get_remaining_packets(PCONNECTION pConn, char * buf, unsigned int bufsiz)
{
unsigned int length;
XECB * ecb;
SPX_HEADER * spx;
while (bufsiz > 0) {
ecb = wait_for_ecb(pConn);
if (ecb == NULL_ECB || ecb->completionCode != SUCCESSFUL) {
spx_abort(pConn);
return (RPC_P_RECEIVE_FAILED);
}
spx = ecb->fragmentDescriptor[0].address;
length = SwapWord(spx->ipx.Length) - sizeof(SPX_HEADER);
memcpy(buf, ecb->fragmentDescriptor[1].address, length);
SPXListenForSequencedPacket(taskid, (ECB *) ecb);
bufsiz -= length;
buf += length;
}
return (RPC_S_OK);
}
RPC_STATUS RPC_ENTRY _loadds
spx_receive(PCONNECTION pConn,
void * * Buffer,
unsigned int * BufferLength
)
{
unsigned int first_packet_length, fragment_length;
SPX_HEADER * spx;
XECB * ecb;
ncacn_header *ncacn;
ecb = wait_for_ecb(pConn);
if (ecb == NULL_ECB || ecb->completionCode != SUCCESSFUL) {
spx_close(pConn);
return (RPC_P_RECEIVE_FAILED);
}
spx = ecb->fragmentDescriptor[0].address;
if (spx->DataType == 0xFE) {
spx_close(pConn);
return (RPC_P_RECEIVE_FAILED);
}
first_packet_length = SwapWord(spx->ipx.Length) - sizeof(SPX_HEADER);
ncacn = (ncacn_header *)ecb->fragmentDescriptor[1].address;
if ( (ncacn->drep[0] & BIG_ENDIAN) == 0) {
fragment_length = SwapWord(ncacn->frag_length);
} else {
fragment_length = ncacn->frag_length; // it's little-endian
}
//
// If the runtime supplied buffer isn't big enough to hold all SPX packets
// which form the RPC fragment, then go back to the runtime to reallocate it.
//
if (fragment_length > *BufferLength) {
if (I_RpcTransClientReallocBuffer(pConn,
Buffer,
0,
fragment_length)) {
return (RPC_S_OUT_OF_MEMORY);
}
}
*BufferLength = fragment_length;
memcpy(*Buffer, ncacn, first_packet_length);
SPXListenForSequencedPacket(taskid, (ECB *) ecb);
if (fragment_length > first_packet_length) {
return get_remaining_packets(pConn,
(char *)*Buffer + first_packet_length,
fragment_length - first_packet_length);
}
return (RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
spx_tower_construct(
IN char * Endpoint,
IN char * NetworkAddress,
OUT unsigned short * Floors,
OUT unsigned long * ByteCount,
OUT unsigned char * * Tower,
IN char * Protseq
)
{
unsigned int TowerSize;
PFLOOR_234 Floor;
IPX_ADDRESS ipx;
RPC_STATUS status;
unsigned portnum;
/* Compute the memory size of the tower. */
*Floors = TOWERFLOORS;
TowerSize = 12;
TowerSize += 2*sizeof(FLOOR_234) - 4;
/* Allocate memory for the tower. */
*ByteCount = TowerSize;
if ((*Tower = (unsigned char *)I_RpcAllocate(TowerSize)) == NULL)
{
return (RPC_S_OUT_OF_MEMORY);
}
/* Put the endpoint address and transport protocol id in the first floor. */
Floor = (PFLOOR_234) *Tower;
Floor->ProtocolIdByteCount = 1;
Floor->FloorId = (unsigned char)(TRANSPORTID & 0xFF);
Floor->AddressByteCount = 2;
if (Endpoint == NULL || *Endpoint == '\0')
{
Endpoint = ENDPOINT_MAPPER_EP;
}
portnum = atoi(Endpoint);
Floor->Data[0] = portnum / 0x100;
Floor->Data[1] = portnum % 0x100;
/* Put the network address and the transport host protocol id in the
second floor. */
Floor = NEXTFLOOR(PFLOOR_234, Floor);
Floor->ProtocolIdByteCount = 1;
Floor->FloorId = (unsigned char)(TRANSPORTHOSTID & 0xFF);
Floor->AddressByteCount = 4 + 6;
memset(Floor->Data, '\0', 10);
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
spx_tower_explode(
IN unsigned char * Tower,
OUT char * * Protseq,
OUT char * * Endpoint,
OUT char * * NetworkAddress
)
{
PFLOOR_234 Floor = (PFLOOR_234) Tower;
RPC_STATUS Status = RPC_S_OK;
unsigned short portnum;
char * spx_protseq = "ncacn_spx";
if (Protseq != NULL) {
*Protseq = (char *)I_RpcAllocate(strlen(spx_protseq) + 1);
if (*Protseq == NULL)
Status = RPC_S_OUT_OF_MEMORY;
else
memcpy(*Protseq, spx_protseq, strlen(spx_protseq) + 1);
}
if ((Endpoint == NULL) || (Status != RPC_S_OK)) {
return (Status);
}
*Endpoint = (char *)I_RpcAllocate(6); //Ports are all <64K [5 decimal dig +1]
if (*Endpoint == NULL) {
Status = RPC_S_OUT_OF_MEMORY;
if (Protseq != NULL) {
I_RpcFree(*Protseq);
}
} else {
portnum = SwapWord(*(short *)Floor->Data);
_itoa(portnum, *Endpoint, 10);
}
return(Status);
}
void PASCAL __loadds
spx_wrapup(void)
{
if (nwipxspx && 0 != GetModuleHandle("NWIPXSPX"))
{
IPXSPXDeinit(taskid);
FreeLibrary(nwipxspx);
}
}
RPC_CLIENT_TRANSPORT_INFO TransInfo =
{
RPC_TRANSPORT_INTERFACE_VERSION,
TRANSPORTID,
(TRANS_CLIENT_TOWERCONSTRUCT) spx_tower_construct,
(TRANS_CLIENT_TOWEREXPLODE) spx_tower_explode,
0,
sizeof(CONNECTION),
(TRANS_CLIENT_OPEN) spx_open,
(TRANS_CLIENT_CLOSE) spx_close,
(TRANS_CLIENT_SEND) spx_send,
(TRANS_CLIENT_RECEIVE) spx_receive,
0,
0,
0,
0
};
RPC_CLIENT_TRANSPORT_INFO * RPC_ENTRY
TransPortLoad (
IN RPC_CHAR * RpcProtocolSequence,
IN RPC_CLIENT_RUNTIME_INFO PAPI * RpcClientRuntimeInfo
)
{
int retcode;
BYTE major_revision, minor_revision;
unsigned int max_connections, available_connections;
if (IPXInitialize(&taskid, MAX_CONNECTIONS * MAX_ECBS, 0) != 0)
{
return 0;
}
AsyncCallComplete = RpcClientRuntimeInfo->AsyncCallComplete;
RpcRuntimeInfo = RpcClientRuntimeInfo;
taskid = 0xffffffff;
retcode = SPXInitialize(&taskid,
MAX_CONNECTIONS * MAX_ECBS, // maxECBs
0,
&major_revision,
&minor_revision,
&max_connections,
&available_connections);
switch (retcode) {
case 0:
do_popup("Not installed");
return (NULL);
case 0xf0:
if (GetWinFlags() & WF_ENHANCED) {
do_popup("not supported");
return (NULL);
}
do_popup("Failed increasing local memory");
return (NULL);
case 0xf1:
do_popup("not initialized");
return (NULL);
case 0xf2:
do_popup("no DOS memory");
return(NULL);
case 0xf3:
do_popup("no free ECB");
return(NULL);
case 0xf4:
do_popup("Lock failed");
return(NULL);
case 0xf5:
do_popup("Over the maximum limit");
return(NULL);
case 0xf6:
do_popup("previously initialized");
//Intentional Fall Through
case SPX_INSTALLED:
break;
default:
do_popup("Unknown SPX Failure");
return(NULL);
}
spx_max_userdata_size = IPXGetMaxPacketSize() - sizeof(SPX_HEADER);
TransInfo.MaximumPacketSize = (spx_max_userdata_size * MAX_ECBS)
& 0xFFF8;
DllTermination = spx_wrapup;
return(&TransInfo);
}