Leaked source code of windows server 2003
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.
 
 
 
 
 
 

807 lines
20 KiB

/*++
Copyright (C) Microsoft Corporation, 1991 - 1999
Module Name:
tower.c
Abstract:
This file contains encoding/decoding for the tower representation
of the binding information that DCE runtime uses.
TowerConstruct/TowerExplode will be called by the Runtime EpResolveBinding
on the client side, TowerExplode will be called by the Endpoint Mapper
and in addition the name service may call TowerExplode, TowerConstruct.
Author:
Bharat Shah (barats) 3-23-92
KamenM 05/02/2002 Major security and cleanup changes
Revision History:
--*/
#include <precomp.hxx>
#include <epmp.h>
#include <twrtypes.h>
#include <twrproto.h>
//
// TowerVerify() defines.
//
// Note: DECnet Protocol uses 6 Floors, all others 5.
//
#define MAX_FLOOR_COUNT 6
#define MIN_FLOOR_COUNT 3
#ifndef UNALIGNED
#error UNALIGNED not defined by sysinc.h or its includes and is needed.
#endif
#pragma pack(1)
/*
Some Lrpc specific stuff
*/
#define NP_TRANSPORTID_LRPC 0x10
#define NP_TOWERS_LRPC 0x04
// "ncalrpc" including the NULL terminator
const int LrpcProtocolSequenceLength = 8;
RPC_STATUS
Floor0or1ToId(
IN PFLOOR_0OR1 Floor,
OUT PGENERIC_ID Id
)
/*++
Routine Description:
This function extracts Xfer Syntax or If info from a
a DCE tower Floor 0 or 1 encoding
Arguments:
Floor - A pointer to Floor0 or Floor 1 encoding
Id - on output, the transfer syntax or interface id
Return Value:
EP_S_CANT_PERFORM_OP - The Encoding for the floor [0 or 1] is incorrect.
N.B.
Caller must have verified that the whole floor is present (i.e. we can't walk
off the end of the buffer)
--*/
{
if (Floor->FloorId != UUID_ENCODING)
{
return (EP_S_CANT_PERFORM_OP);
}
RpcpMemoryCopy((char PAPI *)&Id->Uuid, (char PAPI *) &Floor->Uuid,
sizeof(UUID));
Id->MajorVersion = Floor->MajorVersion;
Id->MinorVersion = Floor->MinorVersion;
return(RPC_S_OK);
}
RPC_STATUS
CopyIdToFloor(
OUT PFLOOR_0OR1 Floor,
IN PGENERIC_ID Id
)
/*++
Routine Description:
This function constructs FLOOR 0 or 1 from the given IF-id or Transfer
Syntax Id.
Arguments:
Floor - Pointer to Floor 0 or 1 structure that will be constructed
Id - Pointer to If-id or Xfer Syntax Id.
Return Value:
RPC_S_OK
--*/
{
Floor->FloorId = UUID_ENCODING;
Floor->ProtocolIdByteCount = sizeof(Floor->Uuid) + sizeof(Floor->FloorId)
+ sizeof(Floor->MajorVersion);
Floor->AddressByteCount = sizeof(Floor->MinorVersion);
RpcpMemoryCopy((char PAPI *) &Floor->Uuid, (char PAPI *) &Id->Uuid,
sizeof(UUID));
Floor->MajorVersion = Id->MajorVersion;
Floor->MinorVersion = Id->MinorVersion;
return(RPC_S_OK);
}
BYTE *
VerifyFloorLHSAndRHS (
IN BYTE *FloorStart,
IN BYTE *UpperBound,
IN ULONG FloorNum
)
/*++
Routine Description:
Verifies that the left hand side (LHS) byte count and the
right hand side (RHS) byte count in the given floor are accurate
with respect to the floor start and size (i.e. jumping from the LHS
we go to the right hand side, and from there, to the end of the floor
without walking off the end).
Arguments:
FloorStart - the start of the current floor.
UpperBound - pointer to first invalid byte after the buffer.
FloorNum - the number of the floor. Used for debugging only
Return Value:
The position of the next floor, or NULL if the floor fails the check.
--*/
{
USHORT LHSBytes, RHSBytes;
if (FloorStart + 2 >= UpperBound)
return NULL;
LHSBytes = *(unsigned short UNALIGNED *)FloorStart;
if (FloorStart + (ULONG)LHSBytes + 4 >= UpperBound) // the LHSBytes counter itself is 2 bytes, and we
{ // must provide at least 2 bytes for the RHSBytes
#ifdef DEBUGRPC
PrintToDebugger("RPC: TowerVerify(): LHS of Tower floor %d "
"greater than equal to FloorSize\n", FloorNum);
#endif // DEBUGRPC
return NULL;
}
FloorStart += LHSBytes + 2;
RHSBytes = *(unsigned short UNALIGNED *)FloorStart;
if (FloorStart + (ULONG)RHSBytes + 2 > UpperBound) // the RHSBytes counter itself is 2 bytes
{
#ifdef DEBUGRPC
PrintToDebugger("RPC: TowerVerify(): RHS of Tower floor %d "
"greater than equal to FloorSize\n", FloorNum);
#endif // DEBUGRPC
return NULL;
}
return FloorStart + RHSBytes + 2;
}
RPC_STATUS
ExtractStringFromUntrustedPacket (
IN BYTE *UpperBound,
IN ULONG ClaimedStringLength,
IN char *StringStart,
OUT char **ExtractedString
)
/*++
Routine Description:
Extracts a string from untrusted packet. Verifies
string boundaries, reasonable length (at least one character
and no more than 1000), and null termination.
Arguments:
UpperBound - the first invalid byte after the end of the buffer.
ClaimedStringLength - the string length that the packet claims.
StringStart - the alleged start of the string - untrusted.
ExtractedString - the extracted string. Must be freed with delete. Undefined
on failure.
Return Value:
RPC_S_OK, RPC_S_OUT_OF_MEMORY or EP_S_CANT_PERFORM_OP
--*/
{
char *NewString;
if ((ClaimedStringLength < 2) || (ClaimedStringLength > 1000))
return EP_S_CANT_PERFORM_OP;
if (StringStart + ClaimedStringLength > (char *)UpperBound)
return EP_S_CANT_PERFORM_OP;
// the claimed string length includes the terminating NULL
if (StringStart[ClaimedStringLength - 1] != '\0')
return EP_S_CANT_PERFORM_OP;
NewString = new char [ClaimedStringLength];
if (NewString == NULL)
return RPC_S_OUT_OF_MEMORY;
RpcpMemoryCopy(NewString, StringStart, ClaimedStringLength);
*ExtractedString = NewString;
return RPC_S_OK;
}
RPC_STATUS
LrpcTowerConstruct(
IN char PAPI * Endpoint,
OUT unsigned short PAPI UNALIGNED * Floors,
OUT unsigned long PAPI UNALIGNED * ByteCount,
OUT unsigned char PAPI * UNALIGNED PAPI * Tower
)
{
unsigned long TowerSize;
FLOOR_234 UNALIGNED *Floor;
int EndpointLength;
*Floors = NP_TOWERS_LRPC;
if ((Endpoint == NULL) || (*Endpoint == '\0'))
{
EndpointLength = 0;
}
else
{
EndpointLength = RpcpStringLengthA(Endpoint) + 1;
}
if (EndpointLength == 0)
TowerSize = 2;
else
TowerSize = EndpointLength;
TowerSize += sizeof(FLOOR_234) - 2;
*ByteCount = TowerSize;
if ((*Tower = (unsigned char *)I_RpcAllocate(TowerSize)) == NULL)
{
return (RPC_S_OUT_OF_MEMORY);
}
Floor = (PFLOOR_234) *Tower;
Floor->ProtocolIdByteCount = 1;
Floor->FloorId = (unsigned char)(NP_TRANSPORTID_LRPC & 0xFF);
if (EndpointLength)
{
Floor->AddressByteCount = (unsigned short)EndpointLength;
RpcpMemoryCopy((char PAPI *)&Floor->Data[0], Endpoint,
EndpointLength);
}
else
{
Floor->AddressByteCount = 2;
Floor->Data[0] = 0;
}
return(RPC_S_OK);
}
RPC_STATUS
LrpcTowerExplode(
IN PFLOOR_234 Floor34,
IN BYTE *UpperBound,
IN ULONG RemainingFloors,
OUT char ** Protseq, OPTIONAL
OUT char ** Endpoint, OPTIONAL
OUT char ** NetworkAddress OPTIONAL
)
{
BYTE *CurrentPosition;
BYTE *NextFloor;
RPC_STATUS RpcStatus;
ULONG EndpointLength;
// Initialize all our OUT pointers so we don't end up deleting uninitialized memory
if (Protseq)
*Protseq = NULL;
if (Endpoint)
*Endpoint = NULL;
// we expect only one floor more
if (RemainingFloors != 1)
return EP_S_CANT_PERFORM_OP;
if (Protseq != NULL)
{
*Protseq = new char[LrpcProtocolSequenceLength];
if (*Protseq == NULL)
{
return(RPC_S_OUT_OF_MEMORY);
}
RpcpMemoryCopy(*Protseq, "ncalrpc", LrpcProtocolSequenceLength);
}
if (Endpoint == NULL)
{
return (RPC_S_OK);
}
CurrentPosition = (BYTE *)Floor34;
// an endpoint must be at least two chars long (null terminator included).
// Since FLOOR_234 has space for 2 chars, we need to subtract one
if (CurrentPosition + sizeof(FLOOR_234) >= UpperBound)
return EP_S_CANT_PERFORM_OP;
NextFloor = VerifyFloorLHSAndRHS (CurrentPosition,
UpperBound,
3 // FloorNum
);
if (NextFloor == NULL)
{
RpcStatus = EP_S_CANT_PERFORM_OP;
goto AbortAndExit;
}
EndpointLength = Floor34->AddressByteCount;
RpcStatus = ExtractStringFromUntrustedPacket (UpperBound,
EndpointLength,
(char *)&Floor34->Data[0],
Endpoint
);
if (RpcStatus == RPC_S_OK)
return(RPC_S_OK);
else
{
// fall through to cleanup call below
}
AbortAndExit:
if (Protseq && *Protseq)
delete [] *Protseq;
if (Endpoint && *Endpoint)
delete [] *Endpoint;
return RpcStatus;
}
RPC_STATUS
GetProtseqAndEndpointFromFloor3(
IN PFLOOR_234 Floor,
IN BYTE *UpperBound,
IN ULONG RemainingFloors,
OUT char **Protseq, OPTIONAL
OUT char **Endpoint, OPTIONAL
OUT char **NWAddress OPTIONAL
)
{
/*++
Routine Description:
This function extracts the Protocol Sequence and Endpoint info
from a "Lower Tower" representation
Arguments:
Floor - Pointer to Floor2 structure.
UpperBound - the first invalid byte after the end of the buffer.
RemainingFloors - the number of floors remaining.
Protseq - A pointer that will contain Protocol seq on return
The memory will be allocated by this routine and caller
will have to free this memory using delete. Undefined on
failure.
Endpoint - A pointer that will contain Endpoint on return
The memory will be allocated by this routine and caller
will have to free this memory using delete. Undefined on
failure.
NWAddress - A pointer that will contain Endpoint on return
The memory will be allocated by this routine and caller
will have to free this memory using delete. Undefined on
failure.
Return Value:
RPC_S_OK
RPC_S_OUT_OF_MEMORY - There is no memory to return Protseq or Endpoint string
EP_S_CANT_PERFORM_OP - Lower Tower Encoding is incorrect.
--*/
USHORT ProtocolType;
RPC_STATUS Status;
BYTE *CurrentPosition;
PFLOOR_234 Floor34;
CurrentPosition = (BYTE *)Floor;
if (CurrentPosition + sizeof(FLOOR_234) >= UpperBound)
{
return EP_S_CANT_PERFORM_OP;
}
Floor34 = (PFLOOR_234)VerifyFloorLHSAndRHS(CurrentPosition,
UpperBound,
2 // FloorNum
);
if (Floor34 == NULL)
return EP_S_CANT_PERFORM_OP;
ProtocolType = Floor->FloorId;
if (NWAddress != 0)
{
*NWAddress = 0;
}
switch(ProtocolType)
{
case CONN_LRPC:
Status = LrpcTowerExplode(Floor34, UpperBound, RemainingFloors - 1,
Protseq, Endpoint, NWAddress);
break;
case CONNECTIONFUL:
case CONNECTIONLESS:
Status = OsfTowerExplode((BYTE *)Floor34, UpperBound, RemainingFloors - 1,
Protseq, Endpoint, NWAddress);
break;
default:
Status = EP_S_CANT_PERFORM_OP;
}
return(Status);
}
RPC_STATUS
TowerExplode(
IN twr_p_t Tower,
OUT RPC_IF_ID *Ifid, OPTIONAL
OUT RPC_TRANSFER_SYNTAX *XferId, OPTIONAL
OUT char **Protseq, OPTIONAL
OUT char **Endpoint, OPTIONAL
OUT char **NWAddress OPTIONAL
)
/*++
Routine Description:
This function converts a DCE tower representation of various binding
information to binding info that is suitable to MS runtime.
Specically it returns Ifid, Xferid, Protseq and Endpoint information
encoded in the tower.
Arguments:
Tower - Tower encoding.
Ifid - A pointer to Ifid
Xferid - A pointer to Xferid
Protseq - A pointer to pointer returning Protseq
Endpoint- A pointer to pointer returning Endpoint
Return Value:
RPC_S_OK
EP_S_CANT_PERFORM_OP - Error while parsing the Tower encoding
RPC_S_OUT_OF_MEMORY - There is no memory to return Protseq and Endpoint
strings.
--*/
{
PFLOOR_0OR1 Floor00;
PFLOOR_0OR1 Floor01;
PFLOOR_234 Floor234;
unsigned short FloorCount;
RPC_STATUS RpcStatus;
BYTE *UpperBound, *LowerBound;
BYTE *CurrentPosition;
if (Tower == NULL)
{
RpcStatus = EP_S_CANT_PERFORM_OP;
goto CleanupAndExit;
}
//
// LowerBound points to Floor1
// UpperBound points to the byte after the last Floor
//
LowerBound = Tower->tower_octet_string + 2; // FloorCount is 2 bytes
UpperBound = Tower->tower_octet_string + Tower->tower_length;
// make sure we at least have the floor count
if (UpperBound <= LowerBound)
{
RpcStatus = EP_S_CANT_PERFORM_OP;
goto CleanupAndExit;
}
// go to the floor count
CurrentPosition = Tower->tower_octet_string;
// the tower octet string immediately follows the tower_length in the IDL
// so we know it is 4 bytes aligned. No need for unaligned here.
FloorCount = *((USHORT *)CurrentPosition);
if ( FloorCount > MAX_FLOOR_COUNT
|| FloorCount < MIN_FLOOR_COUNT)
{
#ifdef DEBUGRPC
PrintToDebugger("RPC: TowerVerify(): Too many/few floors - %d\n",
FloorCount);
#endif // DEBUGRPC
RpcStatus = EP_S_CANT_PERFORM_OP;
goto CleanupAndExit;
}
// skip the floor count and go to the first floor
CurrentPosition += 2; // floor count is 2 bytes
if (CurrentPosition + sizeof(FLOOR_0OR1) >= UpperBound)
{
RpcStatus = EP_S_CANT_PERFORM_OP;
goto CleanupAndExit;
}
Floor01 = (PFLOOR_0OR1)VerifyFloorLHSAndRHS(CurrentPosition,
UpperBound,
0 // FloorNum
);
if (Floor01 == NULL)
{
RpcStatus = EP_S_CANT_PERFORM_OP;
goto CleanupAndExit;
}
Floor00 = (PFLOOR_0OR1) CurrentPosition;
//Process Floor 0 Interface Spec.
if (Ifid != NULL)
{
RpcStatus = Floor0or1ToId(Floor00, (PGENERIC_ID) Ifid);
if (RpcStatus != RPC_S_OK)
{
RpcStatus = EP_S_CANT_PERFORM_OP;
goto CleanupAndExit;
}
}
CurrentPosition = (BYTE *)Floor01;
if (CurrentPosition + sizeof(FLOOR_0OR1) >= UpperBound)
{
RpcStatus = EP_S_CANT_PERFORM_OP;
goto CleanupAndExit;
}
Floor234 = (PFLOOR_234)VerifyFloorLHSAndRHS(CurrentPosition,
UpperBound,
1 // FloorNum
);
if (Floor234 == NULL)
{
RpcStatus = EP_S_CANT_PERFORM_OP;
goto CleanupAndExit;
}
//Now we point to and process Floor 1 Transfer Syntax Spec.
if (XferId != NULL)
{
RpcStatus = Floor0or1ToId(Floor01, (PGENERIC_ID) XferId);
if (RpcStatus != RPC_S_OK)
{
RpcStatus = EP_S_CANT_PERFORM_OP;
goto CleanupAndExit;
}
}
// Now Floor234 points to Floor 2. RpcProtocol [Connect-Datagram]
// we already did 2 floors - subtract them from the count of floors
RpcStatus = GetProtseqAndEndpointFromFloor3(Floor234, UpperBound, FloorCount - 2, Protseq, Endpoint, NWAddress);
// fall through with the status
CleanupAndExit:
#if DBG
if (RpcStatus != RPC_S_OK)
{
DbgPrint("RPCRT4: %X: TowerExplode: Failed to decrypt tower: %X\n",
GetCurrentProcessId(), RpcStatus);
}
#endif // DBG
return RpcStatus;
}
RPC_STATUS
TowerConstruct(
IN RPC_IF_ID PAPI * Ifid,
IN RPC_TRANSFER_SYNTAX PAPI * Xferid,
IN char PAPI * RpcProtocolSequence,
IN char PAPI * Endpoint, OPTIONAL
IN char PAPI * NWAddress, OPTIONAL
OUT twr_t PAPI * PAPI * Tower
)
/*++
Routine Description:
This function constructs a DCE tower representation from
Protseq, Endpoint, XferId and IfId
Arguments:
Ifid - A pointer to Ifid
Xferid - A pointer to Xferid
Protseq - A pointer to Protseq
Endpoint- A pointer to Endpoint
Tower - The constructed tower returmed - The memory is allocated
by the routine and caller will have to free it.
Return Value:
RPC_S_OK
EP_S_CANT_PERFORM_OP - Error while parsing the Tower encoding
RPC_S_OUT_OF_MEMORY - There is no memory to return the constructed
Tower.
--*/
{
unsigned short Numfloors, PAPI *FloorCnt;
twr_t PAPI * Twr;
PFLOOR_0OR1 Floor;
PFLOOR_234 Floor234, Floor234_1;
RPC_STATUS Status;
unsigned long TowerLen, ByteCount;
char PAPI * UpperTower;
unsigned short ProtocolType;
if ( RpcpStringCompareA(RpcProtocolSequence, "ncalrpc") == 0 )
{
ProtocolType = CONN_LRPC;
Status = LrpcTowerConstruct(Endpoint, &Numfloors,
&ByteCount, (unsigned char **)&UpperTower);
}
else
{
if ( (RpcProtocolSequence[0] == 'n')
&& (RpcProtocolSequence[1] == 'c')
&& (RpcProtocolSequence[2] == 'a')
&& (RpcProtocolSequence[3] == 'c')
&& (RpcProtocolSequence[4] == 'n')
&& (RpcProtocolSequence[5] == '_'))
{
ProtocolType = CONNECTIONFUL;
}
else if ( (RpcProtocolSequence[0] == 'n')
&& (RpcProtocolSequence[1] == 'c')
&& (RpcProtocolSequence[2] == 'a')
&& (RpcProtocolSequence[3] == 'd')
&& (RpcProtocolSequence[4] == 'g')
&& (RpcProtocolSequence[5] == '_'))
{
ProtocolType = CONNECTIONLESS;
}
else
{
return(RPC_S_INVALID_RPC_PROTSEQ);
}
Status = OsfTowerConstruct(
RpcProtocolSequence,
Endpoint,
NWAddress,
&Numfloors,
&ByteCount,
(unsigned char **)&UpperTower
);
}
if (Status != RPC_S_OK)
{
return (Status);
}
TowerLen = 2 + ByteCount;
TowerLen += 2 * sizeof(FLOOR_0OR1) + sizeof(FLOOR_2) ;
if ( (*Tower = Twr = (twr_t *)I_RpcAllocate((unsigned int)TowerLen+4)) == NULL)
{
I_RpcFree(UpperTower);
return(RPC_S_OUT_OF_MEMORY);
}
Twr->tower_length = TowerLen;
FloorCnt = (unsigned short PAPI *)&Twr->tower_octet_string;
*FloorCnt = Numfloors;
Floor = (PFLOOR_0OR1)(FloorCnt+1);
//Floor 0 - IfUuid and IfVersion
CopyIdToFloor(Floor, (PGENERIC_ID)Ifid);
Floor++;
//Floor 1 - XferUuid and XferVersion
CopyIdToFloor(Floor, (PGENERIC_ID)Xferid);
//Floor 2
//ProtocolId = CONNECTIONFUL/CONNECTIONLESS/LRPC and Address = 0(ushort)
Floor234 = (PFLOOR_234) (Floor + 1);
Floor234->ProtocolIdByteCount = 1;
Floor234->FloorId = (byte) ProtocolType;
Floor234->Data[0] = 0x0;
Floor234->Data[1] = 0x0;
Floor234->AddressByteCount = 2;
//Floor 3,4,5.. use the tower encoded by the Transports
Floor234_1 = NEXTFLOOR(PFLOOR_234, Floor234);
RpcpMemoryCopy((char PAPI *)Floor234_1, (char PAPI *)UpperTower,
(size_t)ByteCount);
I_RpcFree(UpperTower);
return(RPC_S_OK);
}
#pragma pack()