7806 lines
217 KiB
C++
7806 lines
217 KiB
C++
/*++
|
||
|
||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||
|
||
Module Name:
|
||
|
||
osfsvr.cxx
|
||
|
||
Abstract:
|
||
|
||
This file contains the server side implementation of the OSF connection
|
||
oriented RPC protocol engine.
|
||
|
||
Author:
|
||
|
||
Michael Montague (mikemon) 17-Jul-1990
|
||
|
||
Revision History:
|
||
Mazhar Mohammed (mazharm) 2/1/97 major rehaul to support async
|
||
- Added support for Async RPC, Pipes
|
||
- Changed it to operate as a state machine
|
||
- Changed class structure
|
||
- Got rid of the TRANS classes
|
||
|
||
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 <wincrypt.h>
|
||
#include <rpcssl.h>
|
||
#include <thrdctx.hxx>
|
||
#include <hndlsvr.hxx>
|
||
#include <osfpcket.hxx>
|
||
#include <secsvr.hxx>
|
||
#include <osfsvr.hxx>
|
||
#include <sdict2.hxx>
|
||
#include <rpccfg.h>
|
||
#include <schnlsp.h> // for UNISP_RPC_ID
|
||
#include <charconv.hxx>
|
||
|
||
extern long GroupIdCounter;
|
||
|
||
// explicit placement new operator
|
||
inline
|
||
PVOID __cdecl
|
||
operator new(
|
||
size_t size,
|
||
PVOID pPlacement
|
||
)
|
||
{
|
||
return pPlacement;
|
||
}
|
||
|
||
|
||
OSF_ADDRESS::OSF_ADDRESS (
|
||
IN TRANS_INFO * RpcTransInfo,
|
||
IN OUT RPC_STATUS * Status
|
||
) : RPC_ADDRESS(Status)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
--*/
|
||
{
|
||
RPC_CONNECTION_TRANSPORT *RpcServerInfo =
|
||
(RPC_CONNECTION_TRANSPORT *) RpcTransInfo->InqTransInfo();
|
||
int i;
|
||
RPC_STATUS OriginalFailureStatus;
|
||
|
||
ObjectType = OSF_ADDRESS_TYPE;
|
||
ActiveCallCount = 0;
|
||
ServerListeningFlag = 0;
|
||
ServerInfo = RpcServerInfo;
|
||
TransInfo = RpcTransInfo;
|
||
SetupAddressOccurred = 0;
|
||
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)RpcServerInfo->TransId;
|
||
DebugCell->Status = desAllocated;
|
||
memset(DebugCell->EndpointName, 0, sizeof(DebugCell->EndpointName));
|
||
}
|
||
}
|
||
else
|
||
DebugCell = NULL;
|
||
|
||
#if defined(_WIN64)
|
||
ASSERT((MutexAllocationSize % 8) == 0);
|
||
#else
|
||
ASSERT((MutexAllocationSize % 4) == 0);
|
||
#endif
|
||
|
||
OriginalFailureStatus = RPC_S_OK;
|
||
for (i = 0; i < NumberOfAssociationsDictionaries; i ++)
|
||
{
|
||
// explicit placement
|
||
new (GetAssociationBucketMutex(i)) MUTEX (Status,
|
||
TRUE // pre-allocate semaphores
|
||
);
|
||
|
||
// if there is a failure, remember it, so that subsequent successes
|
||
// don't overwrite the failure
|
||
if ((*Status != RPC_S_OK) && (OriginalFailureStatus == RPC_S_OK))
|
||
{
|
||
OriginalFailureStatus = *Status;
|
||
}
|
||
|
||
// don't check the status - the constructors will
|
||
// check it. Also, we need to invoke all constructors
|
||
// to give them a chance to initialize enough of the
|
||
// object so that it can be destroyed properly
|
||
}
|
||
|
||
if (OriginalFailureStatus != RPC_S_OK)
|
||
*Status = OriginalFailureStatus;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_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:
|
||
|
||
At this point, we need to setup the loadable transport interface.
|
||
We also need to obtain the network address for this server. After
|
||
allocating a buffer to hold the network address, we will call
|
||
the loadable transport interface to let it do its thing.
|
||
|
||
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. Whether or not this is suppored depends
|
||
on the particular combination of transport interface and operating
|
||
system.
|
||
|
||
PendingQueueSize - Supplies the size of the queue of pending
|
||
requests which should be created by the transport. Some transports
|
||
will not be able to make use of this value, while others will.
|
||
|
||
RpcProtocolSequence - Supplies the protocol sequence for which we
|
||
are trying to setup an address. This argument is necessary so
|
||
that a single transport interface dll can support more than one
|
||
protocol sequence.
|
||
|
||
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.
|
||
|
||
--*/
|
||
{
|
||
|
||
RPC_STATUS Status;
|
||
|
||
Status = ServerInfo->Listen(InqRpcTransportAddress(),
|
||
NetworkAddress,
|
||
Endpoint,
|
||
PendingQueueSize,
|
||
SecurityDescriptor,
|
||
EndpointFlags,
|
||
NICFlags,
|
||
ppNetworkAddressVector);
|
||
|
||
if ( Status == RPC_S_OK )
|
||
{
|
||
SetupAddressOccurred = 1;
|
||
}
|
||
|
||
VALIDATE(Status)
|
||
{
|
||
RPC_S_OK,
|
||
RPC_S_INVALID_SECURITY_DESC,
|
||
RPC_S_INVALID_ARG,
|
||
RPC_S_CANT_CREATE_ENDPOINT,
|
||
RPC_S_INVALID_ENDPOINT_FORMAT,
|
||
RPC_S_OUT_OF_RESOURCES,
|
||
RPC_S_PROTSEQ_NOT_SUPPORTED,
|
||
RPC_S_DUPLICATE_ENDPOINT,
|
||
RPC_S_OUT_OF_MEMORY,
|
||
RPC_S_SERVER_UNAVAILABLE
|
||
} END_VALIDATE;
|
||
|
||
return(Status);
|
||
}
|
||
|
||
#ifndef NO_PLUG_AND_PLAY
|
||
|
||
void
|
||
OSF_ADDRESS::PnpNotify (
|
||
)
|
||
{
|
||
ServerInfo->PnpNotify();
|
||
}
|
||
#endif
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_ADDRESS::CompleteListen (
|
||
)
|
||
/*++
|
||
Function Name:CompleteListen
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
if (ServerInfo->CompleteListen != 0)
|
||
{
|
||
ServerInfo->CompleteListen(InqRpcTransportAddress());
|
||
}
|
||
|
||
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 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;
|
||
}
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_ADDRESS::ServerStartingToListen (
|
||
IN unsigned int MinimumCallThreads,
|
||
IN unsigned int MaximumConcurrentCalls
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
MinimumCallThreads - Supplies the minimum number of threads to have
|
||
available to receive remote procedure calls.
|
||
|
||
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 least the minimum number of call threads required (as
|
||
specified by the MinimumCallThreads argument).
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
|
||
UNUSED(MaximumConcurrentCalls);
|
||
UNUSED(MinimumCallThreads);
|
||
|
||
Status = TransInfo->StartServerIfNecessary();
|
||
if (Status == RPC_S_OK)
|
||
{
|
||
ServerListeningFlag = 1;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
OSF_ADDRESS::~OSF_ADDRESS (
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
We need to clean up the address after it has been partially
|
||
initialized. This routine will only be called before FireUpManager
|
||
is called, but it may have been called before or after one of
|
||
SetupAddressWithEndpoint or SetupAddressUnknownEndpoint is called.
|
||
We will keep track of whether or not SetupAddress* occurred
|
||
successfully; if so, we need to call AbortSetupAddress to give the
|
||
loadable transport module a chance to clean things up.
|
||
|
||
--*/
|
||
{
|
||
int i;
|
||
if (SetupAddressOccurred != 0)
|
||
ServerInfo->AbortListen(InqRpcTransportAddress());
|
||
|
||
for (i = 0; i < NumberOfAssociationsDictionaries; i ++)
|
||
{
|
||
GetAssociationBucketMutex(i)->Free();
|
||
}
|
||
|
||
if (DebugCell != NULL)
|
||
{
|
||
FreeCell(DebugCell, &DebugCellTag);
|
||
}
|
||
}
|
||
|
||
|
||
OSF_SCONNECTION *
|
||
OSF_ADDRESS::NewConnection (
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
We will create a new connection which belongs to this address.
|
||
|
||
Arguments:
|
||
|
||
ConnectionKey - Supplies the connection key specified for this
|
||
connection by the loadable transport.
|
||
|
||
Return Value:
|
||
|
||
The new connection will be returned unless insufficient memory
|
||
is available, in which case, zero will be returned.
|
||
|
||
--*/
|
||
{
|
||
OSF_SCONNECTION * SConnection;
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
|
||
SConnection = new (ServerInfo->ServerConnectionSize)
|
||
OSF_SCONNECTION (
|
||
this,
|
||
ServerInfo,
|
||
&Status);
|
||
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
//
|
||
// Server serverinfo to 0, so it doesn't call close
|
||
//
|
||
SConnection->ServerInfo = 0;
|
||
|
||
delete SConnection;
|
||
SConnection = 0;
|
||
}
|
||
|
||
if ( SConnection == 0 )
|
||
{
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
// Add a reference for the receive that is going to be posted by the
|
||
// transport
|
||
//
|
||
SConnection->AddReference(); // CONN++
|
||
|
||
return(SConnection);
|
||
}
|
||
|
||
unsigned int
|
||
OSF_ADDRESS::TransSecondarySize (
|
||
)
|
||
{
|
||
unsigned int Length = RpcpStringLength(InqEndpoint()) + 1;
|
||
|
||
// Will be converted to ANSI in the wire, no need to multiply by
|
||
// sizeof(RPC_CHAR).
|
||
|
||
return(Length);
|
||
}
|
||
|
||
RPC_STATUS
|
||
OSF_ADDRESS::TransSecondary (
|
||
IN unsigned char * Address,
|
||
IN unsigned int AddressLength
|
||
)
|
||
{
|
||
RPC_STATUS Status;
|
||
unsigned char *AnsiAddress;
|
||
|
||
AnsiAddress = UnicodeToAnsiString(InqEndpoint(),&Status);
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
ASSERT(Status == RPC_S_OUT_OF_MEMORY);
|
||
ASSERT(AnsiAddress == 0);
|
||
return Status;
|
||
}
|
||
|
||
RpcpMemoryCopy(Address,AnsiAddress,AddressLength);
|
||
|
||
delete AnsiAddress;
|
||
|
||
return (RPC_S_OK);
|
||
}
|
||
|
||
|
||
void
|
||
OSF_ADDRESS::ServerStoppedListening (
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
We just need to indicate that the server is no longer listening, and
|
||
set the minimum call threads to one.
|
||
|
||
--*/
|
||
{
|
||
ServerListeningFlag = 0;
|
||
}
|
||
|
||
OSF_ASSOCIATION *
|
||
OSF_ADDRESS::RemoveAssociation (
|
||
IN int Key,
|
||
IN OSF_ASSOCIATION *pAssociation
|
||
)
|
||
{
|
||
int HashBucketNumber;
|
||
OSF_ASSOCIATION *pAssociationRemoved;
|
||
|
||
AddressMutex.VerifyNotOwned();
|
||
|
||
HashBucketNumber = GetHashBucketForAssociation(pAssociation->AssocGroupId());
|
||
// verify the the bucket is locked
|
||
GetAssociationBucketMutex(HashBucketNumber)->VerifyOwned();
|
||
|
||
pAssociationRemoved = Associations[HashBucketNumber].Delete(Key);
|
||
|
||
return pAssociationRemoved;
|
||
}
|
||
|
||
int
|
||
OSF_ADDRESS::AddAssociation (
|
||
IN OSF_ASSOCIATION * TheAssociation
|
||
)
|
||
{
|
||
int HashBucketNumber;
|
||
int Key;
|
||
|
||
HashBucketNumber = GetHashBucketForAssociation(TheAssociation->AssocGroupId());
|
||
|
||
AddressMutex.VerifyNotOwned();
|
||
|
||
// lock the bucket
|
||
GetAssociationBucketMutex(HashBucketNumber)->Request();
|
||
Key = Associations[HashBucketNumber].Insert(TheAssociation);
|
||
// unlock the bucket
|
||
GetAssociationBucketMutex(HashBucketNumber)->Clear();
|
||
return Key;
|
||
}
|
||
|
||
OSF_ASSOCIATION *
|
||
OSF_ADDRESS::FindAssociation (
|
||
IN unsigned long AssociationGroupId,
|
||
IN RPC_CLIENT_PROCESS_IDENTIFIER * ClientProcess
|
||
)
|
||
// The AddressMutex has already been requested.
|
||
{
|
||
DictionaryCursor cursor;
|
||
OSF_ASSOCIATION * Association;
|
||
OSF_ASSOCIATION_DICT *pAssocDict;
|
||
int HashBucketNumber;
|
||
|
||
// get the hashed bucket
|
||
HashBucketNumber = GetHashBucketForAssociation(AssociationGroupId);
|
||
pAssocDict = &Associations[HashBucketNumber];
|
||
|
||
AddressMutex.VerifyNotOwned();
|
||
|
||
// lock the bucket
|
||
GetAssociationBucketMutex(HashBucketNumber)->Request();
|
||
// lookup the association in the bucket
|
||
pAssocDict->Reset(cursor);
|
||
while ( (Association = pAssocDict->Next(cursor)) != 0 )
|
||
{
|
||
if ( Association->IsMyAssocGroupId(AssociationGroupId,
|
||
ClientProcess) != 0 )
|
||
{
|
||
Association->AddConnection();
|
||
GetAssociationBucketMutex(HashBucketNumber)->Clear();
|
||
return(Association);
|
||
}
|
||
}
|
||
|
||
// unlock the bucket
|
||
GetAssociationBucketMutex(HashBucketNumber)->Clear();
|
||
return(0);
|
||
}
|
||
|
||
void
|
||
OSF_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 fo context handle destruction for the connection
|
||
oriented protocols. 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:
|
||
|
||
--*/
|
||
{
|
||
int i;
|
||
MUTEX *CurrentBucketMutex;
|
||
DictionaryCursor cursor;
|
||
OSF_ASSOCIATION_DICT *CurrentAssocDict;
|
||
OSF_ASSOCIATION *CurrentAssociation;
|
||
BOOL CopyOfDictionaryUsed;
|
||
OSF_ASSOCIATION_DICT AssocDictCopy;
|
||
OSF_ASSOCIATION_DICT *AssocDictToUse;
|
||
BOOL Res;
|
||
|
||
// N.B. We may or we may not own the ServerMutex here - be prepared
|
||
// for both occasions. The first implication is not to call functions
|
||
// that take the server mutex.
|
||
|
||
for (i = 0; i < NumberOfAssociationsDictionaries; i ++)
|
||
{
|
||
CurrentBucketMutex = GetAssociationBucketMutex(i);
|
||
|
||
CurrentBucketMutex->Request();
|
||
|
||
CurrentAssocDict = &Associations[i];
|
||
CopyOfDictionaryUsed = AssocDictCopy.ExpandToSize(CurrentAssocDict->Size());
|
||
if (CopyOfDictionaryUsed)
|
||
{
|
||
CurrentAssocDict->Reset(cursor);
|
||
while ( (CurrentAssociation = CurrentAssocDict->Next(cursor)) != 0 )
|
||
{
|
||
Res = AssocDictCopy.Insert(CurrentAssociation);
|
||
ASSERT(Res != -1);
|
||
// artifically add a connection count to keep it alive
|
||
// while we destroy the contexts
|
||
CurrentAssociation->AddConnection();
|
||
}
|
||
CurrentBucketMutex->Clear();
|
||
AssocDictToUse = &AssocDictCopy;
|
||
}
|
||
else
|
||
{
|
||
AssocDictToUse = CurrentAssocDict;
|
||
}
|
||
|
||
AssocDictToUse->Reset(cursor);
|
||
while ( (CurrentAssociation = AssocDictToUse->Next(cursor)) != 0 )
|
||
{
|
||
// call into the association to destroy the context handles
|
||
CurrentAssociation->DestroyContextHandlesForInterface(
|
||
RpcInterfaceInformation,
|
||
RundownContextHandles);
|
||
}
|
||
|
||
if (CopyOfDictionaryUsed)
|
||
{
|
||
while ( (CurrentAssociation = AssocDictCopy.Next(cursor)) != 0 )
|
||
{
|
||
// remove the extra refcounts
|
||
CurrentAssociation->RemoveConnection();
|
||
}
|
||
AssocDictCopy.DeleteAll();
|
||
}
|
||
else
|
||
{
|
||
CurrentBucketMutex->Clear();
|
||
}
|
||
}
|
||
}
|
||
|
||
OSF_SBINDING::OSF_SBINDING ( // Constructor.
|
||
IN RPC_INTERFACE * TheInterface,
|
||
IN int PContext,
|
||
IN int SelectedTransferSyntaxIndex
|
||
)
|
||
{
|
||
PresentContext = PContext;
|
||
Interface = TheInterface;
|
||
SequenceNumber = 0;
|
||
CurrentSecId = -1;
|
||
this->SelectedTransferSyntaxIndex = SelectedTransferSyntaxIndex;
|
||
}
|
||
|
||
|
||
OSF_SCALL::OSF_SCALL (
|
||
IN OSF_SCONNECTION *Connection,
|
||
IN OUT RPC_STATUS *Status
|
||
) : CallMutex(Status), SyncEvent(Status, 0)
|
||
{
|
||
ObjectType = OSF_SCALL_TYPE;
|
||
Thread = 0;
|
||
CallOrphaned = 0;
|
||
CancelPending = 0;
|
||
SavedHeader = 0;
|
||
SavedHeaderSize = 0;
|
||
|
||
this->Connection = Connection;
|
||
SendContext = (char *) this+sizeof(OSF_SCALL);
|
||
SetReferenceCount(0);
|
||
|
||
if (IsServerSideDebugInfoEnabled())
|
||
{
|
||
if (*Status != RPC_S_OK)
|
||
{
|
||
DebugCell = NULL;
|
||
return;
|
||
}
|
||
|
||
DebugCell = (DebugCallInfo *)AllocateCell(&CellTag);
|
||
if (DebugCell == NULL)
|
||
*Status = RPC_S_OUT_OF_MEMORY;
|
||
else
|
||
{
|
||
memset(DebugCell, 0, sizeof(DebugCallInfo));
|
||
DebugCell->Type = dctCallInfo;
|
||
DebugCell->Status = (BYTE)csAllocated;
|
||
GetDebugCellIDFromDebugCell((DebugCellUnion *)Connection->DebugCell,
|
||
&Connection->DebugCellTag, &DebugCell->Connection);
|
||
DebugCell->LastUpdateTime = NtGetTickCount();
|
||
// if this is the call for the connection,
|
||
// it will be NULL. If this is a subsequent
|
||
// call on the connection, the CachedSCall would
|
||
// have been set already.
|
||
if (Connection->CachedSCall == NULL)
|
||
DebugCell->CallFlags = DBGCELL_CACHED_CALL;
|
||
}
|
||
}
|
||
else
|
||
DebugCell = NULL;
|
||
|
||
//
|
||
// we don't need to initialize ObjectUuidSpecified, ActualBufferLength,
|
||
// FirstFrag and Alertcount
|
||
//
|
||
}
|
||
|
||
|
||
OSF_SCALL::~OSF_SCALL (
|
||
)
|
||
{
|
||
if (SavedHeader != 0)
|
||
{
|
||
ASSERT(SavedHeaderSize != 0) ;
|
||
RpcpFarFree(SavedHeader);
|
||
}
|
||
|
||
if (DebugCell != NULL)
|
||
{
|
||
FreeCell(DebugCell, &CellTag);
|
||
}
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCALL::InquireObjectUuid (
|
||
OUT RPC_UUID * ObjectUuid
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine copies the object uuid from the server connection into
|
||
the supplied ObjectUuid argument.
|
||
|
||
Arguments:
|
||
|
||
ObjectUuid - Returns a copy of the object uuid in the server connection.
|
||
|
||
--*/
|
||
{
|
||
if (ObjectUuidSpecified == 0)
|
||
ObjectUuid->SetToNullUuid();
|
||
else
|
||
ObjectUuid->CopyUuid(&(this->ObjectUuid));
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCALL::SendFault (
|
||
IN RPC_STATUS Status,
|
||
IN int DidNotExecute
|
||
)
|
||
{
|
||
p_context_id_t p_cont = 0;
|
||
|
||
if (CurrentBinding)
|
||
p_cont = (p_context_id_t)CurrentBinding->GetPresentationContext();
|
||
|
||
Connection->SendFault(Status, DidNotExecute, CallId, p_cont);
|
||
}
|
||
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::SendReceive (
|
||
IN OUT PRPC_MESSAGE Message
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Message - Supplies the request to send to the server and returns the
|
||
response received from the server.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - We successfully sent a remote procedure call request to the
|
||
server and received back a response.
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status, ExceptionCode;
|
||
unsigned int RemoteFaultOccured = 0;
|
||
RPC_MESSAGE RpcMessage ;
|
||
RPC_RUNTIME_INFO RuntimeInfo ;
|
||
PRPC_DISPATCH_TABLE DispatchTableToUse;
|
||
|
||
if (CurrentState == CallAborted)
|
||
{
|
||
return RPC_S_CALL_FAILED;
|
||
}
|
||
|
||
CallStack += 1;
|
||
Address->Server->OutgoingCallback();
|
||
FirstFrag = 1;
|
||
|
||
SyncEvent.Lower();
|
||
|
||
Status = SendRequestOrResponse(Message, rpc_request);
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
CallStack -= 1;
|
||
return Status;
|
||
}
|
||
|
||
for (;TRUE;)
|
||
{
|
||
if (CurrentState == CallAborted)
|
||
{
|
||
Status = RPC_S_CALL_FAILED;
|
||
break;
|
||
}
|
||
//
|
||
// In the callback case, when the receive event is kicked,
|
||
// we have either received a fault or we have received a complete
|
||
// response/request
|
||
//
|
||
SyncEvent.Wait();
|
||
|
||
switch (CurrentState)
|
||
{
|
||
case ReceivedCallback:
|
||
//
|
||
// Just received a new callback,
|
||
// need to dispatch it
|
||
//
|
||
|
||
RuntimeInfo.Length = sizeof(RPC_RUNTIME_INFO) ;
|
||
|
||
RpcMessage.Handle = (RPC_BINDING_HANDLE) this;
|
||
RpcMessage.Buffer = DispatchBuffer ;
|
||
RpcMessage.BufferLength = DispatchBufferOffset;
|
||
RpcMessage.RpcFlags = RPC_BUFFER_COMPLETE;
|
||
RpcMessage.DataRepresentation = Connection->DataRep;
|
||
RpcMessage.ReservedForRuntime = &RuntimeInfo ;
|
||
CurrentBinding->GetSelectedTransferSyntaxAndDispatchTable(
|
||
&RpcMessage.TransferSyntax, &DispatchTableToUse);
|
||
RpcMessage.ProcNum = ProcNum;
|
||
|
||
|
||
//
|
||
// Dispatch the callback
|
||
//
|
||
if ( ObjectUuidSpecified != 0 )
|
||
{
|
||
Status = CurrentBinding->GetInterface()
|
||
->DispatchToStubWithObject(
|
||
&RpcMessage,
|
||
&ObjectUuid,
|
||
1,
|
||
DispatchTableToUse,
|
||
&ExceptionCode);
|
||
}
|
||
else
|
||
{
|
||
Status = CurrentBinding->GetInterface()
|
||
->DispatchToStub(
|
||
&RpcMessage,
|
||
1,
|
||
DispatchTableToUse,
|
||
&ExceptionCode);
|
||
}
|
||
|
||
//
|
||
// Send the reponse
|
||
//
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
|
||
VALIDATE(Status)
|
||
{
|
||
RPC_P_EXCEPTION_OCCURED,
|
||
RPC_S_PROCNUM_OUT_OF_RANGE
|
||
} END_VALIDATE;
|
||
|
||
if ( Status == RPC_S_PROCNUM_OUT_OF_RANGE )
|
||
{
|
||
SendFault(RPC_S_PROCNUM_OUT_OF_RANGE, 1);
|
||
}
|
||
else
|
||
{
|
||
SendFault(ExceptionCode, 0);
|
||
Status = ExceptionCode;
|
||
}
|
||
|
||
continue;
|
||
}
|
||
|
||
FirstFrag = 1;
|
||
Status = SendRequestOrResponse(&RpcMessage, rpc_response);
|
||
if ( Status == RPC_S_CALL_FAILED_DNE )
|
||
{
|
||
Status = RPC_S_CALL_FAILED;
|
||
}
|
||
|
||
//
|
||
// if the client went away, it is wise to simple go away
|
||
//
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Go back to waiting for our original reply
|
||
//
|
||
continue;
|
||
|
||
case ReceivedCallbackReply:
|
||
//
|
||
// Received a reply to our callback
|
||
// need to return to the caller with the reply
|
||
//
|
||
Message->Buffer = DispatchBuffer;
|
||
Message->BufferLength = DispatchBufferOffset;
|
||
Message->DataRepresentation = Connection->DataRep;
|
||
Status = RPC_S_OK;
|
||
break;
|
||
|
||
case ReceivedFault:
|
||
//
|
||
// Received a fault, fail the call / propagate status
|
||
// code
|
||
//
|
||
Status = AsyncStatus;
|
||
break;
|
||
|
||
case CallAborted:
|
||
//
|
||
// Call aborted, possibly because
|
||
//
|
||
Status = RPC_S_CALL_FAILED;
|
||
break;
|
||
|
||
default:
|
||
//
|
||
// Something bad happened, go back to looking
|
||
ASSERT(0);
|
||
}
|
||
break;
|
||
}
|
||
|
||
//
|
||
// We need this so the response to the original call can be sent
|
||
// correctly.
|
||
//
|
||
FirstFrag = 1;
|
||
|
||
CallStack -= 1;
|
||
|
||
if ( Status == RPC_S_OK )
|
||
{
|
||
Message->Handle = (RPC_BINDING_HANDLE) this;
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
RPC_STATUS
|
||
OSF_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;
|
||
|
||
CurrentBinding->GetSelectedTransferSyntaxAndDispatchTable(&Message->TransferSyntax,
|
||
&Ignored);
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::GetBuffer (
|
||
IN OUT PRPC_MESSAGE Message,
|
||
IN UUID *ObjectUuid
|
||
)
|
||
{
|
||
ULONG BufferLengthToAllocate;
|
||
|
||
Message->Handle = (RPC_BINDING_HANDLE) this;
|
||
|
||
if (Message->RpcFlags & RPC_BUFFER_PARTIAL &&
|
||
Message->BufferLength < Connection->MaxFrag)
|
||
{
|
||
ActualBufferLength = Connection->MaxFrag ;
|
||
}
|
||
else
|
||
{
|
||
ActualBufferLength = Message->BufferLength ;
|
||
}
|
||
|
||
// In addition to saving space for the request (or response) header,
|
||
// we want to save space for security information if necessary.
|
||
BufferLengthToAllocate = ActualBufferLength
|
||
+ sizeof(rpcconn_request)
|
||
+ (2* Connection->AdditionalSpaceForSecurity);
|
||
|
||
if (TransGetBuffer(&Message->Buffer, BufferLengthToAllocate))
|
||
{
|
||
ActualBufferLength = 0 ;
|
||
RpcpErrorAddRecord(EEInfoGCRuntime,
|
||
RPC_S_OUT_OF_MEMORY,
|
||
EEInfoDLOSF_SCALL__GetBuffer10,
|
||
BufferLengthToAllocate);
|
||
return(RPC_S_OUT_OF_MEMORY);
|
||
}
|
||
|
||
Message->Buffer = (unsigned char *) Message->Buffer
|
||
+ sizeof(rpcconn_request);
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::GetBufferDo (
|
||
OUT void ** ppBuffer,
|
||
IN unsigned int culRequiredLength,
|
||
IN BOOL fDataValid,
|
||
IN unsigned int DataLength,
|
||
IN unsigned long Extra
|
||
)
|
||
{
|
||
void *NewBuffer;
|
||
|
||
if (TransGetBuffer(&NewBuffer,
|
||
culRequiredLength + sizeof(rpcconn_request)))
|
||
{
|
||
return(RPC_S_OUT_OF_MEMORY);
|
||
}
|
||
|
||
if (fDataValid)
|
||
{
|
||
ASSERT(DataLength < culRequiredLength);
|
||
|
||
NewBuffer = (unsigned char *) NewBuffer + sizeof(rpcconn_request);
|
||
|
||
RpcpMemoryCopy(NewBuffer, *ppBuffer, DataLength);
|
||
|
||
TransFreeBuffer((unsigned char *) *ppBuffer-sizeof(rpcconn_request));
|
||
*ppBuffer = NewBuffer;
|
||
}
|
||
else
|
||
{
|
||
*ppBuffer = (unsigned char *) NewBuffer + sizeof(rpcconn_request);
|
||
}
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCALL::FreeBufferDo (
|
||
IN void *pBuffer
|
||
)
|
||
{
|
||
#if DBG
|
||
if (pBuffer == DispatchBuffer)
|
||
{
|
||
LogEvent(SU_SCALL, EV_DELETE, this, pBuffer, 1, 1);
|
||
}
|
||
#endif
|
||
TransFreeBuffer((unsigned char *) pBuffer - sizeof(rpcconn_request));
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCALL::FreeBuffer (
|
||
IN PRPC_MESSAGE Message
|
||
)
|
||
{
|
||
TransFreeBuffer((unsigned char *) Message->Buffer
|
||
- sizeof(rpcconn_request));
|
||
ActualBufferLength = 0;
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCALL::FreePipeBuffer (
|
||
IN PRPC_MESSAGE Message
|
||
)
|
||
{
|
||
TransFreeBuffer((unsigned char *) Message->Buffer
|
||
- sizeof(rpcconn_request));
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::ReallocPipeBuffer (
|
||
IN PRPC_MESSAGE Message,
|
||
IN unsigned int NewSize
|
||
)
|
||
{
|
||
void *TempBuffer ;
|
||
RPC_STATUS Status ;
|
||
unsigned int SizeToAlloc ;
|
||
|
||
if (NewSize > ActualBufferLength)
|
||
{
|
||
SizeToAlloc = (NewSize > Connection->MaxFrag) ?
|
||
NewSize:Connection->MaxFrag ;
|
||
|
||
Status = TransGetBuffer(&TempBuffer,
|
||
SizeToAlloc + sizeof(rpcconn_request) + sizeof(UUID)
|
||
+ (2* Connection->AdditionalSpaceForSecurity) );
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
ASSERT( Status == RPC_S_OUT_OF_MEMORY );
|
||
return(RPC_S_OUT_OF_MEMORY);
|
||
}
|
||
|
||
if (ActualBufferLength > 0)
|
||
{
|
||
RpcpMemoryCopy((char *) TempBuffer+sizeof(rpcconn_request),
|
||
Message->Buffer, Message->BufferLength) ;
|
||
OSF_SCALL::FreePipeBuffer(Message) ;
|
||
}
|
||
|
||
Message->Buffer = (char *) TempBuffer + sizeof(rpcconn_request);
|
||
ActualBufferLength = SizeToAlloc ;
|
||
}
|
||
|
||
Message->BufferLength = NewSize ;
|
||
|
||
return (RPC_S_OK) ;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::TransGetBuffer (
|
||
OUT void * * Buffer,
|
||
IN unsigned int BufferLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
We need a buffer to receive data into or to put data into to be sent.
|
||
This should be really simple, but we need to make sure that buffer we
|
||
return is aligned on an 8 byte boundary. The stubs make this requirement.
|
||
|
||
Arguments:
|
||
|
||
Buffer - Returns a pointer to the buffer.
|
||
|
||
BufferLength - Supplies the required length of the buffer in bytes.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - We successfully allocated a buffer of at least the required
|
||
size.
|
||
|
||
RPC_S_OUT_OF_MEMORY - There is insufficient memory available to allocate
|
||
the required buffer.
|
||
|
||
--*/
|
||
{
|
||
void *Memory;
|
||
|
||
//
|
||
// The NT memory allocator returns memory which is aligned by at least
|
||
// 8, so we dont need to worry about aligning it.
|
||
//
|
||
Memory = CoAllocateBuffer(BufferLength);
|
||
if ( Memory == 0 )
|
||
{
|
||
return(RPC_S_OUT_OF_MEMORY);
|
||
}
|
||
|
||
ASSERT( IsBufferAligned(Memory) );
|
||
|
||
*Buffer = Memory;
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCALL::TransFreeBuffer (
|
||
IN void * Buffer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
We need to free a buffer which was allocated via TransGetBuffer. The
|
||
only tricky part is remembering to remove the padding before actually
|
||
freeing the memory.
|
||
|
||
--*/
|
||
{
|
||
CoFreeBuffer(Buffer);
|
||
}
|
||
|
||
|
||
BOOL
|
||
OSF_SCALL::BeginRpcCall (
|
||
IN rpcconn_common * Packet,
|
||
IN unsigned int PacketLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Packet - Supplies the packet we received from the connection. Ownership
|
||
of this buffer passes to this routine.
|
||
|
||
PacketLength - Supplies the length of the packet in bytes.
|
||
|
||
Return Value:
|
||
|
||
A non-zero return value indicates that the connection should not
|
||
be placed in the receive any state; instead, the thread should just
|
||
forget about the connection and go back to waiting for more new
|
||
procedure calls.
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
unsigned long SizeofHeaderToSave = 0;
|
||
int retval ;
|
||
BOOL fReceivePosted;
|
||
unsigned int HeaderSize = sizeof(rpcconn_request);
|
||
THREAD *ThisThread;
|
||
|
||
ActivateCall();
|
||
|
||
//
|
||
// Save the unbyteswapped header for the security related stuff
|
||
// Especially if SECURITY is on. For Request/Resonse we save just
|
||
// the greater of rpc_req or rpc_resp. We havent byteswapped anything..
|
||
// but if auth_length is 0, byteswapping is irrelevant..
|
||
//
|
||
if (Packet->auth_length != 0)
|
||
{
|
||
if ((Packet->PTYPE == rpc_request) || (Packet->PTYPE == rpc_response))
|
||
{
|
||
SizeofHeaderToSave = sizeof(rpcconn_request);
|
||
if ( (Packet->pfc_flags & PFC_OBJECT_UUID) != 0 )
|
||
{
|
||
SizeofHeaderToSave += sizeof(UUID);
|
||
}
|
||
}
|
||
|
||
if (SavedHeaderSize < SizeofHeaderToSave)
|
||
{
|
||
if (SavedHeader != 0)
|
||
{
|
||
ASSERT(SavedHeaderSize != 0);
|
||
RpcpFarFree(SavedHeader);
|
||
}
|
||
|
||
SavedHeader = RpcpFarAllocate(SizeofHeaderToSave);
|
||
if (SavedHeader == 0)
|
||
{
|
||
Status = RPC_S_PROTOCOL_ERROR;
|
||
goto Cleanup;
|
||
}
|
||
|
||
SavedHeaderSize = SizeofHeaderToSave;
|
||
RpcpMemoryCopy(SavedHeader, Packet, SizeofHeaderToSave);
|
||
}
|
||
else if (SizeofHeaderToSave != 0)
|
||
{
|
||
RpcpMemoryCopy(SavedHeader, Packet, SizeofHeaderToSave);
|
||
}
|
||
}
|
||
|
||
if (Packet->pfc_flags & PFC_PENDING_CANCEL)
|
||
{
|
||
RpcCancelThread(GetCurrentThread());
|
||
}
|
||
|
||
Status = ValidatePacket(Packet, PacketLength);
|
||
|
||
CallId = Packet->call_id;
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
ASSERT(Status == RPC_S_PROTOCOL_ERROR);
|
||
|
||
//
|
||
// It is not the first packet, so we need to send a fault instead,
|
||
// and then we will blow the connection away.
|
||
//
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// We need to figure out about security: do we need to put authentication
|
||
// information into each packet, and if so, how much space should we
|
||
// reserve. When we allocated the buffer (see OSF_SCALL::GetBuffer)
|
||
// we saved space for security information. We did so we could just
|
||
// stick the authentication information into there without having to
|
||
// copy anything
|
||
//
|
||
|
||
if (Connection->AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
|
||
{
|
||
ASSERT(Connection->AdditionalSpaceForSecurity >=
|
||
MAXIMUM_SECURITY_BLOCK_SIZE);
|
||
|
||
MaxSecuritySize = Connection->AdditionalSpaceForSecurity
|
||
- MAXIMUM_SECURITY_BLOCK_SIZE;
|
||
|
||
if (MaxSecuritySize == sizeof(sec_trailer))
|
||
{
|
||
MaxSecuritySize = 0;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// We need to arrange things so that the length of the stub data
|
||
// is a multiple of MAXIMUM_SECURITY_BLOCK_SIZE:
|
||
// this is a requirement of the security package.
|
||
//
|
||
MaximumFragmentLength -= ((MaximumFragmentLength - HeaderSize
|
||
- MaxSecuritySize) % MAXIMUM_SECURITY_BLOCK_SIZE);
|
||
}
|
||
}
|
||
|
||
|
||
ASSERT(Packet->PTYPE == rpc_request);
|
||
|
||
CurrentBinding = Connection->LookupBinding(
|
||
((rpcconn_request *) Packet)->p_cont_id);
|
||
if (CurrentBinding)
|
||
{
|
||
RPC_INTERFACE *CurrentInterface = CurrentBinding->GetInterface();
|
||
|
||
ASSERT(CurrentState == NewRequest);
|
||
|
||
//
|
||
// Check the security callback on this connection
|
||
// - If IF does not require a security callback, just dispatch
|
||
// - If IF requires a callback and current call is insecure - send a fault
|
||
// and fail the call
|
||
// - If IF requires a callback, have the binding confirm that for this id
|
||
// we did callback once before
|
||
// - If we never did callback.. ever, SBinding->CheckSecurity will force
|
||
// a security callback
|
||
if (CurrentInterface->IsSecurityCallbackReqd() != 0)
|
||
{
|
||
if (Connection->CurrentSecurityContext == 0)
|
||
{
|
||
Status = RPC_S_ACCESS_DENIED;
|
||
goto Cleanup;
|
||
}
|
||
|
||
Status = Connection->CurrentSecurityContext->CheckForFailedThirdLeg();
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
|
||
ASSERT(Connection->CurrentSecurityContext->FullyConstructed() );
|
||
|
||
ThisThread = RpcpGetThreadPointer();
|
||
|
||
// set the current context for this thread so that the app
|
||
// can use the security callback. We'll whack it afterwards
|
||
// as the actual call may not get dispatched on this thread
|
||
RpcpSetThreadContextWithThread(ThisThread, this);
|
||
|
||
Status = CurrentBinding->CheckSecurity(this,
|
||
Connection->CurrentSecurityContext->AuthContextId);
|
||
|
||
RpcpSetThreadContextWithThread(ThisThread, 0);
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
fSecurityFailure = 1;
|
||
|
||
if (Packet->pfc_flags & PFC_LAST_FRAG)
|
||
{
|
||
Status = RPC_S_ACCESS_DENIED;
|
||
Connection->CleanupPac();
|
||
goto Cleanup;
|
||
}
|
||
|
||
SendFault(RPC_S_ACCESS_DENIED, 1);
|
||
|
||
Connection->TransFreeBuffer(Packet);
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
if (CurrentInterface->IsPipeInterface())
|
||
{
|
||
fPipeCall = 1;
|
||
if (DebugCell)
|
||
{
|
||
DebugCell->CallFlags |= DBGCELL_PIPE_CALL;
|
||
}
|
||
}
|
||
|
||
if (CurrentInterface->IsAutoListenInterface())
|
||
{
|
||
CurrentInterface->BeginAutoListenCall();
|
||
}
|
||
|
||
fReceivePosted = ProcessReceivedPDU(Packet, PacketLength, 1);
|
||
|
||
return fReceivePosted;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// We did not find a binding, which indicates the client tried
|
||
// to make a remote procedure call on an unknown interface.
|
||
//
|
||
Status = RPC_S_UNKNOWN_IF;
|
||
}
|
||
|
||
Cleanup:
|
||
Connection->TransFreeBuffer(Packet);
|
||
|
||
//
|
||
// No one else can come in until we post the next receive,
|
||
// so it is ok to send the fault before making the call
|
||
// available
|
||
//
|
||
SendFault(Status,1);
|
||
|
||
if (Status != RPC_S_UNKNOWN_IF)
|
||
{
|
||
Connection->fDontFlush = (CurrentState == NewRequest);
|
||
|
||
//
|
||
// We are going to kill the connection, do't post another receive
|
||
//
|
||
fReceivePosted = 1;
|
||
|
||
Connection->OSF_SCONNECTION::Delete();
|
||
}
|
||
else
|
||
{
|
||
fReceivePosted = 0;
|
||
}
|
||
|
||
//
|
||
// If the call has not been dispatched yet, DispatchBuffer needs to be freed
|
||
//
|
||
ASSERT(fCallDispatched == 0);
|
||
ASSERT(DispatchBuffer == 0);
|
||
|
||
if (Connection->fExclusive)
|
||
{
|
||
DeactivateCall();
|
||
Connection->CachedSCallAvailable = 1;
|
||
}
|
||
|
||
//
|
||
// Remove the reply reference for this call
|
||
//
|
||
OSF_SCALL::RemoveReference(); // CALL--
|
||
|
||
//
|
||
// Remove the dispatch reference for this call
|
||
//
|
||
OSF_SCALL::RemoveReference(); // CALL--
|
||
|
||
return fReceivePosted;
|
||
}
|
||
|
||
#define SC_CLEANUP(_status, _dne) {Status = _status; fDNE = _dne; goto Cleanup;}
|
||
|
||
|
||
BOOL
|
||
OSF_SCALL::ProcessReceivedPDU (
|
||
IN rpcconn_common * Packet,
|
||
IN unsigned int PacketLength,
|
||
IN BOOL fDispatch
|
||
)
|
||
/*++
|
||
Function Name:ProcessReceivedPDU
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
rpcconn_request *Request = (rpcconn_request *) Packet;
|
||
int FragmentLength = (int) PacketLength;
|
||
unsigned char PTYPE, Flags;
|
||
unsigned short OpNum;
|
||
unsigned long Drep;
|
||
int MyCallStack = CallStack;
|
||
BOOL fDNE = 0;
|
||
BOOL fReceivePosted = 0;
|
||
BOOL fCallCleanedUp = FALSE;
|
||
|
||
if (fSecurityFailure)
|
||
{
|
||
|
||
if (Packet->pfc_flags & PFC_LAST_FRAG)
|
||
{
|
||
Connection->TransFreeBuffer(Packet);
|
||
goto Cleanup2;
|
||
}
|
||
|
||
Connection->TransFreeBuffer(Packet);
|
||
|
||
return 0;
|
||
}
|
||
|
||
switch (Packet->PTYPE)
|
||
{
|
||
case rpc_request :
|
||
case rpc_response:
|
||
if (!fDispatch)
|
||
{
|
||
//
|
||
// This must be a request or response
|
||
// save the maximum of req/resonse size [i.e. sizeof request]
|
||
// also, we are not saving the first frag. here .. hence
|
||
// the approp. memory is already set aside
|
||
//
|
||
ASSERT((Connection->AuthInfo.AuthenticationLevel
|
||
== RPC_C_AUTHN_LEVEL_NONE)
|
||
|| (SavedHeaderSize >= sizeof(rpcconn_request)));
|
||
|
||
if (Connection->AuthInfo.AuthenticationLevel
|
||
!= RPC_C_AUTHN_LEVEL_NONE)
|
||
{
|
||
if (SavedHeader == NULL)
|
||
{
|
||
SC_CLEANUP(RPC_S_PROTOCOL_ERROR, 1);
|
||
}
|
||
|
||
RpcpMemoryCopy(SavedHeader, Packet, sizeof(rpcconn_request));
|
||
}
|
||
|
||
Status = ValidatePacket(Packet, PacketLength);
|
||
|
||
if (Status != RPC_S_OK )
|
||
{
|
||
ASSERT(Status == RPC_S_PROTOCOL_ERROR );
|
||
SC_CLEANUP(Status, 1);
|
||
}
|
||
}
|
||
|
||
if (Packet->call_id != CallId)
|
||
{
|
||
SC_CLEANUP(RPC_S_PROTOCOL_ERROR, 0);
|
||
}
|
||
|
||
Flags = Request->common.pfc_flags;
|
||
Drep = *((unsigned long *) Request->common.drep);
|
||
OpNum = Request->opnum;
|
||
PTYPE=Request->common.PTYPE;
|
||
|
||
Status = Connection->EatAuthInfoFromPacket(
|
||
Request,
|
||
&FragmentLength,
|
||
&SavedHeader,
|
||
&SavedHeaderSize);
|
||
if (Status != RPC_S_OK )
|
||
{
|
||
VALIDATE(Status)
|
||
{
|
||
RPC_S_PROTOCOL_ERROR,
|
||
ERROR_SHUTDOWN_IN_PROGRESS,
|
||
RPC_S_ACCESS_DENIED,
|
||
ERROR_PASSWORD_MUST_CHANGE,
|
||
ERROR_PASSWORD_EXPIRED,
|
||
ERROR_ACCOUNT_DISABLED,
|
||
ERROR_INVALID_LOGON_HOURS
|
||
} END_VALIDATE;
|
||
|
||
fSecurityFailure = 1;
|
||
|
||
if (Packet->pfc_flags & PFC_LAST_FRAG
|
||
|| (Status == RPC_S_PROTOCOL_ERROR))
|
||
{
|
||
SC_CLEANUP(Status, 0);
|
||
}
|
||
|
||
SendFault(RPC_S_ACCESS_DENIED, 1);
|
||
|
||
Connection->TransFreeBuffer(Packet);
|
||
return 0;
|
||
}
|
||
|
||
//
|
||
// Ok, if the packet contains an object uuid, we need to shift
|
||
// the stub data so that the packet does not contain an object
|
||
// uuid.
|
||
//
|
||
if ((Flags & PFC_OBJECT_UUID) != 0)
|
||
{
|
||
if (CallStack != 0 )
|
||
{
|
||
//
|
||
// There can not be an object uuid in the message.
|
||
// This is an error.
|
||
//
|
||
SC_CLEANUP(RPC_S_PROTOCOL_ERROR, 0);
|
||
}
|
||
|
||
//
|
||
// First save away the object UUID so that we can get it later.
|
||
//
|
||
ObjectUuidSpecified = 1;
|
||
RpcpMemoryCopy(&ObjectUuid, Request + 1, sizeof(UUID));
|
||
if (DataConvertEndian(((unsigned char *) &Drep)) != 0 )
|
||
{
|
||
ByteSwapUuid(&ObjectUuid);
|
||
}
|
||
|
||
|
||
//
|
||
// Now shift the stub data so that the packet is as if there is
|
||
// no object UUID in the packet.
|
||
//
|
||
RpcpMemoryCopy(Request + 1,
|
||
((unsigned char *) (Request + 1))
|
||
+ sizeof(UUID), FragmentLength);
|
||
}
|
||
|
||
|
||
//
|
||
// we need to keep this peice of code here, because
|
||
// we need to allocate stuff in the callback case.
|
||
//
|
||
if (Flags & PFC_FIRST_FRAG)
|
||
{
|
||
//
|
||
// Optimize for the single PDU RPC case
|
||
//
|
||
if ((Flags & PFC_LAST_FRAG) != 0)
|
||
{
|
||
CurrentState = CallCompleted;
|
||
DispatchBuffer = (void *) (Request+1);
|
||
DispatchBufferOffset = FragmentLength;
|
||
|
||
//
|
||
// Buffers will be freed by callee
|
||
//
|
||
ASSERT(Status == RPC_S_OK);
|
||
return DispatchRPCCall (PTYPE, OpNum);
|
||
}
|
||
|
||
if (Request->alloc_hint)
|
||
{
|
||
AllocHint = Request->alloc_hint;
|
||
}
|
||
else
|
||
{
|
||
AllocHint = FragmentLength;
|
||
}
|
||
|
||
// check the packet size. Note that we check it on first frag
|
||
// only. If they decrease it, we don't care. We will recheck
|
||
// it in all paths below if caller icnreases it.
|
||
if (CurrentBinding->GetInterface()->CallSizeLimitReached(AllocHint))
|
||
{
|
||
fSecurityFailure = 1;
|
||
|
||
SendFault(RPC_S_ACCESS_DENIED, 1);
|
||
|
||
Connection->TransFreeBuffer(Packet);
|
||
return 0;
|
||
}
|
||
|
||
DispatchBufferOffset = 0;
|
||
|
||
Status = GetBufferDo(&DispatchBuffer, AllocHint);
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
SC_CLEANUP(RPC_S_OUT_OF_MEMORY, 0);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (DispatchBuffer == 0)
|
||
{
|
||
//
|
||
// Looks like it is the first fragment on the call, and it doesn't have
|
||
// the first-frag bit set
|
||
//
|
||
SC_CLEANUP(RPC_S_PROTOCOL_ERROR, 0);
|
||
}
|
||
}
|
||
|
||
if (fPipeCall == 0 || CallStack)
|
||
{
|
||
//
|
||
// Non-pipe case
|
||
//
|
||
if (DispatchBufferOffset+FragmentLength > AllocHint)
|
||
{
|
||
Status = GetBufferDo(
|
||
&DispatchBuffer,
|
||
DispatchBufferOffset+FragmentLength,
|
||
1,
|
||
DispatchBufferOffset);
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
SC_CLEANUP(RPC_S_OUT_OF_MEMORY, 0);
|
||
}
|
||
|
||
AllocHint = DispatchBufferOffset + FragmentLength;
|
||
|
||
if (CurrentBinding->GetInterface()->
|
||
CallSizeLimitReached(AllocHint))
|
||
{
|
||
fSecurityFailure = 1;
|
||
|
||
if (Packet->pfc_flags & PFC_LAST_FRAG)
|
||
{
|
||
SC_CLEANUP(RPC_S_ACCESS_DENIED, 0);
|
||
}
|
||
|
||
SendFault(RPC_S_ACCESS_DENIED, 1);
|
||
|
||
Connection->TransFreeBuffer(Packet);
|
||
return 0;
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Copy current buffer into the dispatch buffer
|
||
//
|
||
RpcpMemoryCopy(
|
||
(char *) DispatchBuffer+DispatchBufferOffset,
|
||
Request+1,
|
||
FragmentLength);
|
||
DispatchBufferOffset += FragmentLength;
|
||
|
||
Connection->TransFreeBuffer(Packet);
|
||
|
||
if (Flags & PFC_LAST_FRAG)
|
||
{
|
||
CurrentState = CallCompleted;
|
||
|
||
//
|
||
// Buffers will be freed by callee
|
||
//
|
||
ASSERT(Status == RPC_S_OK);
|
||
|
||
return DispatchRPCCall (PTYPE, OpNum);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Pipe call
|
||
//
|
||
ASSERT(PTYPE == rpc_request);
|
||
|
||
//
|
||
// If it is a pipe call, we need to dispatch as soon as we get
|
||
// at least alloc hint bytes. If it is not a pipe call, we wait until
|
||
// we get the last fragment.
|
||
//
|
||
if (!fCallDispatched)
|
||
{
|
||
if (DispatchBufferOffset+FragmentLength > AllocHint)
|
||
{
|
||
Status = GetBufferDo(
|
||
&DispatchBuffer,
|
||
DispatchBufferOffset+FragmentLength,
|
||
1,
|
||
DispatchBufferOffset);
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
SC_CLEANUP(Status, 0);
|
||
}
|
||
|
||
AllocHint = DispatchBufferOffset + FragmentLength;
|
||
|
||
if (CurrentBinding->GetInterface()->
|
||
CallSizeLimitReached(AllocHint))
|
||
{
|
||
fSecurityFailure = 1;
|
||
|
||
if (Packet->pfc_flags & PFC_LAST_FRAG)
|
||
{
|
||
SC_CLEANUP(RPC_S_ACCESS_DENIED, 0);
|
||
}
|
||
|
||
SendFault(RPC_S_ACCESS_DENIED, 1);
|
||
|
||
Connection->TransFreeBuffer(Packet);
|
||
return 0;
|
||
}
|
||
|
||
}
|
||
//
|
||
// Copy the buffer in
|
||
//
|
||
RpcpMemoryCopy(
|
||
(char *) DispatchBuffer+DispatchBufferOffset,
|
||
Request+1,
|
||
FragmentLength);
|
||
|
||
DispatchBufferOffset += FragmentLength;
|
||
|
||
Connection->TransFreeBuffer(Packet);
|
||
|
||
ASSERT(Status == RPC_S_OK);
|
||
|
||
if (DispatchBufferOffset == AllocHint)
|
||
{
|
||
ASSERT(fSecurityFailure == 0);
|
||
|
||
if (Flags & PFC_LAST_FRAG)
|
||
{
|
||
CurrentState = CallCompleted;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Buffers will be freed by callee
|
||
//
|
||
DispatchFlags = 0;
|
||
}
|
||
|
||
return DispatchRPCCall (PTYPE, OpNum);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Once a pipe call is dispatched, we don't care about how
|
||
// big it gets. The manager routine has the option to abandon
|
||
// the call whenever it wants.
|
||
//
|
||
CallMutex.Request();
|
||
|
||
if ((Connection->fExclusive)
|
||
&& (Connection->CachedSCallAvailable))
|
||
{
|
||
CallMutex.Clear();
|
||
ASSERT (Connection->CachedSCall == this);
|
||
Connection->TransFreeBuffer(Packet);
|
||
return 0;
|
||
}
|
||
//
|
||
// A pipe call is already in progress. We simply need to queue
|
||
// the buffer into the buffer queue. It get picked up later.
|
||
//
|
||
LogEvent(SU_SCALL, EV_BUFFER_IN, Request, this, 0, 1, 0);
|
||
if (BufferQueue.PutOnQueue(Request+1, FragmentLength))
|
||
{
|
||
CallMutex.Clear();
|
||
SC_CLEANUP(RPC_S_OUT_OF_MEMORY, 0);
|
||
}
|
||
RcvBufferLength += FragmentLength;
|
||
|
||
if ((Flags & PFC_LAST_FRAG) != 0)
|
||
{
|
||
CurrentState = CallCompleted;
|
||
}
|
||
|
||
if (pAsync == 0)
|
||
{
|
||
if (BufferQueue.Size() >= 4
|
||
&& Connection->fExclusive
|
||
&& CurrentState != CallCompleted)
|
||
{
|
||
fPeerChoked = 1;
|
||
fReceivePosted = 1;
|
||
}
|
||
|
||
CallMutex.Clear();
|
||
SyncEvent.Raise();
|
||
}
|
||
else
|
||
{
|
||
if (NeededLength > 0 && ((CurrentState == CallCompleted)
|
||
|| (RcvBufferLength >= NeededLength)))
|
||
{
|
||
IssueNotification(RpcReceiveComplete);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Cannot do this for non-exclusive connections because
|
||
// other calls will get blocked
|
||
//
|
||
if (BufferQueue.Size() >= 4
|
||
&& Connection->fExclusive
|
||
&& CurrentState != CallCompleted)
|
||
{
|
||
fPeerChoked = 1;
|
||
fReceivePosted = 1;
|
||
}
|
||
}
|
||
CallMutex.Clear();
|
||
}
|
||
|
||
//
|
||
// We received pipe data
|
||
// there's nothing to cleanup
|
||
//
|
||
return fReceivePosted;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
|
||
case rpc_fault:
|
||
Status = ((rpcconn_fault *)Packet)->status;
|
||
|
||
if ((Status == 0) &&
|
||
(Packet->frag_length >= FaultSizeWithoutEEInfo + 4))
|
||
{
|
||
//
|
||
// DCE 1.0.x style fault status:
|
||
// Zero status and stub data contains the fault.
|
||
//
|
||
Status = *(unsigned long *) ((unsigned char *)Packet + FaultSizeWithoutEEInfo);
|
||
}
|
||
|
||
if (DataConvertEndian(Packet->drep) != 0)
|
||
{
|
||
Status = RpcpByteSwapLong(Status);
|
||
}
|
||
|
||
if (Status == 0)
|
||
{
|
||
Status = RPC_S_CALL_FAILED;
|
||
}
|
||
|
||
AsyncStatus = MapFromNcaStatusCode(Status);
|
||
CurrentState = ReceivedFault;
|
||
|
||
SyncEvent.Raise();
|
||
|
||
Connection->TransFreeBuffer(Packet);
|
||
return 0;
|
||
|
||
case rpc_cancel:
|
||
case rpc_orphaned:
|
||
CancelPending = 1;
|
||
|
||
Connection->TransFreeBuffer(Packet);
|
||
return 0;
|
||
|
||
default :
|
||
//
|
||
// We should never reach here
|
||
//
|
||
ASSERT(0);
|
||
SC_CLEANUP(RPC_S_PROTOCOL_ERROR, 0);
|
||
break;
|
||
}
|
||
|
||
|
||
Cleanup:
|
||
//
|
||
// If we reach here it means that the call failed
|
||
// Every call to ProcessReceivedPDU has a reference on the call,
|
||
// the call is alive here
|
||
//
|
||
ASSERT(Status != RPC_S_OK);
|
||
|
||
Connection->TransFreeBuffer(Packet);
|
||
if ((MyCallStack == 0) && (fCallDispatched == 0))
|
||
{
|
||
CleanupCallAndSendFault(Status, 0);
|
||
fCallCleanedUp = TRUE;
|
||
}
|
||
else
|
||
{
|
||
SendFault(Status, 0);
|
||
}
|
||
|
||
Cleanup2:
|
||
|
||
//
|
||
// There is a chance that this error happened due to a bogus packet
|
||
// We need to make sure that we don't something bad in that case
|
||
//
|
||
if (MyCallStack == 0)
|
||
{
|
||
if (fCallDispatched == 0)
|
||
{
|
||
if (fCallCleanedUp == FALSE)
|
||
CleanupCall();
|
||
|
||
//
|
||
// We cannot continue to use this connection
|
||
//
|
||
Connection->fDontFlush = (CurrentState == NewRequest);
|
||
Connection->OSF_SCONNECTION::Delete();
|
||
|
||
//
|
||
// Remove the reference held by the dispatch
|
||
// thread
|
||
//
|
||
OSF_SCALL::RemoveReference(); // CALL--
|
||
|
||
//
|
||
// We just finished sending the reply (the fault)
|
||
// remove the reply reference
|
||
//
|
||
OSF_SCALL::RemoveReference(); // CALL--
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// The call will go away when the dispatch completes
|
||
//
|
||
Connection->OSF_SCONNECTION::Delete();
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::Receive (
|
||
IN OUT PRPC_MESSAGE Message,
|
||
IN unsigned int Size
|
||
)
|
||
/*++
|
||
Function Name:Receive
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
BOOL fForceExtra = FALSE;
|
||
|
||
if (!EXTRA(Message) && Message->Buffer)
|
||
{
|
||
ASSERT(Message->Buffer != DispatchBuffer);
|
||
|
||
FreeBufferDo((char *)Message->Buffer);
|
||
Message->Buffer = 0;
|
||
Message->BufferLength = 0;
|
||
}
|
||
|
||
if (fSecurityFailure)
|
||
{
|
||
return RPC_S_ACCESS_DENIED;
|
||
}
|
||
|
||
Message->DataRepresentation = Connection->DataRep;
|
||
|
||
while (TRUE)
|
||
{
|
||
switch (CurrentState)
|
||
{
|
||
case CallCompleted:
|
||
//
|
||
// When the last frag is received on this call, the call state
|
||
// transitions to the Complete state. The call states are valid
|
||
// only when using Async and Pipes
|
||
//
|
||
Status = GetCoalescedBuffer(Message, fForceExtra);
|
||
break;
|
||
|
||
case CallCancelled:
|
||
Status = RPC_S_CALL_CANCELLED;
|
||
break;
|
||
|
||
case CallAborted:
|
||
ASSERT(AsyncStatus != RPC_S_OK);
|
||
Status = AsyncStatus;
|
||
break;
|
||
|
||
default:
|
||
if (RcvBufferLength > Connection->MaxFrag)
|
||
{
|
||
Status = GetCoalescedBuffer(Message, fForceExtra);
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
break;
|
||
}
|
||
|
||
if (PARTIAL(Message) && Message->BufferLength >= Size)
|
||
{
|
||
break;
|
||
}
|
||
|
||
fForceExtra = TRUE;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// the call is not yet complete, wait for it.
|
||
//
|
||
SyncEvent.Wait();
|
||
}
|
||
continue;
|
||
}
|
||
break;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::AsyncReceive (
|
||
IN OUT PRPC_MESSAGE Message,
|
||
IN unsigned int Size
|
||
)
|
||
/*++
|
||
Function Name:AsyncReceive
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status ;
|
||
int Extra = IsExtraMessage(Message);
|
||
|
||
ASSERT(EXTRA(Message) == 0 && PARTIAL(Message));
|
||
|
||
if (Message->Buffer)
|
||
{
|
||
ASSERT(Message->Buffer != DispatchBuffer);
|
||
|
||
FreeBufferDo((char *)Message->Buffer);
|
||
Message->Buffer = 0;
|
||
}
|
||
|
||
if (fSecurityFailure)
|
||
{
|
||
return RPC_S_ACCESS_DENIED;
|
||
}
|
||
|
||
switch (CurrentState)
|
||
{
|
||
case CallCompleted:
|
||
Status = GetCoalescedBuffer(Message, FALSE);
|
||
Message->DataRepresentation = Connection->DataRep;
|
||
break;
|
||
|
||
case CallCancelled:
|
||
Status = RPC_S_CALL_CANCELLED;
|
||
break;
|
||
|
||
case CallAborted:
|
||
Status = AsyncStatus;
|
||
break;
|
||
|
||
default:
|
||
CallMutex.Request();
|
||
if (RcvBufferLength < Size)
|
||
{
|
||
if (NOTIFY(Message))
|
||
{
|
||
NeededLength = Size ;
|
||
}
|
||
CallMutex.Clear() ;
|
||
|
||
return RPC_S_ASYNC_CALL_PENDING;
|
||
}
|
||
else
|
||
{
|
||
Status = GetCoalescedBuffer(Message, FALSE);
|
||
Message->DataRepresentation = Connection->DataRep;
|
||
}
|
||
CallMutex.Clear();
|
||
break;
|
||
}
|
||
|
||
return Status ;
|
||
}
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::SetAsyncHandle (
|
||
IN PRPC_ASYNC_STATE pAsync
|
||
)
|
||
/*++
|
||
Function Name:SetAsyncHandle
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
this->pAsync = pAsync;
|
||
Thread->fAsync = TRUE;
|
||
|
||
if (DebugCell)
|
||
{
|
||
DebugCell->CallFlags |= DBGCELL_ASYNC_CALL;
|
||
}
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::AbortAsyncCall (
|
||
IN PRPC_ASYNC_STATE pAsync,
|
||
IN unsigned long ExceptionCode
|
||
)
|
||
/*++
|
||
Function Name:AbortAsyncCall
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
ASSERT(CurrentBinding);
|
||
|
||
CleanupCallAndSendFault(ExceptionCode, 0);
|
||
|
||
//
|
||
// The call was aborted asynchronously
|
||
// Remove the reference held for the reply.
|
||
//
|
||
RemoveReference(); // CALL--
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::GetCoalescedBuffer (
|
||
IN PRPC_MESSAGE Message,
|
||
BOOL fForceExtra
|
||
)
|
||
/*++
|
||
Function Name:GetCoalescedBuffer
|
||
|
||
Parameters:
|
||
Message - the message structure that will receive the params
|
||
|
||
Description:
|
||
This routine will coalesce the buffers in the buffer queue into a single
|
||
buffer and return it in the Message structure. If the RPC_BUFFER_EXTRA
|
||
flag is set, the data is appended to the existing buffer in Message->Buffer.
|
||
|
||
Returns:
|
||
RPC_S_OK - the function was successful in doing its job
|
||
RPC_S_OUT_OF_MEMORY - ran out of memory.
|
||
--*/
|
||
{
|
||
char *Current;
|
||
UINT bufferlength;
|
||
UINT TotalLength;
|
||
RPC_STATUS Status;
|
||
void *NewBuffer, *Buffer;
|
||
int Extra = IsExtraMessage(Message);
|
||
BOOL fExtendedExtra = Extra | fForceExtra;
|
||
BOOL fSubmitReceive = 0;
|
||
|
||
CallMutex.Request();
|
||
if (RcvBufferLength == 0)
|
||
{
|
||
CallMutex.Clear();
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
if (fExtendedExtra)
|
||
{
|
||
TotalLength = RcvBufferLength + Message->BufferLength;
|
||
}
|
||
else
|
||
{
|
||
TotalLength = RcvBufferLength;
|
||
}
|
||
|
||
Status = TransGetBuffer (&NewBuffer,
|
||
TotalLength+sizeof(rpcconn_request));
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
CallMutex.Clear();
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
NewBuffer = (char *) NewBuffer+sizeof(rpcconn_request);
|
||
|
||
if (fExtendedExtra && Message->Buffer)
|
||
{
|
||
|
||
RpcpMemoryCopy(NewBuffer, Message->Buffer, Message->BufferLength);
|
||
Current = (char *) NewBuffer + Message->BufferLength;
|
||
|
||
Connection->TransFreeBuffer((char *) Message->Buffer-sizeof(rpcconn_request));
|
||
|
||
if (Extra)
|
||
{
|
||
//
|
||
// Update the dispatch buffer, but only for the true EXTRA flag, not
|
||
// for the forced extra
|
||
//
|
||
ASSERT(Message->ReservedForRuntime) ;
|
||
((PRPC_RUNTIME_INFO)Message->ReservedForRuntime)->OldBuffer = NewBuffer;
|
||
|
||
if ((CallStack == 0) && (Message->Buffer == DispatchBuffer))
|
||
DispatchBuffer = NewBuffer;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Current = (char *) NewBuffer;
|
||
}
|
||
|
||
while ((Buffer = BufferQueue.TakeOffQueue(&bufferlength)) != 0)
|
||
{
|
||
RpcpMemoryCopy(Current, Buffer, bufferlength);
|
||
Current += bufferlength;
|
||
|
||
Connection->TransFreeBuffer((char *) Buffer-sizeof(rpcconn_request));
|
||
}
|
||
|
||
Message->Buffer = NewBuffer;
|
||
Message->BufferLength = TotalLength;
|
||
|
||
RcvBufferLength = 0;
|
||
|
||
if (CurrentState == CallCompleted)
|
||
{
|
||
Message->RpcFlags = RPC_BUFFER_COMPLETE;
|
||
}
|
||
|
||
if (fPeerChoked)
|
||
{
|
||
fSubmitReceive = 1;
|
||
fPeerChoked = 0;
|
||
}
|
||
CallMutex.Clear();
|
||
|
||
if (fSubmitReceive)
|
||
{
|
||
Connection->TransAsyncReceive();
|
||
}
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCALL::DispatchHelper ()
|
||
{
|
||
THREAD *MyThread;
|
||
RPC_STATUS Status, ExceptionCode;
|
||
DebugCallInfo *Cell;
|
||
DebugThreadInfo *ThreadCell;
|
||
ULONG TickCount;
|
||
PRPC_DISPATCH_TABLE DispatchTableToUse;
|
||
|
||
//
|
||
// We have a new RPC call. We need to dispatch it.
|
||
//
|
||
FirstCallRuntimeInfo.Length = sizeof(RPC_RUNTIME_INFO) ;
|
||
|
||
FirstCallRpcMessage.Handle = (RPC_BINDING_HANDLE) this;
|
||
FirstCallRpcMessage.Buffer = DispatchBuffer;
|
||
FirstCallRpcMessage.BufferLength = DispatchBufferOffset;
|
||
FirstCallRpcMessage.RpcFlags = DispatchFlags ;
|
||
FirstCallRpcMessage.DataRepresentation = Connection->DataRep;
|
||
FirstCallRpcMessage.ReservedForRuntime = &FirstCallRuntimeInfo ;
|
||
CurrentBinding->GetSelectedTransferSyntaxAndDispatchTable(&FirstCallRpcMessage.TransferSyntax,
|
||
&DispatchTableToUse);
|
||
FirstCallRpcMessage.ProcNum = ProcNum;
|
||
|
||
MyThread = (THREAD *) RpcpGetThreadPointer();
|
||
ASSERT(MyThread);
|
||
|
||
RpcpSetThreadContextWithThread(MyThread, this);
|
||
|
||
Thread = MyThread;
|
||
|
||
ThreadCell = Thread->DebugCell;
|
||
|
||
if (ThreadCell)
|
||
{
|
||
TickCount = NtGetTickCount();
|
||
Cell = DebugCell;
|
||
Cell->CallID = CallId;
|
||
Cell->ProcNum = (unsigned short)ProcNum;
|
||
Cell->Status = csDispatched;
|
||
Cell->LastUpdateTime = TickCount;
|
||
Cell->InterfaceUUIDStart
|
||
= CurrentBinding->GetInterface()->GetInterfaceFirstDWORD();
|
||
ThreadCell->Status = dtsDispatched;
|
||
ThreadCell->LastUpdateTime = TickCount;
|
||
GetDebugCellIDFromDebugCell((DebugCellUnion *)ThreadCell, &MyThread->DebugCellTag, &Cell->ServicingTID);
|
||
}
|
||
|
||
//
|
||
// Actually dispatch the RPC call
|
||
//
|
||
if ( ObjectUuidSpecified != 0 )
|
||
{
|
||
Status = CurrentBinding->GetInterface()->DispatchToStubWithObject(
|
||
&FirstCallRpcMessage,
|
||
&ObjectUuid,
|
||
0,
|
||
DispatchTableToUse,
|
||
&ExceptionCode);
|
||
}
|
||
else
|
||
{
|
||
Status = CurrentBinding->GetInterface()->DispatchToStub(
|
||
&FirstCallRpcMessage,
|
||
0,
|
||
DispatchTableToUse,
|
||
&ExceptionCode);
|
||
}
|
||
|
||
//
|
||
// We need to insure that the server thread stops impersonating
|
||
// the client at the end of the call, so we go ahead and call
|
||
// RevertToSelf, and dont worry about the return value.
|
||
//
|
||
|
||
OSF_SCALL::RevertToSelf();
|
||
|
||
if (ThreadCell)
|
||
{
|
||
ThreadCell->Status = dtsProcessing;
|
||
ThreadCell->LastUpdateTime = NtGetTickCount();
|
||
}
|
||
|
||
if(Status != RPC_S_OK)
|
||
{
|
||
//Thread = 0;
|
||
|
||
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,
|
||
RPC_P_EXCEPTION_OCCURED
|
||
} END_VALIDATE;
|
||
|
||
BOOL fDNE = 1;
|
||
|
||
if( Status == RPC_P_EXCEPTION_OCCURED )
|
||
{
|
||
fDNE=0;
|
||
Status = ExceptionCode;
|
||
}
|
||
else if ( Status == RPC_S_NOT_LISTENING )
|
||
{
|
||
Status = RPC_S_SERVER_TOO_BUSY;
|
||
}
|
||
|
||
while (CurrentBufferLength)
|
||
{
|
||
#if DBG
|
||
PrintToDebugger("RPC: Waiting for the async send....\n");
|
||
#endif
|
||
Sleep(200);
|
||
}
|
||
|
||
//
|
||
// There may be another thread still sending data on this call
|
||
// This will be taken care of in CleanupCall
|
||
//
|
||
CleanupCallAndSendFault(Status, fDNE);
|
||
|
||
// It is tempting to think that since an exception was
|
||
// raised, there will be no reply. However, in the pipe
|
||
// case we may make a bunch of sends, and still get
|
||
// an exception in the end. If there were no sends,
|
||
// remove the reply reference for the call
|
||
if (FirstSend)
|
||
{
|
||
OSF_SCALL::RemoveReference(); // CALL--
|
||
}
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
if (MyThread->IsSyncCall())
|
||
{
|
||
ASSERT( FirstCallRpcMessage.Buffer != 0 );
|
||
|
||
if ( CallOrphaned )
|
||
{
|
||
CallOrphaned = 0;
|
||
Thread = 0;
|
||
|
||
//
|
||
// clear cancel if thread didn\'t notice it.
|
||
//
|
||
TestCancel();
|
||
goto Cleanup;
|
||
}
|
||
|
||
FirstCallRpcMessage.RpcFlags = 0;
|
||
OSF_SCALL::Send(&FirstCallRpcMessage);
|
||
}
|
||
|
||
Cleanup:
|
||
RpcpSetThreadContextWithThread(MyThread, 0);
|
||
}
|
||
|
||
|
||
BOOL
|
||
OSF_SCALL::DispatchRPCCall (
|
||
IN unsigned char PTYPE,
|
||
IN unsigned short OpNum
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Dispatch an new RPC call, or wake up thread that will dispatch a callback.
|
||
|
||
Arguments:
|
||
|
||
Packet - Supplies the packet we received from the connection. Ownership
|
||
of this buffer passes to this routine.
|
||
|
||
PacketLength - Supplies the length of the packet in bytes.
|
||
|
||
Return Value:
|
||
|
||
A non-zero return value indicates that the connection should not
|
||
be placed in the receive any state; instead, the thread should just
|
||
forget about the connection and go back to waiting for more new
|
||
procedure calls.
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
BOOL fNeedToSendFault;
|
||
OSF_SCONNECTION *LocalConnection;
|
||
|
||
if (CallStack > 0)
|
||
{
|
||
//
|
||
// This is a callback request/response. We just need to signal the Event
|
||
// and have it pick up the call
|
||
//
|
||
if (PTYPE == rpc_request)
|
||
{
|
||
CurrentState = ReceivedCallback;
|
||
ProcNum = OpNum;
|
||
}
|
||
else
|
||
{
|
||
CurrentState = ReceivedCallbackReply;
|
||
}
|
||
|
||
SyncEvent.Raise();
|
||
return 0;
|
||
}
|
||
|
||
ProcNum = OpNum;
|
||
fCallDispatched = 1;
|
||
|
||
if (Connection->fExclusive == 0 && Connection->MaybeQueueThisCall(this))
|
||
{
|
||
//
|
||
// We don't get to dispatch right now, looks like another call is
|
||
// currently dispatched. When the current call is done, it will do the
|
||
// right thing
|
||
//
|
||
|
||
return 0;
|
||
}
|
||
|
||
fNeedToSendFault = FALSE;
|
||
|
||
//
|
||
// Looks like we are really going to dispatch a call
|
||
// kick off another thread to go and pick up more requests
|
||
//
|
||
Status = Address->CreateThread();
|
||
if (Status == RPC_S_OK)
|
||
{
|
||
//
|
||
// Post another receive
|
||
//
|
||
Status = Connection->TransAsyncReceive();
|
||
}
|
||
else
|
||
{
|
||
Status = RPC_S_OUT_OF_MEMORY;
|
||
fNeedToSendFault = TRUE;
|
||
}
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
FreeBufferDo(DispatchBuffer);
|
||
|
||
if (fNeedToSendFault)
|
||
CleanupCallAndSendFault(Status, 0);
|
||
else
|
||
CleanupCall();
|
||
|
||
if (Connection->fExclusive == 0)
|
||
{
|
||
//
|
||
// By the time we get here, calls may have piled up
|
||
//
|
||
Connection->AbortQueuedCalls();
|
||
}
|
||
|
||
//
|
||
// We cannot continue to use this connection
|
||
//
|
||
Connection->fDontFlush = (CurrentState == NewRequest);
|
||
Connection->Delete();
|
||
|
||
//
|
||
// Remove the reply reference
|
||
//
|
||
RemoveReference(); // CALL--
|
||
|
||
//
|
||
// Remove the dispatch reference
|
||
//
|
||
RemoveReference(); // CALL--
|
||
|
||
return 1;
|
||
}
|
||
|
||
// the call may have been cleaned up after this (though not
|
||
// destroyed) - save the connection in a local variable
|
||
LocalConnection = Connection;
|
||
|
||
//
|
||
// Dispatch the current call
|
||
//
|
||
DispatchHelper();
|
||
|
||
if (LocalConnection->fExclusive == 0)
|
||
{
|
||
LocalConnection->DispatchQueuedCalls();
|
||
}
|
||
|
||
//
|
||
// Remove the dispatch reference
|
||
//
|
||
RemoveReference(); // CALL--
|
||
|
||
return 1;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::SendNextFragment (
|
||
void
|
||
)
|
||
/*++
|
||
Function Name:SendNextFragment
|
||
|
||
Description:
|
||
Send the next response fragment
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
RPC_STATUS RpcStatus2;
|
||
rpcconn_common * pFragment;
|
||
BOOL LastFragmentFlag;
|
||
ULONG PacketLength;
|
||
ULONG MaxDataLength = MaximumFragmentLength
|
||
- sizeof(rpcconn_response) - MaxSecuritySize;
|
||
unsigned char *ReservedForSecurity = (unsigned char *) CurrentBuffer
|
||
+ CurrentOffset + CurrentBufferLength
|
||
+ Connection->AdditionalSpaceForSecurity;
|
||
|
||
pFragment = (rpcconn_common *)
|
||
((char *) CurrentBuffer+CurrentOffset-sizeof(rpcconn_response));
|
||
|
||
if (CurrentBuffer == LastBuffer
|
||
&& CurrentBufferLength <= MaxDataLength)
|
||
{
|
||
LastFragmentFlag = 1;
|
||
PacketLength = CurrentBufferLength;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Each outstanding send needs to hold a reference
|
||
// on the call. Since the call holds a reference
|
||
// on the connection. The connection will also be alive
|
||
//
|
||
AddReference(); // CALL++
|
||
|
||
LastFragmentFlag = 0;
|
||
PacketLength = MaxDataLength;
|
||
}
|
||
|
||
ConstructPacket(pFragment, rpc_response,
|
||
PacketLength+sizeof(rpcconn_response)+MaxSecuritySize);
|
||
|
||
if (FirstSend)
|
||
{
|
||
FirstSend = 0;
|
||
pFragment->pfc_flags |= PFC_FIRST_FRAG;
|
||
}
|
||
|
||
((rpcconn_response *) pFragment)->alloc_hint = CurrentBufferLength;
|
||
((rpcconn_response *) pFragment)->p_cont_id = (unsigned char) CurrentBinding->GetPresentationContext();
|
||
((rpcconn_response *) pFragment)->alert_count = (unsigned char) 0;
|
||
((rpcconn_response *) pFragment)->reserved = 0;
|
||
pFragment->call_id = CallId;
|
||
|
||
LogEvent(SU_SCALL, EV_BUFFER_OUT, this, pFragment, LastFragmentFlag, 1);
|
||
|
||
if (LastFragmentFlag)
|
||
{
|
||
char *BufferToFree = (char *) CurrentBuffer-sizeof(rpcconn_response);
|
||
int MyMaxFrag = MaximumFragmentLength;
|
||
int MyMaxSec = MaxSecuritySize;
|
||
|
||
CurrentBufferLength = 0;
|
||
|
||
CleanupCall();
|
||
|
||
if (Connection->IsHttpTransport())
|
||
{
|
||
RpcStatus2 = Connection->SetLastBufferToFree (BufferToFree);
|
||
VALIDATE(RpcStatus2)
|
||
{
|
||
RPC_S_OK,
|
||
RPC_S_CANNOT_SUPPORT
|
||
} END_VALIDATE;
|
||
|
||
// if the transport does not support SetLastBufferToFree, it will
|
||
// return RPC_S_CANNOT_SUPPORT. In this case we retain ownership of
|
||
// the buffer.
|
||
}
|
||
|
||
//
|
||
// The call should still be alive at this point because the caller
|
||
// of this function has not release the send reference
|
||
//
|
||
Status = Connection->SendFragment(
|
||
pFragment,
|
||
LastFragmentFlag,
|
||
sizeof(rpcconn_response),
|
||
MyMaxSec,
|
||
PacketLength,
|
||
MyMaxFrag,
|
||
ReservedForSecurity);
|
||
|
||
//
|
||
// Last send always succeeds
|
||
//
|
||
Status = RPC_S_OK;
|
||
|
||
if ((Connection->IsHttpTransport() == FALSE) || (RpcStatus2 != RPC_S_OK))
|
||
Connection->TransFreeBuffer(BufferToFree);
|
||
}
|
||
else
|
||
{
|
||
Status = Connection->SendFragment(
|
||
pFragment,
|
||
LastFragmentFlag,
|
||
sizeof(rpcconn_response),
|
||
MaxSecuritySize,
|
||
PacketLength,
|
||
MaximumFragmentLength,
|
||
ReservedForSecurity,
|
||
TRUE,
|
||
SendContext) ;
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
CurrentBufferLength = 0;
|
||
|
||
//
|
||
// Remove the reference for the outstanding send
|
||
//
|
||
OSF_SCALL::RemoveReference(); // CALL--
|
||
}
|
||
}
|
||
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::Send (
|
||
IN OUT PRPC_MESSAGE Message
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
Message - Supplies the buffer containing the response to be sent
|
||
--*/
|
||
{
|
||
void *NewBuffer;
|
||
int RemainingLength = 0;
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
RPC_STATUS StatusToReturn = RPC_S_OK;
|
||
ULONG MaxDataLength = MaximumFragmentLength
|
||
- sizeof(rpcconn_response) - MaxSecuritySize;
|
||
BOOL fOutstandingSend = 0;
|
||
BOOL fBufferSent = 0;
|
||
|
||
|
||
ASSERT(LastBuffer == 0);
|
||
|
||
if (PARTIAL(Message))
|
||
{
|
||
if (Message->BufferLength < MaxDataLength)
|
||
{
|
||
return RPC_S_SEND_INCOMPLETE;
|
||
}
|
||
|
||
RemainingLength = Message->BufferLength % MaxDataLength;
|
||
|
||
if (RemainingLength)
|
||
{
|
||
Status = GetBufferDo(&NewBuffer, RemainingLength);
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
ASSERT(Status == RPC_S_OUT_OF_MEMORY);
|
||
FreeBufferDo(Message->Buffer);
|
||
|
||
return Status;
|
||
}
|
||
|
||
Message->BufferLength -= RemainingLength;
|
||
RpcpMemoryCopy(NewBuffer,
|
||
(char *) Message->Buffer+Message->BufferLength,
|
||
RemainingLength);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
LastBuffer = Message->Buffer;
|
||
}
|
||
|
||
|
||
while (1)
|
||
{
|
||
CallMutex.Request();
|
||
if (CurrentBuffer == 0)
|
||
{
|
||
//
|
||
// If CurrentBuffer == 0, it means that the call is idle
|
||
//
|
||
CurrentOffset = 0;
|
||
CurrentBuffer = Message->Buffer;
|
||
CurrentBufferLength = Message->BufferLength;
|
||
fBufferSent = TRUE;
|
||
|
||
if ((CurrentBuffer != LastBuffer)
|
||
|| (CurrentBufferLength > MaxDataLength))
|
||
{
|
||
UpdateBuffersAfterNonLastSend(
|
||
NewBuffer,
|
||
RemainingLength,
|
||
Message);
|
||
fOutstandingSend = TRUE;
|
||
}
|
||
|
||
CallMutex.Clear();
|
||
|
||
Status = SendNextFragment();
|
||
|
||
if (Status && fOutstandingSend)
|
||
{
|
||
// if we failed on a non last send, there will be
|
||
// nobody else to drive the call - we need to
|
||
// return the unsent buffer to Message->Buffer,
|
||
// so that it can be freed below.
|
||
Message->Buffer = CurrentBuffer;
|
||
CleanupCall();
|
||
}
|
||
|
||
// N.B. Do not touch any call members after
|
||
// this point if the call succeeded - you may affect
|
||
// the next call.
|
||
// This is because once we send, we may get swapped out
|
||
// and other threads could drive the call to
|
||
// completion (i.e. send all fragments and cleanup
|
||
// the call on the last fragment). From then on,
|
||
// it may be another call we're writing on.
|
||
|
||
if (fOutstandingSend && RemainingLength && (Status == RPC_S_OK))
|
||
StatusToReturn = RPC_S_SEND_INCOMPLETE;
|
||
}
|
||
else
|
||
{
|
||
if ((AsyncStatus == RPC_S_OK) && (pAsync == 0) && (BufferQueue.Size() >= 4))
|
||
{
|
||
fChoked = 1;
|
||
CallMutex.Clear();
|
||
|
||
SyncEvent.Wait();
|
||
// if the call already failed, bail out
|
||
if (AsyncStatus != RPC_S_OK)
|
||
{
|
||
Status = AsyncStatus;
|
||
fOutstandingSend = TRUE;
|
||
break;
|
||
}
|
||
continue;
|
||
}
|
||
else if (AsyncStatus != RPC_S_OK)
|
||
{
|
||
CallMutex.Clear();
|
||
Status = AsyncStatus;
|
||
fOutstandingSend = TRUE;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Since CurrentBuffer != 0, the call is busy sending the reply
|
||
//
|
||
if (BufferQueue.PutOnQueue(Message->Buffer, Message->BufferLength))
|
||
{
|
||
Status = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
else
|
||
{
|
||
UpdateBuffersAfterNonLastSend(
|
||
NewBuffer,
|
||
RemainingLength,
|
||
Message);
|
||
|
||
if (RemainingLength)
|
||
StatusToReturn = RPC_S_SEND_INCOMPLETE;
|
||
}
|
||
CallMutex.Clear();
|
||
}
|
||
break;
|
||
}
|
||
|
||
if (Status)
|
||
{
|
||
if (RemainingLength)
|
||
{
|
||
FreeBufferDo(NewBuffer);
|
||
}
|
||
|
||
if (fOutstandingSend)
|
||
{
|
||
FreeBufferDo(Message->Buffer);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (StatusToReturn != RPC_S_OK)
|
||
Status = StatusToReturn;
|
||
}
|
||
|
||
if (fBufferSent)
|
||
{
|
||
//
|
||
// Remove the reference for the call (if failure)
|
||
// or for the outstanding send (if success)
|
||
//
|
||
RemoveReference(); // CALL--
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::AsyncSend (
|
||
IN OUT PRPC_MESSAGE Message
|
||
)
|
||
/*++
|
||
Function Name:AsyncSend
|
||
Parameters:
|
||
Message - Supplies the buffer containing the response to be sent
|
||
|
||
Description:
|
||
It isn't neccassary for us to send the reply using async IO. For the first
|
||
cut, we will send the request synchronously. This will save us a whole lot
|
||
of headache.
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
ULONG OldBufferLength = Message->BufferLength;
|
||
|
||
ASSERT(FirstSend == 0 || BufferQueue.IsQueueEmpty());
|
||
|
||
if (AsyncStatus != RPC_S_OK)
|
||
{
|
||
Status = AsyncStatus;
|
||
|
||
CleanupCall();
|
||
|
||
//
|
||
// Remove the reply reference
|
||
//
|
||
RemoveReference(); // CALL--
|
||
|
||
return Status;
|
||
}
|
||
|
||
Status = Send(Message);
|
||
|
||
if (Status == RPC_S_SEND_INCOMPLETE)
|
||
{
|
||
if (Message->BufferLength == OldBufferLength
|
||
&& (pAsync->Flags & RPC_C_NOTIFY_ON_SEND_COMPLETE))
|
||
{
|
||
CallMutex.Request() ;
|
||
if (!IssueNotification(RpcSendComplete))
|
||
{
|
||
Status = RPC_S_OUT_OF_MEMORY ;
|
||
}
|
||
CallMutex.Clear() ;
|
||
}
|
||
}
|
||
|
||
//
|
||
// In the failure case, the reference has already been removed
|
||
// by the server
|
||
//
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::SendRequestOrResponse (
|
||
IN OUT PRPC_MESSAGE Message,
|
||
IN unsigned char PacketType
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to send to synchoronous sends, as in callbacks
|
||
and callback response.
|
||
|
||
Arguments:
|
||
|
||
Message - Supplies the buffer containing the request or response to be
|
||
sent, and returns the first fragment received from the server.
|
||
|
||
PacketType - Supplies the packet type; this must be rpc_request or
|
||
rpc_response.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - We successfully sent the request and received a fragment from
|
||
the server.
|
||
|
||
RPC_S_CALL_FAILED_DNE - The connection failed part way through sending
|
||
the request or response.
|
||
|
||
RPC_S_CALL_FAILED - The connection failed after sending the request or
|
||
response, and the receive failed.
|
||
|
||
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to perform the
|
||
operation.
|
||
|
||
RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to perform
|
||
the operation.
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
RPC_MESSAGE SendBuffer;
|
||
rpcconn_common * pFragment;
|
||
ULONG LastFragmentFlag = 0;
|
||
ULONG LengthLeft = Message->BufferLength;
|
||
ULONG HeaderSize = sizeof(rpcconn_request);
|
||
ULONG MaxDataLength = MaximumFragmentLength - HeaderSize - MaxSecuritySize;
|
||
unsigned char *ReservedForSecurity = (unsigned char *) Message->Buffer
|
||
+ Message->BufferLength + Connection->AdditionalSpaceForSecurity;
|
||
|
||
ASSERT(!PARTIAL(Message));
|
||
ASSERT( sizeof(rpcconn_response) == sizeof(rpcconn_request));
|
||
|
||
VALIDATE(PacketType)
|
||
{
|
||
rpc_request,
|
||
rpc_response
|
||
} END_VALIDATE;
|
||
|
||
SendBuffer.Buffer = Message->Buffer;
|
||
pFragment = (rpcconn_common *) ((char *) Message->Buffer - HeaderSize);
|
||
|
||
for (;;)
|
||
{
|
||
//
|
||
// Check to see if the remaining data will fit into a single
|
||
// fragment; if so, set the last fragment flag.
|
||
//
|
||
if ( LengthLeft <= MaxDataLength )
|
||
{
|
||
LastFragmentFlag = 1;
|
||
}
|
||
|
||
ConstructPacket(pFragment, PacketType, (LastFragmentFlag != 0 ?
|
||
LengthLeft+HeaderSize+MaxSecuritySize : MaximumFragmentLength));
|
||
|
||
if ((LengthLeft == Message->BufferLength))
|
||
{
|
||
if (FirstFrag)
|
||
{
|
||
FirstFrag = 0;
|
||
pFragment->pfc_flags |= PFC_FIRST_FRAG;
|
||
|
||
if (TestCancel())
|
||
{
|
||
pFragment->pfc_flags |= PFC_PENDING_CANCEL;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (PacketType == rpc_request)
|
||
{
|
||
((rpcconn_request *) pFragment)->alloc_hint = LengthLeft;
|
||
((rpcconn_request *) pFragment)->p_cont_id = (unsigned short) CurrentBinding->GetPresentationContext();
|
||
((rpcconn_request *) pFragment)->opnum = (unsigned short) Message->ProcNum;
|
||
}
|
||
else
|
||
{
|
||
((rpcconn_response *) pFragment)->alloc_hint = LengthLeft;
|
||
((rpcconn_response *) pFragment)->p_cont_id = (unsigned short) CurrentBinding->GetPresentationContext();
|
||
((rpcconn_response *) pFragment)->alert_count = (unsigned char) 0;
|
||
((rpcconn_response *) pFragment)->reserved = 0;
|
||
}
|
||
|
||
pFragment->call_id = CallId;
|
||
|
||
Status = Connection->SendFragment(
|
||
pFragment,
|
||
LastFragmentFlag,
|
||
HeaderSize,
|
||
MaxSecuritySize,
|
||
LengthLeft,
|
||
MaximumFragmentLength,
|
||
ReservedForSecurity) ;
|
||
|
||
if (Status != RPC_S_OK || LastFragmentFlag)
|
||
{
|
||
FreeBuffer(&SendBuffer);
|
||
return (Status) ;
|
||
}
|
||
|
||
pFragment = (rpcconn_common *)
|
||
(((unsigned char *) pFragment) + MaxDataLength);
|
||
|
||
LengthLeft -= MaxDataLength;
|
||
}
|
||
|
||
ASSERT(0);
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCALL::ProcessSendComplete (
|
||
IN RPC_STATUS EventStatus,
|
||
IN BUFFER Buffer
|
||
)
|
||
/*++
|
||
Function Name:ProcessSendComplete
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
int MaxDataLength = MaximumFragmentLength
|
||
- sizeof(rpcconn_response) - MaxSecuritySize;
|
||
unsigned int MyCurrentBufferLength;
|
||
|
||
LogEvent(SU_SCALL, EV_NOTIFY, this, Buffer, EventStatus, 1);
|
||
|
||
ASSERT(Buffer);
|
||
ASSERT((char *) Buffer-CurrentOffset
|
||
+sizeof(rpcconn_request) == CurrentBuffer);
|
||
ASSERT((((rpcconn_common *) Buffer)->pfc_flags & PFC_LAST_FRAG) == 0);
|
||
|
||
if (EventStatus != RPC_S_OK)
|
||
{
|
||
Status = RPC_S_CALL_FAILED;
|
||
goto Abort;
|
||
}
|
||
|
||
MyCurrentBufferLength = CurrentBufferLength - MaxDataLength;
|
||
CurrentOffset += MaxDataLength;
|
||
|
||
CallMutex.Request();
|
||
if (MyCurrentBufferLength == 0)
|
||
{
|
||
Connection->TransFreeBuffer(
|
||
(char *) CurrentBuffer-sizeof(rpcconn_response));
|
||
|
||
CurrentBuffer = BufferQueue.TakeOffQueue(&MyCurrentBufferLength);
|
||
if (CurrentBuffer == 0)
|
||
{
|
||
if (pAsync && (pAsync->Flags & RPC_C_NOTIFY_ON_SEND_COMPLETE))
|
||
{
|
||
if (!IssueNotification(RpcSendComplete))
|
||
{
|
||
AsyncStatus = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
}
|
||
CurrentBufferLength = 0;
|
||
CallMutex.Clear();
|
||
return;
|
||
}
|
||
|
||
CurrentOffset = 0;
|
||
|
||
if (fChoked == 1 && pAsync == 0 && BufferQueue.Size() <=1)
|
||
{
|
||
fChoked = 0;
|
||
SyncEvent.Raise();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// We know that there is more to send in the current buffer
|
||
// We need to restore the part of the buffer which we overwrote
|
||
// with authentication information.
|
||
//
|
||
ASSERT(CurrentBuffer);
|
||
unsigned char *ReservedForSecurity = (unsigned char *) CurrentBuffer
|
||
+ CurrentOffset + MyCurrentBufferLength
|
||
+ Connection->AdditionalSpaceForSecurity;
|
||
|
||
if ((Connection->AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
|
||
&& (MaxSecuritySize != 0))
|
||
{
|
||
RpcpMemoryCopy((char *) Buffer+MaximumFragmentLength-MaxSecuritySize,
|
||
ReservedForSecurity, MaxSecuritySize);
|
||
}
|
||
}
|
||
|
||
ASSERT(MyCurrentBufferLength);
|
||
|
||
CurrentBufferLength = MyCurrentBufferLength;
|
||
CallMutex.Clear();
|
||
|
||
ASSERT(CurrentBuffer);
|
||
|
||
Status = SendNextFragment();
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
goto Abort;
|
||
}
|
||
|
||
//
|
||
// Remove reference held by the outstanding send
|
||
// or the call reference in the case of the last call
|
||
//
|
||
RemoveReference(); // CALL--
|
||
|
||
return;
|
||
|
||
Abort:
|
||
ASSERT(CurrentBuffer);
|
||
ASSERT(Status != RPC_S_OK);
|
||
|
||
|
||
Connection->TransFreeBuffer(
|
||
(char *) CurrentBuffer-sizeof(rpcconn_response));
|
||
|
||
//
|
||
// We cannot remove the reference here, if we do
|
||
// we'll cause the other thread to puke
|
||
//
|
||
AsyncStatus = Status;
|
||
|
||
BUFFER MyBuffer;
|
||
unsigned int ignore;
|
||
|
||
CallMutex.Request();
|
||
while (MyBuffer = BufferQueue.TakeOffQueue(&ignore))
|
||
{
|
||
Connection->TransFreeBuffer((char *) MyBuffer-sizeof(rpcconn_response));
|
||
}
|
||
// wake up the thread that was flow controlled, if any
|
||
if (fChoked == 1 && pAsync == 0)
|
||
{
|
||
fChoked = 0;
|
||
SyncEvent.Raise();
|
||
}
|
||
CallMutex.Clear();
|
||
|
||
CurrentBufferLength = 0;
|
||
|
||
//
|
||
// Remove the reply reference
|
||
//
|
||
RemoveReference(); // CALL--
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::ImpersonateClient (
|
||
)
|
||
/*++
|
||
Function Name:ImpersonateClient
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
This is relatively easy: we check to see if there is RPC protocol level
|
||
security, if there is not, we let the transport try and impersonate
|
||
the client, and if there is, we let the GSSAPI deal with it.
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
return Connection->ImpersonateClient();
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::RevertToSelf (
|
||
)
|
||
/*++
|
||
Function Name:RevertToSelf
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
As with ImpersonateClient, this is relatively easy. We just check
|
||
to see if we should let the RPC protocol level security deal with
|
||
it or the transport.
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
return Connection->RevertToSelf();
|
||
}
|
||
|
||
RPC_STATUS
|
||
OSF_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;
|
||
HANDLE ImpersonationToken;
|
||
BOOL Result;
|
||
PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContextPlaceholder;
|
||
SECURITY_CONTEXT *SecurityContext = Connection->CurrentSecurityContext;
|
||
SECURITY_STATUS SecurityStatus;
|
||
BOOL fNeedToCloseToken;
|
||
AUTHZ_CLIENT_CONTEXT_HANDLE AuthzContext;
|
||
|
||
ASSERT (AuthzResourceManager != NULL);
|
||
|
||
if (!SecurityContext)
|
||
{
|
||
return RPC_S_NO_CONTEXT_AVAILABLE;
|
||
}
|
||
|
||
AuthzContext = SecurityContext->GetAuthzContext();
|
||
|
||
if (ImpersonateOnReturn)
|
||
{
|
||
Status = OSF_SCALL::ImpersonateClient();
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
RpcpErrorAddRecord(EEInfoGCRuntime,
|
||
Status,
|
||
EEInfoDLOSF_SCALL__GetAuthorizationContext10,
|
||
(ULONGLONG)this,
|
||
(ULONGLONG)0);
|
||
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
if (AuthzContext)
|
||
{
|
||
Status = DuplicateAuthzContext(AuthzContext,
|
||
pExpirationTime,
|
||
Identifier,
|
||
Flags,
|
||
DynamicGroupArgs,
|
||
pAuthzClientContext);
|
||
|
||
if ((Status != RPC_S_OK) && ImpersonateOnReturn)
|
||
{
|
||
RevertStatus = OSF_SCALL::RevertToSelf();
|
||
ASSERT(RevertStatus == RPC_S_OK);
|
||
}
|
||
|
||
// EEInfo, if any, has already been added
|
||
return Status;
|
||
}
|
||
|
||
// if there was Authz context created, we would have
|
||
// returned by now. If we are here, this means there
|
||
// is none. Create it.
|
||
Status = SecurityContext->GetAccessToken(&ImpersonationToken,
|
||
&fNeedToCloseToken);
|
||
|
||
if (Status)
|
||
{
|
||
if (ImpersonateOnReturn)
|
||
{
|
||
RevertStatus = OSF_SCALL::RevertToSelf();
|
||
ASSERT(RevertStatus == RPC_S_OK);
|
||
}
|
||
return Status;
|
||
}
|
||
|
||
Status = CreateAndSaveAuthzContextFromToken(SecurityContext->GetAuthzContextAddress(),
|
||
ImpersonationToken,
|
||
AuthzResourceManager,
|
||
pExpirationTime,
|
||
Identifier,
|
||
Flags,
|
||
DynamicGroupArgs,
|
||
pAuthzClientContext);
|
||
|
||
if (fNeedToCloseToken)
|
||
{
|
||
CloseHandle(ImpersonationToken);
|
||
}
|
||
|
||
if (Status)
|
||
{
|
||
if (ImpersonateOnReturn)
|
||
{
|
||
RevertStatus = OSF_SCALL::RevertToSelf();
|
||
ASSERT(RevertStatus == RPC_S_OK);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::GetAssociationContextCollection (
|
||
OUT ContextCollection **CtxCollection
|
||
)
|
||
/*++
|
||
Function Name: GetAssociationContextCollection
|
||
|
||
Parameters:
|
||
CtxCollection - a placeholder where to put the pointer to
|
||
the context collection.
|
||
|
||
Description:
|
||
The context handle code will call the SCALL to get the collection
|
||
of context handles for this association. The SCALL method will
|
||
simply delegate to the association.
|
||
|
||
Returns:
|
||
RPC_S_OK for success or RPC_S_* for error.
|
||
|
||
--*/
|
||
{
|
||
return Connection->GetAssociationContextCollection(CtxCollection);
|
||
}
|
||
|
||
void
|
||
OSF_SCALL::CleanupCallAndSendFault (
|
||
IN RPC_STATUS Status,
|
||
IN int DidNotExecute
|
||
)
|
||
/*++
|
||
Function Name:CleanupCallAndSendFault
|
||
|
||
Parameters: Status - the error code for the fault
|
||
|
||
Description:
|
||
|
||
A syntactic sugar function that saves all relevant call members in a local
|
||
variable, cleans up the call, and then sends the fault directly on the
|
||
connection. Designed to prevent the case where we send the fault to the client
|
||
and the next request comes in before we have made this call available - this
|
||
confuses the server.
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
p_context_id_t p_cont = 0;
|
||
OSF_SCONNECTION *pLocalConnection;
|
||
unsigned long LocalCallId = CallId;
|
||
|
||
if (CurrentBinding)
|
||
p_cont = (p_context_id_t)CurrentBinding->GetPresentationContext();
|
||
|
||
pLocalConnection = Connection;
|
||
|
||
// make the call available before we send the fault
|
||
CleanupCall();
|
||
pLocalConnection->SendFault(Status, DidNotExecute, LocalCallId, p_cont);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::ConvertToServerBinding (
|
||
OUT RPC_BINDING_HANDLE __RPC_FAR * ServerBinding
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
If possible, convert this connection 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.
|
||
|
||
RPC_S_CANNOT_SUPPORT - This will be returned if the transport does
|
||
not support query the network address of the client.
|
||
|
||
--*/
|
||
{
|
||
RPC_CHAR * NetworkAddress;
|
||
RPC_STATUS Status;
|
||
RPC_CHAR * StringBinding;
|
||
|
||
Status = Connection->TransQueryClientNetworkAddress(
|
||
&NetworkAddress);
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
return(Status);
|
||
}
|
||
|
||
Status = RpcStringBindingCompose(0,
|
||
Address->InqRpcProtocolSequence(),
|
||
NetworkAddress,
|
||
0,
|
||
0,
|
||
&StringBinding);
|
||
delete NetworkAddress;
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
return(Status);
|
||
}
|
||
|
||
Status = RpcBindingFromStringBinding(StringBinding, ServerBinding);
|
||
|
||
if ( ObjectUuidSpecified != 0 && RPC_S_OK == Status)
|
||
{
|
||
Status = RpcBindingSetObject(*ServerBinding, (UUID *) &ObjectUuid);
|
||
}
|
||
RpcStringFree(&StringBinding);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
|
||
OSF_SCONNECTION::OSF_SCONNECTION (
|
||
IN OSF_ADDRESS * TheAddress,
|
||
IN RPC_CONNECTION_TRANSPORT * ServerInfo,
|
||
IN OUT RPC_STATUS * Status
|
||
) : ConnMutex(Status)
|
||
{
|
||
ObjectType = OSF_SCONNECTION_TYPE;
|
||
MaxFrag = 512;
|
||
Association = 0;
|
||
AuthContextId = 0;
|
||
SavedHeader = 0;
|
||
SavedHeaderSize = 0;
|
||
CurrentSecurityContext = 0;
|
||
RpcSecurityBeingUsed = 0;
|
||
SecurityContextAltered = 0;
|
||
AdditionalSpaceForSecurity = 0;
|
||
|
||
DceSecurityInfo.SendSequenceNumber = 0;
|
||
DceSecurityInfo.ReceiveSequenceNumber = 0;
|
||
AuthContinueNeeded = 0;
|
||
CurrentCallId=-1;
|
||
CachedSCallAvailable = 1;
|
||
this->ServerInfo = ServerInfo;
|
||
ConnectionClosedFlag = 0;
|
||
Address = TheAddress;
|
||
TransConnection = (char *) this+sizeof(OSF_SCONNECTION);
|
||
|
||
if (IsServerSideDebugInfoEnabled())
|
||
{
|
||
// zero out the CachedSCall - this is a signal that
|
||
// the OSF_SCALL constructor will use to tell
|
||
// it is the cached call
|
||
CachedSCall = NULL;
|
||
DebugCell = (DebugConnectionInfo *) AllocateCell(&DebugCellTag);
|
||
if (DebugCell != 0)
|
||
{
|
||
memset(DebugCell, 0, sizeof(*DebugCell));
|
||
DebugCell->Type = dctConnectionInfo;
|
||
TheAddress->GetDebugCellIDForThisObject(&DebugCell->Endpoint);
|
||
}
|
||
else
|
||
*Status = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
else
|
||
DebugCell = NULL;
|
||
|
||
CachedSCall = new (ServerInfo->SendContextSize)
|
||
OSF_SCALL(this, Status);
|
||
if (CachedSCall == 0)
|
||
{
|
||
*Status = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
fExclusive = 0;
|
||
fDontFlush = 0;
|
||
fFirstCall = 0;
|
||
fCurrentlyDispatched = 0;
|
||
}
|
||
|
||
OSF_SCONNECTION::~OSF_SCONNECTION (
|
||
)
|
||
{
|
||
OSF_SBINDING * SBinding;
|
||
SECURITY_CONTEXT * SecurityContext;
|
||
DictionaryCursor cursor;
|
||
|
||
if (CachedSCall)
|
||
{
|
||
delete CachedSCall;
|
||
}
|
||
|
||
ASSERT( AuthInfo.PacHandle == 0 );
|
||
if ( CurrentSecurityContext && AuthInfo.PacHandle )
|
||
{
|
||
CurrentSecurityContext->DeletePac( AuthInfo.PacHandle );
|
||
}
|
||
|
||
SecurityContextDict.Reset(cursor);
|
||
while ( (SecurityContext = SecurityContextDict.Next(cursor)) != 0 )
|
||
delete SecurityContext;
|
||
|
||
Bindings.Reset(cursor);
|
||
while (SBinding = Bindings.Next(cursor))
|
||
delete SBinding;
|
||
|
||
if (Association)
|
||
Association->RemoveConnection();
|
||
|
||
if (SavedHeader)
|
||
{
|
||
RpcpFarFree(SavedHeader);
|
||
}
|
||
|
||
if (ServerInfo)
|
||
{
|
||
//
|
||
// ServerInfo will be set to 0 when create on the SCONNECTION fails
|
||
// look at NewConnection
|
||
//
|
||
ServerInfo->Close(TransConnection, fDontFlush);
|
||
}
|
||
|
||
if (DebugCell)
|
||
{
|
||
FreeCell(DebugCell, &DebugCellTag);
|
||
}
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCONNECTION::TransSend (
|
||
IN void * Buffer,
|
||
IN unsigned int BufferLength
|
||
)
|
||
/*++
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
|
||
{
|
||
rpcconn_common * pkt = (rpcconn_common *) Buffer;
|
||
LogEvent(SU_SCONN, EV_PKT_OUT, this, 0, (pkt->PTYPE << 16) | pkt->frag_length);
|
||
}
|
||
|
||
if (ConnectionClosedFlag != 0)
|
||
return(RPC_P_CONNECTION_CLOSED);
|
||
|
||
if (DebugCell)
|
||
{
|
||
DebugCell->LastSendTime = NtGetTickCount();
|
||
DebugCell->LastTransmitFragmentSize = (USHORT) BufferLength;
|
||
}
|
||
|
||
DceSecurityInfo.SendSequenceNumber += 1;
|
||
|
||
Status = ServerInfo->SyncSend(
|
||
TransConnection,
|
||
BufferLength,
|
||
Buffer,
|
||
TRUE,
|
||
TRUE,
|
||
INFINITE); // Timeout
|
||
|
||
|
||
VALIDATE(Status)
|
||
{
|
||
RPC_S_OK,
|
||
RPC_S_OUT_OF_MEMORY,
|
||
RPC_S_OUT_OF_RESOURCES,
|
||
RPC_P_SEND_FAILED
|
||
} END_VALIDATE;
|
||
|
||
if ( Status == RPC_S_OK )
|
||
{
|
||
GlobalRpcServer->PacketSent();
|
||
}
|
||
|
||
if ( Status == RPC_P_SEND_FAILED )
|
||
{
|
||
ConnectionClosedFlag = 1;
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCONNECTION::TransAsyncSend (
|
||
IN void * Buffer,
|
||
IN unsigned int BufferLength,
|
||
IN void *SendContext
|
||
)
|
||
/*++
|
||
Function Name:TransAsyncSend
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
|
||
{
|
||
rpcconn_common * pkt = (rpcconn_common *) Buffer;
|
||
LogEvent(SU_SCONN, EV_PKT_OUT, this, 0, (pkt->PTYPE << 16) | pkt->frag_length);
|
||
}
|
||
|
||
if ( ConnectionClosedFlag != 0 )
|
||
{
|
||
return(RPC_P_CONNECTION_CLOSED);
|
||
}
|
||
|
||
if (DebugCell)
|
||
{
|
||
DebugCell->LastSendTime = NtGetTickCount();
|
||
DebugCell->LastTransmitFragmentSize = (USHORT) BufferLength;
|
||
}
|
||
|
||
DceSecurityInfo.SendSequenceNumber += 1;
|
||
|
||
Status = ServerInfo->Send(TransConnection,
|
||
BufferLength,
|
||
(BUFFER) Buffer,
|
||
SendContext);
|
||
|
||
if (Status == RPC_S_OK)
|
||
{
|
||
GlobalRpcServer->PacketSent();
|
||
}
|
||
|
||
if ( Status == RPC_P_SEND_FAILED )
|
||
{
|
||
ConnectionClosedFlag = 1;
|
||
}
|
||
|
||
|
||
VALIDATE(Status)
|
||
{
|
||
RPC_S_OK,
|
||
RPC_S_OUT_OF_MEMORY,
|
||
RPC_S_OUT_OF_RESOURCES,
|
||
RPC_P_SEND_FAILED
|
||
} END_VALIDATE;
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCONNECTION::TransAsyncReceive (
|
||
)
|
||
/*++
|
||
Function Name:TransAsyncReceive
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
|
||
//
|
||
// Each outstanding receive will hold a reference
|
||
// on the connection
|
||
//
|
||
AddReference(); // CONN++
|
||
|
||
if (ConnectionClosedFlag != 0)
|
||
{
|
||
AbortConnection();
|
||
return(RPC_P_CONNECTION_CLOSED);
|
||
}
|
||
|
||
Status = ServerInfo->Recv(TransConnection);
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
VALIDATE(Status)
|
||
{
|
||
RPC_P_RECEIVE_FAILED,
|
||
RPC_P_CONNECTION_SHUTDOWN,
|
||
RPC_P_CONNECTION_CLOSED
|
||
} END_VALIDATE;
|
||
|
||
if (fExclusive && !CachedSCallAvailable)
|
||
CachedSCall->WakeUpPipeThreadIfNecessary(RPC_S_CALL_FAILED);
|
||
|
||
ConnectionClosedFlag = 1;
|
||
AbortConnection();
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
unsigned int
|
||
OSF_SCONNECTION::TransMaximumSend (
|
||
)
|
||
/*++
|
||
|
||
--*/
|
||
{
|
||
return(ServerInfo->MaximumFragmentSize);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCONNECTION::TransImpersonateClient (
|
||
)
|
||
/*++
|
||
Function Name:TransImpersonateClient
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
If the transport module supports impersonation it will provide the
|
||
sImpersonateClient entry point, in which case we call it. If an
|
||
error occurs (indicated by sImpersonateClient returning non-zero),
|
||
then no context is available. NOTE: this is the correct error code
|
||
for NT; it may not be the right one (or only one) for other transports
|
||
which support impersonation.
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
|
||
if ( ServerInfo->ImpersonateClient == 0 )
|
||
{
|
||
return(RPC_S_CANNOT_SUPPORT);
|
||
}
|
||
|
||
Status = ServerInfo->ImpersonateClient(TransConnection);
|
||
|
||
VALIDATE(Status)
|
||
{
|
||
RPC_S_OK,
|
||
RPC_S_NO_CONTEXT_AVAILABLE
|
||
} END_VALIDATE;
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCONNECTION::TransRevertToSelf (
|
||
)
|
||
/*++
|
||
|
||
--*/
|
||
// As with TransImpersonateClient, if the transport module supports
|
||
// impersonation, then sRevertToSelf will be non-zero. We do not have
|
||
// to worry about errors.
|
||
//
|
||
// For revert to self to work in NT, the transport module needs to know
|
||
// the handle of the calling thread when it was originally created. None
|
||
// of the other operating systems we support at this point have
|
||
// impersonation built into the transports.
|
||
{
|
||
RPC_STATUS Status;
|
||
|
||
if ( ServerInfo->RevertToSelf != 0 )
|
||
{
|
||
Status = ServerInfo->RevertToSelf(TransConnection);
|
||
ASSERT( Status == RPC_S_OK );
|
||
}
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCONNECTION::TransQueryClientProcess (
|
||
OUT RPC_CLIENT_PROCESS_IDENTIFIER * ClientProcess
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
We need to obtain the client process identifier for the client process
|
||
at the other end of this connection. This is necessary so that we can
|
||
determine whether or not a connection should belong to a given
|
||
association. We need to do this so that context handles (which hang off
|
||
of associations) are secure.
|
||
|
||
Arguments:
|
||
|
||
ClientProcess - Returns the client process identifier for the client
|
||
process at the other end of this connection.
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
|
||
if ( ServerInfo->QueryClientId == 0 )
|
||
{
|
||
ClientProcess->ZeroOut();
|
||
}
|
||
else
|
||
{
|
||
Status = ServerInfo->QueryClientId(TransConnection,
|
||
ClientProcess);
|
||
ASSERT( Status == RPC_S_OK );
|
||
}
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCONNECTION::TransQueryClientNetworkAddress (
|
||
OUT RPC_CHAR ** NetworkAddress
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to query the network address of the client at the
|
||
other end of this connection.
|
||
|
||
Arguments:
|
||
|
||
NetworkAddress - Returns the client's network address.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - The client's network address has successfully been obtained.
|
||
|
||
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
|
||
operation.
|
||
|
||
RPC_S_CANNOT_SUPPORT - This particular transport implementation does
|
||
not support this operation.
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
|
||
if ( ( ServerInfo->TransInterfaceVersion < 2 )
|
||
|| ( ServerInfo->QueryClientAddress == 0 ) )
|
||
{
|
||
return(RPC_S_CANNOT_SUPPORT);
|
||
}
|
||
|
||
Status = ServerInfo->QueryClientAddress(TransConnection,
|
||
NetworkAddress);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCONNECTION::AbortConnection (
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
--*/
|
||
{
|
||
DictionaryCursor cursor;
|
||
|
||
//
|
||
// When AbortConnection is called,
|
||
// there should be no pending IO
|
||
//
|
||
|
||
//
|
||
// Delete the object, ie: remove the object reference
|
||
//
|
||
Delete();
|
||
|
||
//
|
||
// If there are calls stuck in callbacks, wake them up
|
||
//
|
||
if (fExclusive)
|
||
{
|
||
ConnMutex.Request();
|
||
if (CachedSCallAvailable == 0)
|
||
{
|
||
CachedSCall->DeactivateCall();
|
||
CachedSCallAvailable = 1;
|
||
ConnMutex.Clear();
|
||
|
||
CachedSCall->AbortCall();
|
||
}
|
||
else
|
||
{
|
||
ConnMutex.Clear();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ConnMutex.Request();
|
||
OSF_SCALL *NextCall;
|
||
|
||
CallDict.Reset(cursor);
|
||
while ((NextCall = CallDict.Next(cursor)) != 0)
|
||
{
|
||
NextCall->AbortCall();
|
||
}
|
||
ConnMutex.Clear();
|
||
}
|
||
|
||
//
|
||
// Remove the reference held by the pending receive
|
||
//
|
||
RemoveReference(); // CONN--
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCONNECTION::FreeObject (
|
||
)
|
||
{
|
||
RemoveFromAssociation();
|
||
|
||
delete this;
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCONNECTION::FreeSCall (
|
||
IN OSF_SCALL *SCall,
|
||
IN BOOL fRemove
|
||
)
|
||
/*++
|
||
Function Name:FreeSCall
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
ASSERT(SCall->BufferQueue.IsQueueEmpty());
|
||
|
||
if (fExclusive == 0)
|
||
{
|
||
if (fRemove)
|
||
{
|
||
OSF_SCALL *Call;
|
||
|
||
ConnMutex.Request();
|
||
Call = CallDict.Delete(ULongToPtr(SCall->CallId));
|
||
ConnMutex.Clear();
|
||
|
||
ASSERT(Call == 0 || Call == SCall);
|
||
}
|
||
|
||
// CurrentBinding is initialized in OSF_SCALL::BeginRpcCall
|
||
// by a call to OSF_CCONNECTION::LookupBinding. That call may
|
||
// not succeed if we do not find the binding in the dictionary,
|
||
// or we may fail before initialization.
|
||
if (SCall->CurrentBinding != NULL)
|
||
{
|
||
RPC_INTERFACE *CallInterface;
|
||
|
||
CallInterface = SCall->CurrentBinding->GetInterface();
|
||
|
||
if (SCall->pAsync)
|
||
{
|
||
CallInterface->EndCall(0, 1);
|
||
}
|
||
|
||
if (CallInterface->IsAutoListenInterface())
|
||
{
|
||
CallInterface->EndAutoListenCall();
|
||
}
|
||
}
|
||
|
||
SCall->DeactivateCall();
|
||
if (SCall == CachedSCall)
|
||
{
|
||
CachedSCallAvailable = 1;
|
||
}
|
||
else
|
||
{
|
||
delete SCall;
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Remove the reference held by the call
|
||
//
|
||
RemoveReference(); // CONN--
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCONNECTION::TransGetBuffer (
|
||
OUT void * * Buffer,
|
||
IN unsigned int BufferLength
|
||
)
|
||
{
|
||
int * Memory;
|
||
|
||
//
|
||
// Our memory allocator returns memory which is aligned by at least
|
||
// 8, so we dont need to worry about aligning it.
|
||
//
|
||
Memory = (int *) CoAllocateBuffer(BufferLength);
|
||
if ( Memory == 0 )
|
||
{
|
||
return(RPC_S_OUT_OF_MEMORY);
|
||
}
|
||
|
||
ASSERT( IsBufferAligned(Memory) );
|
||
|
||
*Buffer = Memory;
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
void
|
||
OSF_SCONNECTION::TransFreeBuffer ( // Free a buffer.
|
||
IN void * Buffer
|
||
)
|
||
{
|
||
CoFreeBuffer(Buffer);
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCONNECTION::ProcessReceiveComplete (
|
||
IN RPC_STATUS EventStatus,
|
||
IN BUFFER Buffer,
|
||
IN UINT BufferLength
|
||
)
|
||
/*++
|
||
Function Name:ProcessReceiveComplete
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
rpcconn_common *Packet = (rpcconn_common *) Buffer;
|
||
rpcconn_auth3 * AuthThirdLegPacket;
|
||
sec_trailer * NewSecurityTrailer;
|
||
OSF_SCALL *SCall = 0;
|
||
RPC_STATUS Status;
|
||
SECURITY_BUFFER_DESCRIPTOR InputBufferDescriptor;
|
||
SECURITY_BUFFER InputBuffers[4];
|
||
BOOL fReceivePosted = 0;
|
||
BOOL fDNE = 0;
|
||
|
||
if (EventStatus)
|
||
{
|
||
LogEvent(SU_SCONN, EV_PKT_IN, this, LongToPtr(EventStatus));
|
||
}
|
||
else
|
||
{
|
||
if (Packet->PTYPE == rpc_request)
|
||
{
|
||
LogEvent(SU_SCONN, EV_PKT_IN, this, 0,
|
||
(((rpcconn_request *)Packet)->opnum << 24) | (Packet->PTYPE << 16) | Packet->frag_length);
|
||
}
|
||
else
|
||
{
|
||
LogEvent(SU_SCONN, EV_PKT_IN, this, 0, (Packet->PTYPE << 16) | Packet->frag_length);
|
||
}
|
||
}
|
||
|
||
if (DebugCell)
|
||
{
|
||
DebugCell->LastReceiveTime = NtGetTickCount();
|
||
DebugCell->LastTransmitFragmentSize = (USHORT)BufferLength;
|
||
}
|
||
|
||
if (EventStatus != RPC_S_OK)
|
||
{
|
||
VALIDATE(EventStatus)
|
||
{
|
||
RPC_P_CONNECTION_CLOSED,
|
||
RPC_P_RECEIVE_FAILED,
|
||
RPC_P_CONNECTION_SHUTDOWN
|
||
} END_VALIDATE;
|
||
ConnectionClosedFlag = 1;
|
||
|
||
if (fExclusive && !CachedSCallAvailable)
|
||
CachedSCall->WakeUpPipeThreadIfNecessary(RPC_S_CALL_FAILED);
|
||
|
||
TransFreeBuffer(Buffer);
|
||
|
||
AbortConnection();
|
||
return;
|
||
}
|
||
|
||
ASSERT(EventStatus == 0);
|
||
ASSERT(Buffer);
|
||
|
||
GlobalRpcServer->PacketReceived();
|
||
|
||
//
|
||
// Check and make sure that if this is the first packet on this
|
||
// connection that it is a bind packet.
|
||
//
|
||
if ((Association == 0) && (Packet->PTYPE != rpc_bind))
|
||
{
|
||
SendBindNak(protocol_version_not_supported, Packet->call_id);
|
||
TransFreeBuffer(Packet);
|
||
AbortConnection();
|
||
return;
|
||
}
|
||
|
||
switch (Packet->PTYPE)
|
||
{
|
||
case rpc_request:
|
||
if (fExclusive)
|
||
{
|
||
if (Packet->pfc_flags & PFC_FIRST_FRAG
|
||
&& CachedSCallAvailable)
|
||
{
|
||
//
|
||
// New call is about to be started
|
||
// Add a reference on the connection
|
||
//
|
||
AddReference(); // CONN++
|
||
|
||
CachedSCallAvailable = 0;
|
||
fReceivePosted = CachedSCall->BeginRpcCall(Packet, BufferLength);
|
||
}
|
||
else
|
||
{
|
||
fReceivePosted = CachedSCall->ProcessReceivedPDU(Packet, BufferLength);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ((long) Packet->call_id <= (long) CurrentCallId)
|
||
{
|
||
//
|
||
// If it is a non-first fragment, or if it is a callback
|
||
//
|
||
SCall = FindCall(Packet->call_id);
|
||
if (SCall == 0)
|
||
{
|
||
if ((long) Packet->call_id < (long) CurrentCallId
|
||
|| (Packet->pfc_flags & PFC_FIRST_FRAG) == 0)
|
||
{
|
||
//
|
||
// Can't find the call. This could be because the pipe call
|
||
// raised an exception and the call is now complete.
|
||
//
|
||
TransFreeBuffer(Packet);
|
||
fReceivePosted = 0;
|
||
goto End;
|
||
}
|
||
//
|
||
// If the client is Win95, it will use the same call_id
|
||
// for subsequent calls on the same connection
|
||
//
|
||
}
|
||
}
|
||
|
||
if (SCall == 0)
|
||
{
|
||
CurrentCallId = Packet->call_id;
|
||
|
||
//
|
||
// A new call is about to be started, create one
|
||
//
|
||
if (InterlockedCompareExchange(
|
||
(LPLONG) &CachedSCallAvailable, 0, 1))
|
||
{
|
||
SCall = CachedSCall;
|
||
}
|
||
else
|
||
{
|
||
Status = RPC_S_OK;
|
||
SCall = new (ServerInfo->SendContextSize)
|
||
OSF_SCALL(this, &Status);
|
||
if (SCall == 0 || Status != RPC_S_OK)
|
||
{
|
||
SendFault(RPC_S_OUT_OF_MEMORY, 1, Packet->call_id);
|
||
|
||
if (SCall != 0)
|
||
{
|
||
delete SCall;
|
||
}
|
||
|
||
TransFreeBuffer(Packet);
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// New call is about to be started
|
||
// Add a reference on the connection
|
||
//
|
||
AddReference(); // CONN++
|
||
|
||
int DictKey;
|
||
|
||
ASSERT(SCall);
|
||
ConnMutex.Request();
|
||
DictKey = CallDict.Insert(ULongToPtr(Packet->call_id), SCall);
|
||
ConnMutex.Clear();
|
||
|
||
if (DictKey == -1)
|
||
{
|
||
SendFault(RPC_S_OUT_OF_MEMORY, 1, Packet->call_id);
|
||
FreeSCall(SCall);
|
||
TransFreeBuffer(Packet);
|
||
break;
|
||
}
|
||
|
||
ASSERT(SCall);
|
||
//
|
||
// We need this reference to prevent the call from going
|
||
// away from under us when the client goes away
|
||
//
|
||
SCall->AddReference(); // CALL++
|
||
fReceivePosted = SCall->BeginRpcCall(Packet, BufferLength);
|
||
SCall->OSF_SCALL::RemoveReference(); // CALL--
|
||
}
|
||
else
|
||
{
|
||
ASSERT(SCall);
|
||
|
||
//
|
||
// The packet will be freed by the callee
|
||
//
|
||
fReceivePosted = SCall->ProcessReceivedPDU(Packet, BufferLength);
|
||
|
||
//
|
||
// Remove the reference added by the lookup
|
||
//
|
||
SCall->OSF_SCALL::RemoveReference(); // CALL--
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case rpc_bind:
|
||
case rpc_alter_context:
|
||
//
|
||
// Save the unbyteswapped header for the security related stuff
|
||
// Especially if SECURITY is on.
|
||
// For Bind and AlterContext we save entire packet [we can do better though]
|
||
//
|
||
if (Packet->auth_length != 0)
|
||
{
|
||
if (SavedHeaderSize < BufferLength)
|
||
{
|
||
if (SavedHeader != 0)
|
||
{
|
||
ASSERT(SavedHeaderSize != 0);
|
||
RpcpFarFree(SavedHeader);
|
||
}
|
||
|
||
SavedHeader = RpcpFarAllocate(BufferLength);
|
||
if (SavedHeader == 0)
|
||
{
|
||
if ( Association == 0 )
|
||
{
|
||
SendBindNak(
|
||
protocol_version_not_supported,
|
||
Packet->call_id);
|
||
TransFreeBuffer(Packet);
|
||
AbortConnection();
|
||
return;
|
||
}
|
||
|
||
SC_CLEANUP(RPC_S_OUT_OF_MEMORY, 1);
|
||
}
|
||
SavedHeaderSize = BufferLength;
|
||
RpcpMemoryCopy(SavedHeader, Packet, BufferLength);
|
||
}
|
||
else
|
||
{
|
||
RpcpMemoryCopy(SavedHeader, Packet, BufferLength);
|
||
}
|
||
}
|
||
|
||
//
|
||
// These things can take quite a while and could cause deadlocks
|
||
// if we dont have any listening threads
|
||
//
|
||
Address->CreateThread();
|
||
|
||
Status = ValidatePacket(Packet, BufferLength);
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
ASSERT( Status == RPC_S_PROTOCOL_ERROR );
|
||
|
||
//
|
||
// If this the first packet on the connection, it should be an
|
||
// rpc_bind packet, and we want to send a rpc_bind_nak packet
|
||
// rather than a fault. We can tell that this is the first packet
|
||
// because the association is zero.
|
||
//
|
||
|
||
if ( Association == 0 )
|
||
{
|
||
SendBindNak(protocol_version_not_supported,
|
||
Packet->call_id);
|
||
TransFreeBuffer(Packet);
|
||
|
||
AbortConnection();
|
||
return;
|
||
}
|
||
|
||
//
|
||
// It is not the first packet, so we need to send a fault instead,
|
||
// and then we will blow the connection away.
|
||
//
|
||
|
||
SC_CLEANUP(RPC_S_PROTOCOL_ERROR, 1);
|
||
}
|
||
|
||
if (Packet->PTYPE == rpc_bind)
|
||
{
|
||
if (Association != 0)
|
||
{
|
||
SendBindNak(reason_not_specified_reject,
|
||
Packet->call_id);
|
||
AbortConnection();
|
||
return;
|
||
}
|
||
|
||
//
|
||
// The packet will be freed by the callee
|
||
//
|
||
if (AssociationRequested(
|
||
(rpcconn_bind *) Packet, BufferLength) != 0)
|
||
{
|
||
AbortConnection();
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (Association == 0)
|
||
{
|
||
SendFault(RPC_S_PROTOCOL_ERROR, 1, Packet->call_id);
|
||
}
|
||
|
||
//
|
||
// The packet will be freed by the callee
|
||
//
|
||
if (AlterContextRequested(
|
||
(rpcconn_alter_context *) Packet,
|
||
BufferLength) != 0 )
|
||
{
|
||
AbortConnection();
|
||
return;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case rpc_auth_3:
|
||
//
|
||
// This means that the client sent us back a third leg
|
||
// AuthInfo.Authentication packet.
|
||
//
|
||
ASSERT(AuthContinueNeeded != 0);
|
||
|
||
// Save the unbyteswapped header
|
||
ASSERT(AuthInfo.AuthenticationLevel
|
||
!= RPC_C_AUTHN_LEVEL_NONE);
|
||
|
||
AuthThirdLegPacket = (rpcconn_auth3 *) Buffer;
|
||
|
||
if (AuthContinueNeeded == 0)
|
||
{
|
||
SC_CLEANUP(RPC_S_PROTOCOL_ERROR, 1);
|
||
}
|
||
|
||
if (SavedHeaderSize < BufferLength)
|
||
{
|
||
if (SavedHeader != 0)
|
||
{
|
||
ASSERT(SavedHeaderSize != 0);
|
||
RpcpFarFree(SavedHeader);
|
||
}
|
||
|
||
SavedHeader = RpcpFarAllocate(BufferLength);
|
||
if (SavedHeader == 0)
|
||
{
|
||
SC_CLEANUP(RPC_S_OUT_OF_MEMORY, 1);
|
||
}
|
||
SavedHeaderSize = BufferLength;
|
||
RpcpMemoryCopy(SavedHeader, AuthThirdLegPacket,
|
||
BufferLength);
|
||
}
|
||
else
|
||
{
|
||
RpcpMemoryCopy(SavedHeader, AuthThirdLegPacket,
|
||
BufferLength);
|
||
}
|
||
|
||
//
|
||
// These things can take quite a while and could cause deadlocks
|
||
// if we dont have any listening threads
|
||
//
|
||
Address->CreateThread();
|
||
|
||
Status = ValidatePacket(
|
||
(rpcconn_common *) AuthThirdLegPacket,
|
||
BufferLength);
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
SC_CLEANUP(RPC_S_OUT_OF_MEMORY, 1);
|
||
}
|
||
|
||
if ( AuthThirdLegPacket->common.PTYPE != rpc_auth_3 )
|
||
{
|
||
SC_CLEANUP(RPC_S_OUT_OF_MEMORY, 1);
|
||
}
|
||
|
||
NewSecurityTrailer = (sec_trailer *)
|
||
(((unsigned char *) AuthThirdLegPacket)
|
||
+ AuthThirdLegPacket->common.frag_length - sizeof(sec_trailer)
|
||
- AuthThirdLegPacket->common.auth_length);
|
||
|
||
if ( (NewSecurityTrailer->auth_type != AuthInfo.AuthenticationService)
|
||
|| (NewSecurityTrailer->auth_level != AuthInfo.AuthenticationLevel) )
|
||
{
|
||
SC_CLEANUP(RPC_S_OUT_OF_MEMORY, 1);
|
||
}
|
||
|
||
InputBufferDescriptor.ulVersion = 0;
|
||
InputBufferDescriptor.cBuffers = 4;
|
||
InputBufferDescriptor.pBuffers = InputBuffers;
|
||
|
||
InputBuffers[0].cbBuffer = sizeof(rpcconn_auth3);
|
||
InputBuffers[0].BufferType =
|
||
SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
InputBuffers[0].pvBuffer = SavedHeader;
|
||
|
||
InputBuffers[1].cbBuffer =
|
||
AuthThirdLegPacket->common.frag_length
|
||
- sizeof(rpcconn_auth3)
|
||
- AuthThirdLegPacket->common.auth_length;
|
||
InputBuffers[1].BufferType =
|
||
SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
InputBuffers[1].pvBuffer =
|
||
(char *) SavedHeader + sizeof(rpcconn_auth3);
|
||
|
||
InputBuffers[2].cbBuffer = AuthThirdLegPacket->common.auth_length;
|
||
InputBuffers[2].BufferType = SECBUFFER_TOKEN;
|
||
InputBuffers[2].pvBuffer = NewSecurityTrailer + 1;
|
||
|
||
InputBuffers[3].cbBuffer = sizeof(DCE_INIT_SECURITY_INFO);
|
||
InputBuffers[3].BufferType =
|
||
SECBUFFER_PKG_PARAMS | SECBUFFER_READONLY;
|
||
InputBuffers[3].pvBuffer = &InitSecurityInfo;
|
||
|
||
Status = CurrentSecurityContext->AcceptThirdLeg(
|
||
*((unsigned long *)
|
||
AuthThirdLegPacket->common.drep),
|
||
&InputBufferDescriptor, 0);
|
||
|
||
LogEvent(SU_SCONN, EV_SEC_ACCEPT3, this, LongToPtr(Status), 0);
|
||
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
SC_CLEANUP(RPC_S_OUT_OF_MEMORY, 1);
|
||
}
|
||
TransFreeBuffer(AuthThirdLegPacket);
|
||
|
||
DceSecurityInfo.ReceiveSequenceNumber += 1;
|
||
|
||
//
|
||
// We need to figure out how much space to reserve for security
|
||
// information at the end of request and response packets.
|
||
// In addition to saving space for the signature or header,
|
||
// we need space to pad the packet to a multiple of the maximum
|
||
// security block size as well as for the security trailer.
|
||
//
|
||
if ((AuthInfo.AuthenticationLevel
|
||
== RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
|
||
|| (AuthInfo.AuthenticationLevel
|
||
== RPC_C_AUTHN_LEVEL_PKT)
|
||
|| (AuthInfo.AuthenticationLevel
|
||
== RPC_C_AUTHN_LEVEL_CONNECT) )
|
||
{
|
||
AdditionalSpaceForSecurity = MAXIMUM_SECURITY_BLOCK_SIZE
|
||
+ CurrentSecurityContext->MaximumSignatureLength()
|
||
+ sizeof(sec_trailer);
|
||
}
|
||
else if ( AuthInfo.AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY )
|
||
{
|
||
AdditionalSpaceForSecurity = MAXIMUM_SECURITY_BLOCK_SIZE
|
||
+ CurrentSecurityContext->MaximumHeaderLength()
|
||
+ sizeof(sec_trailer);
|
||
}
|
||
|
||
break;
|
||
|
||
case rpc_cancel :
|
||
case rpc_orphaned :
|
||
case rpc_fault :
|
||
case rpc_response:
|
||
if (fExclusive)
|
||
{
|
||
if (!CachedSCallAvailable)
|
||
{
|
||
//
|
||
// The packet will be freed by the callee
|
||
//
|
||
fReceivePosted = CachedSCall->ProcessReceivedPDU(
|
||
Packet, BufferLength);
|
||
}
|
||
else
|
||
{
|
||
TransFreeBuffer(Packet);
|
||
fReceivePosted = 0;
|
||
goto End;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SCall = FindCall(Packet->call_id);
|
||
if (SCall == 0)
|
||
{
|
||
if (Packet->PTYPE == rpc_cancel
|
||
|| Packet->PTYPE == rpc_orphaned)
|
||
{
|
||
//
|
||
// Too late, looks like the call is complete
|
||
//
|
||
TransFreeBuffer(Packet);
|
||
}
|
||
else
|
||
{
|
||
#if DBG
|
||
PrintToDebugger(
|
||
"RPC: Conn: 0x%lXNo SCall corresponding to the CallId: %d\n",
|
||
this, Packet->call_id);
|
||
ASSERT(0);
|
||
#endif
|
||
SC_CLEANUP(RPC_S_PROTOCOL_ERROR, 0);
|
||
}
|
||
break;
|
||
}
|
||
//
|
||
// The packet will be freed by the callee
|
||
//
|
||
fReceivePosted = SCall->ProcessReceivedPDU(Packet, BufferLength);
|
||
|
||
//
|
||
// Remove the reference added by the lookup
|
||
//
|
||
SCall->OSF_SCALL::RemoveReference(); // CALL--
|
||
}
|
||
|
||
|
||
break;
|
||
|
||
default:
|
||
SC_CLEANUP(RPC_S_PROTOCOL_ERROR, 0);
|
||
}
|
||
|
||
End:
|
||
//
|
||
// Submit the receive for the next packet
|
||
//
|
||
if (!fReceivePosted)
|
||
{
|
||
TransAsyncReceive();
|
||
}
|
||
|
||
//
|
||
// Remove the reference held by the pending receive
|
||
//
|
||
OSF_SCONNECTION::RemoveReference(); // CONN--
|
||
return;
|
||
|
||
Cleanup:
|
||
SendFault(Status, fDNE, Packet->call_id);
|
||
TransFreeBuffer(Packet);
|
||
|
||
AbortConnection();
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCONNECTION::ImpersonateClient (
|
||
)
|
||
/*++
|
||
Function Name:ImpersonateClient
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
|
||
if ( !RpcSecurityBeingUsed )
|
||
{
|
||
Status = SetThreadSecurityContext(
|
||
(SECURITY_CONTEXT *) MAXUINT_PTR);
|
||
if (RPC_S_OK != Status)
|
||
{
|
||
return Status;
|
||
}
|
||
|
||
return TransImpersonateClient();
|
||
}
|
||
|
||
SECURITY_CONTEXT * SecurityContext = CurrentSecurityContext;
|
||
|
||
if (!SecurityContext)
|
||
{
|
||
ASSERT(SecurityContextAltered);
|
||
return RPC_S_NO_CONTEXT_AVAILABLE;
|
||
}
|
||
|
||
Status = SetThreadSecurityContext(
|
||
SecurityContext);
|
||
if (RPC_S_OK != Status)
|
||
{
|
||
return Status;
|
||
}
|
||
|
||
Status = SecurityContext->ImpersonateClient();
|
||
if (RPC_S_OK != Status)
|
||
{
|
||
ClearThreadSecurityContext();
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCONNECTION::RevertToSelf (
|
||
)
|
||
/*++
|
||
Function Name:RevertToSelf
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
SECURITY_CONTEXT * SecurityContext =
|
||
ClearThreadSecurityContext();
|
||
|
||
if (!RpcSecurityBeingUsed)
|
||
{
|
||
if (SecurityContext)
|
||
{
|
||
ASSERT(SecurityContext == (SECURITY_CONTEXT *) MAXUINT_PTR);
|
||
TransRevertToSelf();
|
||
}
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
if (SecurityContext)
|
||
{
|
||
SecurityContext->RevertToSelf();
|
||
}
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCONNECTION::SendFault (
|
||
IN RPC_STATUS Status,
|
||
IN int DidNotExecute,
|
||
IN unsigned long CallId,
|
||
IN p_context_id_t p_cont_id
|
||
)
|
||
/*++
|
||
Function Name:SendFault
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
rpcconn_fault *Fault;
|
||
size_t FaultSize;
|
||
BOOL fEEInfoPresent = FALSE;
|
||
|
||
if (g_fSendEEInfo)
|
||
{
|
||
fEEInfoPresent = PickleEEInfoIntoPacket(FaultSizeWithoutEEInfo,
|
||
(PVOID *)&Fault,
|
||
&FaultSize);
|
||
}
|
||
|
||
if (fEEInfoPresent)
|
||
{
|
||
Fault->reserved = FaultEEInfoPresent;
|
||
Fault->alloc_hint = FaultSize;
|
||
}
|
||
else
|
||
{
|
||
FaultSize = FaultSizeWithoutEEInfo;
|
||
Fault = (rpcconn_fault *)_alloca(FaultSize);
|
||
RpcpMemorySet(Fault, 0, FaultSize);
|
||
}
|
||
|
||
ConstructPacket((rpcconn_common *)Fault, rpc_fault, FaultSize);
|
||
|
||
if (DidNotExecute != 0)
|
||
{
|
||
DidNotExecute = PFC_DID_NOT_EXECUTE;
|
||
}
|
||
|
||
if (Status == ERROR_SHUTDOWN_IN_PROGRESS)
|
||
{
|
||
if (DidNotExecute)
|
||
{
|
||
Status = RPC_S_SERVER_UNAVAILABLE;
|
||
}
|
||
else
|
||
{
|
||
Status = ERROR_SERVER_SHUTDOWN_IN_PROGRESS;
|
||
}
|
||
}
|
||
|
||
Fault->common.pfc_flags |= PFC_FIRST_FRAG | PFC_LAST_FRAG | DidNotExecute;
|
||
Fault->status = MapToNcaStatusCode(Status);
|
||
Fault->common.call_id = CallId;
|
||
Fault->p_cont_id = p_cont_id;
|
||
|
||
TransSend(Fault, FaultSize);
|
||
|
||
if (fEEInfoPresent)
|
||
delete Fault;
|
||
}
|
||
|
||
BOOL
|
||
OSF_SCONNECTION::PickleEEInfoIntoPacket (
|
||
IN size_t PickleStartOffset,
|
||
OUT PVOID *Packet,
|
||
OUT size_t *PacketSize)
|
||
/*++
|
||
Function Name: PickeEEInfoIntoPacket
|
||
|
||
Parameters:
|
||
PickleStartOffset - the offset in bytes where the pickling starts
|
||
Packet - the allocated packet will be placed here on success.
|
||
PacketSize - the size of the packet if success is returned. If
|
||
failure is returned, this parameter is undefined
|
||
|
||
Description:
|
||
Checks for EEInfo on the thread, trims the EEInfo to MaxFrag,
|
||
allocates the packet, zeroes it out, and pickles the EEInfo
|
||
starting from PickleStartOffset.
|
||
|
||
Returns:
|
||
TRUE if EEInfo was pickled. FALSE if not.
|
||
|
||
--*/
|
||
{
|
||
unsigned char *CurrentPacket;
|
||
BOOL fEEInfoPresent = FALSE;
|
||
ExtendedErrorInfo *EEInfo;
|
||
RPC_STATUS RpcStatus;
|
||
size_t CurrentPacketSize;
|
||
|
||
EEInfo = RpcpGetEEInfo();
|
||
if (EEInfo)
|
||
{
|
||
ASSERT(MaxFrag > 0);
|
||
AddComputerNameToChain(EEInfo);
|
||
TrimEEInfoToLength (MaxFrag, &CurrentPacketSize);
|
||
if (CurrentPacketSize != 0)
|
||
{
|
||
CurrentPacketSize += PickleStartOffset;
|
||
CurrentPacket = new unsigned char[CurrentPacketSize];
|
||
|
||
if (CurrentPacket)
|
||
{
|
||
ASSERT(IsBufferAligned(CurrentPacket + PickleStartOffset));
|
||
|
||
RpcpMemorySet(CurrentPacket, 0, CurrentPacketSize);
|
||
|
||
RpcStatus = PickleEEInfo(EEInfo,
|
||
CurrentPacket + PickleStartOffset,
|
||
CurrentPacketSize - PickleStartOffset);
|
||
|
||
if (RpcStatus == RPC_S_OK)
|
||
{
|
||
fEEInfoPresent = TRUE;
|
||
*Packet = CurrentPacket;
|
||
*PacketSize = CurrentPacketSize;
|
||
}
|
||
else
|
||
{
|
||
delete CurrentPacket;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return fEEInfoPresent;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCONNECTION::SendFragment(
|
||
IN OUT rpcconn_common *pFragment,
|
||
IN unsigned int LastFragmentFlag,
|
||
IN unsigned int HeaderSize,
|
||
IN unsigned int MaxSecuritySize,
|
||
IN unsigned int DataLength,
|
||
IN unsigned int MaximumFragmentLength,
|
||
IN unsigned char *MyReservedForSec,
|
||
IN BOOL fAsync,
|
||
IN void *SendContext
|
||
)
|
||
/*++
|
||
Function Name:SendFragment
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
sec_trailer * SecurityTrailer;
|
||
unsigned int SecurityLength;
|
||
unsigned int AuthPadLength;
|
||
SECURITY_BUFFER_DESCRIPTOR BufferDescriptor;
|
||
SECURITY_BUFFER SecurityBuffers[5];
|
||
DCE_MSG_SECURITY_INFO MsgSecurityInfo;
|
||
RPC_STATUS Status;
|
||
unsigned long AuthLevel;
|
||
|
||
AuthLevel = AuthInfo.AuthenticationLevel;
|
||
if ( ((AuthLevel != RPC_C_AUTHN_LEVEL_NONE)
|
||
&& (AuthLevel != RPC_C_AUTHN_LEVEL_CONNECT))
|
||
|| ((AuthLevel == RPC_C_AUTHN_LEVEL_CONNECT)
|
||
&&(MaxSecuritySize != 0)) )
|
||
{
|
||
if ( LastFragmentFlag == 0 )
|
||
{
|
||
SecurityTrailer = (sec_trailer *)
|
||
(((unsigned char *) pFragment)
|
||
+ MaximumFragmentLength - MaxSecuritySize);
|
||
|
||
// It is not the last fragment, so we need to save away the
|
||
// part of the buffer which could get overwritten with
|
||
// authentication information. We can not use memcpy,
|
||
// because the source and destination regions may overlap.
|
||
|
||
RpcpMemoryMove(MyReservedForSec, SecurityTrailer,
|
||
MaxSecuritySize);
|
||
AuthPadLength = 0;
|
||
}
|
||
else
|
||
{
|
||
ASSERT( MAXIMUM_SECURITY_BLOCK_SIZE == 16 );
|
||
AuthPadLength = Pad16(HeaderSize+DataLength+sizeof(sec_trailer));
|
||
DataLength += AuthPadLength;
|
||
ASSERT( ((DataLength + HeaderSize+sizeof(sec_trailer))
|
||
% MAXIMUM_SECURITY_BLOCK_SIZE) == 0 );
|
||
SecurityTrailer = (sec_trailer *)
|
||
(((unsigned char *) pFragment) + DataLength
|
||
+ HeaderSize);
|
||
pFragment->pfc_flags |= PFC_LAST_FRAG;
|
||
}
|
||
|
||
SecurityTrailer->auth_type = (unsigned char) AuthInfo.AuthenticationService;
|
||
SecurityTrailer->auth_level = (unsigned char) AuthLevel;
|
||
SecurityTrailer->auth_pad_length = (unsigned char) AuthPadLength;
|
||
SecurityTrailer->auth_reserved = 0;
|
||
SecurityTrailer->auth_context_id = AuthContextId;
|
||
|
||
BufferDescriptor.ulVersion = 0;
|
||
BufferDescriptor.cBuffers = 5;
|
||
BufferDescriptor.pBuffers = SecurityBuffers;
|
||
|
||
SecurityBuffers[0].cbBuffer = HeaderSize;
|
||
SecurityBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
SecurityBuffers[0].pvBuffer = ((unsigned char *) pFragment);
|
||
|
||
SecurityBuffers[1].cbBuffer = (LastFragmentFlag != 0 ?
|
||
DataLength
|
||
: (MaximumFragmentLength - HeaderSize
|
||
- MaxSecuritySize ));
|
||
SecurityBuffers[1].BufferType = SECBUFFER_DATA;
|
||
SecurityBuffers[1].pvBuffer = ((unsigned char *) pFragment)
|
||
+ HeaderSize;
|
||
|
||
SecurityBuffers[2].cbBuffer = sizeof(sec_trailer);
|
||
SecurityBuffers[2].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
SecurityBuffers[2].pvBuffer = SecurityTrailer;
|
||
|
||
SecurityBuffers[3].cbBuffer = MaxSecuritySize - sizeof(sec_trailer);
|
||
SecurityBuffers[3].BufferType = SECBUFFER_TOKEN;
|
||
SecurityBuffers[3].pvBuffer = SecurityTrailer + 1;
|
||
|
||
SecurityBuffers[4].cbBuffer = sizeof(DCE_MSG_SECURITY_INFO);
|
||
SecurityBuffers[4].BufferType = SECBUFFER_PKG_PARAMS
|
||
| SECBUFFER_READONLY;
|
||
|
||
SecurityBuffers[4].pvBuffer = &MsgSecurityInfo;
|
||
|
||
MsgSecurityInfo.SendSequenceNumber =
|
||
DceSecurityInfo.SendSequenceNumber;
|
||
MsgSecurityInfo.ReceiveSequenceNumber =
|
||
DceSecurityInfo.ReceiveSequenceNumber;
|
||
MsgSecurityInfo.PacketType = pFragment->PTYPE;
|
||
|
||
pFragment->auth_length = (unsigned short) SecurityBuffers[3].cbBuffer;
|
||
SecurityLength = MaxSecuritySize;
|
||
|
||
if ( LastFragmentFlag != 0 )
|
||
{
|
||
pFragment->frag_length = HeaderSize + DataLength + SecurityLength;
|
||
}
|
||
else
|
||
{
|
||
pFragment->frag_length += SecurityLength - MaxSecuritySize;
|
||
}
|
||
|
||
Status = CurrentSecurityContext->SignOrSeal(
|
||
MsgSecurityInfo.SendSequenceNumber,
|
||
AuthLevel != RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
||
&BufferDescriptor);
|
||
|
||
//
|
||
// If the package computes a checksum of the read-only buffers,
|
||
// then it should not change SecurityBuffers[3].cbBuffer.
|
||
//
|
||
|
||
// removed ASSERT( pFragment->auth_length == SecurityBuffers[3].cbBuffer);
|
||
|
||
{
|
||
//
|
||
// The package might have updated SecurityBuffers[3].cbBuffer.
|
||
// update the header appropriately
|
||
//
|
||
unsigned short AuthLengthChange = pFragment->auth_length - (unsigned short) SecurityBuffers[3].cbBuffer;
|
||
|
||
SecurityLength -= AuthLengthChange;
|
||
pFragment->auth_length -= AuthLengthChange;
|
||
pFragment->frag_length -= AuthLengthChange;
|
||
}
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
if ( LastFragmentFlag == 0 )
|
||
{
|
||
RpcpMemoryCopy(SecurityTrailer, MyReservedForSec,
|
||
MaxSecuritySize);
|
||
}
|
||
|
||
if (Status == ERROR_SHUTDOWN_IN_PROGRESS)
|
||
{
|
||
return Status;
|
||
}
|
||
|
||
if ( (Status == SEC_E_CONTEXT_EXPIRED)
|
||
|| (Status == SEC_E_QOP_NOT_SUPPORTED) )
|
||
{
|
||
return (RPC_S_SEC_PKG_ERROR);
|
||
}
|
||
return (RPC_S_ACCESS_DENIED);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SecurityLength = 0;
|
||
}
|
||
|
||
if ( LastFragmentFlag != 0 )
|
||
{
|
||
pFragment->pfc_flags |= PFC_LAST_FRAG;
|
||
|
||
ASSERT(pFragment->frag_length == DataLength+HeaderSize+SecurityLength);
|
||
|
||
if (fAsync)
|
||
{
|
||
Status = TransAsyncSend(
|
||
pFragment,
|
||
pFragment->frag_length,
|
||
SendContext);
|
||
|
||
}
|
||
else
|
||
{
|
||
Status = TransSend(
|
||
pFragment,
|
||
pFragment->frag_length);
|
||
}
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
if ((Status == RPC_P_CONNECTION_CLOSED)
|
||
|| (Status == RPC_P_SEND_FAILED))
|
||
{
|
||
return(RPC_S_CALL_FAILED_DNE);
|
||
}
|
||
if ( Status == RPC_P_RECEIVE_FAILED)
|
||
{
|
||
return(RPC_S_CALL_FAILED);
|
||
}
|
||
|
||
VALIDATE(Status)
|
||
{
|
||
RPC_S_OUT_OF_MEMORY,
|
||
RPC_S_OUT_OF_RESOURCES
|
||
} END_VALIDATE;
|
||
return(Status);
|
||
}
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
|
||
ASSERT(pFragment->frag_length == MaximumFragmentLength
|
||
- MaxSecuritySize + SecurityLength);
|
||
|
||
|
||
if (fAsync)
|
||
{
|
||
Status = TransAsyncSend (
|
||
pFragment,
|
||
pFragment->frag_length,
|
||
SendContext);
|
||
|
||
}
|
||
else
|
||
{
|
||
Status = TransSend(
|
||
pFragment,
|
||
pFragment->frag_length);
|
||
|
||
//
|
||
// We need to restore the part of the buffer which we overwrote
|
||
// with authentication information.
|
||
//
|
||
if ((AuthLevel != RPC_C_AUTHN_LEVEL_NONE)
|
||
&&(MaxSecuritySize != 0))
|
||
{
|
||
RpcpMemoryCopy(SecurityTrailer,
|
||
MyReservedForSec, MaxSecuritySize);
|
||
}
|
||
}
|
||
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
if ( (Status == RPC_P_CONNECTION_CLOSED)
|
||
|| (Status == RPC_P_SEND_FAILED))
|
||
{
|
||
return(RPC_S_CALL_FAILED_DNE);
|
||
}
|
||
|
||
VALIDATE(Status)
|
||
{
|
||
RPC_S_OUT_OF_MEMORY,
|
||
RPC_S_OUT_OF_RESOURCES
|
||
} END_VALIDATE;
|
||
|
||
return(Status);
|
||
}
|
||
|
||
return Status ;
|
||
}
|
||
|
||
RPC_STATUS
|
||
OSF_SCONNECTION::GetServerPrincipalName (
|
||
IN unsigned long Flags,
|
||
OUT RPC_CHAR **ServerPrincipalName OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Obtains the server principal name.
|
||
|
||
Arguments:
|
||
|
||
ServerPrincipalName - Returns the server principal name which the client
|
||
specified.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK or RPC_S_* / Win32 error
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
SECURITY_CONTEXT * SecurityContext;
|
||
|
||
SecurityContext = CurrentSecurityContext;
|
||
|
||
if ( ARGUMENT_PRESENT(ServerPrincipalName) )
|
||
{
|
||
if (AuthInfo.AuthenticationService == RPC_C_AUTHN_GSS_SCHANNEL)
|
||
{
|
||
if (AuthInfo.PacHandle == 0)
|
||
{
|
||
Status = SecurityContext->GetDceInfo(
|
||
&AuthInfo.PacHandle,
|
||
&AuthInfo.AuthorizationService
|
||
);
|
||
if (Status)
|
||
{
|
||
return Status;
|
||
}
|
||
|
||
}
|
||
|
||
Status = RpcCertGeneratePrincipalName( (PCCERT_CONTEXT) AuthInfo.PacHandle,
|
||
Flags,
|
||
ServerPrincipalName
|
||
);
|
||
return Status;
|
||
|
||
}
|
||
else
|
||
{
|
||
Status = Address->Server->InquirePrincipalName(
|
||
SecurityContext->AuthenticationService, ServerPrincipalName);
|
||
|
||
VALIDATE(Status)
|
||
{
|
||
RPC_S_OK,
|
||
RPC_S_OUT_OF_MEMORY
|
||
} END_VALIDATE;
|
||
return(Status);
|
||
}
|
||
}
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCONNECTION::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 - The operation completed successfully.
|
||
|
||
RPC_S_BINDING_HAS_NO_AUTH - The remote procedure call represented by
|
||
this binding is not authenticated.
|
||
|
||
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to inquire the
|
||
server principal name.
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
SECURITY_CONTEXT * SecurityContext;
|
||
|
||
SecurityContext = CurrentSecurityContext;
|
||
if ( !SecurityContext )
|
||
{
|
||
return(RPC_S_BINDING_HAS_NO_AUTH);
|
||
}
|
||
|
||
if (AuthenticationLevel)
|
||
{
|
||
*AuthenticationLevel = SecurityContext->AuthenticationLevel;
|
||
}
|
||
|
||
if (AuthenticationService)
|
||
{
|
||
*AuthenticationService = SecurityContext->AuthenticationService;
|
||
}
|
||
|
||
if (Privileges || AuthorizationService)
|
||
{
|
||
if (AuthInfo.PacHandle == 0)
|
||
{
|
||
SecurityContext->GetDceInfo(
|
||
&AuthInfo.PacHandle,
|
||
&AuthInfo.AuthorizationService
|
||
);
|
||
}
|
||
|
||
if ( Privileges )
|
||
{
|
||
*Privileges = AuthInfo.PacHandle;
|
||
}
|
||
if ( AuthorizationService )
|
||
{
|
||
*AuthorizationService = AuthInfo.AuthorizationService;
|
||
}
|
||
}
|
||
|
||
Status = GetServerPrincipalName(Flags, ServerPrincipalName);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
RPC_STATUS
|
||
OSF_SCONNECTION::InquireCallAttributes (
|
||
IN OUT void *RpcCallAttributes
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Inquire the security context attributes for the OSF 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;
|
||
SECURITY_CONTEXT * SecurityContext;
|
||
RPC_CHAR *ServerPrincipalName = NULL;
|
||
ULONG ServerPrincipalNameLength; // in bytes, including terminating NULL
|
||
|
||
SecurityContext = CurrentSecurityContext;
|
||
if ( !SecurityContext )
|
||
{
|
||
return(RPC_S_BINDING_HAS_NO_AUTH);
|
||
}
|
||
|
||
CallAttributes =
|
||
(RPC_CALL_ATTRIBUTES_V1 *)RpcCallAttributes;
|
||
|
||
CallAttributes->AuthenticationLevel = SecurityContext->AuthenticationLevel;
|
||
CallAttributes->AuthenticationService = SecurityContext->AuthenticationService;
|
||
CallAttributes->NullSession = SecurityContext->ContextAttributes & ASC_RET_NULL_SESSION;
|
||
|
||
if (CallAttributes->Flags & RPC_QUERY_CLIENT_PRINCIPAL_NAME)
|
||
{
|
||
CallAttributes->ClientPrincipalNameBufferLength = 0;
|
||
}
|
||
|
||
if (CallAttributes->Flags & RPC_QUERY_SERVER_PRINCIPAL_NAME)
|
||
{
|
||
Status = GetServerPrincipalName(CallAttributes->Flags,
|
||
&ServerPrincipalName);
|
||
|
||
if (Status != RPC_S_OK)
|
||
return Status;
|
||
|
||
if (ServerPrincipalName)
|
||
{
|
||
ServerPrincipalNameLength = (RpcpStringLength(ServerPrincipalName) + 1) * sizeof(RPC_CHAR);
|
||
// now, see whether the user supplied memory is big enough
|
||
if (CallAttributes->ServerPrincipalNameBufferLength < ServerPrincipalNameLength)
|
||
{
|
||
Status = ERROR_MORE_DATA;
|
||
}
|
||
else
|
||
{
|
||
// a buffer is specified, and it is large enough
|
||
RpcpMemoryCopy(CallAttributes->ServerPrincipalName,
|
||
ServerPrincipalName,
|
||
ServerPrincipalNameLength);
|
||
Status = RPC_S_OK;
|
||
}
|
||
|
||
// in both cases store the resulting length
|
||
CallAttributes->ServerPrincipalNameBufferLength = ServerPrincipalNameLength;
|
||
|
||
RpcStringFree(&ServerPrincipalName);
|
||
}
|
||
else
|
||
{
|
||
CallAttributes->ServerPrincipalNameBufferLength = 0;
|
||
}
|
||
return Status;
|
||
}
|
||
else
|
||
{
|
||
return RPC_S_OK;
|
||
}
|
||
}
|
||
|
||
OSF_SBINDING *
|
||
OSF_SCONNECTION::LookupBinding (
|
||
IN p_context_id_t PresentContextId
|
||
)
|
||
/*++
|
||
Function Name:LookupBinding
|
||
|
||
Parameters:
|
||
|
||
Description:
|
||
|
||
Returns:
|
||
|
||
--*/
|
||
{
|
||
OSF_SBINDING *CurBinding;
|
||
DictionaryCursor cursor;
|
||
|
||
Bindings.Reset(cursor);
|
||
while ((CurBinding = Bindings.Next(cursor)))
|
||
{
|
||
if (CurBinding->GetPresentationContext() == PresentContextId)
|
||
{
|
||
return CurBinding;
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
RPC_STATUS
|
||
OSF_SCONNECTION::GetAssociationContextCollection (
|
||
OUT ContextCollection **CtxCollection
|
||
)
|
||
{
|
||
return Association->GetAssociationContextCollection(CtxCollection);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCONNECTION::IsClientLocal (
|
||
OUT unsigned int * ClientLocalFlag
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
We just need to inquire the client process identifier for this
|
||
connection; if the first part is zero, then the client is local.
|
||
|
||
Arguments:
|
||
|
||
ClientLocalFlag - Returns an indication of whether or not the client is
|
||
local (ie. on the same machine as the server). This field will be
|
||
set to a non-zero value to indicate that the client is local;
|
||
otherwise, the client is remote.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - This will always be used.
|
||
|
||
--*/
|
||
{
|
||
RPC_CLIENT_PROCESS_IDENTIFIER ClientProcess;
|
||
int i;
|
||
|
||
TransQueryClientProcess(&ClientProcess);
|
||
|
||
if ( ClientProcess.IsLocal() == FALSE )
|
||
{
|
||
if (ClientProcess.IsNull())
|
||
return RPC_S_CANNOT_SUPPORT;
|
||
|
||
*ClientLocalFlag = 0;
|
||
}
|
||
else
|
||
{
|
||
*ClientLocalFlag = 1;
|
||
}
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
int
|
||
OSF_SCONNECTION::SendBindNak (
|
||
IN p_reject_reason_t reject_reason,
|
||
IN unsigned long CallId
|
||
)
|
||
{
|
||
rpcconn_bind_nak *BindNak;
|
||
size_t BindNakSize;
|
||
BOOL fEEInfoPresent = FALSE;
|
||
int RetVal;
|
||
|
||
if (g_fSendEEInfo)
|
||
{
|
||
fEEInfoPresent = PickleEEInfoIntoPacket(BindNakSizeWithoutEEInfo,
|
||
(PVOID *) &BindNak,
|
||
&BindNakSize);
|
||
}
|
||
|
||
if (fEEInfoPresent == FALSE)
|
||
{
|
||
BindNakSize = BindNakSizeWithoutEEInfoAndSignature;
|
||
BindNak = (rpcconn_bind_nak *)_alloca(BindNakSize);
|
||
RpcpMemorySet(BindNak, 0, BindNakSize);
|
||
}
|
||
else
|
||
{
|
||
RpcpMemoryCopy (&BindNak->Signature,
|
||
BindNakEEInfoSignature,
|
||
sizeof (UUID));
|
||
}
|
||
|
||
ConstructPacket((rpcconn_common *) BindNak, rpc_bind_nak, BindNakSize);
|
||
BindNak->provider_reject_reason = reject_reason;
|
||
BindNak->versions.n_protocols = 1;
|
||
BindNak->versions.p_protocols[0].major = OSF_RPC_V20_VERS;
|
||
BindNak->versions.p_protocols[0].minor = 0;
|
||
BindNak->common.call_id = CallId;
|
||
BindNak->common.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG ;
|
||
|
||
if (TransSend(BindNak,BindNakSize))
|
||
{
|
||
RetVal = -1;
|
||
}
|
||
else
|
||
{
|
||
RetVal = 0;
|
||
}
|
||
|
||
if (fEEInfoPresent)
|
||
{
|
||
delete BindNak;
|
||
}
|
||
|
||
return RetVal;
|
||
}
|
||
|
||
typedef struct tagSelectedInterfaceAndTransferSyntaxInfo
|
||
{
|
||
RPC_INTERFACE *Interface;
|
||
int SelectedAvailableTransferSyntaxIndex;
|
||
} SelectedInterfaceAndTransferSyntaxInfo;
|
||
|
||
int
|
||
OSF_SCONNECTION::ProcessPContextList (
|
||
IN OSF_ADDRESS * Address,
|
||
IN p_cont_list_t *PContextList,
|
||
IN OUT unsigned int * PContextListLength,
|
||
OUT p_result_list_t *ResultList
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Address - Supplies the address which owns this connection. We need
|
||
this information so that we can try to find the interface (and
|
||
transfer syntax) the client requested.
|
||
|
||
PContextList - Supplies a pointer to the presentation context list
|
||
which the client passed in the rpc_bind packet. It has not yet
|
||
had data conversion performed on it.
|
||
|
||
PContextListLength - Supplies the maximum possible length of the
|
||
presentation context list, and returns its actual length. The
|
||
lengths are in bytes as usual.
|
||
|
||
ResultList - Returns the result list corresponding to the presentation
|
||
context list.
|
||
|
||
Return Value:
|
||
|
||
A non-zero value will be returned if we are unable to process the
|
||
presentation context list. The caller should send an rpc_bind_nak
|
||
packet to the client, and then close the connection.
|
||
|
||
--*/
|
||
{
|
||
p_cont_elem_t *PContextElem;
|
||
unsigned int PContextListIndex;
|
||
unsigned int TransferSyntaxIndex;
|
||
SelectedInterfaceAndTransferSyntaxInfo *SelectionInfo;
|
||
OSF_SBINDING * SBinding;
|
||
RPC_STATUS Status;
|
||
BOOL fInterfaceTransferIsPreferred;
|
||
p_result_t *PResultElem;
|
||
int PreferredPContextIndex;
|
||
BOOL fRejectCurrentContext;
|
||
BOOL fPContextAlreadyAccepted;
|
||
unsigned int NumberOfPContextElements;
|
||
int fIgnored;
|
||
|
||
if (*PContextListLength < sizeof(p_cont_list_t))
|
||
{
|
||
return(1);
|
||
}
|
||
|
||
NumberOfPContextElements = (unsigned int) PContextList->n_context_elem;
|
||
|
||
// make sure the client doesn't offer a gaziliion pcontexts
|
||
if (NumberOfPContextElements > 20)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
SelectionInfo = (SelectedInterfaceAndTransferSyntaxInfo *)
|
||
_alloca(sizeof(SelectedInterfaceAndTransferSyntaxInfo) * NumberOfPContextElements);
|
||
|
||
*PContextListLength -= (sizeof(p_cont_list_t) - sizeof(p_cont_elem_t));
|
||
ResultList->n_results = PContextList->n_context_elem;
|
||
ResultList->reserved = 0;
|
||
ResultList->reserved2 = 0;
|
||
|
||
PreferredPContextIndex = -1;
|
||
|
||
for (PContextListIndex = 0, PContextElem = PContextList->p_cont_elem;
|
||
PContextListIndex < NumberOfPContextElements;
|
||
PContextListIndex ++)
|
||
{
|
||
if (*PContextListLength < sizeof(p_cont_elem_t))
|
||
{
|
||
return(1);
|
||
}
|
||
|
||
if (*PContextListLength < (sizeof(p_cont_elem_t) + sizeof(p_syntax_id_t)
|
||
* (PContextElem->n_transfer_syn - 1)))
|
||
{
|
||
return(1);
|
||
}
|
||
|
||
*PContextListLength -= (sizeof(p_cont_elem_t) + sizeof(p_syntax_id_t)
|
||
* (PContextElem->n_transfer_syn - 1));
|
||
|
||
if ( DataConvertEndian(((unsigned char *) &DataRep)) != 0 )
|
||
{
|
||
PContextElem->p_cont_id = RpcpByteSwapShort(PContextElem->p_cont_id);
|
||
ByteSwapSyntaxId(&PContextElem->abstract_syntax);
|
||
for ( TransferSyntaxIndex = 0;
|
||
TransferSyntaxIndex < PContextElem->n_transfer_syn;
|
||
TransferSyntaxIndex++ )
|
||
{
|
||
ByteSwapSyntaxId(&(PContextElem->transfer_syntaxes[
|
||
TransferSyntaxIndex]));
|
||
}
|
||
}
|
||
|
||
Status = Address->FindInterfaceTransfer(
|
||
(PRPC_SYNTAX_IDENTIFIER)
|
||
&PContextElem->abstract_syntax.if_uuid,
|
||
(PRPC_SYNTAX_IDENTIFIER) PContextElem->transfer_syntaxes,
|
||
PContextElem->n_transfer_syn,
|
||
(PRPC_SYNTAX_IDENTIFIER)
|
||
&(ResultList->p_results[PContextListIndex].transfer_syntax),
|
||
&SelectionInfo[PContextListIndex].Interface,
|
||
&fInterfaceTransferIsPreferred,
|
||
&fIgnored,
|
||
&SelectionInfo[PContextListIndex].SelectedAvailableTransferSyntaxIndex);
|
||
|
||
if (Status == RPC_S_OK)
|
||
{
|
||
ResultList->p_results[PContextListIndex].result = acceptance;
|
||
ResultList->p_results[PContextListIndex].reason = 0;
|
||
|
||
if (fInterfaceTransferIsPreferred)
|
||
{
|
||
// only one pcontext can be preferred. If not, there is
|
||
// error in the stubs
|
||
ASSERT(PreferredPContextIndex == -1);
|
||
PreferredPContextIndex = PContextListIndex;
|
||
}
|
||
|
||
// for all accepted we will make a second pass once we know
|
||
// which transfer syntax will be selected
|
||
}
|
||
else
|
||
{
|
||
ResultList->p_results[PContextListIndex].result =
|
||
provider_rejection;
|
||
if (Status == RPC_S_UNSUPPORTED_TRANS_SYN)
|
||
{
|
||
ResultList->p_results[PContextListIndex].reason =
|
||
proposed_transfer_syntaxes_not_supported;
|
||
}
|
||
else
|
||
{
|
||
ASSERT(Status == RPC_S_UNKNOWN_IF);
|
||
ResultList->p_results[PContextListIndex].reason =
|
||
abstract_syntax_not_supported;
|
||
}
|
||
|
||
memset(&(ResultList->p_results[PContextListIndex].
|
||
transfer_syntax.if_uuid.Data1),0,sizeof(GUID));
|
||
ResultList->p_results[PContextListIndex].
|
||
transfer_syntax.if_version = 0;
|
||
}
|
||
|
||
PContextElem = (p_cont_elem_t *) ((unsigned char *)PContextElem + sizeof(p_cont_elem_t)
|
||
+ sizeof(p_syntax_id_t) * (PContextElem->n_transfer_syn - 1));
|
||
}
|
||
|
||
fPContextAlreadyAccepted = FALSE;
|
||
for (PContextListIndex = 0, PResultElem = ResultList->p_results,
|
||
PContextElem = PContextList->p_cont_elem;
|
||
PContextListIndex < NumberOfPContextElements;
|
||
PContextListIndex ++, PResultElem = &(ResultList->p_results[PContextListIndex]))
|
||
{
|
||
fRejectCurrentContext = TRUE;
|
||
|
||
// if there is a preferred context ...
|
||
if (PreferredPContextIndex >= 0)
|
||
{
|
||
// ... and this is the one, don't reject it
|
||
if ((unsigned int)PreferredPContextIndex == PContextListIndex)
|
||
{
|
||
ASSERT(PResultElem->result == acceptance);
|
||
fRejectCurrentContext = FALSE;
|
||
}
|
||
else
|
||
{
|
||
// else nothing - this is not the preferred one, and the
|
||
// default action is reject it
|
||
}
|
||
}
|
||
else if (PResultElem->result == acceptance)
|
||
{
|
||
// if we haven't already accepted one, accept the current
|
||
if (!fPContextAlreadyAccepted)
|
||
{
|
||
fRejectCurrentContext = FALSE;
|
||
fPContextAlreadyAccepted = TRUE;
|
||
}
|
||
else
|
||
{
|
||
// else nothing - we have already accepted one and
|
||
// we will reject this one
|
||
}
|
||
}
|
||
|
||
if (!fRejectCurrentContext)
|
||
{
|
||
SBinding = new OSF_SBINDING(SelectionInfo[PContextListIndex].Interface,
|
||
PContextElem->p_cont_id,
|
||
SelectionInfo[PContextListIndex].SelectedAvailableTransferSyntaxIndex);
|
||
|
||
if ( (SBinding == 0)
|
||
|| (Bindings.Insert(SBinding) == -1))
|
||
{
|
||
PResultElem->result = provider_rejection;
|
||
PResultElem->reason = local_limit_exceeded;
|
||
memset(&(PResultElem->transfer_syntax.if_uuid.Data1), 0, sizeof(p_syntax_id_t));
|
||
}
|
||
}
|
||
else if (PResultElem->result == acceptance)
|
||
{
|
||
// apparently we have already accepted somebody, and this is not the
|
||
// lucky one
|
||
PResultElem->result = provider_rejection;
|
||
PResultElem->reason = proposed_transfer_syntaxes_not_supported;
|
||
memset(&(PResultElem->transfer_syntax.if_uuid.Data1), 0, sizeof(p_syntax_id_t));
|
||
}
|
||
else
|
||
{
|
||
// nothing - we have to reject the current one, and it has already
|
||
// been rejected
|
||
}
|
||
|
||
PContextElem = (p_cont_elem_t *) ((unsigned char *)PContextElem + sizeof(p_cont_elem_t)
|
||
+ sizeof(p_syntax_id_t) * (PContextElem->n_transfer_syn - 1));
|
||
}
|
||
|
||
return(0);
|
||
}
|
||
|
||
unsigned short // Return the minimum of the three arguments.
|
||
MinOf (
|
||
IN unsigned short Arg1,
|
||
IN unsigned short Arg2,
|
||
IN unsigned short Arg3
|
||
)
|
||
{
|
||
unsigned short Min = 0xFFFF;
|
||
|
||
if (Arg1 < Min)
|
||
Min = Arg1;
|
||
if (Arg2 < Min)
|
||
Min = Arg2;
|
||
if (Arg3 < Min)
|
||
Min = Arg3;
|
||
return(Min);
|
||
}
|
||
|
||
int
|
||
OSF_SCONNECTION::AssociationRequested (
|
||
IN rpcconn_bind * BindPacket,
|
||
IN unsigned int BindPacketLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Address - Supplies the address which owns this connection.
|
||
|
||
BindPacket - Supplies the buffer containing the rpc_bind packet
|
||
received from the client.
|
||
|
||
BindPacketLength - Supplies the length of the buffer in bytes.
|
||
|
||
Return Value:
|
||
|
||
A non-zero return value indicates that the connection needs to
|
||
be deleted by the caller.
|
||
|
||
--*/
|
||
{
|
||
p_cont_list_t * PContextList;
|
||
unsigned int SecondaryAddressLength;
|
||
unsigned int BindAckLength, TokenLength = 0, AuthPadLength;
|
||
rpcconn_bind_ack * BindAck;
|
||
RPC_STATUS Status;
|
||
sec_trailer * SecurityTrailer, * NewSecurityTrailer;
|
||
SECURITY_CREDENTIALS * SecurityCredentials = 0;
|
||
RPC_CLIENT_PROCESS_IDENTIFIER ClientProcess;
|
||
unsigned int CompleteNeeded = 0;
|
||
SECURITY_BUFFER_DESCRIPTOR InputBufferDescriptor;
|
||
SECURITY_BUFFER_DESCRIPTOR OutputBufferDescriptor;
|
||
SECURITY_BUFFER InputBuffers[4];
|
||
SECURITY_BUFFER OutputBuffers[4];
|
||
unsigned long CallId = BindPacket->common.call_id;
|
||
ULONG CalculatedSize;
|
||
|
||
PContextList = (p_cont_list_t *) (BindPacket + 1);
|
||
|
||
CalculatedSize = sizeof(rpcconn_bind)+sizeof(p_cont_list_t)
|
||
+ (PContextList->n_context_elem-1)*sizeof(p_cont_elem_t);
|
||
|
||
DataRep = * (unsigned long *) BindPacket->common.drep;
|
||
|
||
if ( BindPacketLength < CalculatedSize )
|
||
{
|
||
TransFreeBuffer(BindPacket);
|
||
SendBindNak(reason_not_specified_reject, CallId);
|
||
return(1);
|
||
}
|
||
|
||
if ( DataConvertEndian(BindPacket->common.drep) != 0 )
|
||
{
|
||
BindPacket->max_xmit_frag = RpcpByteSwapShort(BindPacket->max_xmit_frag);
|
||
BindPacket->max_recv_frag = RpcpByteSwapShort(BindPacket->max_recv_frag);
|
||
BindPacket->assoc_group_id = RpcpByteSwapLong(BindPacket->assoc_group_id);
|
||
}
|
||
|
||
ASSERT(TransMaximumSend() % 8 == 0);
|
||
|
||
MaxFrag = MinOf(BindPacket->max_xmit_frag,
|
||
BindPacket->max_recv_frag,
|
||
(unsigned short) TransMaximumSend()) & 0xFFFFFFF8;
|
||
|
||
if ( MaxFrag < MUST_RECV_FRAG_SIZE )
|
||
MaxFrag = MUST_RECV_FRAG_SIZE;
|
||
|
||
ASSERT(MaxFrag % 8 == 0);
|
||
|
||
// Now we need to check to see if we should be performing authentication
|
||
// at the rpc protocol level. This will be the case if there is
|
||
// authentication information in the packet.
|
||
|
||
if ( BindPacket->common.auth_length != 0 )
|
||
{
|
||
// Ok, we have got authentication information in the packet. We
|
||
// will save away the information, and then check it.
|
||
|
||
SecurityTrailer = (sec_trailer *)
|
||
(((unsigned char *) BindPacket) + BindPacketLength
|
||
- BindPacket->common.auth_length - sizeof(sec_trailer));
|
||
|
||
|
||
AuthInfo.AuthenticationLevel = SecurityTrailer->auth_level;
|
||
|
||
//Hack for OSF Clients
|
||
//If Level is CALL .. bump it ip to CONNECT
|
||
if (AuthInfo.AuthenticationLevel == RPC_C_AUTHN_LEVEL_CALL)
|
||
{
|
||
AuthInfo.AuthenticationLevel = RPC_C_AUTHN_LEVEL_PKT;
|
||
}
|
||
if ( (AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_CONNECT)
|
||
&& (AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_PKT)
|
||
&& (AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
|
||
&& (AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_PKT_PRIVACY) )
|
||
{
|
||
TransFreeBuffer(BindPacket);
|
||
SendBindNak(reason_not_specified_reject, CallId);
|
||
return(1);
|
||
}
|
||
AuthInfo.AuthenticationService = SecurityTrailer->auth_type;
|
||
AuthContextId = SecurityTrailer->auth_context_id;
|
||
|
||
if ( DataConvertEndian(BindPacket->common.drep) != 0 )
|
||
{
|
||
AuthContextId = RpcpByteSwapLong(AuthContextId);
|
||
}
|
||
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
CurrentSecurityContext = new SECURITY_CONTEXT(
|
||
&AuthInfo,
|
||
AuthContextId,
|
||
FALSE,
|
||
&Status
|
||
);
|
||
|
||
if ( (CurrentSecurityContext == 0)
|
||
|| RPC_S_OK != Status
|
||
||(SecurityContextDict.Insert(CurrentSecurityContext) == -1) )
|
||
{
|
||
TransFreeBuffer(BindPacket);
|
||
SendBindNak(local_limit_exceeded_reject, CallId);
|
||
return(1);
|
||
}
|
||
|
||
CallTestHook( TH_RPC_SECURITY_SERVER_CONTEXT_CREATED, CurrentSecurityContext, this );
|
||
|
||
RpcSecurityBeingUsed = 1;
|
||
Status = Address->Server->AcquireCredentials(
|
||
AuthInfo.AuthenticationService, AuthInfo.AuthenticationLevel,
|
||
&SecurityCredentials);
|
||
if ( Status == RPC_S_OUT_OF_MEMORY )
|
||
{
|
||
TransFreeBuffer(BindPacket);
|
||
SendBindNak(local_limit_exceeded_reject, CallId);
|
||
return(1);
|
||
}
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
TransFreeBuffer(BindPacket);
|
||
RpcpErrorAddRecord(EEInfoGCRuntime,
|
||
Status,
|
||
EEInfoDLAssociationRequested30,
|
||
AuthInfo.AuthenticationService,
|
||
AuthInfo.AuthenticationLevel);
|
||
SendBindNak(authentication_type_not_recognized, CallId);
|
||
return(1);
|
||
}
|
||
ASSERT( SecurityCredentials != 0 );
|
||
}
|
||
|
||
// Calculate the size of the rpc_bind_ack packet.
|
||
|
||
SecondaryAddressLength = Address->TransSecondarySize();
|
||
BindAckLength = sizeof(rpcconn_bind_ack) + SecondaryAddressLength
|
||
+ Pad4(SecondaryAddressLength + 2) + sizeof(p_result_list_t)
|
||
+ sizeof(p_result_t) * (PContextList->n_context_elem - 1);
|
||
|
||
// Ok, we need to save some space for authentication information if
|
||
// necessary. This includes space for the token, the security trailer,
|
||
// and alignment if necessary.
|
||
|
||
if ( SecurityCredentials != 0 )
|
||
{
|
||
AuthPadLength = Pad4(BindAckLength);
|
||
BindAckLength += SecurityCredentials->MaximumTokenLength()
|
||
+ sizeof(sec_trailer) + AuthPadLength;
|
||
}
|
||
|
||
// Allocate the rpc_bind_ack packet. If that fails, send a rpc_bind_nak
|
||
// to the client indicating that the server is out of resources;
|
||
// whoever called AssociationRequested will take care of cleaning up
|
||
// the connection.
|
||
|
||
Status = TransGetBuffer((void **) &BindAck, BindAckLength);
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
ASSERT( Status == RPC_S_OUT_OF_MEMORY );
|
||
|
||
if ( SecurityCredentials != 0 )
|
||
{
|
||
SecurityCredentials->DereferenceCredentials();
|
||
}
|
||
TransFreeBuffer(BindPacket);
|
||
SendBindNak(local_limit_exceeded_reject, CallId);
|
||
return(1);
|
||
}
|
||
|
||
// Finally we get to do something about that authentication that the
|
||
// client sent us.
|
||
|
||
if ( SecurityCredentials != 0 )
|
||
{
|
||
NewSecurityTrailer = (sec_trailer *)
|
||
(((unsigned char *) BindAck) + BindAckLength
|
||
- SecurityCredentials->MaximumTokenLength()
|
||
- sizeof(sec_trailer));
|
||
|
||
InitSecurityInfo.DceSecurityInfo = DceSecurityInfo;
|
||
InitSecurityInfo.PacketType = BindPacket->common.PTYPE;
|
||
InputBufferDescriptor.ulVersion = 0;
|
||
InputBufferDescriptor.cBuffers = 4;
|
||
InputBufferDescriptor.pBuffers = InputBuffers;
|
||
|
||
InputBuffers[0].cbBuffer = sizeof(rpcconn_bind);
|
||
InputBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
InputBuffers[0].pvBuffer = SavedHeader;
|
||
|
||
InputBuffers[1].cbBuffer = BindPacket->common.frag_length
|
||
- sizeof(rpcconn_bind) - BindPacket->common.auth_length;
|
||
InputBuffers[1].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
InputBuffers[1].pvBuffer = (char *) SavedHeader +
|
||
sizeof(rpcconn_bind);
|
||
|
||
InputBuffers[2].cbBuffer = BindPacket->common.auth_length;
|
||
InputBuffers[2].BufferType = SECBUFFER_TOKEN;
|
||
InputBuffers[2].pvBuffer = SecurityTrailer + 1;
|
||
InputBuffers[3].cbBuffer = sizeof(DCE_INIT_SECURITY_INFO);
|
||
InputBuffers[3].BufferType = SECBUFFER_PKG_PARAMS | SECBUFFER_READONLY;
|
||
InputBuffers[3].pvBuffer = &InitSecurityInfo;
|
||
|
||
OutputBufferDescriptor.ulVersion = 0;
|
||
OutputBufferDescriptor.cBuffers = 4;
|
||
OutputBufferDescriptor.pBuffers = OutputBuffers;
|
||
|
||
OutputBuffers[0].cbBuffer = sizeof(rpcconn_bind_ack)
|
||
- sizeof(unsigned short);
|
||
OutputBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
OutputBuffers[0].pvBuffer = BindAck;
|
||
OutputBuffers[1].cbBuffer = BindAckLength
|
||
- SecurityCredentials->MaximumTokenLength()
|
||
- (sizeof(rpcconn_bind_ack) - sizeof(unsigned short));
|
||
OutputBuffers[1].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
OutputBuffers[1].pvBuffer = ((unsigned char *) BindAck)
|
||
+ sizeof(rpcconn_bind_ack) - sizeof(unsigned short);
|
||
OutputBuffers[2].cbBuffer = SecurityCredentials->MaximumTokenLength();
|
||
OutputBuffers[2].BufferType = SECBUFFER_TOKEN;
|
||
OutputBuffers[2].pvBuffer = NewSecurityTrailer + 1;
|
||
OutputBuffers[3].cbBuffer = sizeof(DCE_INIT_SECURITY_INFO);
|
||
OutputBuffers[3].BufferType = SECBUFFER_PKG_PARAMS | SECBUFFER_READONLY;
|
||
OutputBuffers[3].pvBuffer = &InitSecurityInfo;
|
||
|
||
Status = CurrentSecurityContext->AcceptFirstTime(
|
||
SecurityCredentials,
|
||
&InputBufferDescriptor,
|
||
&OutputBufferDescriptor,
|
||
SecurityTrailer->auth_level,
|
||
*((unsigned long *) BindPacket->common.drep),
|
||
0);
|
||
|
||
LogEvent(SU_SCONN, EV_SEC_ACCEPT1, this, LongToPtr(Status), OutputBuffers[2].cbBuffer);
|
||
|
||
#if 0
|
||
if (Status == SEC_E_BUFFER_TOO_SMALL)
|
||
{
|
||
unsigned long NewTokenLength = OutputBuffers[2].cbBuffer;
|
||
|
||
TransFreeBuffer( BindAck );
|
||
|
||
BindAckLength = sizeof(rpcconn_bind_ack) + SecondaryAddressLength
|
||
+ Pad4(SecondaryAddressLength + 2) + sizeof(p_result_list_t)
|
||
+ sizeof(p_result_t) * (PContextList->n_context_elem - 1);
|
||
|
||
AuthPadLength = Pad4(BindAckLength);
|
||
BindAckLength += NewTokenLength
|
||
+ sizeof(sec_trailer) + AuthPadLength;
|
||
|
||
Status = TransGetBuffer((void **) &BindAck, BindAckLength);
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
ASSERT( Status == RPC_S_OUT_OF_MEMORY );
|
||
|
||
SecurityCredentials->DereferenceCredentials();
|
||
|
||
TransFreeBuffer(BindPacket);
|
||
SendBindNak(local_limit_exceeded_reject, CallId);
|
||
return(1);
|
||
}
|
||
|
||
NewSecurityTrailer = (sec_trailer *)
|
||
(((unsigned char *) BindAck) + BindAckLength
|
||
- NewTokenLength
|
||
- sizeof(sec_trailer));
|
||
|
||
OutputBufferDescriptor.ulVersion = 0;
|
||
OutputBufferDescriptor.cBuffers = 4;
|
||
OutputBufferDescriptor.pBuffers = OutputBuffers;
|
||
|
||
OutputBuffers[0].cbBuffer = sizeof(rpcconn_bind_ack)
|
||
- sizeof(unsigned short);
|
||
OutputBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
OutputBuffers[0].pvBuffer = BindAck;
|
||
OutputBuffers[1].cbBuffer = BindAckLength
|
||
- NewTokenLength
|
||
- (sizeof(rpcconn_bind_ack) - sizeof(unsigned short));
|
||
OutputBuffers[1].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
OutputBuffers[1].pvBuffer = ((unsigned char *) BindAck)
|
||
+ sizeof(rpcconn_bind_ack) - sizeof(unsigned short);
|
||
OutputBuffers[2].cbBuffer = NewTokenLength;
|
||
OutputBuffers[2].BufferType = SECBUFFER_TOKEN;
|
||
OutputBuffers[2].pvBuffer = NewSecurityTrailer + 1;
|
||
OutputBuffers[3].cbBuffer = sizeof(DCE_INIT_SECURITY_INFO);
|
||
OutputBuffers[3].BufferType = SECBUFFER_PKG_PARAMS | SECBUFFER_READONLY;
|
||
OutputBuffers[3].pvBuffer = &InitSecurityInfo;
|
||
|
||
Status = CurrentSecurityContext->AcceptFirstTime(
|
||
SecurityCredentials,
|
||
&InputBufferDescriptor,
|
||
&OutputBufferDescriptor,
|
||
SecurityTrailer->auth_level,
|
||
*((unsigned long *) BindPacket->common.drep),
|
||
0);
|
||
|
||
LogEvent(SU_SCONN, EV_SEC_ACCEPT1, this, (void *) Status, OutputBuffers[2].cbBuffer);
|
||
|
||
}
|
||
#endif
|
||
|
||
TokenLength = (unsigned int) OutputBuffers[2].cbBuffer;
|
||
|
||
if ( ( Status == RPC_P_CONTINUE_NEEDED )
|
||
|| ( Status == RPC_S_OK )
|
||
|| ( Status == RPC_P_COMPLETE_NEEDED )
|
||
|| ( Status == RPC_P_COMPLETE_AND_CONTINUE ) )
|
||
{
|
||
if ( Status == RPC_P_CONTINUE_NEEDED )
|
||
{
|
||
AuthContinueNeeded = 1;
|
||
}
|
||
else if ( Status == RPC_P_COMPLETE_AND_CONTINUE )
|
||
{
|
||
AuthContinueNeeded = 1;
|
||
CompleteNeeded = 1;
|
||
}
|
||
else if ( Status == RPC_P_COMPLETE_NEEDED )
|
||
{
|
||
CompleteNeeded = 1;
|
||
}
|
||
|
||
BindAckLength = BindAckLength + TokenLength
|
||
- SecurityCredentials->MaximumTokenLength();
|
||
|
||
NewSecurityTrailer->auth_type = SecurityTrailer->auth_type;
|
||
NewSecurityTrailer->auth_level = SecurityTrailer->auth_level;
|
||
NewSecurityTrailer->auth_pad_length = (unsigned char) AuthPadLength;
|
||
NewSecurityTrailer->auth_reserved = 0;
|
||
NewSecurityTrailer->auth_context_id = AuthContextId;
|
||
|
||
SecurityCredentials->DereferenceCredentials();
|
||
}
|
||
else
|
||
{
|
||
VALIDATE(Status)
|
||
{
|
||
RPC_S_OUT_OF_MEMORY,
|
||
RPC_S_ACCESS_DENIED,
|
||
ERROR_SHUTDOWN_IN_PROGRESS,
|
||
RPC_S_UNKNOWN_AUTHN_SERVICE
|
||
} END_VALIDATE;
|
||
|
||
TransFreeBuffer(BindPacket);
|
||
TransFreeBuffer(BindAck);
|
||
SecurityCredentials->DereferenceCredentials();
|
||
|
||
if (Status == RPC_S_OUT_OF_MEMORY)
|
||
{
|
||
SendBindNak(local_limit_exceeded_reject, CallId);
|
||
}
|
||
else
|
||
if (Status == RPC_S_UNKNOWN_AUTHN_SERVICE ||
|
||
Status == ERROR_SHUTDOWN_IN_PROGRESS )
|
||
{
|
||
SendBindNak(authentication_type_not_recognized, CallId);
|
||
}
|
||
else
|
||
{
|
||
SendBindNak(invalid_checksum, CallId);
|
||
}
|
||
return(1);
|
||
}
|
||
}
|
||
|
||
|
||
TransQueryClientProcess(&ClientProcess);
|
||
|
||
if ( BindPacket->assoc_group_id != 0 )
|
||
{
|
||
// This means this is a connection on an existing association.
|
||
|
||
Association = Address->FindAssociation(
|
||
(int) BindPacket->assoc_group_id, &ClientProcess);
|
||
|
||
if ( Association == 0 )
|
||
{
|
||
RpcpErrorAddRecord (EEInfoGCRuntime,
|
||
RPC_S_ENTRY_NOT_FOUND,
|
||
EEInfoDLAssociationRequested10,
|
||
BindPacket->assoc_group_id,
|
||
ClientProcess.GetDebugULongLong1(),
|
||
ClientProcess.GetDebugULongLong2());
|
||
|
||
TransFreeBuffer(BindPacket);
|
||
TransFreeBuffer(BindAck);
|
||
SendBindNak(reason_not_specified_reject, CallId);
|
||
return(1);
|
||
}
|
||
}
|
||
if ( Association == 0 )
|
||
{
|
||
Association = new OSF_ASSOCIATION(Address, &ClientProcess, &Status);
|
||
if ( (Association == 0) || (Status != RPC_S_OK) )
|
||
{
|
||
if (Association != 0)
|
||
{
|
||
delete Association;
|
||
Association = NULL;
|
||
}
|
||
TransFreeBuffer(BindPacket);
|
||
TransFreeBuffer(BindAck);
|
||
RpcpErrorAddRecord (EEInfoGCRuntime,
|
||
Status,
|
||
EEInfoDLAssociationRequested20,
|
||
sizeof(OSF_ASSOCIATION));
|
||
SendBindNak(local_limit_exceeded_reject, CallId);
|
||
return(1);
|
||
}
|
||
}
|
||
|
||
BindPacketLength -= sizeof(rpcconn_bind);
|
||
if ( ProcessPContextList(Address, PContextList, &BindPacketLength,
|
||
(p_result_list_t *) (((unsigned char *) BindAck) + sizeof(rpcconn_bind_ack)
|
||
+ SecondaryAddressLength + Pad4(SecondaryAddressLength + 2))) != 0 )
|
||
{
|
||
TransFreeBuffer(BindPacket);
|
||
TransFreeBuffer(BindAck);
|
||
SendBindNak(reason_not_specified_reject, CallId);
|
||
return(1);
|
||
}
|
||
|
||
// Fill in the header of the rpc_bind_ack packet.
|
||
|
||
ConstructPacket((rpcconn_common *) BindAck, rpc_bind_ack, BindAckLength);
|
||
|
||
BindAck->max_xmit_frag = BindAck->max_recv_frag = MaxFrag;
|
||
BindAck->assoc_group_id = Association->AssocGroupId();
|
||
BindAck->sec_addr_length = (unsigned short) SecondaryAddressLength;
|
||
BindAck->common.call_id = CallId;
|
||
|
||
if (PFC_CONC_MPX & BindPacket->common.pfc_flags)
|
||
{
|
||
((rpcconn_common *) BindAck)->pfc_flags |=
|
||
(PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_CONC_MPX) ;
|
||
}
|
||
else
|
||
{
|
||
fExclusive = 1;
|
||
((rpcconn_common *) BindAck)->pfc_flags |=
|
||
(PFC_FIRST_FRAG | PFC_LAST_FRAG) ;
|
||
}
|
||
|
||
DceSecurityInfo.ReceiveSequenceNumber += 1;
|
||
|
||
if ( SecondaryAddressLength != 0 )
|
||
{
|
||
Status = Address->TransSecondary((unsigned char *) (BindAck + 1),
|
||
SecondaryAddressLength);
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
ASSERT(Status == RPC_S_OUT_OF_MEMORY);
|
||
TransFreeBuffer(BindPacket);
|
||
TransFreeBuffer(BindAck);
|
||
SendBindNak(reason_not_specified_reject, CallId);
|
||
return(1);
|
||
}
|
||
}
|
||
|
||
// The result list has already been filled in by ProcessPContextList.
|
||
// All that is left to do, is fill in the authentication information.
|
||
|
||
BindAck->common.auth_length = (unsigned short) TokenLength;
|
||
|
||
// Send the rpc_bind_ack packet back to the client.
|
||
|
||
TransFreeBuffer(BindPacket);
|
||
|
||
if ( CompleteNeeded != 0 )
|
||
{
|
||
Status = CurrentSecurityContext->CompleteSecurityToken(
|
||
&OutputBufferDescriptor);
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
TransFreeBuffer(BindAck);
|
||
SendBindNak(invalid_checksum, CallId);
|
||
return(1);
|
||
}
|
||
}
|
||
|
||
//
|
||
// We may need to do third leg AuthInfo.Authentication.
|
||
// we will do that when we receive the third leg packet
|
||
//
|
||
if ( AuthContinueNeeded == 0 )
|
||
{
|
||
//
|
||
// We need to figure out how much space to reserve for security
|
||
// information at the end of request and response packets.
|
||
// In addition to saving space for the signature or header,
|
||
// we need space to pad the packet to a multiple of the maximum
|
||
// security block size as well as for the security trailer.
|
||
//
|
||
|
||
//
|
||
// In the case where we need a third leg, this information will be obtained
|
||
// after we process the third leg packet.
|
||
//
|
||
if ((AuthInfo.AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
|
||
||(AuthInfo.AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT)
|
||
||(AuthInfo.AuthenticationLevel == RPC_C_AUTHN_LEVEL_CONNECT) )
|
||
{
|
||
AdditionalSpaceForSecurity = MAXIMUM_SECURITY_BLOCK_SIZE
|
||
+ CurrentSecurityContext->MaximumSignatureLength()
|
||
+ sizeof(sec_trailer);
|
||
}
|
||
else if (AuthInfo.AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
||
{
|
||
AdditionalSpaceForSecurity = MAXIMUM_SECURITY_BLOCK_SIZE
|
||
+ CurrentSecurityContext->MaximumHeaderLength()
|
||
+ sizeof(sec_trailer);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Sending the bind ack should be the last thing we do
|
||
// in this function. The action will continue in the processing
|
||
// of the third leg.
|
||
//
|
||
Status = TransSend(BindAck, BindAckLength);
|
||
TransFreeBuffer(BindAck);
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
return(1);
|
||
}
|
||
|
||
if (DebugCell)
|
||
{
|
||
DWORD LocalFlags = 0;
|
||
|
||
if (AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
|
||
{
|
||
LocalFlags = AuthInfo.AuthenticationLevel << 1;
|
||
switch (AuthInfo.AuthenticationService)
|
||
{
|
||
case RPC_C_AUTHN_WINNT:
|
||
LocalFlags |= DBGCELL_AUTH_SVC_NTLM;
|
||
break;
|
||
|
||
case RPC_C_AUTHN_GSS_KERBEROS:
|
||
case RPC_C_AUTHN_GSS_NEGOTIATE:
|
||
LocalFlags |= DBGCELL_AUTH_SVC_KERB;
|
||
break;
|
||
|
||
default:
|
||
ASSERT(AuthInfo.AuthenticationService);
|
||
LocalFlags |= DBGCELL_AUTH_SVC_OTHER;
|
||
}
|
||
}
|
||
|
||
if (fExclusive)
|
||
LocalFlags |= 1;
|
||
|
||
DebugCell->ConnectionID[0] = ULongToPtr(ClientProcess.GetDebugULong1());
|
||
DebugCell->ConnectionID[1] = ULongToPtr(ClientProcess.GetDebugULong2());
|
||
|
||
DebugCell->Flags = (unsigned char)LocalFlags;
|
||
}
|
||
|
||
return(0);
|
||
}
|
||
|
||
|
||
int
|
||
OSF_SCONNECTION::AlterContextRequested (
|
||
IN rpcconn_alter_context * AlterContext,
|
||
IN unsigned int AlterContextLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
AlterContext - Supplies the buffer containing the rpc_alter_context
|
||
packet received from the client.
|
||
|
||
AlterContextLength - Supplies the length of the buffer in bytes.
|
||
|
||
Address - Supplies the address which owns this connection.
|
||
|
||
Return Value:
|
||
|
||
A non-zero return value indicates that the connection needs to
|
||
be deleted by the caller.
|
||
|
||
--*/
|
||
{
|
||
p_cont_list_t *PContextList;
|
||
rpcconn_alter_context_resp * AlterContextResp = 0;
|
||
unsigned int AlterContextRespLength = 0;
|
||
unsigned int TokenLength = 0;
|
||
unsigned int CompleteNeeded = 0;
|
||
RPC_STATUS Status;
|
||
sec_trailer * SecurityTrailer, * NewSecurityTrailer;
|
||
SECURITY_BUFFER_DESCRIPTOR InputBufferDescriptor;
|
||
SECURITY_BUFFER_DESCRIPTOR OutputBufferDescriptor;
|
||
SECURITY_BUFFER InputBuffers[4];
|
||
SECURITY_BUFFER OutputBuffers[4];
|
||
DCE_INIT_SECURITY_INFO InitSecurityInfo;
|
||
SECURITY_CREDENTIALS * SecurityCredentials = 0;
|
||
unsigned long SecureAlterContext = 0;
|
||
unsigned int AuthPadLength;
|
||
unsigned long NewContextRequired = 0;
|
||
CLIENT_AUTH_INFO NewClientInfo;
|
||
unsigned NewId;
|
||
SECURITY_CONTEXT * SecId;
|
||
unsigned long CallId = AlterContext->common.call_id;
|
||
ULONG CalculatedSize;
|
||
|
||
//
|
||
// The packet has already been validate by whoever called this method.
|
||
// Data conversion of the common part of the header was performed at
|
||
// that time as well. We do not use the max_xmit_frag, max_recv_frag,
|
||
// or assoc_group_id fields of the packet, so we will not bother to
|
||
// data convert them.
|
||
//
|
||
|
||
// make sure PContextList is there
|
||
if ( AlterContextLength <
|
||
sizeof(rpcconn_alter_context) + sizeof(p_cont_list_t))
|
||
{
|
||
SendFault(RPC_S_ACCESS_DENIED, 1, CallId);
|
||
TransFreeBuffer(AlterContext);
|
||
return(1);
|
||
}
|
||
|
||
PContextList = (p_cont_list_t *) (AlterContext + 1);
|
||
|
||
CalculatedSize = sizeof(rpcconn_alter_context)+sizeof(p_cont_list_t)
|
||
+ (PContextList->n_context_elem-1)*sizeof(p_cont_elem_t);
|
||
|
||
DataRep = * (unsigned long *) AlterContext->common.drep;
|
||
|
||
if ( AlterContextLength < CalculatedSize)
|
||
{
|
||
SendFault(RPC_S_ACCESS_DENIED, 1, CallId);
|
||
TransFreeBuffer(AlterContext);
|
||
return(1);
|
||
}
|
||
|
||
if ( AlterContext->common.auth_length != 0 )
|
||
{
|
||
//
|
||
// We are dealing with a secure alter context
|
||
// it may be adding a presentation context
|
||
// or a new security context
|
||
//
|
||
SecureAlterContext = 1;
|
||
SecurityTrailer = (sec_trailer *)
|
||
(((unsigned char *) AlterContext) + AlterContextLength -
|
||
AlterContext->common.auth_length - sizeof(sec_trailer));
|
||
|
||
NewId = SecurityTrailer->auth_context_id;
|
||
NewClientInfo.AuthenticationLevel = SecurityTrailer->auth_level;
|
||
NewClientInfo.AuthenticationService = SecurityTrailer->auth_type;
|
||
if (DataConvertEndian(((unsigned char *)&DataRep)) != 0)
|
||
{
|
||
NewId = RpcpByteSwapLong(NewId);
|
||
}
|
||
|
||
if (NewClientInfo.AuthenticationLevel == RPC_C_AUTHN_LEVEL_CALL)
|
||
{
|
||
NewClientInfo.AuthenticationLevel = RPC_C_AUTHN_LEVEL_PKT;
|
||
}
|
||
//
|
||
//Check to see if a new context is being added..
|
||
//
|
||
SecId = FindSecurityContext(NewId,
|
||
NewClientInfo.AuthenticationLevel,
|
||
NewClientInfo.AuthenticationService
|
||
);
|
||
|
||
if (SecId == 0)
|
||
{
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
|
||
SecId = new SECURITY_CONTEXT(&NewClientInfo, NewId, FALSE, &Status);
|
||
if ( (SecId == 0)
|
||
|| RPC_S_OK != Status
|
||
||(SecurityContextDict.Insert(SecId) == -1) )
|
||
{
|
||
SendFault(RPC_S_OUT_OF_MEMORY, 1, CallId);
|
||
TransFreeBuffer(AlterContext);
|
||
return (1);
|
||
}
|
||
NewContextRequired = 1;
|
||
|
||
//
|
||
// If previously no secure rpc had taken place
|
||
// set original sec. context
|
||
// else, mark this connection to indicate
|
||
// security context is altered ..
|
||
//
|
||
if (RpcSecurityBeingUsed)
|
||
{
|
||
SecurityContextAltered = 1;
|
||
}
|
||
}
|
||
|
||
AuthInfo = NewClientInfo;
|
||
AuthInfo.ReferenceCredentials();
|
||
|
||
AuthContextId = NewId;
|
||
CurrentSecurityContext = SecId;
|
||
RpcSecurityBeingUsed = 1;
|
||
|
||
if ( (AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_CONNECT)
|
||
&& (AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_PKT)
|
||
&& (AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
|
||
&& (AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_PKT_PRIVACY) )
|
||
{
|
||
SendFault(RPC_S_ACCESS_DENIED, 1, CallId);
|
||
TransFreeBuffer(AlterContext);
|
||
return(1);
|
||
}
|
||
|
||
Status = Address->Server->AcquireCredentials(
|
||
AuthInfo.AuthenticationService,
|
||
AuthInfo.AuthenticationLevel,
|
||
&SecurityCredentials
|
||
);
|
||
|
||
if ( Status == RPC_S_OUT_OF_MEMORY ||
|
||
Status == ERROR_SHUTDOWN_IN_PROGRESS)
|
||
{
|
||
SendFault(Status, 1, CallId);
|
||
TransFreeBuffer(AlterContext);
|
||
return(1);
|
||
}
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
if (SecurityCredentials != 0)
|
||
{
|
||
SecurityCredentials->DereferenceCredentials();
|
||
}
|
||
SendFault(RPC_S_ACCESS_DENIED, 1, CallId);
|
||
TransFreeBuffer(AlterContext);
|
||
|
||
return(1);
|
||
}
|
||
ASSERT( SecurityCredentials != 0 );
|
||
|
||
} //if secure alter context
|
||
|
||
|
||
AlterContextRespLength =
|
||
sizeof(rpcconn_alter_context_resp) + sizeof(p_result_list_t)
|
||
+ sizeof(p_result_t) * (PContextList->n_context_elem - 1);
|
||
|
||
if (SecureAlterContext != 0)
|
||
{
|
||
ASSERT(SecurityCredentials != 0);
|
||
AuthPadLength = Pad4(AlterContextRespLength);
|
||
AlterContextRespLength += AuthPadLength +
|
||
SecurityCredentials->MaximumTokenLength() +
|
||
sizeof(sec_trailer);
|
||
}
|
||
|
||
Status = TransGetBuffer((void **) &AlterContextResp,
|
||
AlterContextRespLength);
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
ASSERT( Status == RPC_S_OUT_OF_MEMORY );
|
||
if (SecurityCredentials != 0)
|
||
{
|
||
SecurityCredentials->DereferenceCredentials();
|
||
}
|
||
SendFault(RPC_S_OUT_OF_MEMORY, 1, CallId);
|
||
TransFreeBuffer(AlterContext);
|
||
return(1);
|
||
}
|
||
|
||
AlterContextLength -= sizeof(rpcconn_alter_context);
|
||
if ( ProcessPContextList(Address, PContextList, &AlterContextLength,
|
||
(p_result_list_t *) (AlterContextResp + 1)) != 0 )
|
||
{
|
||
TransFreeBuffer(AlterContext);
|
||
TransFreeBuffer(AlterContextResp);
|
||
if (SecurityCredentials != 0)
|
||
{
|
||
SecurityCredentials->DereferenceCredentials();
|
||
}
|
||
SendFault(RPC_S_PROTOCOL_ERROR, 1, CallId);
|
||
return(1);
|
||
}
|
||
|
||
if ( SecureAlterContext != 0 )
|
||
{
|
||
ASSERT(SecurityCredentials != 0);
|
||
NewSecurityTrailer = (sec_trailer *)
|
||
(((unsigned char *) AlterContextResp) +
|
||
AlterContextRespLength -
|
||
SecurityCredentials->MaximumTokenLength() -
|
||
sizeof(sec_trailer));
|
||
|
||
InitSecurityInfo.DceSecurityInfo = DceSecurityInfo;
|
||
InitSecurityInfo.PacketType = AlterContext->common.PTYPE;
|
||
InputBufferDescriptor.ulVersion = 0;
|
||
InputBufferDescriptor.cBuffers = 4;
|
||
InputBufferDescriptor.pBuffers = InputBuffers;
|
||
|
||
InputBuffers[0].cbBuffer = sizeof(rpcconn_alter_context);
|
||
InputBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
InputBuffers[0].pvBuffer = SavedHeader;
|
||
|
||
InputBuffers[1].cbBuffer = AlterContext->common.frag_length -
|
||
sizeof(rpcconn_alter_context) -
|
||
AlterContext->common.auth_length;
|
||
InputBuffers[1].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
InputBuffers[1].pvBuffer = (char *) SavedHeader +
|
||
sizeof(rpcconn_alter_context);
|
||
|
||
InputBuffers[2].cbBuffer = AlterContext->common.auth_length;
|
||
InputBuffers[2].BufferType = SECBUFFER_TOKEN;
|
||
InputBuffers[2].pvBuffer = SecurityTrailer + 1;
|
||
InputBuffers[3].cbBuffer = sizeof(DCE_INIT_SECURITY_INFO);
|
||
InputBuffers[3].BufferType = SECBUFFER_PKG_PARAMS | SECBUFFER_READONLY;
|
||
InputBuffers[3].pvBuffer = &InitSecurityInfo;
|
||
|
||
OutputBufferDescriptor.ulVersion = 0;
|
||
OutputBufferDescriptor.cBuffers = 4;
|
||
OutputBufferDescriptor.pBuffers = OutputBuffers;
|
||
OutputBuffers[0].cbBuffer = sizeof(rpcconn_alter_context_resp);
|
||
OutputBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
OutputBuffers[0].pvBuffer = AlterContextResp;
|
||
OutputBuffers[1].cbBuffer = AlterContextRespLength
|
||
- SecurityCredentials->MaximumTokenLength()
|
||
- sizeof(rpcconn_alter_context_resp);
|
||
OutputBuffers[1].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
OutputBuffers[1].pvBuffer = ((unsigned char *) AlterContextResp)
|
||
+ sizeof(rpcconn_alter_context_resp);
|
||
OutputBuffers[2].cbBuffer = SecurityCredentials->MaximumTokenLength();
|
||
OutputBuffers[2].BufferType = SECBUFFER_TOKEN;
|
||
OutputBuffers[2].pvBuffer = NewSecurityTrailer + 1;
|
||
OutputBuffers[3].cbBuffer = sizeof(DCE_INIT_SECURITY_INFO);
|
||
OutputBuffers[3].BufferType = SECBUFFER_PKG_PARAMS | SECBUFFER_READONLY;
|
||
OutputBuffers[3].pvBuffer = &InitSecurityInfo;
|
||
|
||
if ( NewContextRequired != 0 )
|
||
{
|
||
Status = CurrentSecurityContext->AcceptFirstTime(
|
||
SecurityCredentials,
|
||
&InputBufferDescriptor,
|
||
&OutputBufferDescriptor,
|
||
SecurityTrailer->auth_level,
|
||
*((unsigned long *) AlterContext->common.drep),
|
||
NewContextRequired
|
||
);
|
||
|
||
LogEvent(SU_SCONN, EV_SEC_ACCEPT1, this, LongToPtr(Status), OutputBuffers[2].cbBuffer);
|
||
//
|
||
// Since we have (potentially) a new security context we
|
||
// need to figure out
|
||
// additional security related information at this stage..
|
||
//
|
||
|
||
switch (SecurityTrailer->auth_level)
|
||
|
||
{
|
||
|
||
case RPC_C_AUTHN_LEVEL_CONNECT:
|
||
case RPC_C_AUTHN_LEVEL_CALL: //OSF Hack..
|
||
case RPC_C_AUTHN_LEVEL_PKT:
|
||
case RPC_C_AUTHN_LEVEL_PKT_INTEGRITY:
|
||
|
||
AdditionalSpaceForSecurity = MAXIMUM_SECURITY_BLOCK_SIZE +
|
||
CurrentSecurityContext->MaximumSignatureLength() +
|
||
sizeof (sec_trailer);
|
||
break;
|
||
case RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
|
||
AdditionalSpaceForSecurity = MAXIMUM_SECURITY_BLOCK_SIZE +
|
||
CurrentSecurityContext->MaximumHeaderLength() +
|
||
sizeof (sec_trailer);
|
||
break;
|
||
|
||
default:
|
||
ASSERT(!"Unknown Security Level\n");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Status = CurrentSecurityContext->AcceptThirdLeg(
|
||
*((unsigned long *) AlterContext->common.drep),
|
||
&InputBufferDescriptor,
|
||
&OutputBufferDescriptor
|
||
);
|
||
|
||
LogEvent(SU_SCONN, EV_SEC_ACCEPT3, this, LongToPtr(Status), OutputBuffers[2].cbBuffer);
|
||
}
|
||
TokenLength = (unsigned int) OutputBuffers[2].cbBuffer;
|
||
|
||
if ( Status == RPC_S_OK ||
|
||
Status == RPC_P_COMPLETE_NEEDED ||
|
||
Status == RPC_P_CONTINUE_NEEDED ||
|
||
Status == RPC_P_COMPLETE_AND_CONTINUE )
|
||
{
|
||
if ( Status == RPC_P_COMPLETE_NEEDED ||
|
||
Status == RPC_P_COMPLETE_AND_CONTINUE )
|
||
{
|
||
CompleteNeeded = 1;
|
||
}
|
||
|
||
if ( Status == RPC_S_OK ||
|
||
Status == RPC_P_COMPLETE_NEEDED )
|
||
{
|
||
switch (SecurityTrailer->auth_level)
|
||
{
|
||
case RPC_C_AUTHN_LEVEL_CONNECT:
|
||
case RPC_C_AUTHN_LEVEL_CALL: //OSF Hack..
|
||
case RPC_C_AUTHN_LEVEL_PKT:
|
||
case RPC_C_AUTHN_LEVEL_PKT_INTEGRITY:
|
||
|
||
AdditionalSpaceForSecurity = MAXIMUM_SECURITY_BLOCK_SIZE +
|
||
CurrentSecurityContext->MaximumSignatureLength() +
|
||
sizeof (sec_trailer);
|
||
break;
|
||
case RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
|
||
AdditionalSpaceForSecurity = MAXIMUM_SECURITY_BLOCK_SIZE +
|
||
CurrentSecurityContext->MaximumHeaderLength() +
|
||
sizeof (sec_trailer);
|
||
break;
|
||
|
||
default:
|
||
ASSERT(!"Unknown Security Level\n");
|
||
}
|
||
}
|
||
|
||
AlterContextRespLength = AlterContextRespLength +
|
||
TokenLength -
|
||
SecurityCredentials->MaximumTokenLength();
|
||
|
||
NewSecurityTrailer->auth_type = SecurityTrailer->auth_type;
|
||
NewSecurityTrailer->auth_level = SecurityTrailer->auth_level;
|
||
NewSecurityTrailer->auth_pad_length = (unsigned char) AuthPadLength;
|
||
NewSecurityTrailer->auth_reserved = 0;
|
||
NewSecurityTrailer->auth_context_id = AuthContextId;
|
||
|
||
SecurityCredentials->DereferenceCredentials();
|
||
SecurityCredentials = 0;
|
||
|
||
Status = RPC_S_OK;
|
||
}
|
||
|
||
if (Status)
|
||
{
|
||
TransFreeBuffer(AlterContext);
|
||
TransFreeBuffer(AlterContextResp);
|
||
|
||
SecurityCredentials->DereferenceCredentials();
|
||
|
||
SendFault(RPC_S_ACCESS_DENIED, 1, CallId);
|
||
return(1);
|
||
}
|
||
}
|
||
|
||
DceSecurityInfo.ReceiveSequenceNumber++;
|
||
ConstructPacket((rpcconn_common *) AlterContextResp,
|
||
rpc_alter_context_resp, AlterContextRespLength);
|
||
|
||
TransFreeBuffer(AlterContext);
|
||
if ( Association == 0 )
|
||
{
|
||
TransFreeBuffer(AlterContextResp);
|
||
SendFault(RPC_S_PROTOCOL_ERROR, 1, CallId);
|
||
return(1);
|
||
}
|
||
|
||
AlterContextResp->assoc_group_id = Association->AssocGroupId();
|
||
AlterContextResp->sec_addr_length = 0;
|
||
AlterContextResp->max_xmit_frag = AlterContextResp->max_recv_frag = MaxFrag;
|
||
AlterContextResp->common.call_id = CallId;
|
||
AlterContextResp->common.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
|
||
|
||
AlterContextResp->common.auth_length = (unsigned short) TokenLength;
|
||
if (CompleteNeeded != 0)
|
||
{
|
||
CurrentSecurityContext->CompleteSecurityToken(&OutputBufferDescriptor);
|
||
}
|
||
Status= TransSend(AlterContextResp, AlterContextRespLength);
|
||
TransFreeBuffer(AlterContextResp);
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
return(1);
|
||
}
|
||
|
||
return(0);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCONNECTION::EatAuthInfoFromPacket (
|
||
IN rpcconn_request * Request,
|
||
IN OUT int * RequestLength,
|
||
IN OUT void * *SavedHeader,
|
||
IN OUT unsigned long *SavedHeaderSize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
If there is authentication information in the packet, this routine
|
||
will check it, and perform security as necessary. This may include
|
||
calls to the security support package.
|
||
|
||
Arguments:
|
||
|
||
Request - Supplies the packet which may contain authentication
|
||
information.
|
||
|
||
RequestLength - Supplies the length of the packet in bytes, and
|
||
returns the length of the packet without authentication
|
||
information.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - Everything went just fine.
|
||
|
||
RPC_S_ACCESS_DENIED - A security failure of some sort occured.
|
||
|
||
RPC_S_PROTOCOL_ERROR - This will occur if no authentication information
|
||
is in the packet, and some was expected, or visa versa.
|
||
|
||
--*/
|
||
{
|
||
sec_trailer * SecurityTrailer;
|
||
RPC_STATUS Status;
|
||
SECURITY_BUFFER_DESCRIPTOR BufferDescriptor;
|
||
SECURITY_BUFFER SecurityBuffers[5];
|
||
DCE_MSG_SECURITY_INFO MsgSecurityInfo;
|
||
unsigned long Id, Level, Service;
|
||
SECURITY_CONTEXT * SecId;
|
||
unsigned int HeaderSize = sizeof(rpcconn_request);
|
||
unsigned long DataRep = * (unsigned long *) Request->common.drep;
|
||
|
||
#if DBG
|
||
// Check to make sure SavedHeader is OSF_SCALL->SavedHeader.
|
||
// We may need to get to the call object below.
|
||
OSF_SCALL *pSCall = (OSF_SCALL *) ((char *)SavedHeader - FIELD_OFFSET(OSF_SCALL, SavedHeader));
|
||
ASSERT(pSCall->InvalidHandle(OSF_SCALL_TYPE) == 0);
|
||
#endif
|
||
|
||
if ( (Request->common.pfc_flags & PFC_OBJECT_UUID) != 0 )
|
||
{
|
||
HeaderSize += sizeof(UUID);
|
||
}
|
||
|
||
if ( Request->common.auth_length != 0 )
|
||
{
|
||
SecurityTrailer = (sec_trailer *) (((unsigned char *)
|
||
Request) + Request->common.frag_length
|
||
- Request->common.auth_length - sizeof(sec_trailer));
|
||
|
||
if (RpcSecurityBeingUsed == 0)
|
||
{
|
||
return(RPC_S_PROTOCOL_ERROR);
|
||
}
|
||
|
||
|
||
//
|
||
// Find the appropriate security context..
|
||
//
|
||
|
||
Id = SecurityTrailer->auth_context_id;
|
||
Level = SecurityTrailer->auth_level;
|
||
Service = SecurityTrailer->auth_type;
|
||
if (DataConvertEndian(((unsigned char *)&DataRep)) != 0)
|
||
{
|
||
Id = RpcpByteSwapLong(Id);
|
||
}
|
||
|
||
//
|
||
// Osf Hack
|
||
//
|
||
if (Level == RPC_C_AUTHN_LEVEL_CALL)
|
||
{
|
||
Level = RPC_C_AUTHN_LEVEL_PKT;
|
||
}
|
||
|
||
if ( (CurrentSecurityContext == 0)
|
||
||(CurrentSecurityContext->AuthContextId != Id)
|
||
||(CurrentSecurityContext->AuthenticationLevel != Level)
|
||
||(CurrentSecurityContext->AuthenticationService != Service) )
|
||
{
|
||
SecId = FindSecurityContext(Id, Level, Service);
|
||
if (SecId == 0)
|
||
{
|
||
return (RPC_S_PROTOCOL_ERROR);
|
||
}
|
||
CurrentSecurityContext = SecId;
|
||
AuthInfo.AuthenticationLevel = Level;
|
||
AuthInfo.AuthenticationService = Service;
|
||
AuthContextId = Id;
|
||
|
||
switch (Level)
|
||
{
|
||
case RPC_C_AUTHN_LEVEL_CONNECT:
|
||
case RPC_C_AUTHN_LEVEL_CALL: //OSF Hack..
|
||
case RPC_C_AUTHN_LEVEL_PKT:
|
||
case RPC_C_AUTHN_LEVEL_PKT_INTEGRITY:
|
||
|
||
AdditionalSpaceForSecurity = MAXIMUM_SECURITY_BLOCK_SIZE +
|
||
CurrentSecurityContext->MaximumSignatureLength() +
|
||
sizeof (sec_trailer);
|
||
break;
|
||
case RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
|
||
AdditionalSpaceForSecurity = MAXIMUM_SECURITY_BLOCK_SIZE +
|
||
CurrentSecurityContext->MaximumHeaderLength() +
|
||
sizeof (sec_trailer);
|
||
break;
|
||
|
||
default:
|
||
ASSERT(!"Unknown Security Level\n");
|
||
}
|
||
}
|
||
|
||
|
||
*RequestLength -= (Request->common.auth_length
|
||
+HeaderSize + sizeof(sec_trailer) +
|
||
SecurityTrailer->auth_pad_length);
|
||
|
||
MsgSecurityInfo.SendSequenceNumber =
|
||
DceSecurityInfo.SendSequenceNumber;
|
||
MsgSecurityInfo.ReceiveSequenceNumber =
|
||
DceSecurityInfo.ReceiveSequenceNumber;
|
||
MsgSecurityInfo.PacketType = Request->common.PTYPE;
|
||
|
||
BufferDescriptor.ulVersion = 0;
|
||
BufferDescriptor.cBuffers = 5;
|
||
BufferDescriptor.pBuffers = SecurityBuffers;
|
||
|
||
|
||
SecurityBuffers[0].cbBuffer = HeaderSize;
|
||
SecurityBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
SecurityBuffers[0].pvBuffer = (unsigned char *) *SavedHeader;
|
||
|
||
SecurityBuffers[1].cbBuffer = *RequestLength + SecurityTrailer->auth_pad_length;
|
||
SecurityBuffers[1].BufferType = SECBUFFER_DATA;
|
||
SecurityBuffers[1].pvBuffer = ((unsigned char *) Request)
|
||
+ HeaderSize;
|
||
|
||
SecurityBuffers[2].cbBuffer = sizeof(sec_trailer);
|
||
SecurityBuffers[2].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
SecurityBuffers[2].pvBuffer = SecurityTrailer;
|
||
|
||
SecurityBuffers[3].cbBuffer = Request->common.auth_length;
|
||
SecurityBuffers[3].BufferType = SECBUFFER_TOKEN;
|
||
SecurityBuffers[3].pvBuffer = SecurityTrailer + 1;
|
||
|
||
SecurityBuffers[4].cbBuffer = sizeof(DCE_MSG_SECURITY_INFO);
|
||
SecurityBuffers[4].BufferType = SECBUFFER_PKG_PARAMS
|
||
| SECBUFFER_READONLY;
|
||
SecurityBuffers[4].pvBuffer = &MsgSecurityInfo;
|
||
|
||
Status = CurrentSecurityContext->VerifyOrUnseal(
|
||
MsgSecurityInfo.ReceiveSequenceNumber,
|
||
AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
||
&BufferDescriptor);
|
||
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
ASSERT( Status == RPC_S_ACCESS_DENIED ||
|
||
Status == ERROR_SHUTDOWN_IN_PROGRESS ||
|
||
Status == ERROR_PASSWORD_MUST_CHANGE ||
|
||
Status == ERROR_PASSWORD_EXPIRED ||
|
||
Status == ERROR_ACCOUNT_DISABLED ||
|
||
Status == ERROR_INVALID_LOGON_HOURS);
|
||
return(Status);
|
||
}
|
||
}
|
||
else if (CurrentSecurityContext == 0)
|
||
{
|
||
// This is a non-secure connection. There is nothing to be done.
|
||
ASSERT(AuthInfo.AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE);
|
||
ASSERT(*SavedHeader == 0);
|
||
|
||
*RequestLength -= HeaderSize;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// We are doing a nonsecure rpc and previously we did a secure rpc.
|
||
//
|
||
// This switch from a secure to a non-secure connection is only
|
||
// allowed to take place in between calls. A given call has to
|
||
// be either entirely secure or entirely non-secure.
|
||
//
|
||
// If this is the first buffer, then we are allowed to switch.
|
||
// We determine whether this is the first buffer by the flag and the
|
||
// current state of the call object. We can get to the call object because
|
||
// this funciton is called with SavedHeader from OSF_SCALL::SavedHeader.
|
||
// We do not explicitly pass in a call address for perf reasons.
|
||
//
|
||
OSF_SCALL *pSCall = (OSF_SCALL *) ((char *)SavedHeader - FIELD_OFFSET(OSF_SCALL, SavedHeader));
|
||
|
||
if (Request->common.pfc_flags & PFC_FIRST_FRAG &&
|
||
pSCall->RcvBufferLength == 0)
|
||
{
|
||
ASSERT(pSCall->CurrentState == NewRequest);
|
||
|
||
// After we reset the auth level and zero-out the security
|
||
// context the call will not be able to get past security callbacks.
|
||
AuthInfo.AuthenticationLevel = RPC_C_AUTHN_LEVEL_NONE;
|
||
CurrentSecurityContext = 0;
|
||
if (*SavedHeader != 0)
|
||
{
|
||
ASSERT(*SavedHeaderSize != 0);
|
||
RpcpFarFree(*SavedHeader);
|
||
*SavedHeader = 0;
|
||
*SavedHeaderSize = 0;
|
||
}
|
||
|
||
*RequestLength -= HeaderSize;
|
||
}
|
||
// Attempt to switch from a secure to a non-secure RPC within a call - fail.
|
||
else
|
||
{
|
||
ASSERT(0 && "Switch from secure to non-secure RPC in the middle of a call.");
|
||
return RPC_S_ACCESS_DENIED;
|
||
}
|
||
}
|
||
DceSecurityInfo.ReceiveSequenceNumber += 1;
|
||
|
||
if (*RequestLength < 0)
|
||
{
|
||
return RPC_S_ACCESS_DENIED;
|
||
}
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
|
||
BOOL
|
||
OSF_SCONNECTION::MaybeQueueThisCall (
|
||
IN OSF_SCALL *ThisCall
|
||
)
|
||
{
|
||
BOOL fCallQueued = 0;
|
||
|
||
ConnMutex.Request();
|
||
if (fCurrentlyDispatched)
|
||
{
|
||
if (CallQueue.PutOnQueue(ThisCall, 0))
|
||
{
|
||
ThisCall->SendFault(RPC_S_OUT_OF_MEMORY, 1);
|
||
|
||
//
|
||
// Remove the reply reference
|
||
//
|
||
ThisCall->RemoveReference(); // CALL--
|
||
|
||
//
|
||
// Remove the dispatch reference();
|
||
//
|
||
ThisCall->RemoveReference(); // CALL--
|
||
}
|
||
fCallQueued = 1;
|
||
}
|
||
else
|
||
{
|
||
fCurrentlyDispatched = 1;
|
||
}
|
||
ConnMutex.Clear();
|
||
|
||
return fCallQueued;
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCONNECTION::AbortQueuedCalls (
|
||
)
|
||
{
|
||
OSF_SCALL *NextCall;
|
||
unsigned int ignore;
|
||
|
||
while (1)
|
||
{
|
||
ConnMutex.Request();
|
||
NextCall = (OSF_SCALL *) CallQueue.TakeOffQueue(&ignore);
|
||
if (NextCall == 0)
|
||
{
|
||
fCurrentlyDispatched = 0;
|
||
ConnMutex.Clear();
|
||
|
||
break;
|
||
}
|
||
ConnMutex.Clear();
|
||
|
||
//
|
||
// Remove the reply reference
|
||
//
|
||
NextCall->RemoveReference(); // CALL--
|
||
|
||
//
|
||
// Remove the dispatch reference on the call
|
||
//
|
||
NextCall->RemoveReference(); // CALL--
|
||
}
|
||
}
|
||
|
||
|
||
void
|
||
OSF_SCONNECTION::DispatchQueuedCalls (
|
||
)
|
||
{
|
||
OSF_SCALL *NextCall;
|
||
unsigned int ignore;
|
||
|
||
while (1)
|
||
{
|
||
ConnMutex.Request();
|
||
NextCall = (OSF_SCALL *) CallQueue.TakeOffQueue(&ignore);
|
||
if (NextCall == 0)
|
||
{
|
||
fCurrentlyDispatched = 0;
|
||
ConnMutex.Clear();
|
||
|
||
break;
|
||
}
|
||
ConnMutex.Clear();
|
||
|
||
NextCall->DispatchHelper();
|
||
|
||
//
|
||
// Remove the dispatch reference on the call
|
||
//
|
||
NextCall->RemoveReference(); // CALL--
|
||
}
|
||
}
|
||
|
||
|
||
OSF_ASSOCIATION::OSF_ASSOCIATION (
|
||
IN OSF_ADDRESS *TheAddress,
|
||
IN RPC_CLIENT_PROCESS_IDENTIFIER * ClientProcess,
|
||
OUT RPC_STATUS * Status
|
||
)
|
||
{
|
||
ObjectType = OSF_ASSOCIATION_TYPE;
|
||
*Status = RPC_S_OK;
|
||
ConnectionCount = 1;
|
||
Address = TheAddress;
|
||
|
||
this->ClientProcess.Set(ClientProcess);
|
||
|
||
AssociationGroupId = InterlockedExchangeAdd(&GroupIdCounter, 1);
|
||
|
||
AssociationDictKey = Address->AddAssociation(this);
|
||
|
||
if (AssociationDictKey == -1)
|
||
{
|
||
*Status = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
}
|
||
|
||
OSF_ASSOCIATION::~OSF_ASSOCIATION (
|
||
)
|
||
{
|
||
if (AssociationDictKey != -1)
|
||
{
|
||
int HashBucketNumber;
|
||
|
||
HashBucketNumber = Address->GetHashBucketForAssociation(AssocGroupId());
|
||
// lock the bucket
|
||
Address->GetAssociationBucketMutex(HashBucketNumber)->Request();
|
||
|
||
Address->RemoveAssociation(AssociationDictKey, this);
|
||
|
||
// unlock the bucket
|
||
Address->GetAssociationBucketMutex(HashBucketNumber)->Clear();
|
||
}
|
||
}
|
||
|
||
BOOL
|
||
OSF_ASSOCIATION::RemoveConnectionUnsafe (
|
||
void
|
||
)
|
||
{
|
||
int HashBucketNumber;
|
||
|
||
// get the hashed bucket
|
||
HashBucketNumber = Address->GetHashBucketForAssociation(AssociationGroupId);
|
||
// verify the bucket is locked
|
||
Address->GetAssociationBucketMutex(HashBucketNumber)->VerifyOwned();
|
||
|
||
ConnectionCount --;
|
||
|
||
if (ConnectionCount == 0)
|
||
{
|
||
Address->RemoveAssociation(AssociationDictKey, this);
|
||
AssociationDictKey = -1;
|
||
return AssociationDictKey; // AssociationDictKey is a quick non-zero value
|
||
}
|
||
else
|
||
return FALSE;
|
||
}
|
||
|
||
void
|
||
OSF_ASSOCIATION::RemoveConnection (
|
||
)
|
||
{
|
||
int HashBucketNumber;
|
||
BOOL Res;
|
||
|
||
// get the hashed bucket
|
||
HashBucketNumber = Address->GetHashBucketForAssociation(AssociationGroupId);
|
||
// lock the bucket
|
||
Address->GetAssociationBucketMutex(HashBucketNumber)->Request();
|
||
Res = RemoveConnectionUnsafe();
|
||
// unlock the bucket
|
||
Address->GetAssociationBucketMutex(HashBucketNumber)->Clear();
|
||
|
||
if (Res)
|
||
delete this;
|
||
}
|
||
|
||
RPC_STATUS OSF_ASSOCIATION::CreateThread(void)
|
||
{
|
||
return Address->CreateThread();
|
||
}
|
||
|
||
|
||
RPC_ADDRESS *
|
||
OsfCreateRpcAddress (
|
||
IN TRANS_INFO *TransportInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will be called to create an object representing an
|
||
rpc address. That is all it has got to do.
|
||
|
||
Arguments:
|
||
|
||
A new rpc address will be returned, unless insufficient memory is
|
||
available to create the new rpc address, in which case zero will
|
||
be returned.
|
||
|
||
--*/
|
||
{
|
||
RPC_ADDRESS * RpcAddress;
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
RPC_CONNECTION_TRANSPORT *ServerInfo =
|
||
(RPC_CONNECTION_TRANSPORT *) TransportInfo->InqTransInfo();
|
||
|
||
RpcAddress = new (ServerInfo->AddressSize)
|
||
OSF_ADDRESS(TransportInfo, &Status);
|
||
|
||
if ( Status != RPC_S_OK )
|
||
{
|
||
return(0);
|
||
}
|
||
return(RpcAddress);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::Cancel(
|
||
void * ThreadHandle
|
||
)
|
||
{
|
||
InterlockedIncrement(&CancelPending);
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
unsigned
|
||
OSF_SCALL::TestCancel(
|
||
)
|
||
{
|
||
return InterlockedExchange(&CancelPending, 0);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::ToStringBinding (
|
||
OUT RPC_CHAR * * StringBinding
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
We need to convert this connection 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 representation of the binding
|
||
handle.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - The operation completed successfully.
|
||
|
||
RPC_S_OUT_OF_MEMORY - We do not have enough memory available to
|
||
allocate space for the string binding.
|
||
|
||
--*/
|
||
{
|
||
BINDING_HANDLE * BindingHandle;
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
|
||
BindingHandle = Address->InquireBinding();
|
||
if (BindingHandle == 0)
|
||
return(RPC_S_OUT_OF_MEMORY);
|
||
if ( ObjectUuidSpecified != 0)
|
||
{
|
||
Status = RpcBindingSetObject(BindingHandle, (UUID *) &ObjectUuid);
|
||
}
|
||
if (Status == RPC_S_OK)
|
||
{
|
||
Status = BindingHandle->ToStringBinding(StringBinding);
|
||
}
|
||
BindingHandle->BindingFree();
|
||
return(Status);
|
||
}
|
||
|
||
#if DBG
|
||
void
|
||
OSF_SCALL::InterfaceForCallDoesNotUseStrict (
|
||
void
|
||
)
|
||
{
|
||
CurrentBinding->InterfaceForCallDoesNotUseStrict();
|
||
}
|
||
#endif
|
||
|
||
RPC_STATUS
|
||
OSF_SCALL::InqLocalConnAddress (
|
||
IN OUT void *Buffer,
|
||
IN OUT unsigned long *BufferSize,
|
||
OUT unsigned long *AddressFormat
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used by a server application to inquire about the local
|
||
address on which a call is made.
|
||
|
||
Arguments:
|
||
|
||
Buffer - The buffer that will receive the output address
|
||
|
||
BufferSize - the size of the supplied Buffer on input. On output the
|
||
number of bytes written to the buffer. If the buffer is too small
|
||
to receive all the output data, ERROR_MORE_DATA is returned,
|
||
nothing is written to the buffer, and BufferSize is set to
|
||
the size of the buffer needed to return all the data.
|
||
|
||
AddressFormat - a constant indicating the format of the returned address.
|
||
Currently supported are RPC_P_ADDR_FORMAT_TCP_IPV4 and
|
||
RPC_P_ADDR_FORMAT_TCP_IPV6.
|
||
|
||
Return Values:
|
||
|
||
RPC_S_OK - success.
|
||
|
||
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete this
|
||
operation.
|
||
|
||
RPC_S_INVALID_BINDING - The supplied client binding is invalid.
|
||
|
||
RPC_S_CANNOT_SUPPORT - The local address was inquired for a protocol
|
||
sequence that doesn't support this type of functionality. Currently
|
||
only ncacn_ip_tcp supports it.
|
||
|
||
RPC_S_* or Win32 error for other errors
|
||
--*/
|
||
{
|
||
return Connection->InqLocalConnAddress(
|
||
Buffer,
|
||
BufferSize,
|
||
AddressFormat);
|
||
}
|
||
|
||
void
|
||
OSF_SCALL::WakeUpPipeThreadIfNecessary (
|
||
IN RPC_STATUS Status
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
If a pipe thread is being stuck on wait, it fires the event to wake
|
||
it up.
|
||
|
||
Arguments:
|
||
Status - the status with which the call failed.
|
||
|
||
Return Values:
|
||
|
||
--*/
|
||
{
|
||
if (pAsync == 0)
|
||
{
|
||
if (fPipeCall)
|
||
{
|
||
CallMutex.Request();
|
||
|
||
CurrentState = CallAborted;
|
||
AsyncStatus = Status;
|
||
|
||
// wake up the thread that was flow controlled, if any
|
||
fChoked = 0;
|
||
|
||
CallMutex.Clear();
|
||
|
||
LogEvent(SU_SCALL, EV_STATUS, this, SyncEvent.EventHandle, 0, 1, 0);
|
||
SyncEvent.Raise();
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
RPC_STATUS RPC_ENTRY
|
||
I_RpcTransServerReallocPacket (
|
||
IN RPC_TRANSPORT_CONNECTION ThisConnection,
|
||
IN OUT void * * Buffer,
|
||
IN unsigned int OldBufferLength,
|
||
IN unsigned int NewBufferLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The server side transport interface modules will use this routine to
|
||
increase the size of a buffer so that the entire packet to be
|
||
received will fit into it, or to allocate a new buffer. If the buffer
|
||
is to be reallocated, the data from the old buffer is copied
|
||
into the beginning of the new buffer. The old buffer will be freed.
|
||
|
||
Arguments:
|
||
|
||
ThisConnection - Supplies the connection for which we are reallocating
|
||
a transport buffer.
|
||
|
||
Buffer - Supplies the buffer which we want to reallocate to
|
||
be larger. If no buffer is supplied, then a new one is allocated
|
||
anyway. The new buffer is returned via this argument.
|
||
|
||
OldBufferLength - Supplies the current length of the buffer in bytes.
|
||
This information is necessary so we know how much of the buffer
|
||
needs to be copied into the new buffer.
|
||
|
||
NewBufferLength - Supplies the required length of the buffer in bytes.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - The requested larger buffer has successfully been allocated.
|
||
|
||
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
|
||
the buffer.
|
||
|
||
--*/
|
||
{
|
||
ASSERT(0);
|
||
return(RPC_S_INTERNAL_ERROR);
|
||
}
|
||
|
||
|
||
BUFFER RPC_ENTRY
|
||
I_RpcTransServerAllocatePacket (
|
||
IN RPC_TRANSPORT_CONNECTION ThisConnection,
|
||
IN UINT Size
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The server side transport interface modules will use this routine to
|
||
increase the size of a buffer so that the entire packet to be
|
||
received will fit into it, or to allocate a new buffer. If the buffer
|
||
is to be reallocated, the data from the old buffer is copied
|
||
into the beginning of the new buffer. The old buffer will be freed.
|
||
|
||
Arguments:
|
||
|
||
ThisConnection - Supplies the connection for which we are reallocating
|
||
a transport buffer.
|
||
|
||
Buffer - Supplies the buffer which we want to reallocate to
|
||
be larger. If no buffer is supplied, then a new one is allocated
|
||
anyway. The new buffer is returned via this argument.
|
||
|
||
OldBufferLength - Supplies the current length of the buffer in bytes.
|
||
This information is necessary so we know how much of the buffer
|
||
needs to be copied into the new buffer.
|
||
|
||
NewBufferLength - Supplies the required length of the buffer in bytes.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - The requested larger buffer has successfully been allocated.
|
||
|
||
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
|
||
the buffer.
|
||
|
||
--*/
|
||
{
|
||
ASSERT(0);
|
||
return(0);
|
||
}
|
||
|
||
|
||
unsigned short RPC_ENTRY
|
||
I_RpcTransServerMaxFrag (
|
||
IN RPC_TRANSPORT_CONNECTION ThisConnection
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The server side transport interface modules will use this routine to
|
||
determine the negotiated maximum fragment size.
|
||
|
||
Arguments:
|
||
|
||
ThisConnection - Supplies the connection for which we are returning
|
||
the maximum fragment size.
|
||
|
||
--*/
|
||
{
|
||
ASSERT(0);
|
||
return(0);
|
||
}
|
||
|
||
RPC_TRANSPORT_CONNECTION RPC_ENTRY
|
||
I_RpcTransServerNewConnection (
|
||
IN RPC_TRANSPORT_ADDRESS ThisAddress
|
||
)
|
||
{
|
||
OSF_SCONNECTION * SConnection;
|
||
OSF_ADDRESS *Address ;
|
||
|
||
Address = InqTransAddress(ThisAddress) ;
|
||
|
||
SConnection = Address->NewConnection();
|
||
if ( SConnection == 0 )
|
||
{
|
||
return(0);
|
||
}
|
||
|
||
return(SConnection->TransConnection);
|
||
}
|
||
|
||
|
||
|
||
void RPC_ENTRY
|
||
I_RpcTransServerFreePacket (
|
||
IN RPC_TRANSPORT_CONNECTION ThisConnection,
|
||
IN void * Buffer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
We need to free a transport buffer for a transport connection; this
|
||
will typically occur when the connection is being closed.
|
||
|
||
Arguments:
|
||
|
||
ThisConnection - Supplies the transport connection which owns the
|
||
buffer.
|
||
|
||
Buffer - Supplies the buffer to be freed.
|
||
|
||
--*/
|
||
{
|
||
ASSERT(0);
|
||
}
|
||
|
||
|
||
void * RPC_ENTRY
|
||
I_RpcTransProtectThread (
|
||
void
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
In some cases, if an asyncronous io operation has been started by a
|
||
thread, the thread can not be deleted because the io operation will
|
||
be cancelled. This routine will be called by a transport to indicate
|
||
that the current thread can not be deleted.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the thread will be returned. This is necessary, so that
|
||
later the thread can be unprotected.
|
||
|
||
--*/
|
||
{
|
||
#ifdef RPC_OLD_IO_PROTECTION
|
||
THREAD * Thread = RpcpGetThreadPointer();
|
||
|
||
Thread->ProtectThread();
|
||
return((void *) Thread);
|
||
#endif
|
||
return 0;
|
||
}
|
||
|
||
|
||
void RPC_ENTRY
|
||
I_RpcTransUnprotectThread (
|
||
IN void * Thread
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
When a thread no longer needs to be protected from deletion, this
|
||
routine must be called.
|
||
|
||
Arguments:
|
||
|
||
Thread - Supplies the thread which no longer needs to be protected
|
||
from deletion.
|
||
|
||
--*/
|
||
{
|
||
#ifdef RPC_OLD_IO_PROTECTION
|
||
((THREAD *) Thread)->UnprotectThread();
|
||
#endif
|
||
}
|
||
|
||
void
|
||
I_RpcTransVerifyServerRuntimeCallFromContext(
|
||
void *SendContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Verifies that the supplied context follows a valid
|
||
runtime server call object.
|
||
|
||
Arguments:
|
||
|
||
SendContext - the context as seen by the transport
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ASSERT(InqTransSCall(SendContext)->InvalidHandle(OSF_SCALL_TYPE) == 0);
|
||
}
|
||
|
||
const UUID BindNakEEInfoSignatureData = { /* 90740320-fad0-11d3-82d7-009027b130ab */
|
||
0x90740320,
|
||
0xfad0,
|
||
0x11d3,
|
||
{0x82, 0xd7, 0x00, 0x90, 0x27, 0xb1, 0x30, 0xab}
|
||
};
|
||
|
||
const UUID *BindNakEEInfoSignature = &BindNakEEInfoSignatureData;
|