|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1994 - 1999
//
// File: dgpkt.cxx
//
//--------------------------------------------------------------------------
/*++
Module Name:
dgpkt.cxx
Abstract:
Author:
Jeff Roberts (jroberts) 22-May-1995
Revision History:
22-May-1995 jroberts
Created this module.
09-Jul-1997 edwardr
Added support for large packets (>65535) for Falcon/RPC.
--*/
#include <precomp.hxx>
#include <dgpkt.hxx>
unsigned long ProcessStartTime; unsigned RandomCounter = 0x6789abce;
const unsigned RpcToPacketFlagsArray[8] = { 0, DG_PF_IDEMPOTENT, DG_PF_BROADCAST, DG_PF_IDEMPOTENT | DG_PF_BROADCAST, DG_PF_MAYBE, DG_PF_IDEMPOTENT | DG_PF_MAYBE, DG_PF_BROADCAST | DG_PF_MAYBE, DG_PF_IDEMPOTENT | DG_PF_BROADCAST | DG_PF_MAYBE, };
const unsigned PacketToRpcFlagsArray[8] = { 0 | 0 | 0 , RPC_NCA_FLAGS_MAYBE | 0 | 0 , 0 | RPC_NCA_FLAGS_IDEMPOTENT | 0 , RPC_NCA_FLAGS_MAYBE | RPC_NCA_FLAGS_IDEMPOTENT | 0 , 0 | 0 | RPC_NCA_FLAGS_BROADCAST, RPC_NCA_FLAGS_MAYBE | 0 | RPC_NCA_FLAGS_BROADCAST, 0 | RPC_NCA_FLAGS_IDEMPOTENT | RPC_NCA_FLAGS_BROADCAST, RPC_NCA_FLAGS_MAYBE | RPC_NCA_FLAGS_IDEMPOTENT | RPC_NCA_FLAGS_BROADCAST, };
DG_PACKET_ENGINE::DG_PACKET_ENGINE( unsigned char a_PacketType, DG_PACKET * a_Packet, RPC_STATUS * pStatus ) : pSavedPacket (a_Packet), PacketType (a_PacketType), ReferenceCount (0), BaseConnection (0), SourceEndpoint (0), RemoteAddress (0), Buffer (0), BufferLength (0), QueuedBufferHead (0), QueuedBufferTail (0), pReceivedPackets (0), pLastConsecutivePacket(0), ConsecutiveDataBytes (0), ReceiveFragmentBase (0), CachedPacket (0), LastReceiveBuffer (0), LastReceiveBufferLength(0),
Cancelled (FALSE)
{ if (!a_Packet) { *pStatus = RPC_S_OUT_OF_MEMORY; }
if (*pStatus) { return; }
pSavedPacket->Header.RpcVersion = DG_RPC_PROTOCOL_VERSION; pSavedPacket->Header.PacketFlags = 0;
SetMyDataRep(&pSavedPacket->Header);
#ifdef DEBUGRPC
BasePacketFlags = ~0; #endif
}
void DG_PACKET_ENGINE::ReadConnectionInfo( DG_COMMON_CONNECTION * a_Connection, DG_TRANSPORT_ADDRESS a_RemoteAddress ) { BaseConnection = a_Connection; RemoteAddress = a_RemoteAddress;
CurrentPduSize = 0; SetFragmentLengths();
pSavedPacket->Header.InterfaceHint = 0xffff; RpcpMemoryCopy( &pSavedPacket->Header.ActivityId, &a_Connection->ActivityNode.Uuid, sizeof(UUID) ); }
DG_PACKET_ENGINE::~DG_PACKET_ENGINE( ) { ASSERT( !LastReceiveBuffer ); ASSERT( !pReceivedPackets ); ASSERT( !QueuedBufferHead ); ASSERT( !Buffer );
if (pSavedPacket) { FreePacket(pSavedPacket); }
if (CachedPacket) { FreePacket(CachedPacket); }
CleanupReceiveWindow(); }
void DG_PACKET_ENGINE::NewCall() /*++
Routine Description:
A new call dawns.
Arguments:
Return Value:
none
--*/
{ ASSERT( !pLastConsecutivePacket ); ASSERT( !ConsecutiveDataBytes );
ASSERT( !LastReceiveBuffer );
SetFragmentLengths();
Buffer = 0;
fReceivedAllFragments = FALSE; fRetransmitted = FALSE;
TimeoutCount = 0;
RepeatedFack = 0; FackSerialNumber = 0; SendSerialNumber = 0; ReceiveSerialNumber = 0;
SendWindowBase = 0; FirstUnsentFragment = 0; SendBurstLength = SendWindowSize;
ReceiveFragmentBase = 0;
RingBufferBase = 0;
#ifdef DEBUGRPC
for (unsigned i=0; i < MAX_WINDOW_SIZE; i++) { FragmentRingBuffer[i].SerialNumber = 0xeeee0000; FragmentRingBuffer[i].Length = 0xdd000000; FragmentRingBuffer[i].Offset = 0xb000b000; }
#endif
BasePacketFlags2 = 0; }
RPC_STATUS DG_PACKET_ENGINE::PushBuffer( PRPC_MESSAGE Message ) /*++
Function Description:
Submits a buffer to be sent over the network. If a buffer is in progress, the new buffer is added to the "pending" list. IF not, the buffer is placed in the "active" slot.
The only time a buffer will not go in the active slot is during an async pipe call when the app is not waiting for send-complete notifications before submitting new buffers.
Notes:
The buffer sent will be truncated to the nearest packet if RPC_BUFFER_PARTIAL is set, and Message.BufferLength is set to the amount actually sent.
--*/ { // ASSERT( Buffer == 0 || IsBufferAcknowledged() );
RPC_STATUS Status = 0; RPC_STATUS FixupStatus = 0; unsigned FractionalPart = Message->BufferLength % MaxFragmentSize; unsigned SendLength = Message->BufferLength;
if (Message->RpcFlags & RPC_BUFFER_PARTIAL) { SendLength -= FractionalPart; }
if (!Buffer || IsBufferAcknowledged()) { SetCurrentBuffer(Message->Buffer, SendLength, Message->RpcFlags );
Status = SendSomeFragments(); } else { QUEUED_BUFFER * Node = new QUEUED_BUFFER; if (!Node) { return RPC_S_OUT_OF_MEMORY; }
Node->Buffer = Message->Buffer; Node->BufferLength = SendLength; Node->BufferFlags = Message->RpcFlags; Node->Next = 0;
if (QueuedBufferTail) { QueuedBufferTail->Next = Node; } else { ASSERT( !QueuedBufferHead );
QueuedBufferHead = Node; }
QueuedBufferTail = Node;
Status = 0; }
FixupStatus = FixupPartialSend(Message);
if (!Status) { Status = FixupStatus; }
return Status; }
RPC_STATUS DG_PACKET_ENGINE::PopBuffer( BOOL fSend ) /*++
Function Description:
Move the next pending send buffer into the active send buffer slot. This is a no-op except unless this is an async pipe call and the app is not waiting for send-complete notifications.
Notes:
The buffer sent will be truncated to the nearest packet if RPC_BUFFER_PARTIAL is set, and Message.BufferLength is set to the amount actually sent.
--*/ { RPC_STATUS Status = 0; RPC_MESSAGE Message;
Message.Buffer = Buffer; Message.BufferLength = BufferLength;
QUEUED_BUFFER * Node = QueuedBufferHead;
if (Node) { QueuedBufferHead = Node->Next; if (!QueuedBufferHead) { QueuedBufferTail = 0; }
SetCurrentBuffer(Node->Buffer, Node->BufferLength, Node->BufferFlags); if (fSend) { Status = SendSomeFragments(); } delete Node; } else { Buffer = 0; BufferLength = 0; BufferFlags = 0; }
if (Message.Buffer) { CommonFreeBuffer(&Message); }
return Status; }
RPC_STATUS DG_PACKET_ENGINE::FixupPartialSend( RPC_MESSAGE * Message ) /*++
Function Description:
This fn "does the right thing" with the unsent bit at the end of a pipe send. For sync sends, this means moving the unsent bit to the front of the existing buffer. For async sends, this means allocating a new buffer and copying the unsent bit into it.
--*/ { if (!(Message->RpcFlags & RPC_BUFFER_PARTIAL)) { // We need this so Receive will be passed a null buffer
// unless the stub sticks one in the message.
Message->Buffer = 0; Message->BufferLength = 0; return RPC_S_OK; }
unsigned FractionalPart;
// if (Message->RpcFlags & RPC_BUFFER_ASYNC)
// {
RPC_MESSAGE NewMessage;
FractionalPart = Message->BufferLength % MaxFragmentSize; if (!FractionalPart) { Message->Buffer = 0; Message->BufferLength = 0; return RPC_S_OK; }
DG_PACKET * Packet = DG_PACKET::AllocatePacket(CurrentPduSize); if (!Packet) { return RPC_S_OUT_OF_MEMORY; }
RpcpMemoryCopy(Packet->Header.Data, ((char *) Message->Buffer) + (Message->BufferLength - FractionalPart), FractionalPart );
Message->Buffer = Packet->Header.Data; Message->BufferLength = FractionalPart; // }
// else
// {
// char * Temp = (char *) Message->Buffer;
//
// FractionalPart = Message->BufferLength - FirstUnsentOffset;
// if (!FractionalPart)
// {
// return RPC_S_OK;
// }
//
// RpcpMemoryMove(Message->Buffer, Temp + FirstUnsentOffset, FractionalPart);
// Message->BufferLength = FractionalPart;
// }
return RPC_S_OK; }
void DG_PACKET_ENGINE::SetCurrentBuffer( void * a_Buffer, unsigned a_BufferLength, unsigned long a_BufferFlags ) { Buffer = a_Buffer; BufferLength = a_BufferLength; BufferFlags = a_BufferFlags;
TimeoutCount = 0; SendWindowBits = 0; FirstUnsentOffset = 0;
if (BufferLength == 0) { FinalSendFrag = SendWindowBase; } else { FinalSendFrag = SendWindowBase + (BufferLength-1) / MaxFragmentSize; } }
RPC_STATUS DG_PACKET_ENGINE::CommonGetBuffer( RPC_MESSAGE * Message ) { unsigned char SubjectType; void * Subject;
unsigned Length; PDG_PACKET pPacket;
Length = sizeof(NCA_PACKET_HEADER) + Align8(Message->BufferLength) + SecurityTrailerSize;
unsigned BaseLength = BaseConnection->TransportInterface->BasePduSize;
// if (Length <= BaseLength)
// {
// pPacket = DG_PACKET::AllocatePacket(BaseLength);
// }
// else if (Length <= CurrentPduSize)
// {
// pPacket = AllocatePacket();
// }
// else
{ pPacket = DG_PACKET::AllocatePacket(Length); }
if (0 == pPacket) { return RPC_S_OUT_OF_MEMORY; }
//
// Point the buffer at the appropriate place in the packet.
//
Message->Buffer = pPacket->Header.Data;
// if (pPacket->MaxDataLength < 256)
// {
// AddActivePacket(pPacket);
// }
return RPC_S_OK; }
void DG_PACKET_ENGINE::CommonFreeBuffer( RPC_MESSAGE * Message ) { if (!Message->Buffer) { return; }
PDG_PACKET Packet = DG_PACKET::FromStubData(Message->Buffer);
LogEvent(SU_ENGINE, EV_PROC, this, Message->Buffer, 'F' + (('B' + (('u' + ('f' << 8)) << 8)) << 8));
ASSERT( Packet->MaxDataLength < 0x7fffffffUL );
// if (Packet && Packet->MaxDataLength < 256)
// {
// RemoveActivePacket(Packet);
// }
FreePacket(Packet);
if (Message->Buffer == LastReceiveBuffer) { LastReceiveBuffer = 0; LastReceiveBufferLength = 0; }
Message->Buffer = 0; }
RPC_STATUS DG_PACKET_ENGINE::CommonReallocBuffer( IN RPC_MESSAGE * Message, IN unsigned int NewSize ) { if (Message->Buffer == LastReceiveBuffer && NewSize <= LastReceiveBufferLength) { Message->BufferLength = NewSize;
return RPC_S_OK; }
RPC_STATUS Status; RPC_MESSAGE NewMessage;
NewMessage.BufferLength = NewSize;
Status = CommonGetBuffer(&NewMessage); if (RPC_S_OK != Status) { return Status; }
LastReceiveBuffer = NewMessage.Buffer; LastReceiveBufferLength = NewMessage.BufferLength;
if (NewSize >= Message->BufferLength) { RpcpMemoryCopy(NewMessage.Buffer, Message->Buffer, Message->BufferLength ); }
CommonFreeBuffer(Message);
Message->Buffer = NewMessage.Buffer; Message->BufferLength = NewMessage.BufferLength;
return RPC_S_OK; }
void DG_PACKET_ENGINE::CleanupSendWindow() { while (Buffer) { PopBuffer(FALSE); } }
void DG_PACKET_ENGINE::CleanupReceiveWindow() { //
// Free any response packets.
//
while (pReceivedPackets) { PDG_PACKET Next = pReceivedPackets->pNext; FreePacket(pReceivedPackets); pReceivedPackets = Next; }
pLastConsecutivePacket = 0; ConsecutiveDataBytes = 0; }
RPC_STATUS DG_PACKET_ENGINE::SendSomeFragments() /*++
Routine Description:
Sends some fragments of the user buffer.
Arguments:
Return Value:
result of the send operation
--*/
{ RPC_STATUS Status = RPC_S_OK; unsigned short i = 0; unsigned short AckFragment; unsigned short Frag; unsigned short Remainder; unsigned Offset; unsigned FragmentsSent = 0;
#ifdef DEBUGRPC
if (!Buffer && (BufferFlags & RPC_BUFFER_PARTIAL)) { // return RPC_S_SEND_INCOMPLETE;
RpcpBreakPoint(); } #endif
if (SendBurstLength > SendWindowSize) { SendBurstLength = SendWindowSize; }
//
// If we can extend the window, do so; otherwise, resend old packets.
//
if (FirstUnsentFragment <= FinalSendFrag && FirstUnsentFragment < SendWindowBase + SendWindowSize) { unsigned short ThisBurstLength;
Frag = FirstUnsentFragment;
ThisBurstLength = SendBurstLength;
if (ThisBurstLength > FinalSendFrag + 1 - Frag) { ThisBurstLength = FinalSendFrag + 1 - Frag; }
if (Frag + ThisBurstLength > SendWindowBase + SendWindowSize) { ThisBurstLength = (SendWindowBase + SendWindowSize) - Frag; }
while (++FragmentsSent <= ThisBurstLength && Status == RPC_S_OK) { if (FragmentsSent == ThisBurstLength && (Frag != FinalSendFrag || (BufferFlags & RPC_BUFFER_PARTIAL) || (BasePacketFlags2 & DG_PF2_UNRELATED))) { Status = SendFragment(Frag, PacketType, TRUE); } else { Status = SendFragment(Frag, PacketType, FALSE); }
++Frag; }
//
// Cut down the burst length if our window is maxed out.
//
if (Frag - SendWindowBase >= SendWindowSize) { SendBurstLength = (1+SendBurstLength)/2; } }
if (0 == FragmentsSent && !IsBufferAcknowledged()) { // We can get here if all the unacknowledged fragments have serial
// numbers greater than the one the client last acknowledged, and
// the window is also maxed out.
//
// This could mean the network is very slow, or the unack'ed packets
// have been lost.
//
Status = SendFragment(SendWindowBase, PacketType, TRUE); }
return Status; }
RPC_STATUS DG_PACKET_ENGINE::SendFragment( unsigned FragNum, unsigned char PacketType, BOOL fFack ) { NCA_PACKET_HEADER PriorData; UNALIGNED NCA_PACKET_HEADER __RPC_FAR * pHeader;
//
// Figure out where the packet starts and how long it is.
//
unsigned Offset; unsigned Length; unsigned Index = (FragNum - SendWindowBase + RingBufferBase) % MAX_WINDOW_SIZE; unsigned DistanceToEnd;
if (FragNum < FirstUnsentFragment) { Offset = FragmentRingBuffer[Index].Offset; Length = FragmentRingBuffer[Index].Length; DistanceToEnd = BufferLength - Offset;
#ifdef DEBUGRPC
if (Offset >= 0xb000b000 || Length >= 0xdd000000) { RpcpBreakPoint(); } #endif
fRetransmitted = TRUE; } else { ASSERT(FragNum == FirstUnsentFragment);
Offset = FirstUnsentOffset; Length = MaxFragmentSize; DistanceToEnd = BufferLength - Offset;
if (DistanceToEnd < Length) { Length = DistanceToEnd; }
FirstUnsentOffset += Length; FirstUnsentFragment = 1 + FragNum; }
if (BufferLength) { // this is harmless and can sometimes be triggered on the first call of an activity
// ASSERT(Length);
// ASSERT(Offset < BufferLength);
} else { ASSERT(!Length); ASSERT(!Offset); }
//
// Time to start assembling the buffer.
//
pHeader = (PNCA_PACKET_HEADER) (PCHAR(Buffer) - sizeof(NCA_PACKET_HEADER));
*pHeader = pSavedPacket->Header;
pHeader->PacketType = PacketType; pHeader->PacketFlags = BasePacketFlags; pHeader->PacketFlags2 = BasePacketFlags2;
if (FinalSendFrag != 0 || (BufferFlags & RPC_BUFFER_PARTIAL)) { pHeader->PacketFlags |= DG_PF_FRAG;
if (FragNum == FinalSendFrag && 0 == (BufferFlags & RPC_BUFFER_PARTIAL)) { pHeader->PacketFlags |= DG_PF_LAST_FRAG; } }
pHeader->SetPacketBodyLen (Length); pHeader->SetFragmentNumber((unsigned short) FragNum);
if (FALSE == fFack) { pHeader->PacketFlags |= DG_PF_NO_FACK; }
AddSerialNumber(pHeader);
RPC_STATUS Status;
//
// Stub data is encrypted in-place; we need not to encrypt the original data
// so we can retransmit it if necessary.
//
unsigned Frag = (pHeader->PacketType << 16) | pHeader->GetFragmentNumber(); LogEvent(SU_ENGINE, EV_PKT_OUT, this, 0, Frag);
if (BaseConnection->ActiveSecurityContext && BaseConnection->ActiveSecurityContext->AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) { RpcpMemoryCopy(&pSavedPacket->Header, pHeader, sizeof(NCA_PACKET_HEADER)); RpcpMemoryCopy(pSavedPacket->Header.Data, pHeader->Data + Offset, pHeader->GetPacketBodyLen());
Status = BaseConnection->SealAndSendPacket(SourceEndpoint, RemoteAddress, &pSavedPacket->Header, 0); } else { Status = BaseConnection->SealAndSendPacket(SourceEndpoint, RemoteAddress, pHeader, Offset); }
FragmentRingBuffer[Index].SerialNumber = SendSerialNumber; FragmentRingBuffer[Index].Length = Length; FragmentRingBuffer[Index].Offset = Offset;
++SendSerialNumber;
if (Status) { LogError(SU_ENGINE, EV_STATUS, this, 0, Status); }
return Status; }
RPC_STATUS DG_PACKET_ENGINE::UpdateSendWindow( PDG_PACKET pPacket, BOOL * pfUpdated ) /*++
Routine Description:
Update the send window based upon a received FACK or NOCALL. The caller should filter out other packet types.
Arguments:
pPacket - the packet received
Return Value:
return code:
TRUE if PDU size or window size changed FALSE if not --*/ { RPC_STATUS Status = 0;
FACK_BODY_VER_0 PAPI * pBody = (FACK_BODY_VER_0 PAPI *) pPacket->Header.Data;
*pfUpdated = FALSE;
unsigned short Diff; unsigned short RemoteBase = 1+pPacket->GetFragmentNumber();
ASSERT(pPacket->TimeReceived == 0x31415926);
//
// Check that we can understand this packet.
//
if (0 != pPacket->GetPacketBodyLen()) { //
// Version 0 and version 1 are identical.
//
if (0 != pBody->Version && 1 != pBody->Version) { #ifdef DEBUGRPC
PrintToDebugger("RPC DG: warning - FACK body version %u\n", pBody->Version); #endif
pPacket->SetPacketBodyLen(0); } else if (pPacket->GetPacketBodyLen() < sizeof(FACK_BODY_VER_0)) { #ifdef DEBUGRPC
PrintToDebugger("RPC DG: warning - FACK body truncated\n"); #endif
pPacket->SetPacketBodyLen(0); } else if (pPacket->GetPacketBodyLen() < sizeof(FACK_BODY_VER_0) + pBody->AckWordCount * sizeof(unsigned long)) { #ifdef DEBUGRPC
PrintToDebugger("RPC DG: warning - FACK body length inconsistent\n"); #endif
pPacket->SetPacketBodyLen(0); } else { if (NeedsByteSwap(&pPacket->Header)) { ByteSwapFackBody0(pBody); }
//
// NT 1057 used 0xffff to signal no packets have been received.
// This doesn't match OSF.
//
if (0xffff == pBody->SerialNumber) { pBody->SerialNumber = 0; }
//
// If the other guy is resending the same FACK, we should resend.
// If it's different, then we are likely OK.
//
if (pBody->SerialNumber == FackSerialNumber) { goto send; }
if (pBody->SerialNumber < FackSerialNumber) { FackSerialNumber = pBody->SerialNumber; goto dont_send; }
FackSerialNumber = pBody->SerialNumber; } }
//
// Update send window.
//
if (RemoteBase < SendWindowBase) { //
// Fragments previously acknowledged are now missing. Either this
// packet was delivered out of order, or the server crashed and
// restarted. Ignore the packet.
//
goto dont_send; }
if (RemoteBase > FirstUnsentFragment) { #ifdef DEBUGRPC
PrintToDebugger("RPC DG: bogus FACK packet received\n"); #endif
goto dont_send; }
//
// We are moving the window base forward. We need to advance the
// ring buffer base by the same amount, and clear the entries
// corresponding to unsent packets.
//
Diff = RemoteBase - SendWindowBase;
ASSERT(Diff <= MAX_WINDOW_SIZE);
#ifdef DEBUGRPC
while (Diff) { FragmentRingBuffer[RingBufferBase].SerialNumber |= 0xeeee0000; FragmentRingBuffer[RingBufferBase].Length |= 0xdd000000; FragmentRingBuffer[RingBufferBase].Offset |= 0xb0000000;
++RingBufferBase; RingBufferBase %= MAX_WINDOW_SIZE; --Diff; } #else
RingBufferBase += Diff; RingBufferBase %= MAX_WINDOW_SIZE; #endif
SendWindowBase = RemoteBase; SendWindowBits = 0;
ASSERT( SendWindowBase <= FirstUnsentFragment );
if (IsBufferAcknowledged()) { PopBuffer(FALSE); }
if (0 != pPacket->GetPacketBodyLen()) { LogEvent(SU_ENGINE, EV_WINDOW, this, (void *) pBody->WindowSize, pBody->Acks[0]);
if (pBody->AckWordCount) { //
// Save missing-packet bitmask.
//
SendWindowBits = pBody->Acks[0]; }
//
// Adjust window size.
//
if (pBody->WindowSize > MAX_WINDOW_SIZE) { pBody->WindowSize = MAX_WINDOW_SIZE; }
SendWindowSize = pBody->WindowSize;
if (SendBurstLength > SendWindowSize) { SendBurstLength = SendWindowSize; }
//
// Adjust maximum PDU length.
//
unsigned NewPduSize; NewPduSize = pBody->MaxDatagramSize; if (NewPduSize > SourceEndpoint->Stats.PreferredPduSize) { NewPduSize = SourceEndpoint->Stats.PreferredPduSize; }
BaseConnection->CurrentPduSize = (unsigned short) NewPduSize; BaseConnection->RemoteWindowSize = pBody->WindowSize;
//
// If no packets are getting through, we probably are sending
// packets that are too large.
//
if (0 == RemoteBase && 0 == SendWindowBits && NewPduSize < CurrentPduSize) { CurrentPduSize = (unsigned short) NewPduSize; SetFragmentLengths();
FirstUnsentFragment = 0; FirstUnsentOffset = 0; FinalSendFrag = SendWindowBase + (BufferLength-1) / MaxFragmentSize; }
*pfUpdated = TRUE; }
send:
Status = SendSomeFragments();
dont_send:
return Status; }
BOOL DG_PACKET_ENGINE::UpdateReceiveWindow( PDG_PACKET pPacket ) /*++
Routine Description:
Adds a fragment to the receive list, and sends a FACK.
Arguments:
Return Value:
--*/ { ASSERT(pPacket->TimeReceived == 0x31415926);
//
// Don't retain data from previous pipe buffers.
//
if (pPacket->GetFragmentNumber() < ReceiveFragmentBase) { if (0 == (pPacket->Header.PacketFlags & DG_PF_NO_FACK)) { SendFackOrNocall(pPacket, DG_FACK); }
return FALSE; }
//
// Attempt to guess the client's max PDU size. Round down to a multiple
// of eight, for NDR.
//
if (pPacket->DataLength + sizeof(NCA_PACKET_HEADER) > BaseConnection->CurrentPduSize) { unsigned RemoteTransportBuffer = BaseConnection->CurrentPduSize * BaseConnection->RemoteWindowSize;
BaseConnection->CurrentPduSize = ((pPacket->DataLength + sizeof(NCA_PACKET_HEADER)) & ~7); BaseConnection->RemoteWindowSize = RemoteTransportBuffer / BaseConnection->CurrentPduSize; if (0 == BaseConnection->RemoteWindowSize) { BaseConnection->RemoteWindowSize = 1; } }
PNCA_PACKET_HEADER pHeader = &pPacket->Header;
unsigned short Serial = ReadSerialNumber(pHeader);
if (Serial > ReceiveSerialNumber) { ReceiveSerialNumber = Serial; }
//
// Authentication levels above AUTHN_LEVEL_PKT will checksum the packet,
// so we must remove these bits from the header.
//
pPacket->Header.PacketFlags &= ~(DG_PF_FORWARDED); pPacket->Header.PacketFlags2 &= ~(DG_PF2_FORWARDED_2);
//
// Check the easy case: is this a single packet call?
//
if ((pHeader->PacketFlags & DG_PF_FRAG) == 0 && (pHeader->PacketFlags & DG_PF_LAST_FRAG) == 0) { if (pReceivedPackets) { ASSERT( pReceivedPackets->Header.SequenceNumber == pPacket->Header.SequenceNumber ); return FALSE; }
pReceivedPackets = pPacket; pLastConsecutivePacket = pPacket;
pPacket->pNext = pPacket->pPrevious = 0;
ConsecutiveDataBytes += pHeader->GetPacketBodyLen();
fReceivedAllFragments = TRUE;
return TRUE; }
//
// This is a multi-packet call. Insert the packet in pReceivedPackets
// and send a FACK.
//
PDG_PACKET pScan; PDG_PACKET pTrail; BOOL PacketAddedToList = TRUE;
if (pReceivedPackets == 0) { pReceivedPackets = pPacket;
if (ReceiveFragmentBase == pHeader->GetFragmentNumber()) { pLastConsecutivePacket = pPacket; ConsecutiveDataBytes += pHeader->GetPacketBodyLen(); }
pPacket->pNext = pPacket->pPrevious = 0; } else { //
// Not the first packet to be received. So scan for its place in the
// list.
//
unsigned short FragNum = pHeader->GetFragmentNumber();
if (pLastConsecutivePacket) { pScan = pLastConsecutivePacket; } else { pScan = pReceivedPackets; }
pTrail = 0; while (pScan && pScan->GetFragmentNumber() < FragNum) { ASSERT(pScan->TimeReceived == 0x31415926); ASSERT(pScan->Header.SequenceNumber == SequenceNumber);
pTrail = pScan; pScan = pScan->pNext; }
if (pScan != 0) { if (pScan->GetFragmentNumber() > FragNum) { if (pScan->pPrevious && pScan->pPrevious->GetFragmentNumber() >= FragNum) { //
// The new packet is a duplicate of a preexisting one
// upstream from pLastConsecutivePacket.
//
PacketAddedToList = FALSE; } else { //
// Our fragment fills a gap in the series.
//
pPacket->pPrevious = pScan->pPrevious; pPacket->pNext = pScan;
if (pScan->pPrevious == 0) { pReceivedPackets = pPacket; } else { pScan->pPrevious->pNext = pPacket; } pScan->pPrevious = pPacket; } } else { //
// The new packet is a duplicate of a preexisting one
// downstream from pLastConsecutivePacket.
//
PacketAddedToList = FALSE; } } else { //
// The fragnum is larger than everything seen so far.
//
pTrail->pNext = pPacket; pPacket->pPrevious = pTrail; pPacket->pNext = 0; } }
if (TRUE == PacketAddedToList) { //
// Scan the list for the first missing fragment.
//
unsigned short ScanNum; if (pLastConsecutivePacket) { pScan = pLastConsecutivePacket->pNext; ScanNum = pLastConsecutivePacket->GetFragmentNumber() + 1; } else { pScan = pReceivedPackets; ScanNum = ReceiveFragmentBase; }
while (pScan) { if (ScanNum == pScan->GetFragmentNumber()) { ConsecutiveDataBytes += pScan->GetPacketBodyLen(); pLastConsecutivePacket = pScan; }
pScan = pScan->pNext; ++ScanNum; }
//
// We have updated pLastConsecutivePacket; is the whole buffer here?
//
if (pLastConsecutivePacket && pLastConsecutivePacket->Header.PacketFlags & DG_PF_LAST_FRAG) { fReceivedAllFragments = TRUE; } }
ASSERT(pReceivedPackets);
//
// Fack the fragment if necessary.
//
if (0 == (pHeader->PacketFlags & DG_PF_NO_FACK)) { SendFackOrNocall(pPacket, DG_FACK); }
return PacketAddedToList; }
RPC_STATUS DG_PACKET_ENGINE::SendFackOrNocall( PDG_PACKET pPacket, unsigned char PacketType ) { unsigned ReceiveWindowSize;
ReceiveWindowSize = SourceEndpoint->Stats.ReceiveBufferSize / ((1+SourceEndpoint->NumberOfCalls) * CurrentPduSize);
if (0 == ReceiveWindowSize) { ReceiveWindowSize = 1; } else if (ReceiveWindowSize > MAX_WINDOW_SIZE) { ReceiveWindowSize = MAX_WINDOW_SIZE; }
pSavedPacket->Header.PacketType = PacketType; pSavedPacket->Header.SequenceNumber = SequenceNumber; pSavedPacket->Header.PacketFlags2 = 0;
FACK_BODY_VER_0 PAPI * pBody = (FACK_BODY_VER_0 PAPI *) pSavedPacket->Header.Data;
pBody->Version = 1; pBody->Pad1 = 0; pBody->MaxDatagramSize = SourceEndpoint->Stats.PreferredPduSize; pBody->MaxPacketSize = SourceEndpoint->Stats.MaxPacketSize; pBody->AckWordCount = 1; pBody->WindowSize = (unsigned short) ReceiveWindowSize;
if (pPacket) { pBody->SerialNumber = ReadSerialNumber(&pPacket->Header); } else { pBody->SerialNumber = ReceiveSerialNumber; }
unsigned short FragNum = ReceiveFragmentBase-1; PDG_PACKET pScan = 0;
if (pLastConsecutivePacket) { FragNum = pLastConsecutivePacket->GetFragmentNumber(); pScan = pLastConsecutivePacket->pNext; } else if (pReceivedPackets) { pScan = pReceivedPackets->pNext; }
unsigned Bit; pBody->Acks[0] = 0;
while ( pScan ) { Bit = pScan->GetFragmentNumber() - FragNum - 1;
pBody->Acks[0] |= (1 << Bit);
pScan = pScan->pNext; }
if (pBody->Acks[0] == 0) { pBody->AckWordCount = 0; }
pSavedPacket->SetPacketBodyLen( sizeof(FACK_BODY_VER_0) + sizeof(unsigned long) ); pSavedPacket->SetFragmentNumber(FragNum);
AddSerialNumber(&pSavedPacket->Header);
unsigned Frag = (pSavedPacket->Header.PacketType << 16) | pSavedPacket->GetFragmentNumber(); LogEvent(SU_ENGINE, EV_PKT_OUT, this, 0, Frag);
RPC_STATUS Status;
Status = BaseConnection->SealAndSendPacket(SourceEndpoint, RemoteAddress, &pSavedPacket->Header, 0);
if (Status) { LogError(SU_ENGINE, EV_STATUS, this, 0, Status); }
return Status; }
RPC_STATUS DG_PACKET_ENGINE::AssembleBufferFromPackets( RPC_MESSAGE * Message, CALL * Call ) /*++
Routine Description:
This function coalesces the list of consecutive packets into a monolithic buffer.
Arguments:
Message - if .Buffer != 0 , use it. Otherwise allocate one.
Call - in case we need to call GetBuffer
Return Value:
RPC_S_OK - success
RPC_S_OUT_OF_MEMORY - we couldn't allocate or reallocate Message.Buffer
--*/
{ ASSERT( pLastConsecutivePacket ); //
// If only one packet is available, use the packet buffer itself.
//
if (0 == Message->Buffer && 0 == pReceivedPackets->pNext) { ASSERT(ConsecutiveDataBytes == pReceivedPackets->GetPacketBodyLen());
Message->Buffer = pReceivedPackets->Header.Data; Message->BufferLength = ConsecutiveDataBytes; Message->DataRepresentation = 0x00ffffff & (*(unsigned long PAPI *) &pReceivedPackets->Header.DataRep);
if (0 == (pReceivedPackets->Header.PacketFlags & DG_PF_FRAG)) { Message->RpcFlags |= RPC_BUFFER_COMPLETE; }
if (pReceivedPackets->Header.PacketFlags & DG_PF_LAST_FRAG) { Message->RpcFlags |= RPC_BUFFER_COMPLETE; }
pReceivedPackets = 0; pLastConsecutivePacket = 0;
ConsecutiveDataBytes = 0;
++ReceiveFragmentBase;
LastReceiveBuffer = Message->Buffer; LastReceiveBufferLength = Message->BufferLength;
return RPC_S_OK; }
//
// Get a buffer if we need it.
//
RPC_STATUS Status;
if (0 == Message->Buffer) { ASSERT(0 == (Message->RpcFlags & RPC_BUFFER_EXTRA));
Message->BufferLength = ConsecutiveDataBytes;
Status = Call->GetBuffer(Message, 0); if (RPC_S_OK != Status) { return Status; }
LastReceiveBuffer = Message->Buffer; LastReceiveBufferLength = Message->BufferLength; }
//
// Reallocate the buffer if it is too small.
//
char __RPC_FAR * CopyBuffer = (char __RPC_FAR *) Message->Buffer;
if (Message->RpcFlags & (RPC_BUFFER_EXTRA | RPC_BUFFER_PARTIAL)) { ASSERT( !LastReceiveBufferLength || (CopyBuffer >= LastReceiveBuffer && CopyBuffer <= ((char __RPC_FAR *) LastReceiveBuffer) + LastReceiveBufferLength) );
if (0 == (Message->RpcFlags & RPC_BUFFER_EXTRA)) { Message->BufferLength = 0; }
unsigned Offset = Message->BufferLength; CopyBuffer += Offset; if (CopyBuffer + ConsecutiveDataBytes > ((char __RPC_FAR *) LastReceiveBuffer) + LastReceiveBufferLength) { Status = I_RpcReallocPipeBuffer(Message, Offset + ConsecutiveDataBytes); if (RPC_S_OK != Status) { return Status; }
CopyBuffer = (char __RPC_FAR *) Message->Buffer + Offset; } else { Message->BufferLength += ConsecutiveDataBytes; } } else { Message->BufferLength = ConsecutiveDataBytes; }
Message->DataRepresentation = 0x00ffffff & (*(unsigned long PAPI *) &pReceivedPackets->Header.DataRep);
{ PDG_PACKET pkt = DG_PACKET::FromStubData(Message->Buffer);
ASSERT( pkt->MaxDataLength >= Message->BufferLength ); }
//
// Copy the stub data into the buffer.
//
#ifdef DEBUGRPC
unsigned long Count = 0; #endif
PDG_PACKET Packet; BOOL fLastPacket = FALSE; do { ASSERT(pReceivedPackets->TimeReceived == 0x31415926); ASSERT(ReceiveFragmentBase == pReceivedPackets->GetFragmentNumber());
if (pReceivedPackets == pLastConsecutivePacket) { fLastPacket = TRUE;
if (0 == (pReceivedPackets->Header.PacketFlags & DG_PF_FRAG)) { Message->RpcFlags |= RPC_BUFFER_COMPLETE; }
if (pReceivedPackets->Header.PacketFlags & DG_PF_LAST_FRAG) { Message->RpcFlags |= RPC_BUFFER_COMPLETE; } }
unsigned Length = pReceivedPackets->GetPacketBodyLen(); RpcpMemoryCopy(CopyBuffer, pReceivedPackets->Header.Data, Length);
#ifdef DEBUGRPC
Count += Length; #endif
CopyBuffer += Length; Packet = pReceivedPackets;
pReceivedPackets = pReceivedPackets->pNext; ASSERT(!pReceivedPackets || pReceivedPackets->pPrevious == Packet); FreePacket(Packet);
++ReceiveFragmentBase; } while (!fLastPacket);
ASSERT(Count == ConsecutiveDataBytes);
ASSERT(fLastPacket || 0 == Count % 8);
pLastConsecutivePacket = 0; ConsecutiveDataBytes = 0;
if (pReceivedPackets) { pReceivedPackets->pPrevious = 0; }
return RPC_S_OK; }
void DG_PACKET_ENGINE::SetFragmentLengths() { PSECURITY_CONTEXT pSecurityContext = BaseConnection->ActiveSecurityContext;
if (0 == pSecurityContext) { SecurityTrailerSize = 0; } else switch (pSecurityContext->AuthenticationLevel) { case RPC_C_AUTHN_LEVEL_NONE: { SecurityTrailerSize = 0; break; }
case RPC_C_AUTHN_LEVEL_PKT: case RPC_C_AUTHN_LEVEL_PKT_INTEGRITY: { SecurityTrailerSize = (unsigned short) pSecurityContext->MaximumSignatureLength(); SecurityTrailerSize += (unsigned short) Align4(sizeof(DG_SECURITY_TRAILER)); break; }
case RPC_C_AUTHN_LEVEL_PKT_PRIVACY: { SecurityTrailerSize = (unsigned short) pSecurityContext->MaximumHeaderLength(); SecurityTrailerSize += (unsigned short) Align(sizeof(DG_SECURITY_TRAILER), Align4(pSecurityContext->BlockSize())); break; }
default: { ASSERT(0 && "RPC: unknown protect level"); break; } }
if (CurrentPduSize != BaseConnection->CurrentPduSize) { CurrentPduSize = (unsigned short) BaseConnection->CurrentPduSize; SendWindowSize = (unsigned short) BaseConnection->RemoteWindowSize; }
MaxFragmentSize = CurrentPduSize - sizeof(NCA_PACKET_HEADER);
if (SecurityTrailerSize) { MaxFragmentSize -= SecurityTrailerSize; MaxFragmentSize -= MaxFragmentSize % SECURITY_HEADER_ALIGNMENT; } }
void ByteSwapPacketHeader( PDG_PACKET pPacket ) /*++
Routine Description:
Byte swaps the packet header of the specified packet.
Arguments:
pPacket - Pointer to the packet whose header needs byte swapping.
Return Value:
<none>
--*/ { unsigned long __RPC_FAR * VerNum = (unsigned long __RPC_FAR *) &(pPacket->Header.InterfaceVersion);
ByteSwapUuid(&(pPacket->Header.ObjectId)); ByteSwapUuid(&(pPacket->Header.InterfaceId)); ByteSwapUuid(&(pPacket->Header.ActivityId)); pPacket->Header.ServerBootTime = RpcpByteSwapLong(pPacket->Header.ServerBootTime); *VerNum = RpcpByteSwapLong(*VerNum); pPacket->Header.SequenceNumber = RpcpByteSwapLong(pPacket->Header.SequenceNumber); pPacket->Header.OperationNumber = RpcpByteSwapShort(pPacket->Header.OperationNumber); pPacket->Header.InterfaceHint = RpcpByteSwapShort(pPacket->Header.InterfaceHint); pPacket->Header.ActivityHint = RpcpByteSwapShort(pPacket->Header.ActivityHint); pPacket->Header.PacketBodyLen = RpcpByteSwapShort(pPacket->Header.PacketBodyLen); pPacket->Header.FragmentNumber = RpcpByteSwapShort(pPacket->Header.FragmentNumber); }
void ByteSwapFackBody0( FACK_BODY_VER_0 __RPC_FAR * pBody ) { pBody->WindowSize = RpcpByteSwapShort(pBody->WindowSize); pBody->MaxDatagramSize = RpcpByteSwapLong (pBody->MaxDatagramSize); pBody->MaxPacketSize = RpcpByteSwapLong (pBody->MaxPacketSize); pBody->SerialNumber = RpcpByteSwapShort(pBody->SerialNumber); pBody->AckWordCount = RpcpByteSwapShort(pBody->AckWordCount);
unsigned u; for (u=0; u < pBody->AckWordCount; ++u) { pBody->Acks[u] = RpcpByteSwapLong (pBody->Acks[u]); } }
RPCRTAPI RPC_STATUS RPC_ENTRY I_RpcTransDatagramAllocate( IN DG_TRANSPORT_ENDPOINT TransportEndpoint, OUT BUFFER *pBuffer, OUT PUINT pBufferLength, OUT DatagramTransportPair **pAddressPair ) { DG_ENDPOINT * Endpoint = DG_ENDPOINT::FromEndpoint(TransportEndpoint); RPC_DATAGRAM_TRANSPORT * Transport = Endpoint->TransportInterface;
if ( !Endpoint->Stats.PreferredPduSize ) { RpcpBreakPoint(); }
DG_PACKET * Packet = DG_PACKET::AllocatePacket(Endpoint->Stats.PreferredPduSize + Transport->AddressSize + sizeof(DatagramTransportPair)); if (!Packet) { return RPC_S_OUT_OF_MEMORY; }
DG_TRANSPORT_ADDRESS Address = DG_TRANSPORT_ADDRESS(Packet->Header.Data - sizeof(NCA_PACKET_HEADER) + Endpoint->Stats.PreferredPduSize);
*pBuffer = &Packet->Header; *pBufferLength = Endpoint->Stats.PreferredPduSize; *pAddressPair = (DatagramTransportPair *)((char *)Address + Transport->AddressSize); (*pAddressPair)->RemoteAddress = Address;
return RPC_S_OK; }
RPCRTAPI RPC_STATUS RPC_ENTRY I_RpcTransDatagramAllocate2( IN DG_TRANSPORT_ENDPOINT TransportEndpoint, OUT BUFFER *pBuffer, IN OUT PUINT pBufferLength, OUT DG_TRANSPORT_ADDRESS *pAddress ) { DG_ENDPOINT *pEndpoint = DG_ENDPOINT::FromEndpoint(TransportEndpoint); RPC_DATAGRAM_TRANSPORT *pTransport = pEndpoint->TransportInterface; DWORD dwSize = *pBufferLength;
if (dwSize < pEndpoint->Stats.PreferredPduSize) { dwSize = pEndpoint->Stats.PreferredPduSize; }
DG_PACKET * Packet = DG_PACKET::AllocatePacket( dwSize + pTransport->AddressSize);
if (!Packet) { return RPC_S_OUT_OF_MEMORY; }
DG_TRANSPORT_ADDRESS Address = DG_TRANSPORT_ADDRESS(Packet->Header.Data - sizeof(NCA_PACKET_HEADER) + dwSize);
*pBuffer = &Packet->Header; *pBufferLength = dwSize; *pAddress = Address;
return RPC_S_OK; }
RPCRTAPI RPC_STATUS RPC_ENTRY I_RpcTransDatagramFree( IN RPC_TRANSPORT_ADDRESS ThisAddress, IN BUFFER Buffer ) { DG_PACKET * Packet = DG_PACKET::FromPacketHeader( Buffer );
Packet->Free();
return RPC_S_OK; }
RPC_STATUS DG_PACKET::Initialize( ) { return RPC_S_OK; }
BOOL DG_PACKET::DeleteIdlePackets( long CurrentTime ) /*++
Routine Description:
This fn scans the free packet list for very old packets and deletes them.
Arguments:
none
Return Value:
none
--*/ { return FALSE; }
DG_COMMON_CONNECTION::DG_COMMON_CONNECTION( RPC_DATAGRAM_TRANSPORT *a_TransportInterface, RPC_STATUS * pStatus ) : Mutex (pStatus), TimeStamp (0), TransportInterface (a_TransportInterface), ReferenceCount (0), CurrentPduSize (a_TransportInterface->BasePduSize), RemoteWindowSize (1), RemoteDataUpdated (FALSE), LowestActiveSequence(0), LowestUnusedSequence(0), ActiveSecurityContext(0) { }
DG_COMMON_CONNECTION::~DG_COMMON_CONNECTION() { delete ActiveSecurityContext; }
RPC_STATUS SendSecurePacket( IN DG_ENDPOINT * SourceEndpoint, IN DG_TRANSPORT_ADDRESS RemoteAddress, IN UNALIGNED NCA_PACKET_HEADER *pHeader, IN unsigned long DataOffset, IN SECURITY_CONTEXT * SecurityContext ) { RPC_STATUS Status = RPC_S_OK; unsigned TrailerLength = 0; unsigned MaxTrailerSize = 0;
PDG_SECURITY_TRAILER pTrailer = 0;
if (SecurityContext && SecurityContext->AuthenticationLevel > RPC_C_AUTHN_LEVEL_NONE) { // Pad the stub data length to a multiple of 8, so the security
// trailer is properly aligned. OSF requires that the pad bytes
// be included in PacketBodyLen.
//
pHeader->SetPacketBodyLen(Align8(pHeader->GetPacketBodyLen()));
pHeader->AuthProto = (unsigned char) SecurityContext->AuthenticationService;
SECURITY_BUFFER_DESCRIPTOR BufferDescriptor; SECURITY_BUFFER SecurityBuffers[5]; DCE_MSG_SECURITY_INFO MsgSecurityInfo;
BufferDescriptor.ulVersion = 0; BufferDescriptor.cBuffers = 5; BufferDescriptor.pBuffers = SecurityBuffers;
SecurityBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY; SecurityBuffers[0].pvBuffer = pHeader; SecurityBuffers[0].cbBuffer = sizeof(NCA_PACKET_HEADER);
SecurityBuffers[1].BufferType = SECBUFFER_DATA; SecurityBuffers[1].pvBuffer = pHeader->Data + DataOffset; SecurityBuffers[1].cbBuffer = pHeader->GetPacketBodyLen();
if (SecurityContext->AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) { SecurityBuffers[2].cbBuffer = (ULONG) Align(sizeof(DG_SECURITY_TRAILER), Align4(SecurityContext->BlockSize())); SecurityBuffers[3].cbBuffer = SecurityContext->MaximumHeaderLength(); } else { SecurityBuffers[2].cbBuffer = (ULONG) Align4(sizeof(DG_SECURITY_TRAILER)); SecurityBuffers[3].cbBuffer = SecurityContext->MaximumSignatureLength(); }
pTrailer = (PDG_SECURITY_TRAILER) _alloca(SecurityBuffers[2].cbBuffer + SecurityBuffers[3].cbBuffer);
SecurityBuffers[2].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY; SecurityBuffers[2].pvBuffer = pTrailer;
SecurityBuffers[3].BufferType = SECBUFFER_TOKEN; SecurityBuffers[3].pvBuffer = (unsigned char *) pTrailer + SecurityBuffers[2].cbBuffer;
SecurityBuffers[4].BufferType = SECBUFFER_PKG_PARAMS | SECBUFFER_READONLY; SecurityBuffers[4].pvBuffer = &MsgSecurityInfo; SecurityBuffers[4].cbBuffer = sizeof(DCE_MSG_SECURITY_INFO);
MsgSecurityInfo.SendSequenceNumber = pHeader->GetFragmentNumber(); MsgSecurityInfo.ReceiveSequenceNumber = SecurityContext->AuthContextId; MsgSecurityInfo.PacketType = ~0;
TrailerLength = SecurityBuffers[2].cbBuffer;
pTrailer->protection_level = (unsigned char) SecurityContext->AuthenticationLevel; pTrailer->key_vers_num = (unsigned char) SecurityContext->AuthContextId;
Status = SecurityContext->SignOrSeal ( pHeader->SequenceNumber, SecurityContext->AuthenticationLevel != RPC_C_AUTHN_LEVEL_PKT_PRIVACY, &BufferDescriptor );
ASSERT( SecurityBuffers[3].cbBuffer > 0 );
TrailerLength += SecurityBuffers[3].cbBuffer; } else { //
// Unsecure packet.
//
pHeader->AuthProto = 0; }
if (RPC_S_OK == Status) { Status = SourceEndpoint->TransportInterface->Send( &SourceEndpoint->TransportEndpoint, RemoteAddress, pHeader, sizeof(NCA_PACKET_HEADER), pHeader->Data + DataOffset, pHeader->GetPacketBodyLen(), pTrailer, TrailerLength ); }
return Status; }
RPC_STATUS VerifySecurePacket( PDG_PACKET pPacket, SECURITY_CONTEXT * pSecurityContext ) { RPC_STATUS Status = RPC_S_OK; PDG_SECURITY_TRAILER pVerifier = (PDG_SECURITY_TRAILER) (pPacket->Header.Data + pPacket->GetPacketBodyLen());
if (pSecurityContext->AuthenticationLevel < RPC_C_AUTHN_LEVEL_PKT) { return RPC_S_OK; }
ASSERT(pVerifier->protection_level >= RPC_C_AUTHN_LEVEL_PKT); ASSERT(pVerifier->protection_level <= RPC_C_AUTHN_LEVEL_PKT_PRIVACY);
SECURITY_BUFFER_DESCRIPTOR BufferDescriptor; SECURITY_BUFFER SecurityBuffers[5]; DCE_MSG_SECURITY_INFO MsgSecurityInfo;
BufferDescriptor.ulVersion = 0; BufferDescriptor.cBuffers = 5; BufferDescriptor.pBuffers = SecurityBuffers;
SecurityBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY; SecurityBuffers[0].pvBuffer = &pPacket->Header; SecurityBuffers[0].cbBuffer = sizeof(NCA_PACKET_HEADER);
SecurityBuffers[1].BufferType = SECBUFFER_DATA; SecurityBuffers[1].pvBuffer = pPacket->Header.Data; SecurityBuffers[1].cbBuffer = pPacket->GetPacketBodyLen();
SecurityBuffers[2].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY; SecurityBuffers[2].pvBuffer = pVerifier;
if (pVerifier->protection_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) { unsigned Alignment = Align4(pSecurityContext->BlockSize());
SecurityBuffers[2].cbBuffer = (ULONG) Align(sizeof(DG_SECURITY_TRAILER), Alignment); SecurityBuffers[3].pvBuffer = AlignPtr(pVerifier + 1, Alignment); } else { SecurityBuffers[2].cbBuffer = (ULONG) Align4(sizeof(DG_SECURITY_TRAILER)); SecurityBuffers[3].pvBuffer = AlignPtr4(pVerifier + 1); }
SecurityBuffers[3].BufferType = SECBUFFER_TOKEN; SecurityBuffers[3].cbBuffer = pPacket->DataLength - SecurityBuffers[1].cbBuffer - SecurityBuffers[2].cbBuffer;
SecurityBuffers[4].BufferType = SECBUFFER_PKG_PARAMS | SECBUFFER_READONLY; SecurityBuffers[4].pvBuffer = &MsgSecurityInfo; SecurityBuffers[4].cbBuffer = sizeof(DCE_MSG_SECURITY_INFO);
MsgSecurityInfo.SendSequenceNumber = pPacket->GetFragmentNumber(); MsgSecurityInfo.ReceiveSequenceNumber = pSecurityContext->AuthContextId; MsgSecurityInfo.PacketType = ~0;
//
// If the packet came from a big-endian machine, we must restore
// the header to its original condition or the checksum will fail.
//
ByteSwapPacketHeaderIfNecessary(pPacket);
Status = pSecurityContext->VerifyOrUnseal( pPacket->Header.SequenceNumber, pVerifier->protection_level != RPC_C_AUTHN_LEVEL_PKT_PRIVACY, &BufferDescriptor );
//
// Gotta re-swap the header so we can still look at its fields.
//
ByteSwapPacketHeaderIfNecessary(pPacket);
if (RPC_S_OK != Status) { #ifdef DEBUGRPC
DbgPrint("dg rpc: %lx: pkt %lx type %lx has bad security info (error 0x%lx)\n", GetCurrentProcessId(), pPacket, pPacket->Header.PacketType, Status); #endif
ASSERT(Status == RPC_S_ACCESS_DENIED || Status == ERROR_SHUTDOWN_IN_PROGRESS || Status == ERROR_PASSWORD_MUST_CHANGE || Status == ERROR_PASSWORD_EXPIRED || Status == ERROR_ACCOUNT_DISABLED || Status == ERROR_INVALID_LOGON_HOURS); }
return(Status); }
BOOL DG_PickleEEInfoIntoPacket ( IN DG_PACKET * Packet, IN size_t PickleStartOffset ) /*++
Function Name: PickeEEInfoIntoPacket
Parameters: PickleStartOffset - the offset in bytes where the pickling starts pHeader - pointer to the packet to fill
Description: Checks for EEInfo on the thread, trims the EEInfo to Packet->MaxDataLength, and pickles the EEInfo starting from PickleStartOffset.
Returns: TRUE if EEInfo was pickled. FALSE if not.
--*/ { BOOL fEEInfoPresent = FALSE; ExtendedErrorInfo *EEInfo; RPC_STATUS RpcStatus; size_t CurrentPacketSize;
EEInfo = RpcpGetEEInfo(); if (EEInfo) { AddComputerNameToChain(EEInfo); TrimEEInfoToLength (Packet->MaxDataLength, &CurrentPacketSize); if (CurrentPacketSize != 0) { CurrentPacketSize += PickleStartOffset;
ASSERT(IsBufferAligned(Packet->Header.Data + PickleStartOffset));
RpcpMemorySet(Packet->Header.Data, 0, CurrentPacketSize);
RpcStatus = PickleEEInfo( EEInfo, Packet->Header.Data + PickleStartOffset, CurrentPacketSize - PickleStartOffset );
if (RpcStatus == RPC_S_OK) { fEEInfoPresent = TRUE; Packet->SetPacketBodyLen( CurrentPacketSize ); } } }
return fEEInfoPresent; }
void InitErrorPacket( DG_PACKET * pPacket, unsigned char PacketType, RPC_STATUS RpcStatus ) /*++
Routine Description:
Maps <ProcessStatus> to an NCA error code and sends a FAULT or REJECT packet to the client, as appropriate.
Arguments:
pSendPacket - a packet to use, or zero if this fn should allocate one
ProcessStatus - NT RPC error code
Return Value:
none
--*/ { NCA_PACKET_HEADER * pHeader = &pPacket->Header;
CleanupPacket(pHeader);
pHeader->PacketType = PacketType;
size_t FaultSize; BOOL fEEInfoPresent = FALSE;
//
// This mapping distinguishes client-side shutdown from server-side shutdown.
//
if (RpcStatus == ERROR_SHUTDOWN_IN_PROGRESS) { if (PacketType == DG_REJECT) { RpcStatus = RPC_S_SERVER_UNAVAILABLE; } else { RpcStatus = ERROR_SERVER_SHUTDOWN_IN_PROGRESS; } } else if (RpcStatus == RPC_P_CLIENT_SHUTDOWN_IN_PROGRESS) { RpcStatus = ERROR_SHUTDOWN_IN_PROGRESS; }
if (g_fSendEEInfo) { fEEInfoPresent = DG_PickleEEInfoIntoPacket( pPacket, FIELD_OFFSET( EXTENDED_FAULT_BODY, EeInfo) ); }
if (fEEInfoPresent) { //
// Packet body length already set.
//
EXTENDED_FAULT_BODY * body = (EXTENDED_FAULT_BODY *) pHeader->Data;
body->NcaStatus = MapToNcaStatusCode(RpcStatus); body->Magic = DG_EE_MAGIC_VALUE; body->reserved1 = 0; body->reserved2 = 0; } else { size_t XopenFaultSize = sizeof(unsigned long);
*(unsigned long *)(pHeader->Data) = MapToNcaStatusCode(RpcStatus);
pHeader->SetPacketBodyLen(XopenFaultSize); } }
|