7066 lines
188 KiB
C++
7066 lines
188 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (C) Microsoft Corporation, 1992 - 1999
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
lpcsvr.cxx
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Implementation of the RPC on LPC protocol engine for the server.
|
|||
|
|
|||
|
Revision History:
|
|||
|
Mazhar Mohammed: Code fork from spcsvr.cxx, 08/02/95
|
|||
|
05-06-96: Merged WMSG and LRPC into a single protocol
|
|||
|
Mazhar Mohammed Added Pipes Support
|
|||
|
Mazhar Mohammed Added support for Async RPC 08-14-96
|
|||
|
Mazhar Mohammed No more WMSG 9/22/97
|
|||
|
Kamen Moutafov (kamenm) Jan-2000 Support for multiple transfer syntaxes
|
|||
|
Kamen Moutafov (KamenM) Dec 99 - Feb 2000 - Support for cell debugging stuff
|
|||
|
Kamen Moutafov (KamenM) Mar-2000 Support for extended error info
|
|||
|
--*/
|
|||
|
|
|||
|
#include <precomp.hxx>
|
|||
|
#include <queue.hxx>
|
|||
|
#include <hndlsvr.hxx>
|
|||
|
#include <lpcpack.hxx>
|
|||
|
#include <lpcsvr.hxx>
|
|||
|
#include <ProtBind.hxx>
|
|||
|
#include <lpcclnt.hxx>
|
|||
|
#include <CharConv.hxx>
|
|||
|
|
|||
|
|
|||
|
inline BOOL
|
|||
|
RecvLotsaCallsWrapper(
|
|||
|
LRPC_ADDRESS * Address
|
|||
|
)
|
|||
|
{
|
|||
|
Address->ReceiveLotsaCalls();
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
inline RPC_STATUS
|
|||
|
InitializeLrpcIfNecessary(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
description
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
arg1 - description
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
int nIndex ;
|
|||
|
RPC_STATUS Status ;
|
|||
|
|
|||
|
if (GlobalLrpcServer == 0)
|
|||
|
{
|
|||
|
if ((Status = InitializeLrpcServer()) != RPC_S_OK)
|
|||
|
{
|
|||
|
return Status ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return (RPC_S_OK) ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LRPC_SERVER::LRPC_SERVER(
|
|||
|
IN OUT RPC_STATUS *Status
|
|||
|
) : ServerMutex(Status,
|
|||
|
TRUE // pre-allocate semaphore
|
|||
|
)
|
|||
|
{
|
|||
|
Address = NULL ;
|
|||
|
EndpointInitialized = 0 ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SERVER::InitializeAsync (
|
|||
|
)
|
|||
|
{
|
|||
|
RPC_CHAR Endpoint[20];
|
|||
|
RPC_STATUS Status = RPC_S_OK ;
|
|||
|
|
|||
|
if (EndpointInitialized == 0)
|
|||
|
{
|
|||
|
swprintf(Endpoint, RPC_CONST_STRING("MSAsyncRPC_%d"),
|
|||
|
GetCurrentProcessId()) ;
|
|||
|
|
|||
|
Status = RpcServerUseProtseqEpW (
|
|||
|
RPC_STRING_LITERAL("ncalrpc"), 100, Endpoint, NULL) ;
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return Status ;
|
|||
|
}
|
|||
|
|
|||
|
Status = GlobalRpcServer->ServerListen(1, 100, 1) ;
|
|||
|
|
|||
|
if (Status == RPC_S_OK)
|
|||
|
{
|
|||
|
Status = SetEndpoint(Endpoint) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return Status ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
InitializeLrpcServer (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
description
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
arg1 - description
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Function succeeded
|
|||
|
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK ;
|
|||
|
|
|||
|
GlobalMutexRequest() ;
|
|||
|
|
|||
|
if (GlobalLrpcServer == 0)
|
|||
|
{
|
|||
|
GlobalLrpcServer = new LRPC_SERVER(&Status) ;
|
|||
|
|
|||
|
if (GlobalLrpcServer == 0)
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("LRPC: LRPC_SERVER initialization failed\n") ;
|
|||
|
#endif
|
|||
|
|
|||
|
GlobalMutexClear() ;
|
|||
|
|
|||
|
return (RPC_S_OUT_OF_MEMORY) ;
|
|||
|
}
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
GlobalMutexClear() ;
|
|||
|
|
|||
|
delete GlobalLrpcServer ;
|
|||
|
GlobalLrpcServer = 0 ;
|
|||
|
|
|||
|
return Status ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
GlobalMutexClear() ;
|
|||
|
|
|||
|
return (RPC_S_OK) ;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
SetCommonFaultFields (
|
|||
|
IN LRPC_MESSAGE *LrpcMessage,
|
|||
|
IN RPC_STATUS Status,
|
|||
|
IN int Flags,
|
|||
|
IN int AdditionalLength
|
|||
|
)
|
|||
|
{
|
|||
|
LrpcMessage->Fault.RpcHeader.MessageType = LRPC_MSG_FAULT;
|
|||
|
LrpcMessage->Fault.RpcStatus = Status;
|
|||
|
LrpcMessage->LpcHeader.u1.s1.DataLength =
|
|||
|
sizeof(LRPC_FAULT_MESSAGE) - sizeof(PORT_MESSAGE)
|
|||
|
- sizeof(LrpcMessage->Fault.Buffer) + (CSHORT)AdditionalLength;
|
|||
|
LrpcMessage->LpcHeader.u1.s1.TotalLength =
|
|||
|
sizeof(LRPC_FAULT_MESSAGE) - sizeof(LrpcMessage->Fault.Buffer)
|
|||
|
+ (CSHORT)AdditionalLength;
|
|||
|
|
|||
|
if ((Flags & LRPC_SYNC_CLIENT) == 0)
|
|||
|
{
|
|||
|
LrpcMessage->LpcHeader.u2.ZeroInit = 0;
|
|||
|
LrpcMessage->LpcHeader.CallbackId = 0 ;
|
|||
|
LrpcMessage->LpcHeader.MessageId = 0 ;
|
|||
|
LrpcMessage->LpcHeader.u2.s2.DataInfoOffset = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
SetCommonFault2Fields (
|
|||
|
IN LRPC_MESSAGE *LrpcMessage,
|
|||
|
IN RPC_STATUS Status,
|
|||
|
IN unsigned int Length,
|
|||
|
IN void *Buffer
|
|||
|
)
|
|||
|
{
|
|||
|
LrpcMessage->Fault2.RpcHeader.MessageType = LRPC_MSG_FAULT2;
|
|||
|
LrpcMessage->Fault2.RpcStatus = Status;
|
|||
|
LrpcMessage->LpcHeader.u1.s1.DataLength =
|
|||
|
sizeof(LRPC_FAULT2_MESSAGE) - sizeof(PORT_MESSAGE);
|
|||
|
LrpcMessage->LpcHeader.u1.s1.TotalLength =
|
|||
|
sizeof(LRPC_FAULT2_MESSAGE);
|
|||
|
// the Server/DataEntries must have been set in GetBuffer - no
|
|||
|
// need to reset them here
|
|||
|
LrpcMessage->Fault2.RpcHeader.Flags |= LRPC_EEINFO_PRESENT;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
TrimIfNecessaryAndSetImmediateBuffer (
|
|||
|
IN LRPC_MESSAGE *LrpcMessage,
|
|||
|
IN RPC_STATUS Status,
|
|||
|
IN int Flags,
|
|||
|
IN size_t EstimatedEEInfoSize,
|
|||
|
IN BOOL fTrimEEInfo,
|
|||
|
IN ExtendedErrorInfo *CurrentEEInfo
|
|||
|
)
|
|||
|
{
|
|||
|
size_t NeededLength;
|
|||
|
RPC_STATUS RpcStatus;
|
|||
|
|
|||
|
if (fTrimEEInfo)
|
|||
|
{
|
|||
|
ASSERT(MAXIMUM_FAULT_MESSAGE >= MinimumTransportEEInfoLength);
|
|||
|
TrimEEInfoToLength (MAXIMUM_FAULT_MESSAGE, &NeededLength);
|
|||
|
|
|||
|
if (NeededLength == 0)
|
|||
|
{
|
|||
|
SetCommonFaultFields(LrpcMessage, Status, Flags, 0);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(NeededLength <= MAXIMUM_FAULT_MESSAGE);
|
|||
|
EstimatedEEInfoSize = NeededLength;
|
|||
|
// fall through to the next if - it will succeed
|
|||
|
// as we know the length is trimmed.
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT(EstimatedEEInfoSize <= MAXIMUM_FAULT_MESSAGE);
|
|||
|
}
|
|||
|
|
|||
|
RpcStatus = PickleEEInfo(CurrentEEInfo,
|
|||
|
LrpcMessage->Fault.Buffer,
|
|||
|
MAXIMUM_FAULT_MESSAGE);
|
|||
|
if (RpcStatus != RPC_S_OK)
|
|||
|
{
|
|||
|
SetCommonFaultFields(LrpcMessage, Status, Flags, 0);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
SetCommonFaultFields(LrpcMessage, Status, Flags, EstimatedEEInfoSize);
|
|||
|
LrpcMessage->Fault.RpcHeader.Flags |= LRPC_EEINFO_PRESENT;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
SetFaultPacket (
|
|||
|
IN LRPC_MESSAGE *LrpcMessage,
|
|||
|
IN RPC_STATUS Status,
|
|||
|
IN int Flags,
|
|||
|
IN LRPC_SCALL *CurrentCall OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initialize a fault packet
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LrpcMessage - Fault message
|
|||
|
Status - Fault status
|
|||
|
Flags - Flags from the request message
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
THREAD *Thread;
|
|||
|
ExtendedErrorInfo *CurrentEEInfo;
|
|||
|
size_t EstimatedEEInfoSize;
|
|||
|
RPC_STATUS RpcStatus;
|
|||
|
RPC_MESSAGE RpcMessage;
|
|||
|
|
|||
|
// we will see whether there is extended error information here
|
|||
|
// and try to send it. If we run in out-of-memory, or there is
|
|||
|
// no EEInfo, send plain old fault.
|
|||
|
Thread = ThreadSelf();
|
|||
|
if (Thread && g_fSendEEInfo)
|
|||
|
{
|
|||
|
CurrentEEInfo = Thread->GetEEInfo();
|
|||
|
if (CurrentEEInfo)
|
|||
|
{
|
|||
|
// if this function runs in out-of-memory, it will
|
|||
|
// return 0.
|
|||
|
EstimatedEEInfoSize = EstimateSizeOfEEInfo();
|
|||
|
if (EstimatedEEInfoSize == 0)
|
|||
|
{
|
|||
|
SetCommonFaultFields(LrpcMessage, Status, Flags, 0);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// if there is no current call, we cannot send arbitrary length
|
|||
|
// data, so we must trim the EEInfo
|
|||
|
if (CurrentCall == NULL)
|
|||
|
{
|
|||
|
TrimIfNecessaryAndSetImmediateBuffer(LrpcMessage,
|
|||
|
Status,
|
|||
|
Flags,
|
|||
|
EstimatedEEInfoSize,
|
|||
|
TRUE,
|
|||
|
CurrentEEInfo);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (EstimatedEEInfoSize <= MAXIMUM_FAULT_MESSAGE)
|
|||
|
{
|
|||
|
TrimIfNecessaryAndSetImmediateBuffer(LrpcMessage,
|
|||
|
Status,
|
|||
|
Flags,
|
|||
|
EstimatedEEInfoSize,
|
|||
|
FALSE,
|
|||
|
CurrentEEInfo);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(CurrentCall != NULL);
|
|||
|
|
|||
|
// here, the estimated EEInfo size is larger that the available
|
|||
|
// space in the fault packet. We have a call, so we must try
|
|||
|
// sending a fault2 packet.
|
|||
|
RpcMessage.Handle = CurrentCall;
|
|||
|
RpcMessage.RpcFlags = CurrentCall->RpcMessage.RpcFlags;
|
|||
|
// increase the buffer lenght in case we fall in the window
|
|||
|
// b/n MAXIMUM_MESSAGE_BUFFER and the EstimatedEEInfoSize. If we
|
|||
|
// do, GetBuffer will return us an immediate buffer, and this is
|
|||
|
// not something we want
|
|||
|
RpcMessage.BufferLength = max(EstimatedEEInfoSize, MAXIMUM_MESSAGE_BUFFER + 4);
|
|||
|
RpcStatus = CurrentCall->LRPC_SCALL::GetBuffer(&RpcMessage, NULL);
|
|||
|
if (RpcStatus != RPC_S_OK)
|
|||
|
{
|
|||
|
// can't send the full data - trim and send
|
|||
|
TrimIfNecessaryAndSetImmediateBuffer(LrpcMessage,
|
|||
|
Status,
|
|||
|
Flags,
|
|||
|
EstimatedEEInfoSize,
|
|||
|
TRUE,
|
|||
|
CurrentEEInfo);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(CurrentCall->LrpcReplyMessage->Rpc.RpcHeader.Flags != LRPC_BUFFER_IMMEDIATE);
|
|||
|
// on success, GetBuffer has allocated a buffer in RpcMessage.Buffer
|
|||
|
// and has setup CurrentCall->LrpcReplyMessage for sending to
|
|||
|
// the client.
|
|||
|
// Fill in the EEInfo
|
|||
|
RpcStatus = PickleEEInfo(CurrentEEInfo,
|
|||
|
(unsigned char *)RpcMessage.Buffer,
|
|||
|
EstimatedEEInfoSize);
|
|||
|
if (RpcStatus != RPC_S_OK)
|
|||
|
{
|
|||
|
if (!CurrentCall->IsClientAsync())
|
|||
|
CurrentCall->Association->Buffers.DeleteItemByBruteForce(RpcMessage.Buffer);
|
|||
|
RpcpFarFree(RpcMessage.Buffer);
|
|||
|
|
|||
|
// can't send the full data - trim and send
|
|||
|
TrimIfNecessaryAndSetImmediateBuffer(LrpcMessage,
|
|||
|
Status,
|
|||
|
Flags,
|
|||
|
EstimatedEEInfoSize,
|
|||
|
TRUE,
|
|||
|
CurrentEEInfo);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Send to the client
|
|||
|
if (CurrentCall->IsClientAsync())
|
|||
|
{
|
|||
|
if (!CurrentCall->IsSyncCall())
|
|||
|
{
|
|||
|
ASSERT(CurrentCall->LrpcAsyncReplyMessage == CurrentCall->LrpcReplyMessage);
|
|||
|
}
|
|||
|
SetCommonFault2Fields(CurrentCall->LrpcReplyMessage,
|
|||
|
Status,
|
|||
|
RpcMessage.BufferLength,
|
|||
|
RpcMessage.Buffer);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// send the data for sync client
|
|||
|
// set fault2 fields
|
|||
|
|
|||
|
SetCommonFault2Fields(CurrentCall->LrpcReplyMessage,
|
|||
|
Status,
|
|||
|
RpcMessage.BufferLength,
|
|||
|
RpcMessage.Buffer);
|
|||
|
|
|||
|
// our caller will do the sending
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
SetCommonFaultFields(LrpcMessage, Status, Flags, 0);
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
SetBindAckFault (
|
|||
|
IN LRPC_MESSAGE *LrpcMessage,
|
|||
|
IN RPC_STATUS Status
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initialize a fault bind ack packet (bind_nak). It will add extended
|
|||
|
error info if there is some, and sending of eeinfo is enabled.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LrpcMessage - Bind message
|
|||
|
Status - Fault status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
size_t NeededLength;
|
|||
|
ExtendedErrorInfo *EEInfo;
|
|||
|
|
|||
|
ASSERT(IsBufferAligned(LrpcMessage->Bind.BindExchange.Buffer));
|
|||
|
|
|||
|
ASSERT(MAX_BIND_NAK >= MinimumTransportEEInfoLength);
|
|||
|
|
|||
|
LrpcMessage->Bind.BindExchange.RpcStatus = Status;
|
|||
|
|
|||
|
if (g_fSendEEInfo)
|
|||
|
{
|
|||
|
EEInfo = RpcpGetEEInfo();
|
|||
|
if (EEInfo)
|
|||
|
{
|
|||
|
TrimEEInfoToLength (MAX_BIND_NAK, &NeededLength);
|
|||
|
|
|||
|
if (NeededLength != 0)
|
|||
|
{
|
|||
|
Status = PickleEEInfo(EEInfo,
|
|||
|
LrpcMessage->Bind.BindExchange.Buffer,
|
|||
|
MAX_BIND_NAK);
|
|||
|
if (Status == RPC_S_OK)
|
|||
|
{
|
|||
|
LrpcMessage->Bind.BindExchange.Flags |= EXTENDED_ERROR_INFO_PRESENT;
|
|||
|
LrpcMessage->LpcHeader.u1.s1.DataLength = (CSHORT)NeededLength +
|
|||
|
BIND_NAK_PICKLE_BUFFER_OFFSET
|
|||
|
- sizeof(PORT_MESSAGE);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!(LrpcMessage->Bind.BindExchange.Flags & EXTENDED_ERROR_INFO_PRESENT))
|
|||
|
{
|
|||
|
LrpcMessage->LpcHeader.u1.s1.DataLength = sizeof(LRPC_BIND_MESSAGE)
|
|||
|
- sizeof(PORT_MESSAGE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LRPC_ADDRESS::LRPC_ADDRESS (
|
|||
|
OUT RPC_STATUS * Status
|
|||
|
) : RPC_ADDRESS(Status),
|
|||
|
ThreadsDoingLongWait(0)
|
|||
|
/*++
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ObjectType = LRPC_ADDRESS_TYPE;
|
|||
|
LpcAddressPort = 0;
|
|||
|
CallThreadCount = 0;
|
|||
|
ActiveCallCount = 0;
|
|||
|
ServerListeningFlag = 0;
|
|||
|
AssociationCount = 0;
|
|||
|
fServerThreadsStarted = 0;
|
|||
|
SequenceNumber = 1;
|
|||
|
fTickleMessageAvailable = FALSE;
|
|||
|
TickleMessage = NULL;
|
|||
|
|
|||
|
if (IsServerSideDebugInfoEnabled())
|
|||
|
{
|
|||
|
DebugCell = (DebugEndpointInfo *)AllocateCell(&DebugCellTag);
|
|||
|
if (DebugCell == NULL)
|
|||
|
{
|
|||
|
*Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
DebugCell->TypeHeader = 0;
|
|||
|
DebugCell->Type = dctEndpointInfo;
|
|||
|
DebugCell->ProtseqType = (UCHAR)LRPC_TOWER_ID;
|
|||
|
DebugCell->Status = desAllocated;
|
|||
|
memset(DebugCell->EndpointName, 0, sizeof(DebugCell->EndpointName));
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
DebugCell = NULL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_ADDRESS::ServerStartingToListen (
|
|||
|
IN unsigned int MinimumCallThreads,
|
|||
|
IN unsigned int MaximumConcurrentCalls
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine gets called when RpcServerListen is called by the application.
|
|||
|
We need to create the threads we need to receive remote procedure calls.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
MinimumCallThreads - Supplies the minimum number of threads which we
|
|||
|
must create.
|
|||
|
|
|||
|
MaximumConcurrentCalls - Unused.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Ok, this address is all ready to start listening for remote
|
|||
|
procedure calls.
|
|||
|
|
|||
|
RPC_S_OUT_OF_THREADS - We could not create enough threads so that we
|
|||
|
have at least the minimum number of call threads required (as
|
|||
|
specified by the MinimumCallThreads argument).
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status;
|
|||
|
|
|||
|
UNUSED(MaximumConcurrentCalls);
|
|||
|
|
|||
|
if (fServerThreadsStarted == 0)
|
|||
|
{
|
|||
|
Status = InitializeServerSideCellHeapIfNecessary();
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
return Status;
|
|||
|
|
|||
|
this->MinimumCallThreads = MinimumCallThreads;
|
|||
|
AddressMutex.Request();
|
|||
|
if (CallThreadCount < this->MinimumCallThreads)
|
|||
|
{
|
|||
|
Status = Server->CreateThread((THREAD_PROC)&RecvLotsaCallsWrapper,
|
|||
|
this);
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
AddressMutex.Clear();
|
|||
|
VALIDATE(Status)
|
|||
|
{
|
|||
|
RPC_S_OUT_OF_THREADS,
|
|||
|
RPC_S_OUT_OF_MEMORY
|
|||
|
} END_VALIDATE;
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
CallThreadCount += 1;
|
|||
|
}
|
|||
|
AddressMutex.Clear();
|
|||
|
fServerThreadsStarted = 1;
|
|||
|
}
|
|||
|
|
|||
|
ServerListeningFlag = 1;
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
LRPC_ADDRESS::ServerStoppedListening (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We just need to indicate that the server is no longer listening, and
|
|||
|
set the minimum call thread count to one.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ServerListeningFlag = 0;
|
|||
|
MinimumCallThreads = 1;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef DEBUGRPC
|
|||
|
|
|||
|
// Hard coded world (aka EveryOne) SID
|
|||
|
const SID World = { 1, 1, { 0, 0, 0, 0, 0, 1}, 0};
|
|||
|
|
|||
|
// Hard coded anonymous SID
|
|||
|
const SID AnonymousLogonSid = { 1, 1, SECURITY_NT_AUTHORITY, SECURITY_ANONYMOUS_LOGON_RID};
|
|||
|
|
|||
|
SECURITY_DESCRIPTOR *DefaultPortSD = NULL;
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
CreateAndGetDefaultPortSDIfNecessary (
|
|||
|
OUT SECURITY_DESCRIPTOR **PortSD
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name: CreateAndGetDefaultPortSDIfNecessary
|
|||
|
|
|||
|
Parameters:
|
|||
|
PortSD - receives the default port SD on success.
|
|||
|
Undefined on failure
|
|||
|
|
|||
|
Description:
|
|||
|
If the default port SD is not created, creates it,
|
|||
|
and returns it. If it is already created, it simply
|
|||
|
returns it. The function is thread-safe.
|
|||
|
|
|||
|
Returns:
|
|||
|
RPC_S_OK or other codes for error.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD DaclSize;
|
|||
|
PACL Dacl;
|
|||
|
ULONG LengthOfDacl;
|
|||
|
SECURITY_DESCRIPTOR *LocalDefaultSD; // we work on a local copy to make
|
|||
|
// this thread safe
|
|||
|
|
|||
|
if (DefaultPortSD)
|
|||
|
{
|
|||
|
*PortSD = DefaultPortSD;
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
LocalDefaultSD = new SECURITY_DESCRIPTOR;
|
|||
|
|
|||
|
if ( LocalDefaultSD == 0
|
|||
|
|| !InitializeSecurityDescriptor(LocalDefaultSD,
|
|||
|
SECURITY_DESCRIPTOR_REVISION) )
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(GetSidLengthRequired(SID_MAX_SUB_AUTHORITIES) <= 0x44);
|
|||
|
|
|||
|
DaclSize = 2 * sizeof(ACCESS_ALLOWED_ACE) + sizeof(World) + sizeof(AnonymousLogonSid) + 0x44;
|
|||
|
LengthOfDacl = DaclSize + sizeof(ACL);
|
|||
|
Dacl = (ACL *) new char[LengthOfDacl];
|
|||
|
|
|||
|
if (NULL == Dacl)
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(IsValidSid((PVOID)&World));
|
|||
|
ASSERT(IsValidSid((PVOID)&AnonymousLogonSid));
|
|||
|
|
|||
|
InitializeAcl(Dacl, LengthOfDacl, ACL_REVISION);
|
|||
|
|
|||
|
if (!AddAccessAllowedAce(Dacl, ACL_REVISION,
|
|||
|
PORT_ALL_ACCESS,
|
|||
|
(PVOID)&World))
|
|||
|
{
|
|||
|
// this should never fail unless we messed up the
|
|||
|
// parameters or there is a version mismatch
|
|||
|
ASSERT(0);
|
|||
|
delete Dacl;
|
|||
|
delete LocalDefaultSD;
|
|||
|
return(RPC_S_OUT_OF_RESOURCES);
|
|||
|
}
|
|||
|
if (!AddAccessAllowedAce(Dacl, ACL_REVISION,
|
|||
|
PORT_ALL_ACCESS,
|
|||
|
(PVOID)&AnonymousLogonSid ))
|
|||
|
{
|
|||
|
// this should never fail unless we messed up the
|
|||
|
// parameters or there is a version mismatch
|
|||
|
ASSERT(0);
|
|||
|
delete Dacl;
|
|||
|
delete LocalDefaultSD;
|
|||
|
return(RPC_S_OUT_OF_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
if (!SetSecurityDescriptorDacl(LocalDefaultSD, TRUE, Dacl, FALSE))
|
|||
|
{
|
|||
|
delete Dacl;
|
|||
|
delete LocalDefaultSD;
|
|||
|
return(RPC_S_OUT_OF_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
if (InterlockedCompareExchangePointer((PVOID *)&DefaultPortSD,
|
|||
|
LocalDefaultSD,
|
|||
|
NULL) != NULL)
|
|||
|
{
|
|||
|
// somebody beat us to the punch - free our local copy
|
|||
|
delete Dacl;
|
|||
|
delete LocalDefaultSD;
|
|||
|
}
|
|||
|
|
|||
|
*PortSD = DefaultPortSD;
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_ADDRESS::ActuallySetupAddress (
|
|||
|
IN RPC_CHAR * Endpoint,
|
|||
|
IN void * SecurityDescriptor OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name:ActuallySetupAddress
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
Description:
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
RPC_CHAR * LpcPortName;
|
|||
|
UNICODE_STRING UnicodeString;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
RPC_STATUS Status;
|
|||
|
#ifdef DEBUGRPC
|
|||
|
BOOL Result;
|
|||
|
BOOL DaclPresent;
|
|||
|
PACL Dacl;
|
|||
|
BOOL Ignored;
|
|||
|
#endif
|
|||
|
|
|||
|
// Allocate and initialize the port name. We need to stick the
|
|||
|
// LRPC_DIRECTORY_NAME on the front of the endpoint. This is for
|
|||
|
// security reasons (so that anyone can create LRPC endpoints).
|
|||
|
|
|||
|
LpcPortName = new RPC_CHAR[RpcpStringLength(Endpoint)
|
|||
|
+ RpcpStringLength(LRPC_DIRECTORY_NAME) + 1];
|
|||
|
if (LpcPortName == 0)
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
RpcpMemoryCopy(
|
|||
|
LpcPortName,
|
|||
|
LRPC_DIRECTORY_NAME,
|
|||
|
RpcpStringLength(LRPC_DIRECTORY_NAME) *sizeof(RPC_CHAR));
|
|||
|
|
|||
|
RpcpMemoryCopy(
|
|||
|
LpcPortName + RpcpStringLength(LRPC_DIRECTORY_NAME),
|
|||
|
Endpoint,
|
|||
|
(RpcpStringLength(Endpoint) + 1) *sizeof(RPC_CHAR));
|
|||
|
|
|||
|
RtlInitUnicodeString(&UnicodeString, LpcPortName);
|
|||
|
|
|||
|
#ifdef DEBUGRPC
|
|||
|
// in checked builds we check the security descriptor for NULL Dacl,
|
|||
|
// and if present, we replace it with a default "allow everyone"
|
|||
|
// Dacl. This was requested by ChrisW (12/14/2000) from the Security
|
|||
|
// Team so that they can get LPC ports out of the picture, and then
|
|||
|
// ASSERT on NULL Dacls for other objects
|
|||
|
if (SecurityDescriptor)
|
|||
|
{
|
|||
|
Result = GetSecurityDescriptorDacl(SecurityDescriptor,
|
|||
|
&DaclPresent,
|
|||
|
&Dacl,
|
|||
|
&Ignored // lpbDaclDefaulted
|
|||
|
);
|
|||
|
|
|||
|
if (!Result)
|
|||
|
{
|
|||
|
// invalid security descriptor is the only reason this could fail
|
|||
|
delete LpcPortName;
|
|||
|
return RPC_S_INVALID_ENDPOINT_FORMAT;
|
|||
|
}
|
|||
|
|
|||
|
if (DaclPresent && (Dacl == NULL))
|
|||
|
{
|
|||
|
Status = CreateAndGetDefaultPortSDIfNecessary((SECURITY_DESCRIPTOR **)&SecurityDescriptor);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
delete LpcPortName;
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
// We were able to grab a default port SD - just let it through
|
|||
|
}
|
|||
|
// else
|
|||
|
// {
|
|||
|
// the security descriptor supplied by caller has non NULL Dacl - let
|
|||
|
// it through
|
|||
|
// }
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
InitializeObjectAttributes(
|
|||
|
&ObjectAttributes,
|
|||
|
&UnicodeString,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
0,
|
|||
|
SecurityDescriptor);
|
|||
|
|
|||
|
NtStatus = NtCreatePort(
|
|||
|
&LpcAddressPort,
|
|||
|
&ObjectAttributes,
|
|||
|
sizeof(LRPC_BIND_EXCHANGE),
|
|||
|
PORT_MAXIMUM_MESSAGE_LENGTH,
|
|||
|
0);
|
|||
|
|
|||
|
delete LpcPortName;
|
|||
|
if (NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
Status = LrpcSetEndpoint(Endpoint);
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
if (NtStatus == STATUS_NO_MEMORY)
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
if ((NtStatus == STATUS_INSUFFICIENT_RESOURCES)
|
|||
|
|| (NtStatus == STATUS_QUOTA_EXCEEDED))
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_RESOURCES);
|
|||
|
}
|
|||
|
if ((NtStatus == STATUS_OBJECT_PATH_INVALID)
|
|||
|
|| (NtStatus == STATUS_OBJECT_PATH_NOT_FOUND)
|
|||
|
|| (NtStatus == STATUS_OBJECT_NAME_INVALID)
|
|||
|
|| (NtStatus == STATUS_OBJECT_TYPE_MISMATCH)
|
|||
|
|| (NtStatus == STATUS_INVALID_OWNER))
|
|||
|
{
|
|||
|
return(RPC_S_INVALID_ENDPOINT_FORMAT);
|
|||
|
}
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (NtStatus != STATUS_OBJECT_NAME_COLLISION)
|
|||
|
{
|
|||
|
PrintToDebugger("RPC : NtCreatePort : %lx\n", NtStatus);
|
|||
|
}
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
ASSERT(NtStatus == STATUS_OBJECT_NAME_COLLISION);
|
|||
|
return(RPC_S_DUPLICATE_ENDPOINT);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
extern RPC_CHAR *
|
|||
|
ULongToHexString (
|
|||
|
IN RPC_CHAR * String,
|
|||
|
IN unsigned long Number
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_ADDRESS::ServerSetupAddress (
|
|||
|
IN RPC_CHAR * NetworkAddress,
|
|||
|
IN RPC_CHAR * *Endpoint,
|
|||
|
IN unsigned int PendingQueueSize,
|
|||
|
IN void * SecurityDescriptor, OPTIONAL
|
|||
|
IN unsigned long EndpointFlags,
|
|||
|
IN unsigned long NICFlags,
|
|||
|
OUT NETWORK_ADDRESS_VECTOR **ppNetworkAddressVector
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We need to setup the connection port and get ready to receive remote
|
|||
|
procedure calls. We will use the name of this machine as the network
|
|||
|
address.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Endpoint - Supplies the endpoint to be used will this address.
|
|||
|
|
|||
|
NetworkAddress - Returns the network address for this server. The
|
|||
|
ownership of the buffer allocated to contain the network address
|
|||
|
passes to the caller.
|
|||
|
|
|||
|
SecurityDescriptor - Optionally supplies a security descriptor to
|
|||
|
be placed on this address.
|
|||
|
|
|||
|
PendingQueueSize - Unused.
|
|||
|
|
|||
|
RpcProtocolSequence - Unused.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - We successfully setup this address.
|
|||
|
|
|||
|
RPC_S_INVALID_SECURITY_DESC - The supplied security descriptor is
|
|||
|
invalid.
|
|||
|
|
|||
|
RPC_S_CANT_CREATE_ENDPOINT - The endpoint format is correct, but
|
|||
|
the endpoint can not be created.
|
|||
|
|
|||
|
RPC_S_INVALID_ENDPOINT_FORMAT - The endpoint is not a valid
|
|||
|
endpoint for this particular transport interface.
|
|||
|
|
|||
|
RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to
|
|||
|
setup the address.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to setup
|
|||
|
the address.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOL Boolean;
|
|||
|
RPC_CHAR * String;
|
|||
|
RPC_STATUS Status ;
|
|||
|
RPC_CHAR DynamicEndpoint[64];
|
|||
|
static unsigned int DynamicEndpointCount = 0;
|
|||
|
DWORD NetworkAddressLength = MAX_COMPUTERNAME_LENGTH + 1;
|
|||
|
ULONG EndpointLength;
|
|||
|
|
|||
|
UNUSED(PendingQueueSize);
|
|||
|
|
|||
|
if (*Endpoint)
|
|||
|
{
|
|||
|
// the maximum allowed length in bytes is the
|
|||
|
// string length in bytes (string length * 2) + the NULL
|
|||
|
// terminator
|
|||
|
EndpointLength = RpcpStringLength(*Endpoint) * 2 + 2;
|
|||
|
if (EndpointLength > BIND_BACK_PORT_NAME_LEN)
|
|||
|
{
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RPC_S_INVALID_ENDPOINT_FORMAT,
|
|||
|
EEInfoDLLRPC_ADDRESS__ServerSetupAddress10,
|
|||
|
*Endpoint,
|
|||
|
EndpointLength,
|
|||
|
BIND_BACK_PORT_NAME_LEN);
|
|||
|
return RPC_S_INVALID_ENDPOINT_FORMAT;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Status = InitializeLrpcIfNecessary() ;
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return Status ;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(GlobalLrpcServer != 0) ;
|
|||
|
|
|||
|
*ppNetworkAddressVector = (NETWORK_ADDRESS_VECTOR *)
|
|||
|
new char[ sizeof(NETWORK_ADDRESS_VECTOR) + sizeof(RPC_CHAR *) + sizeof(RPC_CHAR) * (MAX_COMPUTERNAME_LENGTH + 1)];
|
|||
|
|
|||
|
if (*ppNetworkAddressVector == NULL)
|
|||
|
{
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
(*ppNetworkAddressVector)->Count = 1;
|
|||
|
(*ppNetworkAddressVector)->NetworkAddresses[0] = (RPC_CHAR *)
|
|||
|
(((char *) *ppNetworkAddressVector) + sizeof(NETWORK_ADDRESS_VECTOR) + sizeof(RPC_CHAR *));
|
|||
|
|
|||
|
Boolean = GetComputerNameW(
|
|||
|
(*ppNetworkAddressVector)->NetworkAddresses[0],
|
|||
|
&NetworkAddressLength);
|
|||
|
|
|||
|
if (Boolean != TRUE)
|
|||
|
{
|
|||
|
Status = GetLastError();
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("RPC : GetComputerNameW : %d\n", Status);
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
if (Status == ERROR_NOT_ENOUGH_MEMORY)
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
else if ((Status == ERROR_NOT_ENOUGH_QUOTA)
|
|||
|
|| (Status == ERROR_NO_SYSTEM_RESOURCES))
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_RESOURCES;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT(0);
|
|||
|
Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
if (*Endpoint)
|
|||
|
{
|
|||
|
Status = ActuallySetupAddress(*Endpoint, SecurityDescriptor);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
for (;;)
|
|||
|
{
|
|||
|
String = DynamicEndpoint;
|
|||
|
|
|||
|
*String++ = RPC_CONST_CHAR('L');
|
|||
|
*String++ = RPC_CONST_CHAR('R');
|
|||
|
*String++ = RPC_CONST_CHAR('P');
|
|||
|
*String++ = RPC_CONST_CHAR('C');
|
|||
|
|
|||
|
String = ULongToHexString(String,
|
|||
|
PtrToUlong(NtCurrentTeb()->ClientId.UniqueProcess));
|
|||
|
DynamicEndpointCount += 1;
|
|||
|
*String++ = RPC_CONST_CHAR('.');
|
|||
|
String = ULongToHexString(String, DynamicEndpointCount);
|
|||
|
*String = 0;
|
|||
|
|
|||
|
Status = ActuallySetupAddress(DynamicEndpoint, SecurityDescriptor);
|
|||
|
|
|||
|
if (Status != RPC_S_DUPLICATE_ENDPOINT)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (Status == RPC_S_OK)
|
|||
|
{
|
|||
|
*Endpoint = DuplicateString(DynamicEndpoint);
|
|||
|
if (*Endpoint == 0)
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Cleanup:
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
delete *ppNetworkAddressVector;
|
|||
|
*ppNetworkAddressVector = 0;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_ADDRESS::CompleteListen (
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name:CompleteListen
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
Description:
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LRPC_ADDRESS *LocalAddress;
|
|||
|
|
|||
|
if (DebugCell)
|
|||
|
{
|
|||
|
CStackAnsi AnsiEndpoint;
|
|||
|
int i;
|
|||
|
RPC_STATUS RpcStatus;
|
|||
|
|
|||
|
i = RpcpStringLength(InqEndpoint()) + 1;
|
|||
|
*(AnsiEndpoint.GetPAnsiString()) = (char *)_alloca(i);
|
|||
|
|
|||
|
RpcStatus = AnsiEndpoint.Attach(InqEndpoint(), i, i * 2);
|
|||
|
|
|||
|
// note that effectively we ignore the result. That's ok - we don't
|
|||
|
// want servers to be unable to start because of code page issues
|
|||
|
// in the debug path. If this fails and we ignore it, the worse
|
|||
|
// that can happen is to have empty endpoint in the debug cell
|
|||
|
// - not a big deal.
|
|||
|
if (RpcStatus == RPC_S_OK)
|
|||
|
{
|
|||
|
strncpy(DebugCell->EndpointName, AnsiEndpoint, sizeof(DebugCell->EndpointName));
|
|||
|
}
|
|||
|
|
|||
|
DebugCell->Status = desActive;
|
|||
|
}
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
AddressChain = LrpcAddressList;
|
|||
|
}
|
|||
|
while (InterlockedCompareExchangePointer((PVOID *)&LrpcAddressList, this, LrpcAddressList) != AddressChain);
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
inline LRPC_SASSOCIATION *
|
|||
|
LRPC_ADDRESS::ReferenceAssociation (
|
|||
|
IN unsigned long AssociationKey
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Given an assocation key, we need to map it into an association. The
|
|||
|
association may already have been deleted, in which case, we need to
|
|||
|
return zero.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AssociationKey - Supplies the key to be used to map into an association.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the association still exists, it will be returned; otherwise, zero
|
|||
|
will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LRPC_SASSOCIATION * Association;
|
|||
|
LPC_KEY *LpcKey = (LPC_KEY *) &AssociationKey;
|
|||
|
USHORT MySequenceNumber;
|
|||
|
|
|||
|
ASSERT(SERVERKEY(AssociationKey));
|
|||
|
|
|||
|
MySequenceNumber = LpcKey->SeqNumber & ~SERVER_KEY_MASK;
|
|||
|
|
|||
|
AddressMutex.Request();
|
|||
|
Association = AssociationDictionary.Find(LpcKey->AssocKey);
|
|||
|
if (Association == 0
|
|||
|
|| Association->SequenceNumber != MySequenceNumber)
|
|||
|
{
|
|||
|
AddressMutex.Clear();
|
|||
|
return(0);
|
|||
|
}
|
|||
|
Association->AssociationReferenceCount++;
|
|||
|
|
|||
|
LogEvent(SU_SASSOC, EV_INC, Association, 0,
|
|||
|
Association->AssociationReferenceCount, 1, 1);
|
|||
|
AddressMutex.Clear();
|
|||
|
|
|||
|
return(Association);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
inline LRPC_CASSOCIATION *
|
|||
|
LRPC_ADDRESS::ReferenceClientAssoc (
|
|||
|
IN unsigned long AssociationKey
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Given an assocation key, we need to map it into an association. The
|
|||
|
association may already have been deleted, in which case, we need to
|
|||
|
return zero.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AssociationKey - Supplies the key to be used to map into an association.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the association still exists, it will be returned; otherwise, zero
|
|||
|
will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LRPC_CASSOCIATION * Association;
|
|||
|
LPC_KEY *LpcKey = (LPC_KEY *) &AssociationKey;
|
|||
|
|
|||
|
LrpcMutexRequest();
|
|||
|
Association = LrpcAssociationDict->Find(LpcKey->AssocKey);
|
|||
|
if (Association == 0
|
|||
|
|| Association->SequenceNumber != LpcKey->SeqNumber)
|
|||
|
{
|
|||
|
LrpcMutexClear();
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
Association->AddReference();
|
|||
|
LrpcMutexClear();
|
|||
|
|
|||
|
return(Association);
|
|||
|
}
|
|||
|
|
|||
|
#if defined(_WIN64)
|
|||
|
#define BAD_HANDLE_CONST ((HANDLE)0xbaaaaaadbaaaaaad)
|
|||
|
#else
|
|||
|
#define BAD_HANDLE_CONST (ULongToHandle(0xbaaaaaad))
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
inline void
|
|||
|
LRPC_ADDRESS::DereferenceAssociation (
|
|||
|
IN LRPC_SASSOCIATION * Association
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We are done using this address, so the reference count can be decremented.
|
|||
|
If no one is referencing this association, then we can go ahead and
|
|||
|
delete it.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Association - Supplies the association whose reference count should be
|
|||
|
decremented.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
|
|||
|
AddressMutex.Request();
|
|||
|
|
|||
|
Association->AssociationReferenceCount -= 1;
|
|||
|
|
|||
|
ASSERT(Association->AssociationReferenceCount >= 0);
|
|||
|
|
|||
|
LogEvent(SU_SASSOC, EV_DEC, Association, 0,
|
|||
|
Association->AssociationReferenceCount, 1, 1);
|
|||
|
|
|||
|
if (Association->AssociationReferenceCount <= 0)
|
|||
|
{
|
|||
|
AssociationDictionary.Delete(Association->DictionaryKey);
|
|||
|
AssociationCount--;
|
|||
|
AddressMutex.Clear();
|
|||
|
|
|||
|
if (Association->LpcServerPort)
|
|||
|
{
|
|||
|
NtStatus = NtClose(Association->LpcServerPort);
|
|||
|
Association->LpcServerPort = BAD_HANDLE_CONST;
|
|||
|
LogEvent(SU_SASSOC, EV_STOP, Association, Association->LpcServerPort,
|
|||
|
Association->AssociationReferenceCount, 1, 1);
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (!NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
PrintToDebugger("RPC : NtClose : %lx\n", NtStatus);
|
|||
|
ASSERT(0) ;
|
|||
|
}
|
|||
|
#endif // DBG
|
|||
|
}
|
|||
|
|
|||
|
if (Association->LpcReplyPort)
|
|||
|
{
|
|||
|
NtStatus = NtClose(Association->LpcReplyPort);
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (!NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
PrintToDebugger("RPC : NtClose : %lx\n", NtStatus);
|
|||
|
ASSERT(0) ;
|
|||
|
}
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
delete Association;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
AddressMutex.Clear();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
LRPC_ADDRESS::DealWithLRPCRequest (
|
|||
|
IN LRPC_MESSAGE * LrpcMessage,
|
|||
|
IN LRPC_MESSAGE * LrpcReply,
|
|||
|
IN LRPC_SASSOCIATION *Association,
|
|||
|
OUT LRPC_MESSAGE **LrpcResponse
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Deal with a new LRPC request.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LrpcMessage - request message
|
|||
|
LrpcReply - the reply is placed here
|
|||
|
Association - the association on which the request arrived
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FALSE if the thread should stay, or !FALSE if the thread should go
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
int retval ;
|
|||
|
LRPC_SCALL *SCall;
|
|||
|
NTSTATUS NtStatus ;
|
|||
|
RPC_STATUS Status;
|
|||
|
LRPC_SCALL *NewSCall ;
|
|||
|
int Flags = LrpcMessage->Rpc.RpcHeader.Flags ;
|
|||
|
|
|||
|
if (ServerListeningFlag == 0
|
|||
|
&& GlobalRpcServer->InqNumAutoListenInterfaces() == 0)
|
|||
|
{
|
|||
|
*LrpcResponse = LrpcMessage ;
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RPC_S_SERVER_TOO_BUSY,
|
|||
|
EEInfoDLDealWithLRPCRequest10,
|
|||
|
(ULONG)ServerListeningFlag,
|
|||
|
(ULONG)GlobalRpcServer->InqNumAutoListenInterfaces());
|
|||
|
SetFaultPacket(*LrpcResponse,
|
|||
|
RPC_S_SERVER_TOO_BUSY, Flags, NULL);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
Status = Association->AllocateSCall(LrpcMessage,
|
|||
|
LrpcReply,
|
|||
|
Flags,
|
|||
|
&SCall) ;
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
*LrpcResponse = LrpcMessage ;
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
Status,
|
|||
|
EEInfoDLDealWithLRPCRequest20);
|
|||
|
SetFaultPacket(*LrpcResponse, Status, Flags, NULL);
|
|||
|
return 0 ;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(SCall);
|
|||
|
|
|||
|
Status = SCall->LrpcMessageToRpcMessage(LrpcMessage,
|
|||
|
&(SCall->RpcMessage));
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("LRPC: LrpcMessageToRpcMessage failed: %d\n",
|
|||
|
Status) ;
|
|||
|
#endif
|
|||
|
|
|||
|
*LrpcResponse = LrpcMessage ;
|
|||
|
SetFaultPacket(*LrpcResponse, Status, Flags, NULL);
|
|||
|
|
|||
|
Association->FreeSCall (SCall) ;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
AddressMutex.Request();
|
|||
|
|
|||
|
if (SCall->Flags & LRPC_CAUSAL)
|
|||
|
{
|
|||
|
retval = Association->MaybeQueueSCall(SCall) ;
|
|||
|
switch (retval)
|
|||
|
{
|
|||
|
case 0:
|
|||
|
break;
|
|||
|
|
|||
|
case 1:
|
|||
|
AddressMutex.Clear();
|
|||
|
*LrpcResponse = NULL ;
|
|||
|
return 0;
|
|||
|
|
|||
|
case -1:
|
|||
|
AddressMutex.Clear();
|
|||
|
*LrpcResponse = LrpcMessage ;
|
|||
|
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RPC_S_OUT_OF_MEMORY,
|
|||
|
EEInfoDLDealWithLRPCRequest30);
|
|||
|
SetFaultPacket(*LrpcResponse, LRPC_MSG_FAULT, Flags, NULL);
|
|||
|
|
|||
|
Association->FreeSCall (SCall) ;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ActiveCallCount += 1;
|
|||
|
|
|||
|
if (ActiveCallCount >= CallThreadCount)
|
|||
|
{
|
|||
|
Status = Server->CreateThread(
|
|||
|
(THREAD_PROC)&RecvLotsaCallsWrapper,
|
|||
|
this);
|
|||
|
|
|||
|
if (Status == RPC_S_OK)
|
|||
|
{
|
|||
|
CallThreadCount += 1;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// If the above SCall is causal and creating the thread has failed
|
|||
|
// then the call has been put into the dictionary and needs
|
|||
|
// to be removed. It will be the only scall for the key.
|
|||
|
if (SCall->Flags & LRPC_CAUSAL)
|
|||
|
Association->ClientThreadDict.Delete(MsgClientIdToClientId(SCall->LrpcRequestMessage->Rpc.LpcHeader.ClientId).UniqueThread) ;
|
|||
|
|
|||
|
ActiveCallCount -= 1;
|
|||
|
ASSERT((int)ActiveCallCount >= 0);
|
|||
|
AddressMutex.Clear();
|
|||
|
*LrpcResponse = LrpcMessage ;
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
Status,
|
|||
|
EEInfoDLDealWithLRPCRequest40);
|
|||
|
SetFaultPacket(*LrpcResponse,
|
|||
|
RPC_S_SERVER_TOO_BUSY, Flags, NULL);
|
|||
|
|
|||
|
Association->FreeSCall(SCall) ;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
AddressMutex.Clear();
|
|||
|
|
|||
|
while (1)
|
|||
|
{
|
|||
|
LrpcReply->Rpc.RpcHeader.Flags = 0;
|
|||
|
|
|||
|
SCall->DealWithRequestMessage();
|
|||
|
|
|||
|
if ((SCall->Flags & LRPC_CAUSAL) == 0)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
NewSCall = Association->GetNextSCall(SCall) ;
|
|||
|
if (NewSCall)
|
|||
|
{
|
|||
|
SCall->SendReply();
|
|||
|
|
|||
|
SCall = NewSCall ;
|
|||
|
while (SCall->Deleted)
|
|||
|
{
|
|||
|
FreeMessage(SCall->LrpcRequestMessage) ;
|
|||
|
|
|||
|
NewSCall = Association->GetNextSCall(SCall) ;
|
|||
|
|
|||
|
AddressMutex.Request();
|
|||
|
|
|||
|
//
|
|||
|
// N.B. If a causally ordered call fails
|
|||
|
// in DealWithRequestMessage, this is fine, because
|
|||
|
// in SendReply, if we send back a fault,
|
|||
|
// we will mark all calls in the SCallDict with Deleted,
|
|||
|
// and in this loop, we will skip them.
|
|||
|
//
|
|||
|
if (NewSCall == 0)
|
|||
|
{
|
|||
|
if (fKeepThread())
|
|||
|
{
|
|||
|
retval = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CallThreadCount -= 1;
|
|||
|
retval = 1;
|
|||
|
}
|
|||
|
ActiveCallCount -= 1;
|
|||
|
ASSERT((int)ActiveCallCount >= 0);
|
|||
|
AddressMutex.Clear();
|
|||
|
|
|||
|
Association->FreeSCall(SCall) ;
|
|||
|
DereferenceAssociation(Association) ;
|
|||
|
|
|||
|
*LrpcResponse = NULL ;
|
|||
|
|
|||
|
return retval;
|
|||
|
}
|
|||
|
|
|||
|
AddressMutex.Clear();
|
|||
|
|
|||
|
Association->FreeSCall(SCall) ;
|
|||
|
DereferenceAssociation(Association) ;
|
|||
|
|
|||
|
SCall = NewSCall ;
|
|||
|
}
|
|||
|
|
|||
|
RpcpPurgeEEInfo();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// Make sure that the LrpcReplyMessage is always pointing to the
|
|||
|
// one located on this thread's stack. It is possible that we
|
|||
|
// will pick up a queued scall that was put into the queue on
|
|||
|
// another thread. In this case, the LrpcReplyMessage may point to
|
|||
|
// that thread's stack - a recepie for disaster.
|
|||
|
// Note that LrpcReply is located on the stack for the current thread.
|
|||
|
LrpcReply->Rpc.RpcHeader.CallId = SCall->CallId ;
|
|||
|
SCall->LrpcReplyMessage = LrpcReply;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
AddressMutex.Request();
|
|||
|
if (fKeepThread())
|
|||
|
{
|
|||
|
if (SCall->IsSyncCall() && SCall->IsClientAsync() == 0)
|
|||
|
{
|
|||
|
ActiveCallCount -= 1;
|
|||
|
ASSERT((int)ActiveCallCount >= 0);
|
|||
|
AddressMutex.Clear();
|
|||
|
|
|||
|
*LrpcResponse = SCall->InitMsg();
|
|||
|
|
|||
|
Association->FreeSCall(SCall) ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
AddressMutex.Clear();
|
|||
|
|
|||
|
*LrpcResponse = NULL;
|
|||
|
SCall->SendReply();
|
|||
|
|
|||
|
AddressMutex.Request();
|
|||
|
ActiveCallCount -= 1;
|
|||
|
ASSERT((int)ActiveCallCount >= 0);
|
|||
|
AddressMutex.Clear();
|
|||
|
}
|
|||
|
|
|||
|
return 0 ;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// This thread is extraneous, reply and return this
|
|||
|
// thread to the system.
|
|||
|
//
|
|||
|
ActiveCallCount -= 1;
|
|||
|
ASSERT((int)ActiveCallCount >= 0);
|
|||
|
CallThreadCount -= 1;
|
|||
|
AddressMutex.Clear();
|
|||
|
|
|||
|
SCall->SendReply();
|
|||
|
|
|||
|
return 1 ;
|
|||
|
}
|
|||
|
|
|||
|
#define LRPC_LISTEN_TIMEOUT 5*60*1000
|
|||
|
|
|||
|
inline void
|
|||
|
FormatTimeOut(
|
|||
|
OUT PLARGE_INTEGER TimeOut,
|
|||
|
IN DWORD Milliseconds
|
|||
|
)
|
|||
|
{
|
|||
|
ASSERT(Milliseconds != -1);
|
|||
|
|
|||
|
TimeOut->QuadPart = UInt32x32To64( Milliseconds, 10000 );
|
|||
|
TimeOut->QuadPart *= -1;
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_ADDRESS::BeginLongCall(
|
|||
|
void
|
|||
|
)
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
|
|||
|
AddressMutex.Request();
|
|||
|
|
|||
|
if (ActiveCallCount + 1 >= CallThreadCount)
|
|||
|
{
|
|||
|
AddressMutex.Clear();
|
|||
|
|
|||
|
Status = Server->CreateThread(
|
|||
|
(THREAD_PROC)&RecvLotsaCallsWrapper,
|
|||
|
this);
|
|||
|
|
|||
|
AddressMutex.Request();
|
|||
|
|
|||
|
// N.B. We increase the active call count
|
|||
|
// regrdless of Status. This is OK, because
|
|||
|
// if we return failure, the caller of this function
|
|||
|
// is responsible to decrease it
|
|||
|
ActiveCallCount ++;
|
|||
|
|
|||
|
if (Status == RPC_S_OK)
|
|||
|
{
|
|||
|
CallThreadCount += 1;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ActiveCallCount ++;
|
|||
|
}
|
|||
|
AddressMutex.Clear();
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
void LRPC_ADDRESS::HandleInvalidAssociationReference (
|
|||
|
IN LRPC_MESSAGE *RequestMessage,
|
|||
|
IN OUT LRPC_MESSAGE **ReplyMessage,
|
|||
|
IN ULONG AssociationKey
|
|||
|
)
|
|||
|
{
|
|||
|
ASSERT(RequestMessage != NULL);
|
|||
|
ASSERT(ReplyMessage != NULL);
|
|||
|
|
|||
|
// we handle only binds, requests and copies
|
|||
|
if ((RequestMessage->Bind.MessageType != LRPC_MSG_REQUEST)
|
|||
|
&& (RequestMessage->Bind.MessageType != LRPC_MSG_BIND)
|
|||
|
&& (RequestMessage->Bind.MessageType != LRPC_MSG_COPY))
|
|||
|
{
|
|||
|
*ReplyMessage = NULL;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RPC_S_CALL_FAILED_DNE,
|
|||
|
EEInfoDLLRPC_ADDRESS__HandleInvalidAssociationReference10,
|
|||
|
AssociationKey);
|
|||
|
|
|||
|
if (RequestMessage->Bind.MessageType == LRPC_MSG_BIND)
|
|||
|
{
|
|||
|
SetBindAckFault(RequestMessage, RPC_S_CALL_FAILED_DNE);
|
|||
|
|
|||
|
// if this is bind, patch up the fields a bit, as SetFaultPacket
|
|||
|
// does not set everything right for the bind case
|
|||
|
RequestMessage->Bind.MessageType = LRPC_BIND_ACK;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
SetFaultPacket(RequestMessage,
|
|||
|
RPC_S_CALL_FAILED_DNE,
|
|||
|
RequestMessage->Rpc.RpcHeader.Flags,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
|
|||
|
*ReplyMessage = RequestMessage;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
LRPC_ADDRESS::EndLongCall(
|
|||
|
void
|
|||
|
)
|
|||
|
{
|
|||
|
AddressMutex.Request();
|
|||
|
ActiveCallCount -= 1;
|
|||
|
|
|||
|
int SpareThreads = CallThreadCount -
|
|||
|
(ActiveCallCount + MinimumCallThreads);
|
|||
|
|
|||
|
if (SpareThreads > 0)
|
|||
|
{
|
|||
|
ASSERT(CallThreadCount > ActiveCallCount);
|
|||
|
|
|||
|
AddressMutex.Clear();
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
AddressMutex.Clear();
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
LRPC_ADDRESS::ReceiveLotsaCalls (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Here is where we receive remote procedure calls to this address. One
|
|||
|
more threads will be executing this routine at once.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
LRPC_SASSOCIATION * Association;
|
|||
|
LRPC_CASSOCIATION *CAssociation;
|
|||
|
unsigned long AssociationKey;
|
|||
|
char *PaddedMessage;
|
|||
|
LRPC_MESSAGE * Reply ;
|
|||
|
LRPC_MESSAGE * LrpcMessage = 0;
|
|||
|
LRPC_MESSAGE * LrpcReplyMessage = 0;
|
|||
|
int AssociationType = 0;
|
|||
|
int Flags = 0;
|
|||
|
BOOL PartialFlag ;
|
|||
|
BOOL fStatus ;
|
|||
|
RPC_STATUS Status;
|
|||
|
unsigned long ReplyKey = -1;
|
|||
|
LARGE_INTEGER LongTimeout;
|
|||
|
LARGE_INTEGER ShortTimeout;
|
|||
|
PLARGE_INTEGER pliTimeout = &ShortTimeout;
|
|||
|
ULONG_PTR Key;
|
|||
|
THREAD *ThisThread;
|
|||
|
DebugThreadInfo *DebugCell;
|
|||
|
|
|||
|
FormatTimeOut(&ShortTimeout, gThreadTimeout);
|
|||
|
FormatTimeOut(&LongTimeout, LRPC_LISTEN_TIMEOUT);
|
|||
|
pliTimeout = &ShortTimeout;
|
|||
|
|
|||
|
PaddedMessage = (char *) _alloca(PadToNaturalBoundary(sizeof(LRPC_MESSAGE) + 1) + sizeof(LRPC_MESSAGE));
|
|||
|
Reply = (LRPC_MESSAGE *) AlignOnNaturalBoundary(PaddedMessage) ;
|
|||
|
|
|||
|
ThisThread = RpcpGetThreadPointer();
|
|||
|
ASSERT(ThisThread);
|
|||
|
|
|||
|
DebugCell = ThisThread->DebugCell;
|
|||
|
|
|||
|
if (DebugCell)
|
|||
|
{
|
|||
|
if (this->DebugCell)
|
|||
|
{
|
|||
|
GetDebugCellIDFromDebugCell(
|
|||
|
(DebugCellUnion *)this->DebugCell,
|
|||
|
&this->DebugCellTag,
|
|||
|
&ThisThread->DebugCell->Endpoint);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
for (;;)
|
|||
|
{
|
|||
|
if (LrpcMessage == 0)
|
|||
|
{
|
|||
|
while ((LrpcMessage = AllocateMessage()) == 0)
|
|||
|
{
|
|||
|
Sleep(100) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(LrpcReplyMessage == 0
|
|||
|
|| LrpcReplyMessage->Rpc.RpcHeader.MessageType <= MAX_LRPC_MSG);
|
|||
|
|
|||
|
if (DebugCell)
|
|||
|
{
|
|||
|
DebugCell->Status = dtsIdle;
|
|||
|
DebugCell->LastUpdateTime = NtGetTickCount();
|
|||
|
}
|
|||
|
|
|||
|
RpcpPurgeEEInfoFromThreadIfNecessary(ThisThread);
|
|||
|
|
|||
|
NtStatus = NtReplyWaitReceivePortEx(LpcAddressPort,
|
|||
|
(PVOID *) &Key,
|
|||
|
(PORT_MESSAGE *) LrpcReplyMessage,
|
|||
|
(PORT_MESSAGE *) LrpcMessage,
|
|||
|
pliTimeout);
|
|||
|
AssociationKey = (ULONG) Key; // need this for 64bit
|
|||
|
|
|||
|
if (NtStatus != STATUS_TIMEOUT
|
|||
|
&& NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
if (pliTimeout != &ShortTimeout)
|
|||
|
{
|
|||
|
#if defined (RPC_GC_AUDIT)
|
|||
|
DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LPC Thread %X: coming back from long wait\n",
|
|||
|
GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId());
|
|||
|
#endif
|
|||
|
ASSERT((pliTimeout == NULL) || (pliTimeout == &LongTimeout));
|
|||
|
ThreadsDoingLongWait.Decrement();
|
|||
|
pliTimeout = &ShortTimeout;
|
|||
|
}
|
|||
|
|
|||
|
if (DebugCell)
|
|||
|
{
|
|||
|
DebugCell->Status = dtsProcessing;
|
|||
|
DebugCell->LastUpdateTime = NtGetTickCount();
|
|||
|
}
|
|||
|
|
|||
|
#if 0
|
|||
|
if (LrpcMessage->LpcHeader.u2.s2.Type == LPC_CONNECTION_REQUEST)
|
|||
|
LogEvent(SU_PACKET, EV_PKT_IN, (void *) LrpcMessage->LpcHeader.u2.ZeroInit,
|
|||
|
(void *)LrpcMessage->Connect.BindExchange.ConnectType, AssociationKey);
|
|||
|
else
|
|||
|
LogEvent(SU_PACKET, EV_PKT_IN, (void *) LrpcMessage->LpcHeader.u2.ZeroInit,
|
|||
|
0, AssociationKey);
|
|||
|
#endif
|
|||
|
|
|||
|
if (LrpcMessage->LpcHeader.u2.s2.Type == LPC_DATAGRAM
|
|||
|
|| LrpcMessage->LpcHeader.u2.s2.Type == LPC_REQUEST)
|
|||
|
{
|
|||
|
if (!SERVERKEY(AssociationKey))
|
|||
|
{
|
|||
|
VALIDATE(LrpcMessage->Bind.MessageType)
|
|||
|
{
|
|||
|
LRPC_MSG_FAULT,
|
|||
|
LRPC_MSG_FAULT2,
|
|||
|
LRPC_MSG_RESPONSE,
|
|||
|
LRPC_CLIENT_SEND_MORE
|
|||
|
} END_VALIDATE;
|
|||
|
|
|||
|
//
|
|||
|
// response or fault on the back connection.
|
|||
|
// we are using async rpc or pipes
|
|||
|
//
|
|||
|
CAssociation = ReferenceClientAssoc(AssociationKey);
|
|||
|
if (CAssociation)
|
|||
|
{
|
|||
|
BeginLongCall();
|
|||
|
|
|||
|
LrpcReplyMessage = 0;
|
|||
|
|
|||
|
CAssociation->ProcessResponse(LrpcMessage, &LrpcReplyMessage);
|
|||
|
|
|||
|
//
|
|||
|
// the receive thread needs to allocate a new message
|
|||
|
//
|
|||
|
LrpcMessage = 0 ;
|
|||
|
|
|||
|
CAssociation->RemoveReference() ;
|
|||
|
|
|||
|
EndLongCall();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
HandleInvalidAssociationReference(LrpcMessage,
|
|||
|
&LrpcReplyMessage,
|
|||
|
AssociationKey);
|
|||
|
}
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
Association = ReferenceAssociation(AssociationKey);
|
|||
|
if (Association == 0)
|
|||
|
{
|
|||
|
HandleInvalidAssociationReference(LrpcMessage,
|
|||
|
&LrpcReplyMessage,
|
|||
|
AssociationKey);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
ReplyKey = AssociationKey;
|
|||
|
Flags = LrpcMessage->Rpc.RpcHeader.Flags ;
|
|||
|
PartialFlag = FALSE ;
|
|||
|
|
|||
|
if (LrpcMessage->Bind.MessageType == LRPC_MSG_REQUEST)
|
|||
|
{
|
|||
|
//
|
|||
|
// Optimize the common case
|
|||
|
//
|
|||
|
fStatus = DealWithLRPCRequest (
|
|||
|
LrpcMessage,
|
|||
|
Reply,
|
|||
|
Association,
|
|||
|
&LrpcReplyMessage) ;
|
|||
|
|
|||
|
if (fStatus)
|
|||
|
{
|
|||
|
// this is the first of two exits from the loop
|
|||
|
// (the second is below)
|
|||
|
if (DebugCell)
|
|||
|
{
|
|||
|
DebugCell->Status = dtsAllocated;
|
|||
|
DebugCell->LastUpdateTime = NtGetTickCount();
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (LrpcReplyMessage == 0)
|
|||
|
{
|
|||
|
LrpcMessage = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
DereferenceAssociation(Association);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
switch (LrpcMessage->Bind.MessageType)
|
|||
|
{
|
|||
|
case LRPC_PARTIAL_REQUEST:
|
|||
|
case LRPC_SERVER_SEND_MORE:
|
|||
|
case LRPC_MSG_CANCEL:
|
|||
|
LrpcReplyMessage = Association->
|
|||
|
DealWithPartialRequest(&LrpcMessage) ;
|
|||
|
break;
|
|||
|
|
|||
|
case LRPC_MSG_COPY:
|
|||
|
LrpcReplyMessage = Association->DealWithCopyMessage(
|
|||
|
(LRPC_COPY_MESSAGE *)LrpcMessage);
|
|||
|
break;
|
|||
|
|
|||
|
case LRPC_MSG_BIND :
|
|||
|
Association->DealWithBindMessage(LrpcMessage);
|
|||
|
|
|||
|
LrpcReplyMessage = 0 ;
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
case LRPC_MSG_BIND_BACK:
|
|||
|
BeginLongCall();
|
|||
|
|
|||
|
LrpcReplyMessage = Association->
|
|||
|
DealWithBindBackMessage(LrpcMessage);
|
|||
|
|
|||
|
EndLongCall();
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("RPC : Bad Message Type (%d) - %d\n",
|
|||
|
LrpcMessage->Bind.MessageType,
|
|||
|
LrpcMessage->LpcHeader.u2.s2.Type);
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
ASSERT(0) ;
|
|||
|
LrpcReplyMessage = 0 ;
|
|||
|
Association->Delete();
|
|||
|
break;
|
|||
|
}
|
|||
|
DereferenceAssociation(Association);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
switch (LrpcMessage->LpcHeader.u2.s2.Type)
|
|||
|
{
|
|||
|
case LPC_CONNECTION_REQUEST:
|
|||
|
if (LrpcMessage->Connect.BindExchange.ConnectType
|
|||
|
== LRPC_CONNECT_REQUEST)
|
|||
|
{
|
|||
|
BeginLongCall();
|
|||
|
|
|||
|
DealWithNewClient(LrpcMessage) ;
|
|||
|
|
|||
|
EndLongCall();
|
|||
|
}
|
|||
|
else if (LrpcMessage->Connect.BindExchange.ConnectType
|
|||
|
== LRPC_CONNECT_RESPONSE)
|
|||
|
{
|
|||
|
DealWithConnectResponse(LrpcMessage) ;
|
|||
|
}
|
|||
|
else if (LrpcMessage->Connect.BindExchange.ConnectType
|
|||
|
== LRPC_CONNECT_TICKLE)
|
|||
|
{
|
|||
|
HANDLE Ignore;
|
|||
|
|
|||
|
// always reject - this just has the purpose of tickling
|
|||
|
// a thread on a long wait
|
|||
|
NtStatus = NtAcceptConnectPort(&Ignore,
|
|||
|
NULL,
|
|||
|
(PORT_MESSAGE *) LrpcMessage,
|
|||
|
FALSE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
#if defined (RPC_GC_AUDIT)
|
|||
|
DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LPC Thread %X: tickled\n",
|
|||
|
GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId());
|
|||
|
#endif
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT(0) ;
|
|||
|
}
|
|||
|
LrpcReplyMessage = 0;
|
|||
|
break;
|
|||
|
|
|||
|
case LPC_CLIENT_DIED:
|
|||
|
LrpcReplyMessage = 0;
|
|||
|
break;
|
|||
|
|
|||
|
case LPC_PORT_CLOSED:
|
|||
|
if (SERVERKEY(AssociationKey))
|
|||
|
{
|
|||
|
Association = ReferenceAssociation(AssociationKey);
|
|||
|
if (Association == 0)
|
|||
|
{
|
|||
|
LrpcReplyMessage = 0;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
BeginLongCall();
|
|||
|
|
|||
|
Association->Delete();
|
|||
|
DereferenceAssociation(Association);
|
|||
|
|
|||
|
LrpcReplyMessage = 0;
|
|||
|
|
|||
|
EndLongCall();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CAssociation = ReferenceClientAssoc(AssociationKey);
|
|||
|
if (CAssociation)
|
|||
|
{
|
|||
|
BeginLongCall();
|
|||
|
CAssociation->AbortAssociation(1) ;
|
|||
|
CAssociation->RemoveReference() ;
|
|||
|
EndLongCall();
|
|||
|
}
|
|||
|
|
|||
|
LrpcReplyMessage = 0;
|
|||
|
}
|
|||
|
continue;
|
|||
|
|
|||
|
default:
|
|||
|
LrpcReplyMessage = 0 ;
|
|||
|
ASSERT(0);
|
|||
|
} // switch
|
|||
|
} // else
|
|||
|
} // if
|
|||
|
else
|
|||
|
{
|
|||
|
switch (NtStatus)
|
|||
|
{
|
|||
|
case STATUS_NO_MEMORY:
|
|||
|
case STATUS_INSUFFICIENT_RESOURCES:
|
|||
|
case STATUS_UNSUCCESSFUL:
|
|||
|
PauseExecution(500L);
|
|||
|
break;
|
|||
|
|
|||
|
case STATUS_TIMEOUT:
|
|||
|
#if defined (RPC_GC_AUDIT)
|
|||
|
DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LPC Thread %X: timed out - gc\n",
|
|||
|
GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId());
|
|||
|
#endif
|
|||
|
|
|||
|
PerformGarbageCollection();
|
|||
|
|
|||
|
if (pliTimeout == &ShortTimeout)
|
|||
|
{
|
|||
|
// be conservative and presume we will
|
|||
|
// be doing long wait. If later we find out
|
|||
|
// we won't, we'll reverse that. Also, this must
|
|||
|
// be done nefore we check for
|
|||
|
// GarbageCollectedRequested - this allows other
|
|||
|
// threads to safely count the number of threads
|
|||
|
// on short wait without taking a mutex
|
|||
|
ThreadsDoingLongWait.Increment();
|
|||
|
|
|||
|
LrpcReplyMessage = 0;
|
|||
|
// if there is garbage collection
|
|||
|
// requested, don't switch to long
|
|||
|
// wait
|
|||
|
if (GarbageCollectionRequested)
|
|||
|
{
|
|||
|
#if defined (RPC_GC_AUDIT)
|
|||
|
DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LPC Thread %X: gc requested - can't do long wait\n",
|
|||
|
GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId());
|
|||
|
#endif
|
|||
|
ThreadsDoingLongWait.Decrement();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
#if defined (RPC_GC_AUDIT)
|
|||
|
DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LPC Thread %X: going to long wait\n",
|
|||
|
GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId());
|
|||
|
#endif
|
|||
|
// there is no garbage collection requested
|
|||
|
// switch to longer wait (but not infinite yet)
|
|||
|
pliTimeout = &LongTimeout;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (pliTimeout == &LongTimeout)
|
|||
|
{
|
|||
|
// if this is a long wait, and we're a spare
|
|||
|
// thread, we can go
|
|||
|
AddressMutex.Request();
|
|||
|
if (CallThreadCount - ActiveCallCount > 1)
|
|||
|
{
|
|||
|
CallThreadCount -= 1;
|
|||
|
ASSERT(CallThreadCount > ActiveCallCount);
|
|||
|
AddressMutex.Clear();
|
|||
|
|
|||
|
// decrease the counter of threads doing long
|
|||
|
// listen after we decrease the CallThreadCount
|
|||
|
// This allows other threads to use the number
|
|||
|
// of threads doing short wait without taking
|
|||
|
// a mutex
|
|||
|
ThreadsDoingLongWait.Decrement();
|
|||
|
|
|||
|
FreeMessage(LrpcMessage);
|
|||
|
|
|||
|
// N.B. This is the second exit from the loop (see above)
|
|||
|
if (DebugCell)
|
|||
|
{
|
|||
|
DebugCell->Status = dtsAllocated;
|
|||
|
DebugCell->LastUpdateTime = NtGetTickCount();
|
|||
|
}
|
|||
|
|
|||
|
return ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// We are assuming that if the call has timed out, the reply has
|
|||
|
// been sent
|
|||
|
//
|
|||
|
LrpcReplyMessage = 0;
|
|||
|
pliTimeout = NULL;
|
|||
|
#if defined (RPC_GC_AUDIT)
|
|||
|
DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LPC Thread %X: going to infinite wait\n",
|
|||
|
GetCurrentProcessId(), GetCurrentProcessId(), GetCurrentThreadId());
|
|||
|
#endif
|
|||
|
}
|
|||
|
AddressMutex.Clear();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT(!"We cannot get a timeout on wait with infinite timeout");
|
|||
|
}
|
|||
|
|
|||
|
if (DebugCell)
|
|||
|
{
|
|||
|
RelocateCellIfPossible((void **) &DebugCell, &ThisThread->DebugCellTag);
|
|||
|
ThisThread->DebugCell = DebugCell;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
if (LrpcReplyMessage)
|
|||
|
{
|
|||
|
LrpcReplyMessage = 0;
|
|||
|
if (ReplyKey != -1)
|
|||
|
{
|
|||
|
Association = ReferenceAssociation(ReplyKey);
|
|||
|
if (Association == 0)
|
|||
|
{
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
continue;
|
|||
|
|
|||
|
BeginLongCall();
|
|||
|
|
|||
|
Association->Delete();
|
|||
|
DereferenceAssociation(Association);
|
|||
|
|
|||
|
EndLongCall();
|
|||
|
}
|
|||
|
break;
|
|||
|
} // switch
|
|||
|
} // else
|
|||
|
} // for
|
|||
|
}
|
|||
|
|
|||
|
#define DEFAULT_PORT_DIR "\\RPC Control\\"
|
|||
|
#define DEFAULT_PORT_NAME "ARPC Port1"
|
|||
|
#define DEFAULT_REPLY_NAME "ARPC Reply Port"
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
LRPC_ADDRESS::DealWithNewClient (
|
|||
|
IN LRPC_MESSAGE * ConnectionRequest
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
A new client has connected with our address port. We need to take
|
|||
|
care of the new client and send a response.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ConnectionRequest - Supplies information need by LPC to abort the
|
|||
|
connect request. Includes the bind request from the client.
|
|||
|
This contains the information about which interface the client
|
|||
|
wants to bind with. and which we use to send the status code
|
|||
|
back in.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LRPC_SASSOCIATION * Association;
|
|||
|
NTSTATUS NtStatus;
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
DWORD Key;
|
|||
|
LPC_KEY *LpcKey = (LPC_KEY *) &Key;
|
|||
|
|
|||
|
Association = new LRPC_SASSOCIATION(this,
|
|||
|
&Status);
|
|||
|
if (Association == 0)
|
|||
|
{
|
|||
|
RejectNewClient(ConnectionRequest, RPC_S_OUT_OF_MEMORY);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
delete Association ;
|
|||
|
RejectNewClient(ConnectionRequest, RPC_S_OUT_OF_MEMORY);
|
|||
|
return ;
|
|||
|
}
|
|||
|
|
|||
|
AddressMutex.Request();
|
|||
|
Association->DictionaryKey = (unsigned short)
|
|||
|
AssociationDictionary.Insert(Association);
|
|||
|
AssociationCount++;
|
|||
|
SequenceNumber = (SequenceNumber+1) % (0x7FFF);
|
|||
|
Association->SequenceNumber = SequenceNumber;
|
|||
|
AddressMutex.Clear();
|
|||
|
|
|||
|
if (Association->DictionaryKey == -1)
|
|||
|
{
|
|||
|
AddressMutex.Request();
|
|||
|
AssociationCount-- ;
|
|||
|
AddressMutex.Clear();
|
|||
|
|
|||
|
delete Association ;
|
|||
|
RejectNewClient(ConnectionRequest, RPC_S_OUT_OF_MEMORY);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (ConnectionRequest->Connect.BindExchange.Flags & BIND_BACK_FLAG)
|
|||
|
{
|
|||
|
ConnectionRequest->Connect.BindExchange.szPortName[PORT_NAME_LEN-1] = NULL;
|
|||
|
|
|||
|
Status = Association->BindBack(
|
|||
|
(RPC_CHAR *)ConnectionRequest->Connect.BindExchange.szPortName,
|
|||
|
ConnectionRequest->Connect.BindExchange.AssocKey) ;
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
RejectNewClient(ConnectionRequest, RPC_S_OUT_OF_MEMORY);
|
|||
|
Association->Delete() ;
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ConnectionRequest->Connect.BindExchange.RpcStatus = RPC_S_OK;
|
|||
|
|
|||
|
ASSERT(sizeof(unsigned long) <= sizeof(PVOID));
|
|||
|
|
|||
|
ASSERT((Association->SequenceNumber & SERVER_KEY_MASK) == 0);
|
|||
|
|
|||
|
LpcKey->SeqNumber = Association->SequenceNumber | SERVER_KEY_MASK;
|
|||
|
LpcKey->AssocKey = Association->DictionaryKey;
|
|||
|
|
|||
|
// After the call to NtAcceptConnectPort, the client will become unblocked
|
|||
|
// the association will be in the dictionary and will have refcount 1. If the client quits
|
|||
|
// or closes port the association will be deleted. Then NtCompleteConnectPort
|
|||
|
// may touch invalid memory or operate on a bad handle. To prevent that we
|
|||
|
// need to hold an extra count between the two calls.
|
|||
|
//
|
|||
|
// Since this thread is the only one playing with the association up to now,
|
|||
|
// there is no need for a lock.
|
|||
|
Association->AssociationReferenceCount++;
|
|||
|
|
|||
|
NtStatus = NtAcceptConnectPort(&(Association->LpcServerPort),
|
|||
|
ULongToPtr(Key),
|
|||
|
(PORT_MESSAGE *) ConnectionRequest,
|
|||
|
TRUE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
if (NT_ERROR(NtStatus))
|
|||
|
{
|
|||
|
Association->Delete();
|
|||
|
|
|||
|
// We just have to dereference the association to remove the extra
|
|||
|
// count added above. This should cause its deletion.
|
|||
|
DereferenceAssociation(Association);
|
|||
|
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("RPC : NtAcceptConnectPort : %lx\n", NtStatus);
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
NtStatus = NtCompleteConnectPort(Association->LpcServerPort);
|
|||
|
|
|||
|
if (NT_ERROR(NtStatus))
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("RPC : NtCompleteConnectPort : %lx\n", NtStatus);
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
// If Association->Delete() has already been called on a different
|
|||
|
// theread due to a closed client port, this call will be ignored...
|
|||
|
Association->Delete();
|
|||
|
|
|||
|
// and the final reference will be removed here causing a deletion.
|
|||
|
DereferenceAssociation(Association);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Remove the extra-reference.
|
|||
|
DereferenceAssociation(Association);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
LRPC_ADDRESS::DealWithConnectResponse (
|
|||
|
IN LRPC_MESSAGE * ConnectResponse
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Just received a connect response from the remove server,
|
|||
|
need to handle that.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ConnectionRequest -
|
|||
|
Needed to get the pAssoc
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
HANDLE temp ;
|
|||
|
LRPC_CASSOCIATION * Association ;
|
|||
|
DWORD Key;
|
|||
|
|
|||
|
Key = ConnectResponse->Connect.BindExchange.AssocKey;
|
|||
|
|
|||
|
Association = ReferenceClientAssoc(Key);
|
|||
|
if (Association == 0)
|
|||
|
{
|
|||
|
RejectNewClient(ConnectResponse, RPC_S_PROTOCOL_ERROR);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
NtStatus = NtAcceptConnectPort(&temp,
|
|||
|
ULongToPtr(Key),
|
|||
|
(PPORT_MESSAGE) ConnectResponse,
|
|||
|
TRUE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
Association->SetReceivePort(temp) ;
|
|||
|
|
|||
|
NtStatus = NtCompleteConnectPort(temp);
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("LRPC: NtCompleteConnectPort(1) failed: %lx\n",
|
|||
|
NtStatus) ;
|
|||
|
#endif
|
|||
|
|
|||
|
Association->Delete();
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("LRPC: NtAcceptConnectionPort(1) failed: %lx\n",
|
|||
|
NtStatus) ;
|
|||
|
#endif
|
|||
|
|
|||
|
Association->Delete();
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remove the reference we added above
|
|||
|
//
|
|||
|
Association->RemoveReference() ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
LRPC_ADDRESS::RejectNewClient (
|
|||
|
IN LRPC_MESSAGE * ConnectionRequest,
|
|||
|
IN RPC_STATUS Status
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
A new client has connected with our address port. We need to reject
|
|||
|
the client.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ConnectionRequest - Supplies information need by LPC to abort the
|
|||
|
connect request. Includes the bind request from the client,
|
|||
|
which we use to send the status code back in.
|
|||
|
|
|||
|
|
|||
|
Status - Supplies the reason the client is being rejected.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
HANDLE Ignore;
|
|||
|
|
|||
|
ASSERT(Status != RPC_S_OK);
|
|||
|
|
|||
|
ConnectionRequest->Connect.BindExchange.RpcStatus = Status;
|
|||
|
ConnectionRequest->Connect.BindExchange.Flags |= SERVER_BIND_EXCH_RESP;
|
|||
|
NtStatus = NtAcceptConnectPort(&Ignore,
|
|||
|
NULL,
|
|||
|
(PORT_MESSAGE *) ConnectionRequest,
|
|||
|
FALSE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
#if DBG
|
|||
|
if (!NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
PrintToDebugger("RPC : NtAcceptConnectPort : %lx\n", NtStatus);
|
|||
|
|
|||
|
// if the client thread dies for whatever reason, NtAcceptConnectPort
|
|||
|
// can return STATUS_REPLY_MESSAGE_MISMATCH
|
|||
|
VALIDATE(NtStatus)
|
|||
|
{
|
|||
|
STATUS_INVALID_CID,
|
|||
|
STATUS_REPLY_MESSAGE_MISMATCH
|
|||
|
} END_VALIDATE;
|
|||
|
}
|
|||
|
#endif // DBG
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
LRPC_ADDRESS::EnumerateAndCallEachAssociation (
|
|||
|
IN AssociationCallbackType asctType,
|
|||
|
IN OUT void *Context OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name: EnumerateAndCallEachAssociation
|
|||
|
|
|||
|
Parameters:
|
|||
|
asctType - type of callback to make
|
|||
|
Context - opaque memory block specific for the callback
|
|||
|
type.
|
|||
|
|
|||
|
Description:
|
|||
|
Common infrastructure for calling into each association
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LRPC_SASSOCIATION *CurrentAssociation;
|
|||
|
BOOL CopyOfDictionaryUsed;
|
|||
|
LRPC_SASSOCIATION_DICT AssocDictCopy;
|
|||
|
LRPC_SASSOCIATION_DICT *AssocDictToUse;
|
|||
|
BOOL Res;
|
|||
|
DictionaryCursor cursor;
|
|||
|
DestroyContextHandleCallbackContext *CallbackContext;
|
|||
|
|
|||
|
AddressMutex.Request();
|
|||
|
|
|||
|
CopyOfDictionaryUsed = AssocDictCopy.ExpandToSize(AssociationDictionary.Size());
|
|||
|
if (CopyOfDictionaryUsed)
|
|||
|
{
|
|||
|
AssociationDictionary.Reset(cursor);
|
|||
|
while ( (CurrentAssociation = AssociationDictionary.Next(cursor)) != 0 )
|
|||
|
{
|
|||
|
Res = AssocDictCopy.Insert(CurrentAssociation);
|
|||
|
ASSERT(Res != -1);
|
|||
|
// artifically add a count to keep it alive
|
|||
|
// while we destroy the contexts
|
|||
|
CurrentAssociation->AssociationReferenceCount++;
|
|||
|
}
|
|||
|
|
|||
|
AddressMutex.Clear();
|
|||
|
|
|||
|
AssocDictToUse = &AssocDictCopy;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
AssocDictToUse = &AssociationDictionary;
|
|||
|
}
|
|||
|
|
|||
|
AssocDictToUse->Reset(cursor);
|
|||
|
while ( (CurrentAssociation = AssocDictToUse->Next(cursor)) != 0 )
|
|||
|
{
|
|||
|
switch (asctType)
|
|||
|
{
|
|||
|
case asctDestroyContextHandle:
|
|||
|
CallbackContext = (DestroyContextHandleCallbackContext *)Context;
|
|||
|
|
|||
|
// call into the association to destroy the context handles
|
|||
|
CurrentAssociation->DestroyContextHandlesForInterface(
|
|||
|
CallbackContext->RpcInterfaceInformation,
|
|||
|
CallbackContext->RundownContextHandles);
|
|||
|
break;
|
|||
|
|
|||
|
case asctCleanupIdleSContext:
|
|||
|
CurrentAssociation->CleanupIdleSContexts();
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
ASSERT(0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (CopyOfDictionaryUsed)
|
|||
|
{
|
|||
|
while ( (CurrentAssociation = AssocDictCopy.Next(cursor)) != 0 )
|
|||
|
{
|
|||
|
// remove the extra refcounts
|
|||
|
DereferenceAssociation(CurrentAssociation);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
AddressMutex.Clear();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
LRPC_ADDRESS::DestroyContextHandlesForInterface (
|
|||
|
IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
|
|||
|
IN BOOL RundownContextHandles
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name: DestroyContextHandlesForInterface
|
|||
|
|
|||
|
Parameters:
|
|||
|
RpcInterfaceInformation - the interface for which context handles
|
|||
|
are to be unregistered
|
|||
|
RundownContextHandles - if non-zero, rundown the context handles. If
|
|||
|
FALSE, destroy the runtime portion of the context handle resource,
|
|||
|
but don't call the user rundown routine.
|
|||
|
|
|||
|
Description:
|
|||
|
The implementation for context handle destruction for the local RPC
|
|||
|
(LRPC). Using the callback infrastructure it will walk the list of
|
|||
|
associations, and for each one it will ask the association to
|
|||
|
destroy the context handles for that interface.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DestroyContextHandleCallbackContext CallbackContext;
|
|||
|
|
|||
|
CallbackContext.RpcInterfaceInformation = RpcInterfaceInformation;
|
|||
|
CallbackContext.RundownContextHandles = RundownContextHandles;
|
|||
|
|
|||
|
EnumerateAndCallEachAssociation(asctDestroyContextHandle,
|
|||
|
&CallbackContext);
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
LRPC_ADDRESS::CleanupIdleSContexts (
|
|||
|
void
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name: CleanupIdleSContexts
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
Description:
|
|||
|
The implementation for idle SContext cleanup for the local RPC
|
|||
|
(LRPC). Using the callback infrastructure it will walk the list of
|
|||
|
associations, and for each one it will ask the association to
|
|||
|
destroy the idle scontexts
|
|||
|
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LogEvent(SU_GC, EV_PRUNE, this, 0, 0, 0, 0);
|
|||
|
|
|||
|
EnumerateAndCallEachAssociation(asctCleanupIdleSContext,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
LRPC_ADDRESS::PrepareForLoopbackTickling (
|
|||
|
void
|
|||
|
)
|
|||
|
{
|
|||
|
RPC_CHAR * LpcPortName;
|
|||
|
int DirectoryNameLength;
|
|||
|
int EndpointLength;
|
|||
|
|
|||
|
LrpcMutexVerifyOwned();
|
|||
|
|
|||
|
DirectoryNameLength = RpcpStringLength(LRPC_DIRECTORY_NAME);
|
|||
|
EndpointLength = RpcpStringLength(InqEndpoint());
|
|||
|
|
|||
|
LpcPortName = new RPC_CHAR[
|
|||
|
EndpointLength
|
|||
|
+ DirectoryNameLength + 1];
|
|||
|
if (LpcPortName == 0)
|
|||
|
{
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
TickleMessage = new LRPC_BIND_EXCHANGE;
|
|||
|
if (TickleMessage == NULL)
|
|||
|
{
|
|||
|
delete LpcPortName;
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
RpcpMemoryCopy(LpcPortName, LRPC_DIRECTORY_NAME,
|
|||
|
DirectoryNameLength * sizeof(RPC_CHAR));
|
|||
|
|
|||
|
RpcpMemoryCopy(LpcPortName + DirectoryNameLength,
|
|||
|
InqEndpoint(),
|
|||
|
(EndpointLength + 1) * sizeof(RPC_CHAR));
|
|||
|
|
|||
|
RtlInitUnicodeString(&ThisAddressLoopbackString, LpcPortName);
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
LRPC_ADDRESS::LoopbackTickle (
|
|||
|
void
|
|||
|
)
|
|||
|
{
|
|||
|
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
|
|||
|
HANDLE LoopbackPort;
|
|||
|
ULONG TickleMessageLength = sizeof(LRPC_BIND_EXCHANGE);
|
|||
|
NTSTATUS NtStatus;
|
|||
|
|
|||
|
ASSERT (IsPreparedForLoopbackTickling());
|
|||
|
|
|||
|
SecurityQualityOfService.EffectiveOnly = FALSE;
|
|||
|
SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
|||
|
SecurityQualityOfService.ImpersonationLevel = SecurityAnonymous;
|
|||
|
SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
|
|||
|
|
|||
|
TickleMessage->ConnectType = LRPC_CONNECT_TICKLE ;
|
|||
|
// TickleMessage->AssocKey = Key;
|
|||
|
TickleMessage->Flags = 0;
|
|||
|
|
|||
|
NtStatus = NtConnectPort(
|
|||
|
&LoopbackPort,
|
|||
|
&ThisAddressLoopbackString,
|
|||
|
&SecurityQualityOfService,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
TickleMessage,
|
|||
|
&TickleMessageLength);
|
|||
|
|
|||
|
if (NtStatus == STATUS_PORT_CONNECTION_REFUSED)
|
|||
|
return TRUE;
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT(NtStatus != RPC_S_OK);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LRPC_SASSOCIATION::LRPC_SASSOCIATION (
|
|||
|
IN LRPC_ADDRESS * Address,
|
|||
|
IN RPC_STATUS *Status
|
|||
|
) : AssociationMutex(Status)
|
|||
|
/*++
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ObjectType = LRPC_SASSOCIATION_TYPE;
|
|||
|
LpcServerPort = 0;
|
|||
|
LpcReplyPort = 0 ;
|
|||
|
this->Address = Address;
|
|||
|
AssociationReferenceCount = 1;
|
|||
|
Aborted = 0 ;
|
|||
|
Deleted = -1 ;
|
|||
|
|
|||
|
if (*Status == RPC_S_OK)
|
|||
|
{
|
|||
|
CachedSCall = new LRPC_SCALL(Status);
|
|||
|
if (CachedSCall == 0)
|
|||
|
{
|
|||
|
*Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CachedSCall = NULL;
|
|||
|
}
|
|||
|
|
|||
|
CachedSCallAvailable = 0;
|
|||
|
fFirstCall = 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LRPC_SASSOCIATION::~LRPC_SASSOCIATION (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We will call this routine when the client has notified us that this port
|
|||
|
has closed, and there are no calls outstanding on it.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PVOID Buffer;
|
|||
|
LRPC_SBINDING * Binding;
|
|||
|
LRPC_SCALL *SCall ;
|
|||
|
unsigned int Length ;
|
|||
|
LRPC_SCONTEXT *SContext;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
while (SCall = (LRPC_SCALL *) FreeSCallQueue.TakeOffQueue(&Length))
|
|||
|
{
|
|||
|
delete SCall;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Bindings.Reset(cursor);
|
|||
|
while ((Binding = Bindings.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
delete Binding;
|
|||
|
}
|
|||
|
|
|||
|
if (CachedSCall)
|
|||
|
{
|
|||
|
delete CachedSCall;
|
|||
|
}
|
|||
|
|
|||
|
SContextDict.Reset(cursor);
|
|||
|
while ((SContext = SContextDict.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
delete SContext;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SASSOCIATION::AllocateSCall (
|
|||
|
IN LRPC_MESSAGE * LrpcMessage,
|
|||
|
IN LRPC_MESSAGE * LrpcReplyMessage,
|
|||
|
IN unsigned int Flags,
|
|||
|
IN LRPC_SCALL **SCall
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Allocate an SCall
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LrpcMessage - Request message
|
|||
|
LrpcReplyMessage - Reply message
|
|||
|
Flags - Request flags
|
|||
|
|
|||
|
Return Value:
|
|||
|
Pointer to the SCall
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
unsigned int Length ;
|
|||
|
RPC_STATUS Status ;
|
|||
|
LRPC_SCALL *NewSCall;
|
|||
|
|
|||
|
*SCall = NULL;
|
|||
|
|
|||
|
if (InterlockedIncrement(&CachedSCallAvailable) == 1)
|
|||
|
{
|
|||
|
NewSCall = CachedSCall;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
AssociationMutex.Request() ;
|
|||
|
NewSCall = (LRPC_SCALL *) FreeSCallQueue.TakeOffQueue(&Length) ;
|
|||
|
AssociationMutex.Clear() ;
|
|||
|
|
|||
|
if (NewSCall == 0)
|
|||
|
{
|
|||
|
NewSCall = new LRPC_SCALL(&Status) ;
|
|||
|
if (NewSCall == 0)
|
|||
|
{
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
delete NewSCall;
|
|||
|
return Status;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Status = NewSCall->ActivateCall(this,
|
|||
|
LrpcMessage,
|
|||
|
LrpcReplyMessage,
|
|||
|
Flags) ;
|
|||
|
|
|||
|
|
|||
|
if ((Flags & LRPC_BUFFER_PARTIAL)
|
|||
|
|| NewSCall->IsClientAsync())
|
|||
|
{
|
|||
|
Status = NewSCall->SetupCall() ;
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
if (NewSCall != CachedSCall)
|
|||
|
{
|
|||
|
delete NewSCall ;
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_OUT_OF_MEMORY ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LogEvent(SU_SCALL, EV_CREATE, NewSCall, 0, Flags, 1);
|
|||
|
|
|||
|
*SCall = NewSCall;
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
LRPC_SASSOCIATION::FreeSCall (
|
|||
|
IN LRPC_SCALL *SCall
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Free the SCall
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SCall - Pointer to the SCall object
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ASSERT(SCall->pAsync != (PRPC_ASYNC_STATE) -1);
|
|||
|
|
|||
|
if (SCall->pAsync)
|
|||
|
{
|
|||
|
SCall->DoPostDispatchProcessing();
|
|||
|
}
|
|||
|
|
|||
|
if (SCall->SBinding
|
|||
|
&& SCall->SBinding->RpcInterface->IsAutoListenInterface())
|
|||
|
{
|
|||
|
SCall->SBinding->RpcInterface->EndAutoListenCall() ;
|
|||
|
}
|
|||
|
|
|||
|
if (SCall->ReceiveEvent)
|
|||
|
{
|
|||
|
AssociationMutex.Request() ;
|
|||
|
SCallDict.Delete(ULongToPtr(SCall->CallId));
|
|||
|
AssociationMutex.Clear() ;
|
|||
|
}
|
|||
|
|
|||
|
LogEvent(SU_SCALL, EV_DELETE, SCall, SCall->pAsync, SCall->Flags, 1);
|
|||
|
|
|||
|
SCall->pAsync = (PRPC_ASYNC_STATE) -1;
|
|||
|
if (SCall->SContext)
|
|||
|
{
|
|||
|
SCall->SContext->RemoveReference();
|
|||
|
}
|
|||
|
|
|||
|
if (SCall->ClientPrincipalName != NULL)
|
|||
|
{
|
|||
|
delete SCall->ClientPrincipalName;
|
|||
|
SCall->ClientPrincipalName = NULL;
|
|||
|
}
|
|||
|
|
|||
|
SCall->DeactivateCall();
|
|||
|
if (SCall == CachedSCall)
|
|||
|
{
|
|||
|
CachedSCallAvailable = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
AssociationMutex.Request() ;
|
|||
|
SCall->pAsync = (PRPC_ASYNC_STATE) -1;
|
|||
|
if (FreeSCallQueue.PutOnQueue(SCall, 0))
|
|||
|
delete SCall ;
|
|||
|
AssociationMutex.Clear() ;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
LRPC_SASSOCIATION::MaybeQueueSCall (
|
|||
|
IN LRPC_SCALL *SCall
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
if the thread is currently executing a call, the call
|
|||
|
is queued up, otherwise it is signalled to be dispatched.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SCall - the SCall to be dispatched.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
0: dispatch the call
|
|||
|
1: don't dispatch the call
|
|||
|
-1: error
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
LRPC_SCALL *FirstSCall ;
|
|||
|
int Status ;
|
|||
|
|
|||
|
AssociationMutex.Request() ;
|
|||
|
|
|||
|
FirstSCall = ClientThreadDict.Find(
|
|||
|
MsgClientIdToClientId(SCall->LrpcRequestMessage->Rpc.LpcHeader.ClientId).UniqueThread) ;
|
|||
|
|
|||
|
if (FirstSCall == 0)
|
|||
|
{
|
|||
|
Status = ClientThreadDict.Insert(
|
|||
|
MsgClientIdToClientId(SCall->LrpcRequestMessage->Rpc.LpcHeader.ClientId).UniqueThread,
|
|||
|
SCall) ;
|
|||
|
|
|||
|
SCall->LastSCall = SCall ;
|
|||
|
|
|||
|
AssociationMutex.Clear() ;
|
|||
|
|
|||
|
VALIDATE(Status)
|
|||
|
{
|
|||
|
0,
|
|||
|
-1
|
|||
|
} END_VALIDATE;
|
|||
|
|
|||
|
return Status ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ASSERT(FirstSCall->LastSCall);
|
|||
|
|
|||
|
FirstSCall->LastSCall->NextSCall = SCall ;
|
|||
|
FirstSCall->LastSCall = SCall ;
|
|||
|
|
|||
|
AssociationMutex.Clear() ;
|
|||
|
|
|||
|
return 1 ;
|
|||
|
}
|
|||
|
|
|||
|
LRPC_SCALL *
|
|||
|
LRPC_SASSOCIATION::GetNextSCall (
|
|||
|
IN LRPC_SCALL *SCall
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
description
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SCall - description
|
|||
|
|
|||
|
Return Value:
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
LRPC_SCALL *NextSCall ;
|
|||
|
|
|||
|
ASSERT(SCall) ;
|
|||
|
|
|||
|
AssociationMutex.Request() ;
|
|||
|
NextSCall = SCall->NextSCall ;
|
|||
|
if (NextSCall != 0)
|
|||
|
{
|
|||
|
ASSERT(SCall->LastSCall);
|
|||
|
|
|||
|
NextSCall->LastSCall = SCall->LastSCall ;
|
|||
|
ClientThreadDict.Update (
|
|||
|
MsgClientIdToClientId(SCall->LrpcRequestMessage->Rpc.LpcHeader.ClientId).UniqueThread,
|
|||
|
NextSCall) ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ClientThreadDict.Delete (
|
|||
|
MsgClientIdToClientId(SCall->LrpcRequestMessage->Rpc.LpcHeader.ClientId).UniqueThread) ;
|
|||
|
}
|
|||
|
AssociationMutex.Clear() ;
|
|||
|
|
|||
|
return NextSCall ;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
LRPC_SASSOCIATION::Delete(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
description
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
arg1 - description
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Function succeeded
|
|||
|
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
LRPC_SCALL *SCall ;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
if (InterlockedIncrement(&Deleted) == 0)
|
|||
|
{
|
|||
|
AssociationMutex.Request() ;
|
|||
|
SCallDict.Reset(cursor) ;
|
|||
|
while ((SCall = SCallDict.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
SCall->Deleted = 1;
|
|||
|
if (SCall->ReceiveEvent)
|
|||
|
{
|
|||
|
SCall->ReceiveEvent->Raise();
|
|||
|
}
|
|||
|
}
|
|||
|
AssociationMutex.Clear() ;
|
|||
|
|
|||
|
LogEvent(SU_SASSOC, EV_DELETE,
|
|||
|
this, 0, AssociationReferenceCount, 1, 1);
|
|||
|
|
|||
|
Address->DereferenceAssociation(this);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SASSOCIATION::BindBack (
|
|||
|
IN RPC_CHAR *Endpoint,
|
|||
|
IN DWORD AssocKey
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Create a back connection to the client.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LrpcThread - LrpcThread to connect to.
|
|||
|
pAssoc - Pointer to client association.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Function succeeded
|
|||
|
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
|
|||
|
RPC_CHAR * LpcPortName ;
|
|||
|
UNICODE_STRING unicodePortName;
|
|||
|
LRPC_BIND_EXCHANGE BindExchange;
|
|||
|
unsigned long BindExchangeLength = sizeof(LRPC_BIND_EXCHANGE);
|
|||
|
|
|||
|
LpcPortName = new RPC_CHAR[RpcpStringLength(Endpoint)
|
|||
|
+ RpcpStringLength(LRPC_DIRECTORY_NAME) + 1];
|
|||
|
|
|||
|
if (LpcPortName == 0)
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("LRPC: Out of memory in DealWithNewClient\n") ;
|
|||
|
#endif
|
|||
|
return RPC_S_OUT_OF_MEMORY ;
|
|||
|
}
|
|||
|
|
|||
|
RpcpMemoryCopy(LpcPortName,
|
|||
|
LRPC_DIRECTORY_NAME,
|
|||
|
RpcpStringLength(LRPC_DIRECTORY_NAME) * sizeof(RPC_CHAR));
|
|||
|
|
|||
|
RpcpMemoryCopy(LpcPortName + RpcpStringLength(LRPC_DIRECTORY_NAME),
|
|||
|
Endpoint,
|
|||
|
(RpcpStringLength(Endpoint) + 1) * sizeof(RPC_CHAR));
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodePortName, LpcPortName);
|
|||
|
|
|||
|
// Hack Hack, where do I get the real QOS values from ??
|
|||
|
SecurityQualityOfService.EffectiveOnly = TRUE;
|
|||
|
SecurityQualityOfService.ContextTrackingMode = SECURITY_STATIC_TRACKING;
|
|||
|
SecurityQualityOfService.ImpersonationLevel = SecurityAnonymous;
|
|||
|
|
|||
|
SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
|
|||
|
|
|||
|
|
|||
|
BindExchange.ConnectType = LRPC_CONNECT_RESPONSE ;
|
|||
|
BindExchange.AssocKey = AssocKey ;
|
|||
|
|
|||
|
NtStatus = NtConnectPort(&LpcReplyPort,
|
|||
|
&unicodePortName,
|
|||
|
&SecurityQualityOfService,
|
|||
|
0,
|
|||
|
0,
|
|||
|
0,
|
|||
|
&BindExchange,
|
|||
|
&BindExchangeLength);
|
|||
|
|
|||
|
delete LpcPortName ;
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("LRPC: NtConnectPort : %lx\n", NtStatus);
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
return RPC_S_OUT_OF_MEMORY ;
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_OK ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LRPC_MESSAGE *
|
|||
|
LRPC_SASSOCIATION::DealWithBindBackMessage (
|
|||
|
IN LRPC_MESSAGE *BindBackMessage
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Used in conjuction with Async RPC. This function
|
|||
|
creates a back connection to the client so that two asynchronous
|
|||
|
flow of data can occur.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BindBackMessage - The message receive from the client
|
|||
|
|
|||
|
Return Value:
|
|||
|
reply message.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
RPC_STATUS Status ;
|
|||
|
|
|||
|
BindBackMessage->BindBack.szPortName[PORT_NAME_LEN-1] = NULL;
|
|||
|
|
|||
|
Status = BindBack((RPC_CHAR *) BindBackMessage->BindBack.szPortName,
|
|||
|
BindBackMessage->BindBack.AssocKey) ;
|
|||
|
|
|||
|
BindBackMessage->Ack.MessageType = LRPC_MSG_ACK ;
|
|||
|
BindBackMessage->Ack.RpcStatus = Status ;
|
|||
|
BindBackMessage->LpcHeader.u1.s1.DataLength =
|
|||
|
sizeof(LRPC_BIND_MESSAGE) - sizeof(PORT_MESSAGE);
|
|||
|
BindBackMessage->LpcHeader.u1.s1.TotalLength =
|
|||
|
sizeof(LRPC_BIND_MESSAGE);
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
Delete() ;
|
|||
|
}
|
|||
|
|
|||
|
return BindBackMessage ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SASSOCIATION::AddBinding (
|
|||
|
IN OUT LRPC_BIND_EXCHANGE * BindExchange
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We will attempt to add a new binding to this association.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BindExchange - Supplies a description of the interface to which the
|
|||
|
client wish to bind.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status;
|
|||
|
RPC_SYNTAX_IDENTIFIER TransferSyntax;
|
|||
|
RPC_INTERFACE * RpcInterface;
|
|||
|
LRPC_SBINDING * Binding;
|
|||
|
BOOL fIgnored;
|
|||
|
int DictKey;
|
|||
|
RPC_SYNTAX_IDENTIFIER ProposedSyntaxes[MaximumNumberOfTransferSyntaxes];
|
|||
|
int PresentationContexts[MaximumNumberOfTransferSyntaxes];
|
|||
|
int TransferSyntaxFlagSettings[MaximumNumberOfTransferSyntaxes];
|
|||
|
int NextProposedSyntax;
|
|||
|
int ChosenProposedTransferSyntax;
|
|||
|
int ChosenAvailableTransferSyntax;
|
|||
|
|
|||
|
NextProposedSyntax = 0;
|
|||
|
if (BindExchange->TransferSyntaxSet & TS_NDR20_FLAG)
|
|||
|
{
|
|||
|
RpcpMemoryCopy(&ProposedSyntaxes[NextProposedSyntax],
|
|||
|
NDR20TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER));
|
|||
|
PresentationContexts[NextProposedSyntax] = (int)BindExchange->PresentationContext[0];
|
|||
|
TransferSyntaxFlagSettings[NextProposedSyntax] = TS_NDR20_FLAG;
|
|||
|
NextProposedSyntax ++;
|
|||
|
}
|
|||
|
|
|||
|
if (BindExchange->TransferSyntaxSet & TS_NDR64_FLAG)
|
|||
|
{
|
|||
|
RpcpMemoryCopy(&ProposedSyntaxes[NextProposedSyntax],
|
|||
|
NDR64TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER));
|
|||
|
PresentationContexts[NextProposedSyntax] = (int)BindExchange->PresentationContext[1];
|
|||
|
TransferSyntaxFlagSettings[NextProposedSyntax] = TS_NDR64_FLAG;
|
|||
|
NextProposedSyntax ++;
|
|||
|
}
|
|||
|
|
|||
|
if (BindExchange->TransferSyntaxSet & TS_NDRTEST_FLAG)
|
|||
|
{
|
|||
|
RpcpMemoryCopy(&ProposedSyntaxes[NextProposedSyntax],
|
|||
|
NDRTestTransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER));
|
|||
|
PresentationContexts[NextProposedSyntax] = (int)BindExchange->PresentationContext[2];
|
|||
|
TransferSyntaxFlagSettings[NextProposedSyntax] = TS_NDRTEST_FLAG;
|
|||
|
NextProposedSyntax ++;
|
|||
|
}
|
|||
|
|
|||
|
if (NextProposedSyntax == 0)
|
|||
|
{
|
|||
|
// no syntaxes proposed - protocol error
|
|||
|
ASSERT(0);
|
|||
|
return RPC_S_PROTOCOL_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(NextProposedSyntax <= MaximumNumberOfTransferSyntaxes);
|
|||
|
|
|||
|
Status = Address->FindInterfaceTransfer(&(BindExchange->InterfaceId),
|
|||
|
ProposedSyntaxes,
|
|||
|
NextProposedSyntax,
|
|||
|
&TransferSyntax,
|
|||
|
&RpcInterface,
|
|||
|
&fIgnored,
|
|||
|
&ChosenProposedTransferSyntax,
|
|||
|
&ChosenAvailableTransferSyntax);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
ASSERT (ChosenProposedTransferSyntax < NextProposedSyntax);
|
|||
|
|
|||
|
Binding = new LRPC_SBINDING(RpcInterface,
|
|||
|
ChosenAvailableTransferSyntax);
|
|||
|
if (Binding == 0)
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
Binding->SetPresentationContext(PresentationContexts[ChosenProposedTransferSyntax]);
|
|||
|
DictKey = (unsigned char) Bindings.Insert(Binding);
|
|||
|
if (DictKey == -1)
|
|||
|
{
|
|||
|
delete Binding;
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
BindExchange->TransferSyntaxSet = TransferSyntaxFlagSettings[ChosenProposedTransferSyntax];
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SASSOCIATION::SaveToken (
|
|||
|
IN LRPC_MESSAGE *LrpcMessage,
|
|||
|
OUT HANDLE *pTokenHandle,
|
|||
|
IN BOOL fRestoreToken
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Impersonate the client and save away the token.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LrpcMessage - request message
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Function succeeded
|
|||
|
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS NtStatus ;
|
|||
|
HANDLE ImpersonationToken = 0;
|
|||
|
RPC_STATUS Status;
|
|||
|
|
|||
|
if (fRestoreToken)
|
|||
|
{
|
|||
|
//
|
|||
|
// Save away the old token
|
|||
|
//
|
|||
|
if (OpenThreadToken (GetCurrentThread(),
|
|||
|
TOKEN_IMPERSONATE | TOKEN_QUERY,
|
|||
|
TRUE,
|
|||
|
&ImpersonationToken) == FALSE)
|
|||
|
{
|
|||
|
ImpersonationToken = 0;
|
|||
|
#if DBG
|
|||
|
if (GetLastError() != ERROR_NO_TOKEN)
|
|||
|
{
|
|||
|
PrintToDebugger("LRPC: OpenThreadToken failed %d\n", GetLastError());
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NtStatus = NtImpersonateClientOfPort(LpcServerPort,
|
|||
|
(PORT_MESSAGE *) LrpcMessage);
|
|||
|
|
|||
|
if (NT_ERROR(NtStatus))
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("LRPC: NtImpersonateClientOfPort failed: 0x%lX\n",
|
|||
|
NtStatus) ;
|
|||
|
#endif
|
|||
|
|
|||
|
return RPC_S_INVALID_AUTH_IDENTITY ;
|
|||
|
}
|
|||
|
|
|||
|
Status = RPC_S_OK;
|
|||
|
|
|||
|
if (OpenThreadToken (GetCurrentThread(),
|
|||
|
TOKEN_IMPERSONATE | TOKEN_QUERY,
|
|||
|
TRUE,
|
|||
|
pTokenHandle) == FALSE)
|
|||
|
{
|
|||
|
*pTokenHandle = 0;
|
|||
|
|
|||
|
if (GetLastError() == ERROR_CANT_OPEN_ANONYMOUS)
|
|||
|
{
|
|||
|
Status = ERROR_CANT_OPEN_ANONYMOUS;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("LRPC: OpenThreadToken failed\n") ;
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (fRestoreToken)
|
|||
|
{
|
|||
|
//
|
|||
|
// Restore the token
|
|||
|
//
|
|||
|
NtStatus = NtSetInformationThread(NtCurrentThread(),
|
|||
|
ThreadImpersonationToken,
|
|||
|
&ImpersonationToken,
|
|||
|
sizeof(HANDLE));
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (!NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
PrintToDebugger("RPC : NtSetInformationThread : %lx\n", NtStatus);
|
|||
|
}
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
if (ImpersonationToken)
|
|||
|
{
|
|||
|
CloseHandle(ImpersonationToken);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SASSOCIATION::GetClientName (
|
|||
|
IN LRPC_SCALL *SCall,
|
|||
|
IN OUT ULONG *ClientPrincipalNameBufferLength OPTIONAL, // in bytes
|
|||
|
OUT RPC_CHAR **ClientPrincipalName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Gets the client name for the given scall
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SCall - the SCall for which to get the client name
|
|||
|
ClientPrincipalNameBufferLength - if present, *ClientPrincipalName must
|
|||
|
point to a caller supplied buffer, which if big enough,
|
|||
|
will be filled with the client principal name. If not present,
|
|||
|
*ClientPrincipalName must be NULL.
|
|||
|
ClientPrincipalName - see ClientPrincipalNameBufferLength
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK for success, or RPC_S_* / Win32 error code for error.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
BOOL Result;
|
|||
|
unsigned long Size;
|
|||
|
HANDLE TokenHandle = 0;
|
|||
|
LRPC_SCONTEXT *SContext = 0;
|
|||
|
TOKEN_STATISTICS TokenStatisticsInformation;
|
|||
|
DictionaryCursor cursor;
|
|||
|
BOOL fAnonymous;
|
|||
|
BOOL fMutexHeld = FALSE;
|
|||
|
BOOL fAssociationSContextUsed = FALSE;
|
|||
|
RPC_CHAR *CurrentUserName;
|
|||
|
ULONG CurrentUserNameLength;
|
|||
|
|
|||
|
if (SCall->SContext == NULL)
|
|||
|
{
|
|||
|
// take the lock opportunistically
|
|||
|
AssociationMutex.Request();
|
|||
|
|
|||
|
fMutexHeld = TRUE;
|
|||
|
|
|||
|
if (SCall->SContext == NULL)
|
|||
|
{
|
|||
|
Status = SaveToken(
|
|||
|
SCall->LrpcRequestMessage,
|
|||
|
&TokenHandle, 1);
|
|||
|
if ((Status != RPC_S_OK) && (Status != ERROR_CANT_OPEN_ANONYMOUS))
|
|||
|
{
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
if (Status == RPC_S_OK)
|
|||
|
{
|
|||
|
Result = GetTokenInformation(
|
|||
|
TokenHandle,
|
|||
|
TokenStatistics,
|
|||
|
&TokenStatisticsInformation,
|
|||
|
sizeof(TokenStatisticsInformation),
|
|||
|
&Size
|
|||
|
);
|
|||
|
if (Result != TRUE)
|
|||
|
{
|
|||
|
Status = RPC_S_INVALID_AUTH_IDENTITY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
fAnonymous = FALSE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT(Status == ERROR_CANT_OPEN_ANONYMOUS);
|
|||
|
fAnonymous = TRUE;
|
|||
|
TokenHandle = 0;
|
|||
|
}
|
|||
|
|
|||
|
SContextDict.Reset(cursor);
|
|||
|
while ((SContext = SContextDict.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
// if either input and found are anonymous, or the modified
|
|||
|
// ids match, we have found it
|
|||
|
if ((fAnonymous && SContext->GetAnonymousFlag())
|
|||
|
||
|
|||
|
FastCompareLUIDAligned(&SContext->ClientLuid,
|
|||
|
&TokenStatisticsInformation.ModifiedId))
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (SContext == 0)
|
|||
|
{
|
|||
|
SContext = new LRPC_SCONTEXT(NULL,
|
|||
|
fAnonymous ? NULL : ((LUID *) &TokenStatisticsInformation.ModifiedId),
|
|||
|
this,
|
|||
|
FALSE, // fDefaultLogonId
|
|||
|
fAnonymous
|
|||
|
);
|
|||
|
if (SContext == 0)
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
if (SContextDict.Insert(SContext) == -1)
|
|||
|
{
|
|||
|
delete SContext;
|
|||
|
Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
// mark the context as server side only
|
|||
|
SContext->SetServerSideOnlyFlag();
|
|||
|
|
|||
|
// record that we have used this recently to prevent it from being
|
|||
|
// garbage collected
|
|||
|
SContext->UpdateLastAccessTime();
|
|||
|
|
|||
|
EnableIdleLrpcSContextsCleanup();
|
|||
|
|
|||
|
// tell the garbage collector that we have something to be
|
|||
|
// collected
|
|||
|
GarbageCollectionNeeded(FALSE, // fOneTimeCleanup
|
|||
|
LRPC_SCONTEXT::CONTEXT_IDLE_TIMEOUT);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// record that we have used this recently to prevent it from being
|
|||
|
// garbage collected
|
|||
|
SContext->UpdateLastAccessTime();
|
|||
|
}
|
|||
|
|
|||
|
// we have taken or created the current SContext in the association
|
|||
|
// we need to prevent the garbage collection thread from destroying
|
|||
|
// it underneath us. We add one refcount for the purpose and record
|
|||
|
// this
|
|||
|
SContext->AddReference();
|
|||
|
|
|||
|
fAssociationSContextUsed = TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
SContext = SCall->SContext;
|
|||
|
|
|||
|
// record that we have used this recently to prevent it from being
|
|||
|
// garbage collected
|
|||
|
SContext->UpdateLastAccessTime();
|
|||
|
}
|
|||
|
AssociationMutex.Clear() ;
|
|||
|
fMutexHeld = FALSE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
SContext = SCall->SContext;
|
|||
|
|
|||
|
// record that we have used this recently to prevent it from being
|
|||
|
// garbage collected
|
|||
|
SContext->UpdateLastAccessTime();
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(SContext);
|
|||
|
|
|||
|
// if we go through the path where the token is retrieved from
|
|||
|
// the SContext, passing NULL TokenHandle to get user name is Ok
|
|||
|
// as it will retrieve the token from the SContext
|
|||
|
Status = SContext->GetUserName(ClientPrincipalNameBufferLength, ClientPrincipalName, TokenHandle);
|
|||
|
|
|||
|
// If ARGUMENT_PRESENT(ClientPrincipalNameBufferLength), Status may be
|
|||
|
// ERROR_MORE_DATA, which is a success error code.
|
|||
|
|
|||
|
if (fAssociationSContextUsed)
|
|||
|
{
|
|||
|
if ((Status == RPC_S_OK)
|
|||
|
&& (!ARGUMENT_PRESENT(ClientPrincipalNameBufferLength)))
|
|||
|
{
|
|||
|
// we weren't supplied a user buffer. Copy the principal
|
|||
|
// name to a call variable to avoid the garbage collector
|
|||
|
// collecting this under the feet of our caller. Then
|
|||
|
// we can release the refcount
|
|||
|
if (SCall->ClientPrincipalName == NULL)
|
|||
|
{
|
|||
|
CurrentUserNameLength = (RpcpStringLength(*ClientPrincipalName) + 1) * sizeof(RPC_CHAR);
|
|||
|
// CurrentUserNameLength is in bytes. Allocate chars for it and cast it back
|
|||
|
CurrentUserName = (RPC_CHAR *) new char [CurrentUserNameLength];
|
|||
|
if (CurrentUserName != NULL)
|
|||
|
{
|
|||
|
RpcpMemoryCopy(CurrentUserName,
|
|||
|
*ClientPrincipalName,
|
|||
|
CurrentUserNameLength);
|
|||
|
SCall->ClientPrincipalName = CurrentUserName;
|
|||
|
*ClientPrincipalName = CurrentUserName;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
// fall through in cleanup path
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
*ClientPrincipalName = SCall->ClientPrincipalName;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// succeeded or not, drop the refcount
|
|||
|
SContext->RemoveReference();
|
|||
|
}
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
// N.B. failure of this function doesn't mean we have
|
|||
|
// to delete a newly created scontext. scontexts without
|
|||
|
// names are perfectly valid, and since we know the only
|
|||
|
// missing part from this scontext is the name, we can
|
|||
|
// leave it alone, return failure, and attempt to get the
|
|||
|
// name next time
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
Cleanup:
|
|||
|
|
|||
|
if (fMutexHeld)
|
|||
|
{
|
|||
|
AssociationMutex.Clear() ;
|
|||
|
}
|
|||
|
|
|||
|
if (TokenHandle)
|
|||
|
{
|
|||
|
CloseHandle(TokenHandle);
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
#if defined(_WIN64)
|
|||
|
C_ASSERT((FIELD_OFFSET(TOKEN_STATISTICS, ModifiedId) % 8) == 0);
|
|||
|
C_ASSERT((FIELD_OFFSET(LRPC_SCONTEXT, ClientLuid) % 8) == 0);
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
LRPC_SASSOCIATION::DealWithBindMessage (
|
|||
|
IN LRPC_MESSAGE * LrpcMessage
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
LRPC_ADDRESS::ReceiveLotsaCalls will call this routine when the client
|
|||
|
sends a bind message. We need to process the bind message, and send
|
|||
|
a response to the client.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LrpcMessage - Supplies the bind message. We will also use this to send
|
|||
|
the response.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The reply message to be sent to the client will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
NTSTATUS NtStatus ;
|
|||
|
HANDLE ImpersonationToken = 0;
|
|||
|
HANDLE TokenHandle;
|
|||
|
unsigned long Size;
|
|||
|
BOOL Result;
|
|||
|
LRPC_SCONTEXT *SContext;
|
|||
|
ULONG SecurityContextId = -1;
|
|||
|
DictionaryCursor cursor;
|
|||
|
BOOL fBindDefaultLogonId;
|
|||
|
BOOL fAnonymous;
|
|||
|
|
|||
|
if (LrpcMessage->Bind.BindExchange.Flags & NEW_SECURITY_CONTEXT_FLAG)
|
|||
|
{
|
|||
|
TOKEN_STATISTICS TokenStatisticsInformation;
|
|||
|
|
|||
|
//
|
|||
|
// If SaveToken succeeds, as a side-effect, it will
|
|||
|
// fill in the SecurityContextId field of the BindExchange
|
|||
|
//
|
|||
|
Status = SaveToken(
|
|||
|
LrpcMessage,
|
|||
|
&TokenHandle) ;
|
|||
|
|
|||
|
if ((Status != RPC_S_OK) && (Status != ERROR_CANT_OPEN_ANONYMOUS))
|
|||
|
{
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
Status,
|
|||
|
EEInfoDLDealWithBindMessage10);
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
if (TokenHandle || (Status == ERROR_CANT_OPEN_ANONYMOUS))
|
|||
|
{
|
|||
|
if (TokenHandle)
|
|||
|
{
|
|||
|
Result = GetTokenInformation(
|
|||
|
TokenHandle,
|
|||
|
TokenStatistics,
|
|||
|
&TokenStatisticsInformation,
|
|||
|
sizeof(TokenStatisticsInformation),
|
|||
|
&Size
|
|||
|
);
|
|||
|
if (Result != TRUE)
|
|||
|
{
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RPC_S_INVALID_AUTH_IDENTITY,
|
|||
|
EEInfoDLDealWithBindMessage20,
|
|||
|
GetLastError());
|
|||
|
CloseHandle(TokenHandle);
|
|||
|
Status = RPC_S_INVALID_AUTH_IDENTITY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
fAnonymous = FALSE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
fAnonymous = TRUE;
|
|||
|
Status = RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
AssociationMutex.Request();
|
|||
|
|
|||
|
int Key = 0;
|
|||
|
fBindDefaultLogonId =
|
|||
|
(LrpcMessage->Bind.BindExchange.Flags & DEFAULT_LOGONID_FLAG)
|
|||
|
? TRUE : FALSE;
|
|||
|
SContextDict.Reset(cursor);
|
|||
|
while ((SContext = SContextDict.NextWithKey(cursor, &Key)) != 0)
|
|||
|
{
|
|||
|
if ((fAnonymous && SContext->GetAnonymousFlag())
|
|||
|
||
|
|||
|
(FastCompareLUIDAligned(&SContext->ClientLuid,
|
|||
|
&TokenStatisticsInformation.ModifiedId)
|
|||
|
&&
|
|||
|
(SContext->GetDefaultLogonIdFlag() == fBindDefaultLogonId)))
|
|||
|
{
|
|||
|
SecurityContextId = Key;
|
|||
|
SContext->ClearServerSideOnlyFlag();
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (SContext == 0)
|
|||
|
{
|
|||
|
if (fAnonymous)
|
|||
|
{
|
|||
|
SContext = new LRPC_SCONTEXT(TokenHandle,
|
|||
|
(LUID *) NULL,
|
|||
|
this,
|
|||
|
0,
|
|||
|
fAnonymous);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
SContext = new LRPC_SCONTEXT(TokenHandle,
|
|||
|
(LUID *) &TokenStatisticsInformation.ModifiedId,
|
|||
|
this,
|
|||
|
fBindDefaultLogonId,
|
|||
|
0 // fAnonymousToken
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
if (SContext == 0)
|
|||
|
{
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RPC_S_OUT_OF_MEMORY,
|
|||
|
EEInfoDLDealWithBindMessage30,
|
|||
|
sizeof(LRPC_SCONTEXT));
|
|||
|
CloseHandle(TokenHandle);
|
|||
|
Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
AssociationMutex.Clear();
|
|||
|
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
if ((SecurityContextId = SContextDict.Insert(SContext)) == -1)
|
|||
|
{
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RPC_S_OUT_OF_MEMORY,
|
|||
|
EEInfoDLDealWithBindMessage40);
|
|||
|
delete SContext;
|
|||
|
Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
AssociationMutex.Clear();
|
|||
|
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
else if (SContext->hToken == NULL)
|
|||
|
{
|
|||
|
// if the context had no token, add one. This can happen
|
|||
|
// if previous callers for this modified id just queried
|
|||
|
// the user name. In this case, we won't cache the token
|
|||
|
SContext->hToken = TokenHandle;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CloseHandle(TokenHandle);
|
|||
|
}
|
|||
|
|
|||
|
AssociationMutex.Clear();
|
|||
|
}
|
|||
|
|
|||
|
Cleanup:
|
|||
|
//
|
|||
|
// Revert
|
|||
|
//
|
|||
|
NtStatus = NtSetInformationThread(NtCurrentThread(),
|
|||
|
ThreadImpersonationToken,
|
|||
|
&ImpersonationToken,
|
|||
|
sizeof(HANDLE));
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (!NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
PrintToDebugger("RPC : NtSetInformationThread : %lx\n", NtStatus);
|
|||
|
}
|
|||
|
#endif // DBG
|
|||
|
}
|
|||
|
|
|||
|
if (Status == RPC_S_OK
|
|||
|
&& LrpcMessage->Bind.BindExchange.Flags & NEW_PRESENTATION_CONTEXT_FLAG)
|
|||
|
{
|
|||
|
Status = AddBinding(&(LrpcMessage->Bind.BindExchange));
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
Status,
|
|||
|
EEInfoDLDealWithBindMessage50);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LrpcMessage->Bind.BindExchange.RpcStatus = Status ;
|
|||
|
|
|||
|
if (LrpcMessage->Bind.OldSecurityContexts.NumContexts > 0)
|
|||
|
{
|
|||
|
DWORD i;
|
|||
|
LRPC_SCONTEXT *SContext;
|
|||
|
DWORD NumContexts = LrpcMessage->Bind.OldSecurityContexts.NumContexts;
|
|||
|
DWORD CalculatedSize = ((NumContexts-1) * sizeof(DWORD))+sizeof(LRPC_BIND_MESSAGE);
|
|||
|
|
|||
|
if (NumContexts > MAX_LRPC_CONTEXTS
|
|||
|
|| CalculatedSize > (DWORD) LrpcMessage->LpcHeader.u1.s1.TotalLength)
|
|||
|
{
|
|||
|
//
|
|||
|
// Bogus request
|
|||
|
//
|
|||
|
LrpcMessage->Bind.BindExchange.RpcStatus = RPC_S_PROTOCOL_ERROR;
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RPC_S_PROTOCOL_ERROR,
|
|||
|
EEInfoDLDealWithBindMessage60,
|
|||
|
NumContexts,
|
|||
|
CalculatedSize,
|
|||
|
(DWORD) LrpcMessage->LpcHeader.u1.s1.TotalLength);
|
|||
|
goto Reply;
|
|||
|
}
|
|||
|
|
|||
|
AssociationMutex.Request();
|
|||
|
for (i = 0; i < NumContexts; i++)
|
|||
|
{
|
|||
|
SContext = SContextDict.Delete(
|
|||
|
LrpcMessage->Bind.OldSecurityContexts.SecurityContextId[i]);
|
|||
|
if (SContext)
|
|||
|
{
|
|||
|
SContext->Destroy();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT(0);
|
|||
|
}
|
|||
|
}
|
|||
|
AssociationMutex.Clear();
|
|||
|
}
|
|||
|
|
|||
|
Reply:
|
|||
|
// if failure, check out of EEInfo
|
|||
|
if ((LrpcMessage->Bind.BindExchange.RpcStatus != RPC_S_OK) && (g_fSendEEInfo))
|
|||
|
{
|
|||
|
SetBindAckFault(LrpcMessage,
|
|||
|
LrpcMessage->Bind.BindExchange.RpcStatus);
|
|||
|
}
|
|||
|
|
|||
|
LrpcMessage->Bind.MessageType = LRPC_BIND_ACK ;
|
|||
|
LrpcMessage->Bind.BindExchange.SecurityContextId = SecurityContextId;
|
|||
|
if (!(LrpcMessage->Bind.BindExchange.Flags & EXTENDED_ERROR_INFO_PRESENT))
|
|||
|
{
|
|||
|
LrpcMessage->LpcHeader.u1.s1.DataLength = sizeof(LRPC_BIND_MESSAGE)
|
|||
|
- sizeof(PORT_MESSAGE);
|
|||
|
}
|
|||
|
|
|||
|
ReplyMessage(LrpcMessage);
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS LRPC_SASSOCIATION::CreateThread(void)
|
|||
|
{
|
|||
|
RPC_STATUS status;
|
|||
|
status = Address->BeginLongCall();
|
|||
|
if (status != RPC_S_OK)
|
|||
|
{
|
|||
|
Address->EndLongCall();
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
void LRPC_SASSOCIATION::RundownNotificationCompleted(void)
|
|||
|
{
|
|||
|
Address->EndLongCall();
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SBINDING::CheckSecurity (
|
|||
|
SCALL * Context
|
|||
|
)
|
|||
|
{
|
|||
|
if ( (RpcInterface->SequenceNumber == SequenceNumber)
|
|||
|
|| (RpcInterface->IsSecurityCallbackReqd() == 0))
|
|||
|
{
|
|||
|
return (RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS Status = RpcInterface->CheckSecurityIfNecessary(Context);
|
|||
|
|
|||
|
NukeStaleEEInfoIfNecessary(Status);
|
|||
|
|
|||
|
Context->RevertToSelf();
|
|||
|
|
|||
|
if (Status == RPC_S_OK)
|
|||
|
{
|
|||
|
SequenceNumber = RpcInterface->SequenceNumber ;
|
|||
|
return (RPC_S_OK);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
SequenceNumber = 0;
|
|||
|
RpcpErrorAddRecord(EEInfoGCApplication,
|
|||
|
RPC_S_ACCESS_DENIED,
|
|||
|
EEInfoDLCheckSecurity10,
|
|||
|
Status);
|
|||
|
return (RPC_S_ACCESS_DENIED);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
LRPC_SCALL::DealWithRequestMessage (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We will process the original request message in this routine, dispatch
|
|||
|
the remote procedure call to the stub, and then send the response
|
|||
|
message.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RpcMessage - Contains the request buffer
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status, ExceptionCode;
|
|||
|
int Flags = LrpcRequestMessage->Rpc.RpcHeader.Flags ;
|
|||
|
LRPC_SBINDING *LrpcBinding ;
|
|||
|
THREAD *ThisThread;
|
|||
|
DebugThreadInfo *ThreadDebugCell;
|
|||
|
DebugCallInfo *CallDebugCell;
|
|||
|
ULONG TickCount;
|
|||
|
PRPC_DISPATCH_TABLE DispatchTableToUse;
|
|||
|
|
|||
|
RuntimeInfo.Length = sizeof(RPC_RUNTIME_INFO) ;
|
|||
|
|
|||
|
ClientId = MsgClientIdToClientId(LrpcRequestMessage->LpcHeader.ClientId);
|
|||
|
MessageId = LrpcRequestMessage->LpcHeader.MessageId;
|
|||
|
CallbackId = LrpcRequestMessage->LpcHeader.CallbackId;
|
|||
|
|
|||
|
LrpcBinding = LookupBinding(
|
|||
|
LrpcRequestMessage->Rpc.RpcHeader.PresentContext);
|
|||
|
if (LrpcBinding == 0)
|
|||
|
{
|
|||
|
COPYMSG(LrpcReplyMessage, LrpcRequestMessage) ;
|
|||
|
FreeBuffer(&RpcMessage);
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RPC_S_UNKNOWN_IF,
|
|||
|
EEInfoDLDealWithRequestMessage10,
|
|||
|
LrpcRequestMessage->Rpc.RpcHeader.PresentContext);
|
|||
|
SetFaultPacket(LrpcReplyMessage, RPC_S_UNKNOWN_IF, Flags, NULL);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
SBinding = LrpcBinding;
|
|||
|
|
|||
|
if (SBinding->RpcInterface->IsAutoListenInterface())
|
|||
|
{
|
|||
|
LrpcBinding->RpcInterface->BeginAutoListenCall() ;
|
|||
|
}
|
|||
|
|
|||
|
LrpcBinding->GetSelectedTransferSyntaxAndDispatchTable(&RpcMessage.TransferSyntax,
|
|||
|
&DispatchTableToUse);
|
|||
|
RpcMessage.ProcNum = LrpcRequestMessage->Rpc.RpcHeader.ProcedureNumber;
|
|||
|
RpcMessage.Handle = this;
|
|||
|
RpcMessage.ReservedForRuntime = &RuntimeInfo ;
|
|||
|
|
|||
|
// NDR_DREP_ASCII | NDR_DREP_LITTLE_ENDIAN | NDR_DREP_IEEE
|
|||
|
|
|||
|
RpcMessage.DataRepresentation = 0x00 | 0x10 | 0x0000;
|
|||
|
|
|||
|
if ((LrpcRequestMessage->Rpc.RpcHeader.Flags & LRPC_OBJECT_UUID))
|
|||
|
{
|
|||
|
ObjectUuidFlag = 1;
|
|||
|
RpcpMemoryCopy(&ObjectUuid,
|
|||
|
&(LrpcRequestMessage->Rpc.RpcHeader.ObjectUuid), sizeof(UUID));
|
|||
|
}
|
|||
|
|
|||
|
ThisThread = RpcpGetThreadPointer();
|
|||
|
|
|||
|
ASSERT(ThisThread);
|
|||
|
|
|||
|
RpcpSetThreadContextWithThread(ThisThread, this);
|
|||
|
|
|||
|
ThreadDebugCell = ThisThread->DebugCell;
|
|||
|
|
|||
|
//
|
|||
|
// Check IF Level Security
|
|||
|
//
|
|||
|
if (LrpcBinding->RpcInterface->IsSecurityCallbackReqd() != 0)
|
|||
|
{
|
|||
|
Status = LrpcBinding->CheckSecurity(this);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
COPYMSG(LrpcReplyMessage, LrpcRequestMessage) ;
|
|||
|
|
|||
|
FreeBuffer(&RpcMessage);
|
|||
|
|
|||
|
// the error record (if any) was already added
|
|||
|
// by CheckSecurity
|
|||
|
SetFaultPacket(LrpcReplyMessage,
|
|||
|
RPC_S_ACCESS_DENIED,
|
|||
|
Flags,
|
|||
|
NULL) ;
|
|||
|
|
|||
|
RpcpSetThreadContextWithThread(ThisThread, 0) ;
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (ThreadDebugCell)
|
|||
|
{
|
|||
|
TickCount = NtGetTickCount();
|
|||
|
|
|||
|
ThreadDebugCell->Status = dtsDispatched;
|
|||
|
ThreadDebugCell->LastUpdateTime = TickCount;
|
|||
|
|
|||
|
CallDebugCell = DebugCell;
|
|||
|
CallDebugCell->InterfaceUUIDStart = LrpcBinding->RpcInterface->GetInterfaceFirstDWORD();
|
|||
|
CallDebugCell->CallID = CallId;
|
|||
|
CallDebugCell->LastUpdateTime = TickCount;
|
|||
|
// shoehorn the PID and TID into shorts - most of the time
|
|||
|
// it doesn't actually truncate important information
|
|||
|
CallDebugCell->PID = (USHORT)ClientId.UniqueProcess;
|
|||
|
CallDebugCell->TID = (USHORT)ClientId.UniqueThread;
|
|||
|
CallDebugCell->ProcNum = (unsigned short)RpcMessage.ProcNum;
|
|||
|
CallDebugCell->Status = csDispatched;
|
|||
|
GetDebugCellIDFromDebugCell((DebugCellUnion *)ThreadDebugCell,
|
|||
|
&ThisThread->DebugCellTag, &CallDebugCell->ServicingTID);
|
|||
|
if (LrpcBinding->RpcInterface->IsPipeInterface())
|
|||
|
CallDebugCell->CallFlags |= DBGCELL_PIPE_CALL;
|
|||
|
}
|
|||
|
|
|||
|
if (ObjectUuidFlag != 0)
|
|||
|
{
|
|||
|
Status = LrpcBinding->RpcInterface->DispatchToStubWithObject(
|
|||
|
&RpcMessage,
|
|||
|
&ObjectUuid,
|
|||
|
0,
|
|||
|
DispatchTableToUse,
|
|||
|
&ExceptionCode);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = LrpcBinding->RpcInterface->DispatchToStub(
|
|||
|
&RpcMessage,
|
|||
|
0,
|
|||
|
DispatchTableToUse,
|
|||
|
&ExceptionCode);
|
|||
|
}
|
|||
|
|
|||
|
RpcpSetThreadContextWithThread(ThisThread, 0);
|
|||
|
|
|||
|
LRPC_SCALL::RevertToSelf();
|
|||
|
|
|||
|
if (ThreadDebugCell)
|
|||
|
{
|
|||
|
ThreadDebugCell->Status = dtsProcessing;
|
|||
|
ThreadDebugCell->LastUpdateTime = NtGetTickCount();
|
|||
|
}
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
if (Status == RPC_P_EXCEPTION_OCCURED)
|
|||
|
{
|
|||
|
SetFaultPacket(LrpcReplyMessage,
|
|||
|
LrpcMapRpcStatus(ExceptionCode),
|
|||
|
Flags,
|
|||
|
this) ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
VALIDATE(Status)
|
|||
|
{
|
|||
|
RPC_S_PROCNUM_OUT_OF_RANGE,
|
|||
|
RPC_S_UNKNOWN_IF,
|
|||
|
RPC_S_NOT_LISTENING,
|
|||
|
RPC_S_SERVER_TOO_BUSY,
|
|||
|
RPC_S_UNSUPPORTED_TYPE
|
|||
|
} END_VALIDATE;
|
|||
|
|
|||
|
if (Status == RPC_S_NOT_LISTENING)
|
|||
|
{
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
Status,
|
|||
|
EEInfoDLDealWithRequestMessage20);
|
|||
|
Status = RPC_S_SERVER_TOO_BUSY;
|
|||
|
}
|
|||
|
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
Status,
|
|||
|
EEInfoDLDealWithRequestMessage30);
|
|||
|
SetFaultPacket(LrpcReplyMessage,
|
|||
|
LrpcMapRpcStatus(Status),
|
|||
|
Flags,
|
|||
|
this);
|
|||
|
}
|
|||
|
|
|||
|
if (IsSyncCall())
|
|||
|
{
|
|||
|
INITMSG(LrpcReplyMessage,
|
|||
|
ClientId,
|
|||
|
CallbackId,
|
|||
|
MessageId) ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (Flags & LRPC_NON_PIPE)
|
|||
|
{
|
|||
|
INITMSG(LrpcReplyMessage,
|
|||
|
ClientId,
|
|||
|
CallbackId,
|
|||
|
MessageId) ;
|
|||
|
|
|||
|
Association->ReplyMessage(LrpcReplyMessage);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if ((LrpcReplyMessage->Rpc.RpcHeader.MessageType != LRPC_MSG_FAULT2)
|
|||
|
|| (!IsClientAsync()))
|
|||
|
{
|
|||
|
SendDGReply(LrpcReplyMessage);
|
|||
|
}
|
|||
|
}
|
|||
|
RemoveReference();
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// The rest of the response headers are set in ::GetBuffer.
|
|||
|
//
|
|||
|
LrpcReplyMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_RESPONSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
LRPC_SCALL::SendReply (
|
|||
|
)
|
|||
|
{
|
|||
|
RPC_STATUS Status;
|
|||
|
BOOL Shutup ;
|
|||
|
LRPC_SASSOCIATION *LocalAssociation;
|
|||
|
|
|||
|
if (IsSyncCall())
|
|||
|
{
|
|||
|
if (IsClientAsync())
|
|||
|
{
|
|||
|
if (LrpcReplyMessage->Fault.RpcHeader.MessageType == LRPC_MSG_FAULT)
|
|||
|
{
|
|||
|
SendDGReply(LrpcReplyMessage);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
RpcMessage.RpcFlags = 0;
|
|||
|
Status = SendRequest(&RpcMessage, &Shutup) ;
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("RPC: SendRequest failed: %d\n", Status);
|
|||
|
#endif
|
|||
|
Association->Delete();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
INITMSG(LrpcReplyMessage,
|
|||
|
ClientId,
|
|||
|
CallbackId,
|
|||
|
MessageId) ;
|
|||
|
|
|||
|
Association->ReplyMessage(LrpcReplyMessage);
|
|||
|
}
|
|||
|
|
|||
|
FreeMessage(LrpcRequestMessage) ;
|
|||
|
|
|||
|
LocalAssociation = Association;
|
|||
|
Association->FreeSCall(this) ;
|
|||
|
|
|||
|
// don't touch the this pointer after FreeSCall - it may be freed
|
|||
|
LocalAssociation->Address->DereferenceAssociation(LocalAssociation);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if ((LrpcReplyMessage->Rpc.RpcHeader.MessageType != LRPC_MSG_FAULT2)
|
|||
|
|| (!IsClientAsync()))
|
|||
|
{
|
|||
|
RemoveReference();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
BOOL Shutup;
|
|||
|
RpcMessage.RpcFlags = 0;
|
|||
|
Status = SendRequest(&RpcMessage, &Shutup) ;
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("RPC: SendRequest failed: %d\n", Status);
|
|||
|
#endif
|
|||
|
Association->Delete();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LRPC_MESSAGE *
|
|||
|
LRPC_SASSOCIATION::DealWithCopyMessage (
|
|||
|
IN LRPC_COPY_MESSAGE * LrpcMessage
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We will process a copy message in this routine; this means that we need
|
|||
|
to copy a buffer of data from the server into the client's address
|
|||
|
space.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LrpcMessage - Supplies the copy message which was received from
|
|||
|
the client.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The reply message to be sent to the client will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
SIZE_T NumberOfBytesWritten;
|
|||
|
PVOID Buffer;
|
|||
|
|
|||
|
ASSERT(LrpcMessage->IsPartial == 0);
|
|||
|
|
|||
|
AssociationMutex.Request() ;
|
|||
|
|
|||
|
// We need this only to prevent an attack
|
|||
|
// Also, the pointer is to a server address. It is ok to just cast it
|
|||
|
// to the server's pointer type and it won't hurt anything in the case
|
|||
|
// of 32/64 bit LRPC.
|
|||
|
Buffer = Buffers.DeleteItemByBruteForce(MsgPtrToPtr(LrpcMessage->Server.Buffer));
|
|||
|
AssociationMutex.Clear() ;
|
|||
|
|
|||
|
if (LrpcMessage->RpcStatus == RPC_S_OK)
|
|||
|
{
|
|||
|
if (Buffer == 0)
|
|||
|
{
|
|||
|
LrpcMessage->RpcStatus = RPC_S_PROTOCOL_ERROR;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
NtStatus = NtWriteRequestData(LpcServerPort,
|
|||
|
(PORT_MESSAGE *) LrpcMessage,
|
|||
|
0,
|
|||
|
(PVOID) Buffer,
|
|||
|
LrpcMessage->Server.Length,
|
|||
|
&NumberOfBytesWritten);
|
|||
|
|
|||
|
if (NT_ERROR(NtStatus))
|
|||
|
{
|
|||
|
LrpcMessage->RpcStatus = RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT(LrpcMessage->Server.Length == NumberOfBytesWritten);
|
|||
|
LrpcMessage->RpcStatus = RPC_S_OK;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LrpcMessage->LpcHeader.u1.s1.DataLength = sizeof(LRPC_COPY_MESSAGE)
|
|||
|
- sizeof(PORT_MESSAGE);
|
|||
|
LrpcMessage->LpcHeader.u1.s1.TotalLength = sizeof(LRPC_COPY_MESSAGE);
|
|||
|
|
|||
|
if (Buffer != 0)
|
|||
|
{
|
|||
|
RpcpFarFree(Buffer);
|
|||
|
}
|
|||
|
|
|||
|
return((LRPC_MESSAGE *) LrpcMessage);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LRPC_MESSAGE *
|
|||
|
LRPC_SASSOCIATION::DealWithPartialRequest (
|
|||
|
IN LRPC_MESSAGE **LrpcMessage
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Deal with more data on a dispatched call. This
|
|||
|
only happens when you have pipes. Pipe data on
|
|||
|
async calls is handled differently from sync calls.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LrpcMessage - the LRPC message. For pipe data, we always
|
|||
|
take the slow path (ie: NtReadRequestData).
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NULL: if the request was processed.
|
|||
|
not NULL: if there was a problem. the return value contains the
|
|||
|
reply message.
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
LRPC_SCALL *SCall ;
|
|||
|
RPC_STATUS Status ;
|
|||
|
|
|||
|
AssociationMutex.Request() ;
|
|||
|
SCall = SCallDict.Find(ULongToPtr((*LrpcMessage)->Rpc.RpcHeader.CallId));
|
|||
|
AssociationMutex.Clear() ;
|
|||
|
|
|||
|
// we have to wait until the server either calls
|
|||
|
// Receive or calls Register. If it Calls Receive,
|
|||
|
// we know that it is synchronous. If it calls
|
|||
|
// Register, we know that it is async.
|
|||
|
|
|||
|
if (SCall)
|
|||
|
{
|
|||
|
Status = SCall->ProcessResponse(LrpcMessage) ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("LRPC: No call corresponding the the pipe request\n");
|
|||
|
#endif
|
|||
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|||
|
}
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
SetFaultPacket(*LrpcMessage,
|
|||
|
Status,
|
|||
|
LRPC_SYNC_CLIENT,
|
|||
|
NULL) ;
|
|||
|
return *LrpcMessage ;
|
|||
|
}
|
|||
|
|
|||
|
return NULL ;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
LRPC_SASSOCIATION::CleanupIdleSContexts (
|
|||
|
void
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Walks the list of SContexts, finds the ones
|
|||
|
that are idle and server side only, and cleans
|
|||
|
them up.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LRPC_SCONTEXT *SContext;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
SContextDict.Reset(cursor);
|
|||
|
|
|||
|
AssociationMutex.Request();
|
|||
|
while ((SContext = SContextDict.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
if (SContext->GetServerSideOnlyFlag())
|
|||
|
{
|
|||
|
if (SContext->IsIdle())
|
|||
|
{
|
|||
|
SContext = (LRPC_SCONTEXT *)SContextDict.DeleteItemByBruteForce(SContext);
|
|||
|
ASSERT(SContext);
|
|||
|
|
|||
|
SContext->Destroy();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
AssociationMutex.Clear();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::SetupCall(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Helper function that does the setup needed to use the
|
|||
|
call in conjuction with Pipes or Async RPC.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Function succeeded
|
|||
|
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK ;
|
|||
|
|
|||
|
//
|
|||
|
// Stuff from ActivateCall
|
|||
|
//
|
|||
|
RcvBufferLength = 0;
|
|||
|
CallId = LrpcRequestMessage->Rpc.RpcHeader.CallId ;
|
|||
|
ReceiveComplete = 0;
|
|||
|
AsyncReply = 0;
|
|||
|
CachedAPCInfoAvailable = 1;
|
|||
|
Choked = 0;
|
|||
|
AsyncStatus = RPC_S_OK ;
|
|||
|
NeededLength = 0;
|
|||
|
NotificationIssued = -1;
|
|||
|
|
|||
|
if (ReceiveEvent == 0)
|
|||
|
{
|
|||
|
ReceiveEvent = new EVENT(&Status, 0);
|
|||
|
if (ReceiveEvent == 0 || Status)
|
|||
|
{
|
|||
|
delete ReceiveEvent;
|
|||
|
ReceiveEvent = 0;
|
|||
|
return RPC_S_OUT_OF_MEMORY ;
|
|||
|
}
|
|||
|
|
|||
|
CallMutex = new MUTEX(&Status) ;
|
|||
|
if (CallMutex == 0 || Status)
|
|||
|
{
|
|||
|
Association->SCallDict.Delete(ULongToPtr(CallId));
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ReceiveEvent->Lower();
|
|||
|
}
|
|||
|
|
|||
|
Association->AssociationMutex.Request() ;
|
|||
|
if (Association->SCallDict.Insert(ULongToPtr(CallId), this) == -1)
|
|||
|
{
|
|||
|
Association->AssociationMutex.Clear() ;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
Association->AssociationMutex.Clear() ;
|
|||
|
|
|||
|
LrpcReplyMessage->Rpc.RpcHeader.CallId = CallId ;
|
|||
|
|
|||
|
return (RPC_S_OK) ;
|
|||
|
|
|||
|
Cleanup:
|
|||
|
delete CallMutex ;
|
|||
|
delete ReceiveEvent;
|
|||
|
|
|||
|
CallMutex = 0;
|
|||
|
ReceiveEvent = 0;
|
|||
|
|
|||
|
return RPC_S_OUT_OF_MEMORY ;
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::NegotiateTransferSyntax (
|
|||
|
IN OUT PRPC_MESSAGE Message
|
|||
|
)
|
|||
|
{
|
|||
|
// this can happen in the callback case only.
|
|||
|
// Just return the already negotiated transfer syntax
|
|||
|
PRPC_DISPATCH_TABLE Ignored;
|
|||
|
|
|||
|
SBinding->GetSelectedTransferSyntaxAndDispatchTable(&Message->TransferSyntax,
|
|||
|
&Ignored);
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::GetBuffer (
|
|||
|
IN OUT PRPC_MESSAGE Message,
|
|||
|
IN UUID *
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We will allocate a buffer which will be used to either send a request
|
|||
|
or receive a response.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - Supplies the length of the buffer that is needed. The buffer
|
|||
|
will be returned.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - A buffer has been successfully allocated. It will be of at
|
|||
|
least the required length.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate that
|
|||
|
large a buffer.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
int BufferKey ;
|
|||
|
|
|||
|
ASSERT(LrpcReplyMessage != 0) ;
|
|||
|
|
|||
|
if (PARTIAL(Message))
|
|||
|
{
|
|||
|
CurrentBufferLength =
|
|||
|
(Message->BufferLength < MINIMUM_PARTIAL_BUFFLEN)
|
|||
|
? MINIMUM_PARTIAL_BUFFLEN:Message->BufferLength ;
|
|||
|
|
|||
|
Message->Buffer = RpcpFarAllocate(CurrentBufferLength) ;
|
|||
|
if (Message->Buffer == 0)
|
|||
|
{
|
|||
|
CurrentBufferLength = 0;
|
|||
|
return (RPC_S_OUT_OF_MEMORY) ;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (Message->BufferLength <= MAXIMUM_MESSAGE_BUFFER)
|
|||
|
{
|
|||
|
ASSERT(((ULONG_PTR) LrpcReplyMessage->Rpc.Buffer) % 8 == 0);
|
|||
|
// uncomment this to check for 16 byte alignment on 64 bits
|
|||
|
// ASSERT(IsBufferAligned(LrpcReplyMessage->Rpc.Buffer));
|
|||
|
Message->Buffer = LrpcReplyMessage->Rpc.Buffer;
|
|||
|
LrpcReplyMessage->LpcHeader.u2.ZeroInit = 0;
|
|||
|
LrpcReplyMessage->Rpc.RpcHeader.Flags = LRPC_BUFFER_IMMEDIATE;
|
|||
|
LrpcReplyMessage->LpcHeader.u1.s1.DataLength = (USHORT)
|
|||
|
(Align4(Message->BufferLength) + sizeof(LRPC_RPC_HEADER));
|
|||
|
|
|||
|
return (RPC_S_OK) ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Message->Buffer = RpcpFarAllocate(Message->BufferLength);
|
|||
|
if (Message->Buffer == 0)
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LrpcReplyMessage->Rpc.RpcHeader.Flags = LRPC_BUFFER_SERVER;
|
|||
|
LrpcReplyMessage->LpcHeader.u2.ZeroInit = 0;
|
|||
|
|
|||
|
if (PARTIAL(Message) || IsClientAsync())
|
|||
|
{
|
|||
|
LrpcReplyMessage->Rpc.Request.CountDataEntries = 1;
|
|||
|
LrpcReplyMessage->LpcHeader.MessageId = 0;
|
|||
|
LrpcReplyMessage->LpcHeader.CallbackId = 0;
|
|||
|
LrpcReplyMessage->LpcHeader.u2.s2.DataInfoOffset =
|
|||
|
sizeof(PORT_MESSAGE) + sizeof(LRPC_RPC_HEADER);
|
|||
|
LrpcReplyMessage->LpcHeader.u1.s1.DataLength =
|
|||
|
sizeof(LRPC_RPC_HEADER) + sizeof(PORT_DATA_INFORMATION);
|
|||
|
LrpcReplyMessage->Rpc.Request.DataEntries[0].Base = PtrToMsgPtr(Message->Buffer);
|
|||
|
LrpcReplyMessage->Rpc.Request.DataEntries[0].Size = Message->BufferLength;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Association->AssociationMutex.Request() ;
|
|||
|
BufferKey = Association->Buffers.Insert((LRPC_CLIENT_BUFFER *) Message->Buffer) ;
|
|||
|
Association->AssociationMutex.Clear() ;
|
|||
|
|
|||
|
if (BufferKey == -1)
|
|||
|
{
|
|||
|
RpcpFarFree(Message->Buffer) ;
|
|||
|
return RPC_S_OUT_OF_MEMORY ;
|
|||
|
}
|
|||
|
|
|||
|
LrpcReplyMessage->LpcHeader.u1.s1.DataLength =
|
|||
|
sizeof(LRPC_RPC_HEADER) + sizeof(LRPC_SERVER_BUFFER) ;
|
|||
|
|
|||
|
ASSERT(Message->BufferLength < 0x80000000);
|
|||
|
|
|||
|
LrpcReplyMessage->Rpc.Server.Length = Message->BufferLength ;
|
|||
|
LrpcReplyMessage->Rpc.Server.Buffer = PtrToMsgPtr(Message->Buffer) ;
|
|||
|
}
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
LRPC_SCALL::FreeBuffer (
|
|||
|
IN PRPC_MESSAGE Message
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We will free the supplied buffer.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - Supplies the buffer to be freed.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ASSERT(LrpcReplyMessage != NULL) ;
|
|||
|
|
|||
|
if (!(Message->Buffer == LrpcRequestMessage->Rpc.Buffer
|
|||
|
|| Message->Buffer == LrpcReplyMessage->Rpc.Buffer))
|
|||
|
{
|
|||
|
if (!PARTIAL(Message) && !IsClientAsync())
|
|||
|
{
|
|||
|
Association->AssociationMutex.Request() ;
|
|||
|
Association->Buffers.DeleteItemByBruteForce((LRPC_CLIENT_BUFFER *) Message->Buffer);
|
|||
|
Association->AssociationMutex.Clear() ;
|
|||
|
}
|
|||
|
|
|||
|
RpcpFarFree(Message->Buffer);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
LRPC_SCALL::FreePipeBuffer (
|
|||
|
IN PRPC_MESSAGE Message
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
description
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
arg1 - description
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Function succeeded
|
|||
|
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
RpcpFarFree(Message->Buffer) ;
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::ReallocPipeBuffer (
|
|||
|
IN PRPC_MESSAGE Message,
|
|||
|
IN unsigned int NewSize
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
description
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
arg1 - description
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Function succeeded
|
|||
|
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
int BufferKey;
|
|||
|
PVOID Buffer ;
|
|||
|
void *NewBuffer ;
|
|||
|
BOOL BufferChanged = FALSE ;
|
|||
|
|
|||
|
if (NewSize > CurrentBufferLength)
|
|||
|
{
|
|||
|
NewBuffer = RpcpFarAllocate(NewSize) ;
|
|||
|
if (NewBuffer == 0)
|
|||
|
{
|
|||
|
RpcpFarFree(Message->Buffer) ;
|
|||
|
|
|||
|
return (RPC_S_OUT_OF_MEMORY) ;
|
|||
|
}
|
|||
|
|
|||
|
if (CurrentBufferLength > 0)
|
|||
|
{
|
|||
|
RpcpMemoryCopy(NewBuffer, Message->Buffer, Message->BufferLength) ;
|
|||
|
FreePipeBuffer(Message) ;
|
|||
|
}
|
|||
|
Message->Buffer = NewBuffer ;
|
|||
|
CurrentBufferLength = NewSize ;
|
|||
|
BufferChanged = TRUE ;
|
|||
|
}
|
|||
|
|
|||
|
Message->BufferLength = NewSize ;
|
|||
|
|
|||
|
LrpcReplyMessage->Rpc.RpcHeader.Flags = LRPC_BUFFER_SERVER;
|
|||
|
|
|||
|
ASSERT(Message->BufferLength < 0x80000000);
|
|||
|
|
|||
|
LrpcReplyMessage->Rpc.Request.DataEntries[0].Base = PtrToMsgPtr(Message->Buffer);
|
|||
|
LrpcReplyMessage->Rpc.Request.DataEntries[0].Size = Message->BufferLength;
|
|||
|
|
|||
|
|
|||
|
return (RPC_S_OK) ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::AbortAsyncCall (
|
|||
|
IN PRPC_ASYNC_STATE pAsync,
|
|||
|
IN unsigned long ExceptionCode
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
|
|||
|
NukeStaleEEInfoIfNecessary(ExceptionCode);
|
|||
|
|
|||
|
RpcpErrorAddRecord(EEInfoGCApplication,
|
|||
|
ExceptionCode,
|
|||
|
EEInfoDLAbortCall,
|
|||
|
SBinding->GetInterfaceFirstDWORD(),
|
|||
|
(short)RpcMessage.ProcNum,
|
|||
|
RpcMessage.RpcFlags);
|
|||
|
|
|||
|
SetFaultPacket(LrpcReplyMessage, ExceptionCode, Flags, this);
|
|||
|
|
|||
|
if (IsClientAsync())
|
|||
|
{
|
|||
|
if (LrpcReplyMessage->Rpc.RpcHeader.MessageType != LRPC_MSG_FAULT2)
|
|||
|
{
|
|||
|
NtStatus = SendDGReply(LrpcReplyMessage) ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
BOOL Ignored;
|
|||
|
RpcMessage.RpcFlags = 0;
|
|||
|
RpcMessage.Buffer = NULL;
|
|||
|
Status = SendRequest(&RpcMessage,
|
|||
|
&Ignored // shutup parameter - it is not relevant for us
|
|||
|
);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("RPC: SendRequest failed: %d\n", Status);
|
|||
|
#endif
|
|||
|
Association->Delete();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
INITMSG(LrpcReplyMessage,
|
|||
|
ClientId,
|
|||
|
CallbackId,
|
|||
|
MessageId);
|
|||
|
|
|||
|
NtStatus = Association->ReplyMessage(LrpcReplyMessage);
|
|||
|
}
|
|||
|
|
|||
|
if (NT_ERROR(NtStatus))
|
|||
|
{
|
|||
|
Status = RPC_S_CALL_FAILED ;
|
|||
|
}
|
|||
|
|
|||
|
RemoveReference();
|
|||
|
|
|||
|
return Status ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::Receive (
|
|||
|
IN PRPC_MESSAGE Message,
|
|||
|
IN unsigned int Size
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
Receive routine used by pipes
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - contains to buffer to receive in
|
|||
|
pSize - pointer to a size value that contains the minimum amount of
|
|||
|
data that needs to be received.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - We have successfully converted the message.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to do the
|
|||
|
conversion.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
int RequestedSize;
|
|||
|
unsigned long Extra = IsExtraMessage(Message) ;
|
|||
|
|
|||
|
ASSERT(ReceiveEvent) ;
|
|||
|
|
|||
|
Message->DataRepresentation = 0x00 | 0x10 | 0x0000;
|
|||
|
|
|||
|
if (!Extra && Message->Buffer)
|
|||
|
{
|
|||
|
ASSERT(LrpcRequestMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_REQUEST);
|
|||
|
|
|||
|
RpcpFarFree(Message->Buffer);
|
|||
|
Message->Buffer = 0;
|
|||
|
Message->BufferLength = 0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// It is ok for us to find out that the buffer is complete
|
|||
|
// before SavedBuffer is set,
|
|||
|
// we need to take the CallMutex in GetCoalescedBuffer
|
|||
|
//
|
|||
|
while (!BufferComplete && (!PARTIAL(Message) || RcvBufferLength < Size))
|
|||
|
{
|
|||
|
if (ReceiveEvent->Wait() == WAIT_FAILED)
|
|||
|
{
|
|||
|
return RPC_S_CALL_FAILED;
|
|||
|
}
|
|||
|
|
|||
|
if (AsyncStatus != RPC_S_OK)
|
|||
|
{
|
|||
|
return AsyncStatus;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return GetCoalescedBuffer(Message, Extra) ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::Send (
|
|||
|
IN OUT PRPC_MESSAGE Message
|
|||
|
)
|
|||
|
{
|
|||
|
BOOL Shutup ;
|
|||
|
|
|||
|
Message->RpcFlags |= RPC_BUFFER_PARTIAL;
|
|||
|
|
|||
|
return SendRequest(Message, &Shutup) ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::SendRequest (
|
|||
|
IN OUT PRPC_MESSAGE Message,
|
|||
|
OUT BOOL *Shutup
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
description
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
arg1 - description
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Function succeeded
|
|||
|
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
RPC_STATUS Status;
|
|||
|
NTSTATUS NtStatus ;
|
|||
|
int RemainingLength = 0;
|
|||
|
LRPC_MESSAGE ReplyMessage ;
|
|||
|
|
|||
|
*Shutup = 0;
|
|||
|
|
|||
|
if (PARTIAL(Message))
|
|||
|
{
|
|||
|
if (Message->BufferLength < MINIMUM_PARTIAL_BUFFLEN)
|
|||
|
{
|
|||
|
return (RPC_S_SEND_INCOMPLETE) ;
|
|||
|
}
|
|||
|
|
|||
|
if (NOT_MULTIPLE_OF_EIGHT(Message->BufferLength))
|
|||
|
{
|
|||
|
RemainingLength = Message->BufferLength & LOW_BITS ;
|
|||
|
Message->BufferLength &= ~LOW_BITS ;
|
|||
|
}
|
|||
|
|
|||
|
LrpcReplyMessage->Rpc.RpcHeader.Flags |= LRPC_BUFFER_PARTIAL ;
|
|||
|
}
|
|||
|
|
|||
|
if (FirstSend)
|
|||
|
{
|
|||
|
// this code will get executed only in
|
|||
|
// the non async case
|
|||
|
FirstSend = 0;
|
|||
|
|
|||
|
if (ReceiveEvent == 0)
|
|||
|
{
|
|||
|
Status = SetupCall() ;
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
if (PARTIAL(Message)
|
|||
|
&& LrpcReplyMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_SERVER)
|
|||
|
{
|
|||
|
RpcpFarFree(Message->Buffer);
|
|||
|
}
|
|||
|
return Status ;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (LrpcReplyMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_SERVER)
|
|||
|
{
|
|||
|
ASSERT((Message->Buffer == NULL)
|
|||
|
|| (PtrToMsgPtr(Message->Buffer) == LrpcReplyMessage->Rpc.Request.DataEntries[0].Base));
|
|||
|
|
|||
|
LrpcReplyMessage->LpcHeader.u1.s1.TotalLength =
|
|||
|
LrpcReplyMessage->LpcHeader.u1.s1.DataLength
|
|||
|
+ sizeof(PORT_MESSAGE);
|
|||
|
if (LrpcReplyMessage->Rpc.RpcHeader.Flags & LRPC_EEINFO_PRESENT)
|
|||
|
{
|
|||
|
LrpcReplyMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_FAULT2;
|
|||
|
// for FAULT2, the length has already been set
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
LrpcReplyMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_RESPONSE;
|
|||
|
LrpcReplyMessage->Rpc.Request.DataEntries[0].Size =
|
|||
|
Message->BufferLength ;
|
|||
|
}
|
|||
|
LrpcReplyMessage->Rpc.RpcHeader.CallId = CallId;
|
|||
|
|
|||
|
NtStatus = NtRequestWaitReplyPort(Association->LpcReplyPort,
|
|||
|
(PORT_MESSAGE *) LrpcReplyMessage,
|
|||
|
(PORT_MESSAGE *) &ReplyMessage) ;
|
|||
|
|
|||
|
if (NT_ERROR(NtStatus))
|
|||
|
{
|
|||
|
if (Message->Buffer)
|
|||
|
{
|
|||
|
RpcpFarFree(Message->Buffer);
|
|||
|
}
|
|||
|
return RPC_S_CALL_FAILED ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT((ReplyMessage.Rpc.RpcHeader.MessageType == LRPC_MSG_ACK)
|
|||
|
||
|
|||
|
(ReplyMessage.Rpc.RpcHeader.MessageType == LRPC_MSG_FAULT));
|
|||
|
|
|||
|
if (!PARTIAL(Message) &&
|
|||
|
(LrpcReplyMessage->Rpc.RpcHeader.MessageType != LRPC_MSG_FAULT2) &&
|
|||
|
(LrpcReplyMessage->Rpc.RpcHeader.MessageType != LRPC_MSG_FAULT))
|
|||
|
{
|
|||
|
if (Message->Buffer)
|
|||
|
{
|
|||
|
RpcpFarFree(Message->Buffer);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (ReplyMessage.Rpc.RpcHeader.MessageType == LRPC_MSG_ACK)
|
|||
|
{
|
|||
|
*Shutup = ReplyMessage.Ack.Shutup;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = ReplyMessage.Fault.RpcStatus;
|
|||
|
return Status;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT(!PARTIAL(Message)) ;
|
|||
|
|
|||
|
LrpcReplyMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_RESPONSE;
|
|||
|
NtStatus = SendDGReply(LrpcReplyMessage) ;
|
|||
|
|
|||
|
if (NT_ERROR(NtStatus))
|
|||
|
{
|
|||
|
return RPC_S_CALL_FAILED ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (RemainingLength)
|
|||
|
{
|
|||
|
ASSERT(PARTIAL(Message)) ;
|
|||
|
RpcpMemoryMove(Message->Buffer,
|
|||
|
(char *) Message->Buffer + Message->BufferLength,
|
|||
|
RemainingLength) ;
|
|||
|
|
|||
|
Message->BufferLength = RemainingLength ;
|
|||
|
return (RPC_S_SEND_INCOMPLETE) ;
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_OK ;
|
|||
|
}
|
|||
|
|
|||
|
inline RPC_STATUS
|
|||
|
LRPC_SCALL::GetBufferDo(
|
|||
|
IN OUT PRPC_MESSAGE Message,
|
|||
|
IN unsigned long NewSize,
|
|||
|
IN BOOL fDataValid
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
description
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
arg1 - description
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Function succeeded
|
|||
|
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
void *NewBuffer ;
|
|||
|
|
|||
|
if (NewSize < CurrentBufferLength)
|
|||
|
{
|
|||
|
Message->BufferLength = NewSize ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
NewBuffer = RpcpFarAllocate(NewSize) ;
|
|||
|
if (NewBuffer == 0)
|
|||
|
{
|
|||
|
RpcpFarFree(Message->Buffer) ;
|
|||
|
|
|||
|
Message->BufferLength = 0;
|
|||
|
return RPC_S_OUT_OF_MEMORY ;
|
|||
|
}
|
|||
|
|
|||
|
if (fDataValid && Message->BufferLength > 0)
|
|||
|
{
|
|||
|
RpcpMemoryCopy(NewBuffer,
|
|||
|
Message->Buffer,
|
|||
|
Message->BufferLength) ;
|
|||
|
}
|
|||
|
|
|||
|
if (EXTRA(Message))
|
|||
|
{
|
|||
|
ASSERT(Message->ReservedForRuntime) ;
|
|||
|
((PRPC_RUNTIME_INFO)Message->ReservedForRuntime)->OldBuffer =
|
|||
|
NewBuffer;
|
|||
|
}
|
|||
|
|
|||
|
RpcpFarFree(Message->Buffer) ;
|
|||
|
Message->Buffer = NewBuffer ;
|
|||
|
Message->BufferLength = NewSize ;
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_OK ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::SendReceive (
|
|||
|
IN OUT PRPC_MESSAGE Message
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - Supplies the request and returns the response of a remote
|
|||
|
procedure call.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The remote procedure call completed successful.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to perform the
|
|||
|
remote procedure call.
|
|||
|
|
|||
|
RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to complete
|
|||
|
the remote procedure call.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
RPC_STATUS ExceptionCode, Status;
|
|||
|
LRPC_MESSAGE *LrpcSavedMessage;
|
|||
|
SIZE_T NumberOfBytesRead;
|
|||
|
RPC_MESSAGE RpcMessage ;
|
|||
|
RPC_RUNTIME_INFO RuntimeInfo ;
|
|||
|
PRPC_DISPATCH_TABLE DispatchTableToUse;
|
|||
|
|
|||
|
|
|||
|
// The LrpcMessage must be saved, it is in use by the stub. The current
|
|||
|
// LrpcReplyMessage can be used for the callback request message and reply.
|
|||
|
//
|
|||
|
// We must:
|
|||
|
// Save the current LrpcRequestMessage
|
|||
|
// Make the current LrpcReplyMessage the LrpcRequestMessage
|
|||
|
// Allocate a new LrpcReplyMessage.
|
|||
|
|
|||
|
LrpcSavedMessage = LrpcRequestMessage;
|
|||
|
LrpcRequestMessage = LrpcReplyMessage;
|
|||
|
LrpcReplyMessage = 0; // Only needed if we receive a recursive request.
|
|||
|
|
|||
|
Association->Address->Server->OutgoingCallback();
|
|||
|
|
|||
|
// NDR_DREP_ASCII | NDR_DREP_LITTLE_ENDIAN | NDR_DREP_IEEE
|
|||
|
Message->DataRepresentation = 0x00 | 0x10 | 0x0000;
|
|||
|
|
|||
|
LrpcRequestMessage->LpcHeader.u1.s1.TotalLength = sizeof(PORT_MESSAGE)
|
|||
|
+ LrpcRequestMessage->LpcHeader.u1.s1.DataLength;
|
|||
|
LrpcRequestMessage->LpcHeader.u2.s2.Type = LPC_REQUEST;
|
|||
|
INITMSG(LrpcRequestMessage, ClientId, CallbackId, MessageId);
|
|||
|
LrpcRequestMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_CALLBACK;
|
|||
|
LrpcRequestMessage->Rpc.RpcHeader.ProcedureNumber = (unsigned short) Message->ProcNum;
|
|||
|
LrpcRequestMessage->Rpc.RpcHeader.PresentContext =
|
|||
|
SBinding->GetOnTheWirePresentationContext();
|
|||
|
|
|||
|
NtStatus = NtRequestWaitReplyPort(Association->LpcServerPort,
|
|||
|
(PORT_MESSAGE *) LrpcRequestMessage,
|
|||
|
(PORT_MESSAGE *) LrpcRequestMessage);
|
|||
|
|
|||
|
if (NT_ERROR(NtStatus))
|
|||
|
{
|
|||
|
LrpcReplyMessage = LrpcRequestMessage;
|
|||
|
LrpcRequestMessage = LrpcSavedMessage;
|
|||
|
|
|||
|
if (NtStatus == STATUS_NO_MEMORY)
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
if (NtStatus == STATUS_INSUFFICIENT_RESOURCES)
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_RESOURCES);
|
|||
|
}
|
|||
|
#if DBG
|
|||
|
if ((NtStatus != STATUS_INVALID_PORT_HANDLE)
|
|||
|
&& (NtStatus != STATUS_INVALID_HANDLE)
|
|||
|
&& (NtStatus != STATUS_INVALID_CID)
|
|||
|
&& (NtStatus != STATUS_PORT_DISCONNECTED)
|
|||
|
&& (NtStatus != STATUS_LPC_REPLY_LOST))
|
|||
|
{
|
|||
|
PrintToDebugger("RPC : NtRequestWaitReplyPort : %lx\n",
|
|||
|
NtStatus);
|
|||
|
|
|||
|
ASSERT(0) ;
|
|||
|
}
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
return(RPC_S_CALL_FAILED);
|
|||
|
}
|
|||
|
|
|||
|
for (;;)
|
|||
|
{
|
|||
|
if (LrpcRequestMessage->Rpc.RpcHeader.MessageType
|
|||
|
== LRPC_MSG_FAULT)
|
|||
|
{
|
|||
|
Status = LrpcRequestMessage->Fault.RpcStatus;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (LrpcRequestMessage->Rpc.RpcHeader.MessageType
|
|||
|
== LRPC_MSG_RESPONSE)
|
|||
|
{
|
|||
|
if (LrpcRequestMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_REQUEST)
|
|||
|
{
|
|||
|
LrpcRequestMessage->LpcHeader.ClientId = LrpcSavedMessage->Rpc.LpcHeader.ClientId;
|
|||
|
LrpcRequestMessage->LpcHeader.CallbackId = LrpcRequestMessage->Rpc.LpcHeader.CallbackId + 1;
|
|||
|
LrpcSavedMessage->LpcHeader.MessageId = LrpcSavedMessage->Rpc.LpcHeader.MessageId;
|
|||
|
}
|
|||
|
Status = LrpcMessageToRpcMessage(LrpcRequestMessage, Message);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (LrpcRequestMessage->Rpc.RpcHeader.MessageType
|
|||
|
== LRPC_MSG_PUSH)
|
|||
|
{
|
|||
|
ASSERT(PushedResponse == 0);
|
|||
|
PushedResponse = RpcpFarAllocate(
|
|||
|
(unsigned int)
|
|||
|
LrpcRequestMessage->Push.Response.DataEntries[0].Size);
|
|||
|
if (PushedResponse == 0)
|
|||
|
{
|
|||
|
LrpcRequestMessage->Push.RpcStatus = RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
NtStatus = NtReadRequestData(
|
|||
|
Association->LpcServerPort,
|
|||
|
(PORT_MESSAGE *) LrpcRequestMessage,
|
|||
|
0,
|
|||
|
PushedResponse,
|
|||
|
LrpcRequestMessage->Push.Response.DataEntries[0].Size,
|
|||
|
&NumberOfBytesRead);
|
|||
|
|
|||
|
if (NT_ERROR(NtStatus))
|
|||
|
{
|
|||
|
RpcpFarFree(PushedResponse);
|
|||
|
PushedResponse = 0;
|
|||
|
LrpcRequestMessage->Push.RpcStatus = RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT(LrpcRequestMessage->Push.Response.DataEntries[0].Size
|
|||
|
== NumberOfBytesRead);
|
|||
|
LrpcRequestMessage->Push.RpcStatus = RPC_S_OK;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
INITMSG(LrpcRequestMessage,
|
|||
|
ClientId,
|
|||
|
CallbackId,
|
|||
|
MessageId) ;
|
|||
|
|
|||
|
NtStatus = NtReplyWaitReplyPort(Association->LpcServerPort,
|
|||
|
(PORT_MESSAGE *) LrpcRequestMessage);
|
|||
|
|
|||
|
if (PushedResponse)
|
|||
|
{
|
|||
|
RpcpFarFree(PushedResponse);
|
|||
|
PushedResponse = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
VALIDATE(LrpcRequestMessage->Rpc.RpcHeader.MessageType)
|
|||
|
{
|
|||
|
LRPC_MSG_REQUEST
|
|||
|
} END_VALIDATE;
|
|||
|
|
|||
|
Status = LrpcMessageToRpcMessage(LrpcRequestMessage,
|
|||
|
Message);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
LrpcRequestMessage->Fault.RpcHeader.MessageType =
|
|||
|
LRPC_MSG_FAULT;
|
|||
|
LrpcRequestMessage->Fault.RpcStatus = LrpcMapRpcStatus(Status);
|
|||
|
LrpcRequestMessage->LpcHeader.u1.s1.DataLength =
|
|||
|
sizeof(LRPC_FAULT_MESSAGE) - sizeof(PORT_MESSAGE);
|
|||
|
LrpcRequestMessage->LpcHeader.u1.s1.TotalLength =
|
|||
|
sizeof(LRPC_FAULT_MESSAGE);
|
|||
|
|
|||
|
INITMSG(LrpcRequestMessage,
|
|||
|
ClientId,
|
|||
|
CallbackId,
|
|||
|
MessageId) ;
|
|||
|
|
|||
|
NtStatus = NtReplyWaitReplyPort(Association->LpcServerPort,
|
|||
|
(PORT_MESSAGE *) LrpcRequestMessage);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
|
|||
|
LrpcReplyMessage = new LRPC_MESSAGE;
|
|||
|
|
|||
|
if (LrpcReplyMessage != 0)
|
|||
|
{
|
|||
|
SBinding->GetSelectedTransferSyntaxAndDispatchTable(&Message->TransferSyntax,
|
|||
|
&DispatchTableToUse);
|
|||
|
Message->ProcNum =
|
|||
|
LrpcRequestMessage->Rpc.RpcHeader.ProcedureNumber;
|
|||
|
|
|||
|
RuntimeInfo.Length = sizeof(RPC_RUNTIME_INFO) ;
|
|||
|
RpcMessage = *Message ;
|
|||
|
RpcMessage.ReservedForRuntime = &RuntimeInfo ;
|
|||
|
|
|||
|
if (ObjectUuidFlag != 0)
|
|||
|
{
|
|||
|
Status = SBinding->RpcInterface->
|
|||
|
DispatchToStubWithObject(
|
|||
|
&RpcMessage,
|
|||
|
&ObjectUuid,
|
|||
|
1,
|
|||
|
DispatchTableToUse,
|
|||
|
&ExceptionCode);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = SBinding->RpcInterface->
|
|||
|
DispatchToStub(
|
|||
|
&RpcMessage,
|
|||
|
1,
|
|||
|
DispatchTableToUse,
|
|||
|
&ExceptionCode);
|
|||
|
}
|
|||
|
|
|||
|
*Message = RpcMessage ;
|
|||
|
|
|||
|
// Because we must send the reply and recieve the
|
|||
|
// reply into the same message, we just copy the
|
|||
|
// response into the LrpcRequestMessage
|
|||
|
|
|||
|
RpcpMemoryCopy(LrpcRequestMessage,
|
|||
|
LrpcReplyMessage,
|
|||
|
sizeof(LRPC_MESSAGE));
|
|||
|
delete LrpcReplyMessage;
|
|||
|
LrpcReplyMessage = 0;
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
VALIDATE(Status)
|
|||
|
{
|
|||
|
RPC_S_OUT_OF_MEMORY,
|
|||
|
RPC_P_EXCEPTION_OCCURED,
|
|||
|
RPC_S_PROCNUM_OUT_OF_RANGE
|
|||
|
} END_VALIDATE;
|
|||
|
|
|||
|
if (Status == RPC_P_EXCEPTION_OCCURED)
|
|||
|
{
|
|||
|
Status = LrpcMapRpcStatus(ExceptionCode);
|
|||
|
}
|
|||
|
|
|||
|
LrpcRequestMessage->Fault.RpcStatus = Status;
|
|||
|
LrpcRequestMessage->LpcHeader.u1.s1.DataLength =
|
|||
|
sizeof(LRPC_FAULT_MESSAGE) - sizeof(PORT_MESSAGE);
|
|||
|
LrpcRequestMessage->LpcHeader.u1.s1.TotalLength =
|
|||
|
sizeof(LRPC_FAULT_MESSAGE);
|
|||
|
LrpcRequestMessage->Fault.RpcHeader.MessageType =
|
|||
|
LRPC_MSG_FAULT;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
LrpcRequestMessage->LpcHeader.u1.s1.TotalLength =
|
|||
|
sizeof(PORT_MESSAGE)
|
|||
|
+ LrpcRequestMessage->LpcHeader.u1.s1.DataLength;
|
|||
|
LrpcRequestMessage->Rpc.RpcHeader.MessageType =
|
|||
|
LRPC_MSG_RESPONSE;
|
|||
|
}
|
|||
|
|
|||
|
INITMSG(LrpcRequestMessage,
|
|||
|
ClientId,
|
|||
|
CallbackId,
|
|||
|
MessageId) ;
|
|||
|
|
|||
|
NtStatus = NtReplyWaitReplyPort(Association->LpcServerPort,
|
|||
|
(PORT_MESSAGE *) LrpcRequestMessage);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (NT_ERROR(NtStatus))
|
|||
|
{
|
|||
|
if (NtStatus == STATUS_NO_MEMORY)
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
else if (NtStatus == STATUS_INSUFFICIENT_RESOURCES)
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_RESOURCES;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
VALIDATE(NtStatus)
|
|||
|
{
|
|||
|
STATUS_INVALID_PORT_HANDLE,
|
|||
|
STATUS_INVALID_HANDLE,
|
|||
|
STATUS_INVALID_CID,
|
|||
|
STATUS_PORT_DISCONNECTED,
|
|||
|
STATUS_LPC_REPLY_LOST
|
|||
|
} END_VALIDATE;
|
|||
|
|
|||
|
Status = RPC_S_CALL_FAILED;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (Status == RPC_S_OK)
|
|||
|
{
|
|||
|
Message->Handle = (RPC_BINDING_HANDLE) this;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(LrpcReplyMessage == 0);
|
|||
|
LrpcReplyMessage = LrpcRequestMessage;
|
|||
|
LrpcRequestMessage = LrpcSavedMessage;
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
LRPC_SCALL::FreeObject (
|
|||
|
)
|
|||
|
{
|
|||
|
LRPC_SASSOCIATION *MyAssociation;
|
|||
|
|
|||
|
ASSERT(pAsync) ;
|
|||
|
ASSERT(DispatchBuffer) ;
|
|||
|
|
|||
|
if (DispatchBuffer != LrpcRequestMessage->Rpc.Buffer)
|
|||
|
{
|
|||
|
RpcpFarFree(DispatchBuffer);
|
|||
|
}
|
|||
|
|
|||
|
FreeMessage(LrpcRequestMessage) ;
|
|||
|
|
|||
|
SBinding->RpcInterface->EndCall(0, 1) ;
|
|||
|
|
|||
|
MyAssociation = Association;
|
|||
|
|
|||
|
MyAssociation->FreeSCall(this) ;
|
|||
|
MyAssociation->Address->DereferenceAssociation(MyAssociation);
|
|||
|
|
|||
|
// Warning: The SCALL could have been nuked at this point.
|
|||
|
// DO NOT touch the SCALL after this
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::AsyncSend (
|
|||
|
IN OUT PRPC_MESSAGE Message
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Send an async reply. This request can either be partial or complete.
|
|||
|
If it is a complete request, we cleanup the SCall.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - contains the request
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Function succeeded
|
|||
|
RPC_S_SEND_INCOMPLETE - some data still needs to be sent.
|
|||
|
Message->Buffer pointes to the remaining data, and
|
|||
|
Message->BufferLength is the length of the remaining data.
|
|||
|
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
NTSTATUS NtStatus ;
|
|||
|
BOOL fRetVal ;
|
|||
|
BOOL Shutup ;
|
|||
|
|
|||
|
ASSERT(ReceiveEvent) ;
|
|||
|
|
|||
|
if (AsyncStatus != RPC_S_OK)
|
|||
|
{
|
|||
|
if (PARTIAL(Message))
|
|||
|
{
|
|||
|
Status = AsyncStatus;
|
|||
|
}
|
|||
|
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
FirstSend = 0;
|
|||
|
|
|||
|
if (Flags & LRPC_NON_PIPE)
|
|||
|
{
|
|||
|
LrpcReplyMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_RESPONSE;
|
|||
|
|
|||
|
ASSERT(!IsClientAsync()) ;
|
|||
|
NtStatus = Association->ReplyMessage(LrpcReplyMessage);
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = SendRequest(Message, &Shutup) ;
|
|||
|
}
|
|||
|
|
|||
|
if (PARTIAL(Message))
|
|||
|
{
|
|||
|
if (Status == RPC_S_OK
|
|||
|
|| Status == RPC_S_SEND_INCOMPLETE)
|
|||
|
{
|
|||
|
if ((pAsync->Flags & RPC_C_NOTIFY_ON_SEND_COMPLETE) && !Shutup)
|
|||
|
{
|
|||
|
CallMutex->Request() ;
|
|||
|
if (!IssueNotification(RpcSendComplete))
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|||
|
}
|
|||
|
CallMutex->Clear() ;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// Non partial async sends will always succeed
|
|||
|
// if they fail, we will hide the error
|
|||
|
//
|
|||
|
Status = RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
Cleanup:
|
|||
|
//
|
|||
|
// on the server, the stub never calls FreeBuffer
|
|||
|
//
|
|||
|
RemoveReference();
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::AsyncReceive (
|
|||
|
IN OUT PRPC_MESSAGE Message,
|
|||
|
IN unsigned int Size
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
On the server, this routine is only called when the stub needs
|
|||
|
more data to unmarshall the non pipe parameters, or when it needs
|
|||
|
pipe data.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - contains information about the request
|
|||
|
Size - needed size
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Function succeeded
|
|||
|
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status ;
|
|||
|
int Extra = IsExtraMessage(Message);
|
|||
|
|
|||
|
ASSERT(ReceiveEvent) ;
|
|||
|
|
|||
|
if (PARTIAL(Message) == 0)
|
|||
|
{
|
|||
|
return Receive(Message, Size);
|
|||
|
}
|
|||
|
|
|||
|
if (Extra)
|
|||
|
{
|
|||
|
Status = Receive(Message, Size);
|
|||
|
//
|
|||
|
// don't need to check the status. If Receive failed, we are
|
|||
|
// never going to access dispatch buffer anyway
|
|||
|
//
|
|||
|
DispatchBuffer = Message->Buffer ;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
CallMutex->Request();
|
|||
|
|
|||
|
Message->DataRepresentation = 0x00 | 0x10 | 0x0000;
|
|||
|
|
|||
|
if (BufferComplete == 0
|
|||
|
&& RcvBufferLength < Size)
|
|||
|
{
|
|||
|
if (NOTIFY(Message))
|
|||
|
{
|
|||
|
NeededLength = Size ;
|
|||
|
}
|
|||
|
CallMutex->Clear() ;
|
|||
|
|
|||
|
return RPC_S_ASYNC_CALL_PENDING;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = GetCoalescedBuffer(Message, 0);
|
|||
|
}
|
|||
|
CallMutex->Clear();
|
|||
|
|
|||
|
return Status ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::SetAsyncHandle (
|
|||
|
IN PRPC_ASYNC_STATE pAsync
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Set the async handle corresponding this SCALL. This call is made
|
|||
|
by the stubs.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pAsync - The async handle to association with this SCall
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Function succeeded
|
|||
|
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status ;
|
|||
|
THREAD *Thread = RpcpGetThreadPointer();
|
|||
|
|
|||
|
ASSERT(Thread);
|
|||
|
ASSERT(pAsync);
|
|||
|
|
|||
|
Thread->fAsync = TRUE;
|
|||
|
|
|||
|
if (DebugCell)
|
|||
|
{
|
|||
|
ASSERT(IsServerSideDebugInfoEnabled());
|
|||
|
DebugCell->CallFlags |= DBGCELL_ASYNC_CALL;
|
|||
|
}
|
|||
|
|
|||
|
if (ReceiveEvent == 0)
|
|||
|
{
|
|||
|
Status = SetupCall();
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (LrpcAsyncReplyMessage == 0)
|
|||
|
{
|
|||
|
LrpcAsyncReplyMessage = AllocateMessage() ;
|
|||
|
if (LrpcAsyncReplyMessage == 0)
|
|||
|
{
|
|||
|
return RPC_S_OUT_OF_MEMORY ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LrpcReplyMessage = LrpcAsyncReplyMessage;
|
|||
|
LrpcReplyMessage->Rpc.RpcHeader.CallId = CallId ;
|
|||
|
|
|||
|
INITMSG(LrpcReplyMessage,
|
|||
|
ClientId,
|
|||
|
CallbackId,
|
|||
|
MessageId) ;
|
|||
|
|
|||
|
this->pAsync = pAsync ;
|
|||
|
return RPC_S_OK ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::ProcessResponse (
|
|||
|
IN LRPC_MESSAGE **LrpcMessage
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
A buffer has just arrived, process it. If some other buffer is already
|
|||
|
processing buffers, simply queue it and go away. Otherwise, does
|
|||
|
the processing ourselves.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - Details on the arrived message
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_MESSAGE Message ;
|
|||
|
RPC_STATUS Status ;
|
|||
|
|
|||
|
switch ((*LrpcMessage)->Rpc.RpcHeader.MessageType)
|
|||
|
{
|
|||
|
case LRPC_SERVER_SEND_MORE:
|
|||
|
if (pAsync && (pAsync->Flags & RPC_C_NOTIFY_ON_SEND_COMPLETE))
|
|||
|
{
|
|||
|
if (!IssueNotification(RpcSendComplete))
|
|||
|
{
|
|||
|
AsyncStatus = RPC_S_OUT_OF_MEMORY ;
|
|||
|
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("RPC: IssueNotification failed\n") ;
|
|||
|
#endif
|
|||
|
//
|
|||
|
// We are pretty much hosed here, but we'll try to
|
|||
|
// queue notification anyway.
|
|||
|
//
|
|||
|
IssueNotification() ;
|
|||
|
return RPC_S_OUT_OF_MEMORY ;
|
|||
|
}
|
|||
|
}
|
|||
|
return RPC_S_OK ;
|
|||
|
|
|||
|
case LRPC_MSG_CANCEL:
|
|||
|
InterlockedExchange(&CancelPending, 1);
|
|||
|
return RPC_S_OK;
|
|||
|
|
|||
|
default:
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
CallMutex->Request() ;
|
|||
|
ASSERT(BufferComplete == 0);
|
|||
|
|
|||
|
Message.RpcFlags = 0;
|
|||
|
Status = LrpcMessageToRpcMessage(
|
|||
|
*LrpcMessage,
|
|||
|
&Message) ;
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("RPC: LrpcMessageToRpcMessage failed: %x\n", Status) ;
|
|||
|
#endif
|
|||
|
|
|||
|
AsyncStatus = Status ;
|
|||
|
IssueNotification() ;
|
|||
|
return Status ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (COMPLETE(&Message))
|
|||
|
{
|
|||
|
ASSERT(BufferComplete == 0);
|
|||
|
BufferComplete = 1;
|
|||
|
}
|
|||
|
|
|||
|
if (Message.BufferLength)
|
|||
|
{
|
|||
|
RcvBufferLength += Message.BufferLength ;
|
|||
|
if (BufferQueue.PutOnQueue(Message.Buffer,
|
|||
|
Message.BufferLength))
|
|||
|
{
|
|||
|
AsyncStatus = Status = RPC_S_OUT_OF_MEMORY ;
|
|||
|
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("RPC: PutOnQueue failed\n") ;
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (IsSyncCall())
|
|||
|
{
|
|||
|
CallMutex->Clear() ;
|
|||
|
|
|||
|
ReceiveEvent->Raise();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (Status == RPC_S_OK
|
|||
|
&& NeededLength > 0
|
|||
|
&& RcvBufferLength >= NeededLength)
|
|||
|
{
|
|||
|
IssueNotification(RpcReceiveComplete);
|
|||
|
}
|
|||
|
CallMutex->Clear() ;
|
|||
|
}
|
|||
|
|
|||
|
return Status ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::GetCoalescedBuffer (
|
|||
|
IN PRPC_MESSAGE Message,
|
|||
|
IN BOOL BufferValid
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Remove buffers from the queue and coalesce them into a single buffer.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - on return this will contain the coalesced buffer, Message->BufferLength
|
|||
|
gives us the length of the coalesced buffer.
|
|||
|
BufferValid - Tells us if Message->Buffer is valid on entry.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Function succeeded
|
|||
|
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
void *NewBuffer, *Buffer ;
|
|||
|
char *Current ;
|
|||
|
unsigned int bufferlength ;
|
|||
|
unsigned int TotalLength ;
|
|||
|
LRPC_MESSAGE SendMore ;
|
|||
|
NTSTATUS NtStatus ;
|
|||
|
|
|||
|
CallMutex->Request() ;
|
|||
|
|
|||
|
ASSERT(RcvBufferLength);
|
|||
|
|
|||
|
if (BufferValid)
|
|||
|
{
|
|||
|
TotalLength = RcvBufferLength + Message->BufferLength ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
TotalLength = RcvBufferLength ;
|
|||
|
}
|
|||
|
|
|||
|
NewBuffer = RpcpFarAllocate(TotalLength) ;
|
|||
|
if (NewBuffer == 0)
|
|||
|
{
|
|||
|
CallMutex->Clear() ;
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
if (BufferValid)
|
|||
|
{
|
|||
|
RpcpMemoryCopy(NewBuffer, Message->Buffer, Message->BufferLength) ;
|
|||
|
Current = (char *) NewBuffer + Message->BufferLength ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Current = (char *) NewBuffer;
|
|||
|
}
|
|||
|
|
|||
|
while ((Buffer = BufferQueue.TakeOffQueue(&bufferlength)) != 0)
|
|||
|
{
|
|||
|
RpcpMemoryCopy(Current, Buffer, bufferlength) ;
|
|||
|
Current += bufferlength ;
|
|||
|
RpcpFarFree(Buffer);
|
|||
|
}
|
|||
|
|
|||
|
if (BufferValid && Message->Buffer)
|
|||
|
{
|
|||
|
RpcpFarFree(Message->Buffer);
|
|||
|
|
|||
|
//
|
|||
|
// Update the dispatch buffer
|
|||
|
//
|
|||
|
ASSERT(Message->ReservedForRuntime) ;
|
|||
|
((PRPC_RUNTIME_INFO)Message->ReservedForRuntime)->OldBuffer = NewBuffer;
|
|||
|
|
|||
|
if (Message->Buffer == DispatchBuffer)
|
|||
|
DispatchBuffer = NewBuffer;
|
|||
|
}
|
|||
|
|
|||
|
Message->Buffer = NewBuffer ;
|
|||
|
Message->BufferLength = TotalLength ;
|
|||
|
|
|||
|
RcvBufferLength = 0;
|
|||
|
|
|||
|
if (BufferComplete)
|
|||
|
{
|
|||
|
Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (Choked)
|
|||
|
{
|
|||
|
CallMutex->Clear() ;
|
|||
|
|
|||
|
//
|
|||
|
// send a message to the client
|
|||
|
// to start sending data again
|
|||
|
//
|
|||
|
SendMore.Rpc.RpcHeader.MessageType = LRPC_CLIENT_SEND_MORE;
|
|||
|
SendMore.LpcHeader.u1.s1.DataLength =
|
|||
|
sizeof(LRPC_MESSAGE) - sizeof(PORT_MESSAGE);
|
|||
|
SendMore.LpcHeader.u2.ZeroInit = 0;
|
|||
|
SendMore.Rpc.RpcHeader.CallId = CallId ;
|
|||
|
|
|||
|
NtStatus = SendDGReply(&SendMore) ;
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
return RPC_S_CALL_FAILED ;
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CallMutex->Clear() ;
|
|||
|
|
|||
|
return RPC_S_OK ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::ImpersonateClient (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We will impersonate the client which made the remote procedure call.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
RPC_STATUS Status;
|
|||
|
HANDLE hToken;
|
|||
|
DWORD LastError;
|
|||
|
|
|||
|
Status = SetThreadSecurityContext((SECURITY_CONTEXT *) MAXUINT_PTR);
|
|||
|
if (RPC_S_OK != Status)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
if (SContext)
|
|||
|
{
|
|||
|
if (SContext->GetAnonymousFlag())
|
|||
|
{
|
|||
|
NtStatus = NtImpersonateAnonymousToken(NtCurrentThread());
|
|||
|
if (!NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RPC_S_ACCESS_DENIED,
|
|||
|
EEInfoDLLRPC_SCALL__ImpersonateClient10,
|
|||
|
(ULONG)NtStatus,
|
|||
|
(ULONG)GetCurrentThreadId());
|
|||
|
|
|||
|
ClearThreadSecurityContext();
|
|||
|
|
|||
|
return RPC_S_ACCESS_DENIED;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (SetThreadToken(NULL, SContext->hToken) == FALSE)
|
|||
|
{
|
|||
|
LastError = GetLastError();
|
|||
|
|
|||
|
ClearThreadSecurityContext();
|
|||
|
|
|||
|
if (LastError == ERROR_OUTOFMEMORY)
|
|||
|
{
|
|||
|
return (RPC_S_OUT_OF_MEMORY) ;
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_ACCESS_DENIED;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
NtStatus = NtImpersonateClientOfPort(Association->LpcServerPort,
|
|||
|
(PORT_MESSAGE *) LrpcRequestMessage);
|
|||
|
|
|||
|
if ((NtStatus == STATUS_INVALID_CID)
|
|||
|
|| (NtStatus == STATUS_PORT_DISCONNECTED)
|
|||
|
|| (NtStatus == STATUS_REPLY_MESSAGE_MISMATCH))
|
|||
|
{
|
|||
|
ClearThreadSecurityContext();
|
|||
|
return RPC_S_NO_CONTEXT_AVAILABLE;
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("RPC : NtImpersonateClientOfPort : %lx\n",NtStatus);
|
|||
|
#endif // DBG
|
|||
|
return RPC_S_ACCESS_DENIED;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::RevertToSelf (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This reverts a server thread back to itself after impersonating a client.
|
|||
|
We just check to see if the server thread is impersonating; this optimizes
|
|||
|
the common case.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
HANDLE ImpersonationToken = 0;
|
|||
|
NTSTATUS NtStatus;
|
|||
|
|
|||
|
if (ClearThreadSecurityContext())
|
|||
|
{
|
|||
|
NtStatus = NtSetInformationThread(
|
|||
|
NtCurrentThread(),
|
|||
|
ThreadImpersonationToken,
|
|||
|
&ImpersonationToken,
|
|||
|
sizeof(HANDLE));
|
|||
|
#if DBG
|
|||
|
if (!NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
PrintToDebugger("RPC : NtSetInformationThread : %lx\n", NtStatus);
|
|||
|
}
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus))
|
|||
|
{
|
|||
|
if (NtStatus == STATUS_NO_MEMORY)
|
|||
|
{
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
return RPC_S_ACCESS_DENIED;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::GetAuthorizationContext (
|
|||
|
IN BOOL ImpersonateOnReturn,
|
|||
|
IN AUTHZ_RESOURCE_MANAGER_HANDLE AuthzResourceManager,
|
|||
|
IN PLARGE_INTEGER pExpirationTime OPTIONAL,
|
|||
|
IN LUID Identifier,
|
|||
|
IN DWORD Flags,
|
|||
|
IN PVOID DynamicGroupArgs OPTIONAL,
|
|||
|
OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Gets an authorization context for the client that can be used
|
|||
|
with Authz functions. The resulting context is owned by the caller
|
|||
|
and must be freed by it.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ImpersonateOnReturn - if TRUE, when we return, we should be impersonating.
|
|||
|
AuthzResourceManager - the resource manager to use (passed to Authz)
|
|||
|
pExpirationTime - the expiration time to use (passed to Authz)
|
|||
|
Identifier - the LUID (passed to Authz)
|
|||
|
Flags - Flags (passed to Authz)
|
|||
|
DynamicGroupArgs - parameter required by Authz (passed to Authz)
|
|||
|
pAuthzClientContext - the authorization context, returned on success.
|
|||
|
Undefined on failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
RPC_STATUS RevertStatus;
|
|||
|
BOOL fNeedToRevert = FALSE;
|
|||
|
HANDLE ImpersonationToken;
|
|||
|
BOOL Result;
|
|||
|
BOOL fImpersonating = FALSE;
|
|||
|
PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContextPlaceholder;
|
|||
|
|
|||
|
ASSERT (AuthzResourceManager != NULL);
|
|||
|
|
|||
|
if (ImpersonateOnReturn
|
|||
|
|| (SContext == NULL)
|
|||
|
|| (SContext->AuthzClientContext == NULL))
|
|||
|
{
|
|||
|
Status = LRPC_SCALL::ImpersonateClient();
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
Status,
|
|||
|
EEInfoDLLRPC_SCALL__GetAuthorizationContext10,
|
|||
|
(ULONG)ImpersonateOnReturn,
|
|||
|
(ULONGLONG)SContext);
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
fImpersonating = TRUE;
|
|||
|
if (!ImpersonateOnReturn)
|
|||
|
{
|
|||
|
fNeedToRevert = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (SContext && SContext->AuthzClientContext)
|
|||
|
{
|
|||
|
Status = DuplicateAuthzContext(SContext->AuthzClientContext,
|
|||
|
pExpirationTime,
|
|||
|
Identifier,
|
|||
|
Flags,
|
|||
|
DynamicGroupArgs,
|
|||
|
pAuthzClientContext);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// either we don't have an scontext, or its
|
|||
|
// AuthzClientContext is not set yet.
|
|||
|
// Get the token from the thread
|
|||
|
Result = OpenThreadToken(GetCurrentThread(),
|
|||
|
TOKEN_QUERY,
|
|||
|
TRUE,
|
|||
|
&ImpersonationToken);
|
|||
|
|
|||
|
if (Result)
|
|||
|
{
|
|||
|
if (SContext)
|
|||
|
pAuthzClientContextPlaceholder = &SContext->AuthzClientContext;
|
|||
|
else
|
|||
|
pAuthzClientContextPlaceholder = NULL;
|
|||
|
|
|||
|
Status = CreateAndSaveAuthzContextFromToken(pAuthzClientContextPlaceholder,
|
|||
|
ImpersonationToken,
|
|||
|
AuthzResourceManager,
|
|||
|
pExpirationTime,
|
|||
|
Identifier,
|
|||
|
Flags,
|
|||
|
DynamicGroupArgs,
|
|||
|
pAuthzClientContext);
|
|||
|
|
|||
|
CloseHandle(ImpersonationToken);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = GetLastError();
|
|||
|
if (Status == ERROR_CANT_OPEN_ANONYMOUS)
|
|||
|
{
|
|||
|
Result = AuthzInitializeContextFromSidFn(
|
|||
|
AUTHZ_SKIP_TOKEN_GROUPS,
|
|||
|
(PSID)&AnonymousSid,
|
|||
|
AuthzResourceManager,
|
|||
|
pExpirationTime,
|
|||
|
Identifier,
|
|||
|
DynamicGroupArgs,
|
|||
|
pAuthzClientContext);
|
|||
|
|
|||
|
if (Result)
|
|||
|
{
|
|||
|
if (SContext)
|
|||
|
{
|
|||
|
if (InterlockedCompareExchangePointer((PVOID *)&SContext->AuthzClientContext,
|
|||
|
pAuthzClientContext,
|
|||
|
NULL) != NULL)
|
|||
|
{
|
|||
|
// somebody beat us to the punch - free the context we obtained
|
|||
|
AuthzFreeContextFn(*pAuthzClientContext);
|
|||
|
*pAuthzClientContext = SContext->AuthzClientContext;
|
|||
|
}
|
|||
|
}
|
|||
|
// else
|
|||
|
// the authz context is already loaded in pAuthzClientContext
|
|||
|
Status = RPC_S_OK;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = GetLastError();
|
|||
|
|
|||
|
RpcpErrorAddRecord(EEInfoGCAuthz,
|
|||
|
Status,
|
|||
|
EEInfoDLLRPC_SCALL__GetAuthorizationContext30,
|
|||
|
GetCurrentThreadId(),
|
|||
|
(ULONGLONG)AuthzResourceManager);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
Status,
|
|||
|
EEInfoDLLRPC_SCALL__GetAuthorizationContext20,
|
|||
|
GetCurrentThreadId());
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// if caller didn't ask us to impersonate and we are,
|
|||
|
// or we if he did ask us, but we failed somewhere,
|
|||
|
// revert to self
|
|||
|
if (fNeedToRevert || (Status && fImpersonating))
|
|||
|
{
|
|||
|
RevertStatus = LRPC_SCALL::RevertToSelf();
|
|||
|
ASSERT(RevertStatus == RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::IsClientLocal (
|
|||
|
OUT unsigned int * ClientLocalFlag
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
A client using LRPC will always be local.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ClientLocalFlag - Returns a flag which will always be set to a non-zero
|
|||
|
value indicating that the client is local.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UNUSED(this);
|
|||
|
|
|||
|
*ClientLocalFlag = 1;
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::ConvertToServerBinding (
|
|||
|
OUT RPC_BINDING_HANDLE __RPC_FAR * ServerBinding
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
If possible, convert this call into a server binding, meaning a
|
|||
|
binding handle pointing back to the client.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerBinding - Returns the server binding.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The server binding has successfully been created.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
|
|||
|
a new binding handle.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOL Boolean;
|
|||
|
RPC_STATUS Status;
|
|||
|
RPC_CHAR UuidString[37];
|
|||
|
RPC_CHAR * StringBinding;
|
|||
|
RPC_CHAR * NetworkAddress;
|
|||
|
DWORD NetworkAddressLength = MAX_COMPUTERNAME_LENGTH + 1;
|
|||
|
|
|||
|
if (ObjectUuidFlag != 0)
|
|||
|
{
|
|||
|
ObjectUuid.ConvertToString(UuidString);
|
|||
|
UuidString[36] = '\0';
|
|||
|
}
|
|||
|
|
|||
|
NetworkAddress = new RPC_CHAR[NetworkAddressLength];
|
|||
|
if (NetworkAddress == 0)
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
Boolean = GetComputerNameW(
|
|||
|
NetworkAddress,
|
|||
|
&NetworkAddressLength);
|
|||
|
|
|||
|
if (Boolean != TRUE)
|
|||
|
{
|
|||
|
Status = GetLastError();
|
|||
|
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("RPC : GetComputerNameW : %d\n", Status);
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
if (Status == ERROR_NOT_ENOUGH_MEMORY)
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
else if ((Status == ERROR_NOT_ENOUGH_QUOTA)
|
|||
|
|| (Status == ERROR_NO_SYSTEM_RESOURCES))
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_RESOURCES;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT(0);
|
|||
|
Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
delete NetworkAddress;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
Status = RpcStringBindingComposeW(
|
|||
|
(ObjectUuidFlag != 0 ? UuidString : 0),
|
|||
|
RPC_STRING_LITERAL("ncalrpc"),
|
|||
|
NetworkAddress,
|
|||
|
0,
|
|||
|
0,
|
|||
|
&StringBinding);
|
|||
|
delete NetworkAddress;
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
Status = RpcBindingFromStringBindingW(
|
|||
|
StringBinding,
|
|||
|
ServerBinding);
|
|||
|
|
|||
|
RpcStringFreeW(&StringBinding);
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
LRPC_SCALL::InquireObjectUuid (
|
|||
|
OUT RPC_UUID * ObjectUuid
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine copies the object uuid from the call into the supplied
|
|||
|
ObjectUuid argument.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ObjectUuid - Returns a copy of the object uuid passed by the client
|
|||
|
in the remote procedure call.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if (ObjectUuidFlag == 0)
|
|||
|
{
|
|||
|
ObjectUuid->SetToNullUuid();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ObjectUuid->CopyUuid(&(this->ObjectUuid));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::ToStringBinding (
|
|||
|
OUT RPC_CHAR ** StringBinding
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We need to convert this call into a string binding. We will ask the
|
|||
|
address for a binding handle which we can then convert into a string
|
|||
|
binding.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
StringBinding - Returns the string binding for this call.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status;
|
|||
|
BINDING_HANDLE * BindingHandle
|
|||
|
= Association->Address->InquireBinding();
|
|||
|
|
|||
|
if (BindingHandle == 0)
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
Status = BindingHandle->ToStringBinding(StringBinding);
|
|||
|
BindingHandle->BindingFree();
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::GetAssociationContextCollection (
|
|||
|
OUT ContextCollection **CtxCollection
|
|||
|
)
|
|||
|
{
|
|||
|
return Association->GetAssociationContextCollection(CtxCollection);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
inline RPC_STATUS
|
|||
|
LRPC_SCALL::LrpcMessageToRpcMessage (
|
|||
|
IN LRPC_MESSAGE * LrpcMessage,
|
|||
|
IN OUT PRPC_MESSAGE Message
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We will convert from an LRPC_MESSAGE representation of a buffer (and
|
|||
|
its length) to an RPC_MESSAGE representation.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RpcMessage - Returns the RPC_MESSAGE representation.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - We have successfully converted the message.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to do the
|
|||
|
conversion.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
SIZE_T NumberOfBytesRead;
|
|||
|
unsigned char MessageType = LrpcMessage->Rpc.RpcHeader.MessageType;
|
|||
|
RPC_STATUS Status = RPC_S_OK ;
|
|||
|
LRPC_MESSAGE ReplyMessage ;
|
|||
|
|
|||
|
if(LrpcMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_IMMEDIATE)
|
|||
|
{
|
|||
|
Message->Buffer = LrpcMessage->Rpc.Buffer;
|
|||
|
ASSERT(LrpcMessage->LpcHeader.u1.s1.DataLength
|
|||
|
>= sizeof(LRPC_RPC_HEADER));
|
|||
|
Message->BufferLength =
|
|||
|
(unsigned int) LrpcMessage->LpcHeader.u1.s1.DataLength
|
|||
|
- sizeof(LRPC_RPC_HEADER);
|
|||
|
Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
|
|||
|
}
|
|||
|
else if (LrpcMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_REQUEST)
|
|||
|
{
|
|||
|
Message->BufferLength = LrpcMessage->Rpc.Request.DataEntries[0].Size;
|
|||
|
|
|||
|
if (LrpcMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_PARTIAL)
|
|||
|
{
|
|||
|
CallMutex->Request() ;
|
|||
|
|
|||
|
//
|
|||
|
// If the user ever specifies a Size > LRPC_THRESHOLD_SIZE
|
|||
|
// our performance will be bad.
|
|||
|
//
|
|||
|
if (RcvBufferLength >= LRPC_THRESHOLD_SIZE)
|
|||
|
{
|
|||
|
Choked = 1;
|
|||
|
}
|
|||
|
CallMutex->Clear() ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
|
|||
|
}
|
|||
|
|
|||
|
Message->Buffer = RpcpFarAllocate(Message->BufferLength) ;
|
|||
|
if (Message->Buffer == 0)
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
Status,
|
|||
|
EEInfoDLLrpcMessageToRpcMessage10,
|
|||
|
Message->BufferLength);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
NtStatus = NtReadRequestData(Association->LpcServerPort,
|
|||
|
(PORT_MESSAGE *) LrpcMessage,
|
|||
|
0,
|
|||
|
Message->Buffer,
|
|||
|
Message->BufferLength,
|
|||
|
&NumberOfBytesRead) ;
|
|||
|
|
|||
|
if (NT_ERROR(NtStatus))
|
|||
|
{
|
|||
|
RpcpFarFree(Message->Buffer) ;
|
|||
|
Message->Buffer = 0;
|
|||
|
|
|||
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
Status,
|
|||
|
EEInfoDLLrpcMessageToRpcMessage20,
|
|||
|
NtStatus);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT(Message->BufferLength == NumberOfBytesRead) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (IsClientAsync())
|
|||
|
{
|
|||
|
COPYMSG((&ReplyMessage), LrpcMessage) ;
|
|||
|
ReplyMessage.Ack.MessageType = LRPC_MSG_ACK ;
|
|||
|
ReplyMessage.Ack.RpcStatus = Status;
|
|||
|
ReplyMessage.Ack.Shutup = (short) Choked ;
|
|||
|
ReplyMessage.LpcHeader.u1.s1.DataLength =
|
|||
|
sizeof(LRPC_ACK_MESSAGE) - sizeof(PORT_MESSAGE) ;
|
|||
|
|
|||
|
NtStatus = Association->ReplyMessage(&ReplyMessage);
|
|||
|
|
|||
|
if (NT_ERROR(NtStatus))
|
|||
|
{
|
|||
|
RpcpFarFree(Message->Buffer);
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RPC_S_OUT_OF_MEMORY,
|
|||
|
EEInfoDLLrpcMessageToRpcMessage30,
|
|||
|
NtStatus);
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT((LrpcMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_IMMEDIATE)
|
|||
|
|| (LrpcMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_REQUEST));
|
|||
|
}
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::InquireAuthClient (
|
|||
|
OUT RPC_AUTHZ_HANDLE * Privileges,
|
|||
|
OUT RPC_CHAR * * ServerPrincipalName, OPTIONAL
|
|||
|
OUT unsigned long * AuthenticationLevel,
|
|||
|
OUT unsigned long * AuthenticationService,
|
|||
|
OUT unsigned long * AuthorizationService,
|
|||
|
IN unsigned long Flags
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Each protocol module must define this routine: it is used to obtain
|
|||
|
the authentication and authorization information about a client making
|
|||
|
the remote procedure call represented by this.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Privileges - Returns a the privileges of the client.
|
|||
|
|
|||
|
ServerPrincipalName - Returns the server principal name which the client
|
|||
|
specified.
|
|||
|
|
|||
|
AuthenticationLevel - Returns the authentication level requested by
|
|||
|
the client.
|
|||
|
|
|||
|
AuthenticationService - Returns the authentication service requested by
|
|||
|
the client.
|
|||
|
|
|||
|
AuthorizationService - Returns the authorization service requested by
|
|||
|
the client.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK or RPC_S_* / Win32 error
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status;
|
|||
|
|
|||
|
if(ARGUMENT_PRESENT(Privileges))
|
|||
|
{
|
|||
|
*(RPC_CHAR **)Privileges = NULL;
|
|||
|
Status = Association->GetClientName(this,
|
|||
|
NULL, // ClientPrincipalNameBufferLength
|
|||
|
(RPC_CHAR **) Privileges);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(ServerPrincipalName))
|
|||
|
{
|
|||
|
*ServerPrincipalName = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if(ARGUMENT_PRESENT(AuthenticationLevel))
|
|||
|
{
|
|||
|
*AuthenticationLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY ;
|
|||
|
}
|
|||
|
|
|||
|
if(ARGUMENT_PRESENT(AuthenticationService))
|
|||
|
{
|
|||
|
*AuthenticationService = RPC_C_AUTHN_WINNT ;
|
|||
|
}
|
|||
|
|
|||
|
if(ARGUMENT_PRESENT(AuthorizationService))
|
|||
|
{
|
|||
|
*AuthorizationService = RPC_C_AUTHZ_NONE ;
|
|||
|
}
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCALL::InquireCallAttributes (
|
|||
|
IN OUT void *RpcCallAttributes
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Inquire the security context attributes for the LRPC client
|
|||
|
|
|||
|
Arguments:
|
|||
|
RpcCallAttributes - a pointer to
|
|||
|
RPC_CALL_ATTRIBUTES_V1_W structure. The Version
|
|||
|
member must be initialized.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK or RPC_S_* / Win32 error. EEInfo will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_CALL_ATTRIBUTES_V1 *CallAttributes;
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
|
|||
|
CallAttributes =
|
|||
|
(RPC_CALL_ATTRIBUTES_V1 *)RpcCallAttributes;
|
|||
|
|
|||
|
CallAttributes->AuthenticationLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
|
|||
|
CallAttributes->AuthenticationService = RPC_C_AUTHN_WINNT;
|
|||
|
CallAttributes->NullSession = FALSE;
|
|||
|
|
|||
|
if (CallAttributes->Flags & RPC_QUERY_CLIENT_PRINCIPAL_NAME)
|
|||
|
{
|
|||
|
Status = Association->GetClientName(this,
|
|||
|
&CallAttributes->ClientPrincipalNameBufferLength,
|
|||
|
&CallAttributes->ClientPrincipalName);
|
|||
|
|
|||
|
if ((Status != RPC_S_OK) && (Status != ERROR_MORE_DATA))
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (CallAttributes->Flags & RPC_QUERY_SERVER_PRINCIPAL_NAME)
|
|||
|
{
|
|||
|
CallAttributes->ServerPrincipalNameBufferLength = 0;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
LRPC_SBINDING *
|
|||
|
LRPC_SCALL::LookupBinding (
|
|||
|
IN unsigned short PresentContextId
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name:LookupBinding
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
Description:
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LRPC_SBINDING *CurBinding;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
Association->Bindings.Reset(cursor);
|
|||
|
while ((CurBinding = Association->Bindings.Next(cursor)))
|
|||
|
{
|
|||
|
if (CurBinding->GetPresentationContext() == PresentContextId)
|
|||
|
{
|
|||
|
return CurBinding;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
LRPC_SCONTEXT::LRPC_SCONTEXT (
|
|||
|
IN HANDLE MyToken,
|
|||
|
IN LUID *UserLuid,
|
|||
|
IN LRPC_SASSOCIATION *MyAssociation,
|
|||
|
IN BOOL fDefaultLogonId,
|
|||
|
IN BOOL fAnonymousToken
|
|||
|
)
|
|||
|
{
|
|||
|
hToken = MyToken;
|
|||
|
ClientName = NULL;
|
|||
|
RefCount = 1;
|
|||
|
ClearDeletedFlag();
|
|||
|
Association = MyAssociation;
|
|||
|
AuthzClientContext = NULL;
|
|||
|
if (fAnonymousToken)
|
|||
|
SetAnonymousFlag();
|
|||
|
else
|
|||
|
ClearAnonymousFlag();
|
|||
|
if (fAnonymousToken)
|
|||
|
{
|
|||
|
ASSERT(fDefaultLogonId == FALSE);
|
|||
|
ASSERT(UserLuid == NULL);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT(fAnonymousToken == FALSE);
|
|||
|
if (fDefaultLogonId)
|
|||
|
SetDefaultLogonIdFlag();
|
|||
|
else
|
|||
|
ClearDefaultLogonIdFlag();
|
|||
|
FastCopyLUID(&ClientLuid, UserLuid);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LRPC_SCONTEXT::~LRPC_SCONTEXT (
|
|||
|
void
|
|||
|
)
|
|||
|
{
|
|||
|
if (hToken)
|
|||
|
{
|
|||
|
CloseHandle(hToken);
|
|||
|
}
|
|||
|
RpcpFarFree(ClientName);
|
|||
|
|
|||
|
if (AuthzClientContext)
|
|||
|
{
|
|||
|
AuthzFreeContextFn(AuthzClientContext);
|
|||
|
AuthzClientContext = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (GetServerSideOnlyFlag())
|
|||
|
{
|
|||
|
// if this is server side only context, remove us
|
|||
|
// from the garbage collection count
|
|||
|
InterlockedDecrement(&PeriodicGarbageCollectItems);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCONTEXT::GetUserName (
|
|||
|
IN OUT ULONG *ClientPrincipalNameBufferLength OPTIONAL,
|
|||
|
OUT RPC_CHAR **UserName,
|
|||
|
IN HANDLE hUserToken OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Gets the user name for the given context.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ClientPrincipalNameBufferLength - if present, *UserName must
|
|||
|
point to a caller supplied buffer, which if big enough,
|
|||
|
will be filled with the client principal name. If not present,
|
|||
|
*UserName must be NULL.
|
|||
|
UserName - see ClientPrincipalNameBufferLength
|
|||
|
hUserToken - if present, the user name for the given token will
|
|||
|
be retrieved instead of the user name for the token inside
|
|||
|
the LRPC_SCONTEXT
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK for success, or RPC_S_* / Win32 error code for error.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
TOKEN_USER *pUser;
|
|||
|
RPC_STATUS Status;
|
|||
|
RPC_CHAR *ClientPrincipalName;
|
|||
|
ULONG ClientPrincipalNameLength; // in bytes, including NULL terminator
|
|||
|
|
|||
|
if (ClientName == 0)
|
|||
|
{
|
|||
|
if (GetAnonymousFlag() == 0)
|
|||
|
{
|
|||
|
if (hUserToken == NULL)
|
|||
|
{
|
|||
|
ASSERT(hToken != NULL);
|
|||
|
hUserToken = hToken;
|
|||
|
}
|
|||
|
|
|||
|
pUser = GetSID(hUserToken);
|
|||
|
if (pUser == 0)
|
|||
|
{
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
Status = LookupUser((SID *)pUser->User.Sid, &ClientPrincipalName);
|
|||
|
delete pUser;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = LookupUser((SID *)&AnonymousSid, &ClientPrincipalName);
|
|||
|
}
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
if (InterlockedCompareExchangePointer((PVOID *)&ClientName, ClientPrincipalName, NULL) != NULL)
|
|||
|
{
|
|||
|
// somebody beat us to the punch. Free the allocated string
|
|||
|
delete ClientPrincipalName;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// at this stage, ClientName must contain the client principal name
|
|||
|
ASSERT(ClientName);
|
|||
|
|
|||
|
// See where our caller wants us to put it
|
|||
|
if (ARGUMENT_PRESENT(ClientPrincipalNameBufferLength))
|
|||
|
{
|
|||
|
// in the future, we may think of caching the length to avoid
|
|||
|
// computing it every time
|
|||
|
ClientPrincipalNameLength = (RpcpStringLength(ClientName) + 1) * sizeof(RPC_CHAR);
|
|||
|
|
|||
|
// if there is enough space in the data, copy it to user buffer
|
|||
|
if (ClientPrincipalNameLength <= *ClientPrincipalNameBufferLength)
|
|||
|
{
|
|||
|
RpcpMemoryCopy(*UserName,
|
|||
|
ClientName,
|
|||
|
ClientPrincipalNameLength);
|
|||
|
Status = RPC_S_OK;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = ERROR_MORE_DATA;
|
|||
|
}
|
|||
|
|
|||
|
*ClientPrincipalNameBufferLength = ClientPrincipalNameLength;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT(*UserName == NULL);
|
|||
|
*UserName = ClientName;
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
TOKEN_USER *
|
|||
|
LRPC_SCONTEXT::GetSID (
|
|||
|
IN HANDLE hToken
|
|||
|
)
|
|||
|
{
|
|||
|
char *Buf = NULL;
|
|||
|
ULONG Bufflen = 64 ;
|
|||
|
ULONG Length;
|
|||
|
|
|||
|
Buf = new char[Bufflen];
|
|||
|
if (Buf == 0)
|
|||
|
{
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
while (1)
|
|||
|
{
|
|||
|
if (GetTokenInformation(hToken,
|
|||
|
TokenUser, Buf, Bufflen,
|
|||
|
&Length) == FALSE)
|
|||
|
{
|
|||
|
if (Length > Bufflen)
|
|||
|
{
|
|||
|
Bufflen = Length ;
|
|||
|
delete Buf;
|
|||
|
|
|||
|
Buf = new char[Bufflen];
|
|||
|
if (Buf == 0)
|
|||
|
{
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
continue;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("LRPC: GetTokenInformation failed\n") ;
|
|||
|
#endif
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return (TOKEN_USER *) Buf;
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
LRPC_SCONTEXT::LookupUser (
|
|||
|
IN SID *pSid,
|
|||
|
OUT RPC_CHAR **UserName
|
|||
|
)
|
|||
|
{
|
|||
|
unsigned long UserLength = USER_NAME_LEN ;
|
|||
|
unsigned long OldDomainLen, OldUserLen;
|
|||
|
unsigned long DomainLen = DOMAIN_NAME_LEN ;
|
|||
|
RPC_CHAR *DomainName = NULL, *MyUserName = NULL;
|
|||
|
SID_NAME_USE Name ;
|
|||
|
RPC_STATUS Status = RPC_S_OK ;
|
|||
|
|
|||
|
MyUserName = new RPC_CHAR[UserLength];
|
|||
|
if (MyUserName == 0)
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|||
|
goto Cleanup ;
|
|||
|
}
|
|||
|
|
|||
|
DomainLen += UserLength ;
|
|||
|
DomainName = new RPC_CHAR [DomainLen];
|
|||
|
if (DomainName == 0)
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|||
|
goto Cleanup ;
|
|||
|
}
|
|||
|
|
|||
|
OldDomainLen = DomainLen ;
|
|||
|
OldUserLen = UserLength ;
|
|||
|
|
|||
|
while (1)
|
|||
|
{
|
|||
|
if (LookupAccountSidW(NULL, pSid,
|
|||
|
MyUserName, &UserLength,
|
|||
|
DomainName, &DomainLen, &Name) == FALSE)
|
|||
|
{
|
|||
|
if ((UserLength > OldUserLen) || (DomainLen > OldDomainLen))
|
|||
|
{
|
|||
|
if (UserLength > OldUserLen)
|
|||
|
{
|
|||
|
OldUserLen = UserLength ;
|
|||
|
delete MyUserName;
|
|||
|
|
|||
|
MyUserName = new RPC_CHAR[UserLength];
|
|||
|
if (MyUserName == 0)
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|||
|
goto Cleanup ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (DomainLen > OldDomainLen)
|
|||
|
{
|
|||
|
DomainLen += UserLength;
|
|||
|
OldDomainLen = DomainLen;
|
|||
|
|
|||
|
delete DomainName;
|
|||
|
|
|||
|
DomainName = new RPC_CHAR[DomainLen];
|
|||
|
if (DomainName == 0)
|
|||
|
{
|
|||
|
Status = RPC_S_OUT_OF_MEMORY ;
|
|||
|
goto Cleanup ;
|
|||
|
}
|
|||
|
}
|
|||
|
continue;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("LRPC: LookupAccountSid failed\n");
|
|||
|
#endif
|
|||
|
Status = RPC_S_UNKNOWN_PRINCIPAL;
|
|||
|
goto Cleanup ;
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
RpcpStringConcatenate(DomainName, RPC_CONST_STRING("\\")) ;
|
|||
|
RpcpStringConcatenate(DomainName, MyUserName) ;
|
|||
|
|
|||
|
delete MyUserName;
|
|||
|
*UserName = DomainName ;
|
|||
|
ASSERT(Status == RPC_S_OK);
|
|||
|
|
|||
|
Cleanup:
|
|||
|
if (Status)
|
|||
|
{
|
|||
|
if (MyUserName)
|
|||
|
delete MyUserName;
|
|||
|
if (DomainName)
|
|||
|
delete DomainName;
|
|||
|
|
|||
|
return Status ;
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
LRPC_ADDRESS *LrpcAddressList = NULL;
|
|||
|
|
|||
|
|
|||
|
RPC_ADDRESS *
|
|||
|
LrpcCreateRpcAddress (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We just to create a new LRPC_ADDRESS. This routine is a proxy for the
|
|||
|
new constructor to isolate the other modules.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
RPC_ADDRESS * RpcAddress;
|
|||
|
|
|||
|
RpcAddress = new LRPC_ADDRESS(&Status);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return(0);
|
|||
|
}
|
|||
|
return(RpcAddress);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
This private API was requested by KumarP from the LSA group on 04/05/2000.
|
|||
|
Here's his justification:
|
|||
|
|
|||
|
I am adding a new auditing feature to LSA that will allow any local process
|
|||
|
to make an rpc call to LSA and generate an arbitrary audit. To be able to
|
|||
|
make this call, the clients will first issue one call to get an audit-context
|
|||
|
handle from LSA. LSA will maintain a list of handles till the client
|
|||
|
explicitly closes the audit-context.
|
|||
|
|
|||
|
The reason I would like to have this API is to track which processes have
|
|||
|
opened audit-contexts. This will help in situations where there is a
|
|||
|
rogue/mal-functioning process that opens up a large number of audit-contexts.
|
|||
|
In this case, I should be able to break LSA into debugger and dump the context
|
|||
|
list and know which process has opened which handles. This may optionally
|
|||
|
allow me to prevent certain processes from calling this API (though currently
|
|||
|
there is no such requirement).
|
|||
|
|
|||
|
*/
|
|||
|
RPC_STATUS
|
|||
|
RPC_ENTRY
|
|||
|
I_RpcBindingInqLocalClientPID (
|
|||
|
IN RPC_BINDING_HANDLE Binding,
|
|||
|
OUT unsigned long *Pid
|
|||
|
)
|
|||
|
{
|
|||
|
LRPC_SCALL * Call;
|
|||
|
HANDLE LocalPid;
|
|||
|
|
|||
|
InitializeIfNecessary();
|
|||
|
|
|||
|
if (Binding == NULL)
|
|||
|
{
|
|||
|
Call = (LRPC_SCALL *) RpcpGetThreadContext();
|
|||
|
if (Call == NULL)
|
|||
|
return RPC_S_NO_CALL_ACTIVE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Call = (LRPC_SCALL *) Binding;
|
|||
|
}
|
|||
|
|
|||
|
if (Call->InvalidHandle(LRPC_SCALL_TYPE))
|
|||
|
return(RPC_S_INVALID_BINDING);
|
|||
|
|
|||
|
LocalPid = Call->InqLocalClientPID();
|
|||
|
|
|||
|
*Pid = HandleToUlong(LocalPid);
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
const SID AnonymousSid = { 1, 1, SECURITY_NT_AUTHORITY, SECURITY_ANONYMOUS_LOGON_RID};
|