Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4543 lines
132 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
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:
--*/
#include <precomp.hxx>
#include <rpctran.h>
#include <thrdctx.hxx>
#include <hndlsvr.hxx>
#include <osfpcket.hxx>
#include <secsvr.hxx>
#include <osfsvr.hxx>
#include <sdict2.hxx>
#include <queue.hxx>
#include <transvr.hxx>
#include <rpccfg.h>
#define MINIMUM_CALL_THREADS 3
extern long GroupIdCounter;
inline void
ReceiveLotsaCallsWrapper(
IN OSF_ADDRESS PAPI * Address
)
{
Address->ReceiveLotsaCalls();
}
inline void
RecvDirectWrapper(
IN OSF_SCONNECTION PAPI * SConnection
)
{
ASSERT(SConnection->InvalidHandle(SCONNECTION_TYPE) == 0) ;
SConnection->ReceiveDirect();
}
OSF_ADDRESS::OSF_ADDRESS (
IN OUT RPC_STATUS PAPI * RpcStatus
) : RPC_ADDRESS(RpcStatus)
/*++
Routine Description:
--*/
{
CallThreadCount = 0;
ActiveCallCount = 0;
MinimumCallThreads = 0;
ServerListeningFlag = 0;
ReceiveDirectCount = 0;
}
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 RpcStatus;
unsigned char *AnsiAddress;
#ifdef NTENV
AnsiAddress = UnicodeToAnsiString(InqEndpoint(),&RpcStatus);
if (RpcStatus != RPC_S_OK)
{
ASSERT(RpcStatus == RPC_S_OUT_OF_MEMORY);
ASSERT(AnsiAddress == 0);
return RpcStatus;
}
RpcpMemoryCopy(Address,AnsiAddress,AddressLength);
delete AnsiAddress;
#endif
#ifdef DOSWIN32RPC
RpcpMemoryCopy(Address, InqEndpoint(), AddressLength);
#endif
return (RPC_S_OK);
}
void
OSF_ADDRESS::ReceiveLotsaCalls (
)
/*++
Routine Description:
Each thread used to received remote procedure calls on an address will
execute this routine. This routine will never routine; each thread will
kill itself off when it is no longer needed.
--*/
{
OSF_SCONNECTION * SConnection;
void PAPI * Buffer;
unsigned int BufferLength;
RPC_STATUS RpcStatus;
for (;;)
{
RpcStatus = TransReceive(&SConnection, &Buffer, &BufferLength);
ASSERT( (RpcStatus == RPC_S_OK)
|| (RpcStatus == RPC_P_CONNECTION_CLOSED));
if ( RpcStatus == RPC_P_CONNECTION_CLOSED )
{
ASSERT( SConnection != 0 );
SConnection->Delete() ;
continue;
}
AddressMutex.Request();
// We must always have one more thread waiting to receive than there
// are calls in progress. This is necessary because the address
// TransReceive call is used to receive all packets from all
// connections to the address.
ActiveCallCount++;
if ( ActiveCallCount >= CallThreadCount )
{
RpcStatus = RPCSTATUS_GET_CREATETHREAD(this);
if ( RpcStatus == RPC_S_OK )
{
CallThreadCount++;
}
else
{
ActiveCallCount -= 1;
AddressMutex.Clear();
// BUGBUG: We might have a similar problem with
// alter context PDUs
if (((rpcconn_common *) Buffer)->PTYPE == rpc_bind)
{
SConnection->SendBindNak(temporary_congestion) ;
}
else
{
SConnection->SetCallId(((rpcconn_common *)Buffer)->call_id);
SConnection->SendFault(RPC_S_OUT_OF_MEMORY, 1);
SConnection->Delete();
}
continue;
}
}
AddressMutex.Clear();
for (;;)
{
ASSERT(SConnection->InvalidHandle(SCONNECTION_TYPE) == 0) ;
if (SConnection->DispatchPacket((rpcconn_common *) Buffer,
BufferLength, this) != 0)
{
break;
}
if ( TransMarkReceiveAny(SConnection) == 0 )
{
break;
}
RpcStatus = SConnection->TransReceive(&Buffer, &BufferLength, 0);
if ( RpcStatus == RPC_P_CONNECTION_CLOSED )
{
SConnection->Delete() ;
break;
}
ASSERT( RpcStatus == RPC_S_OK );
}
AddressMutex.Request();
ActiveCallCount--;
// If there is more than one excess thread, and the number of
// call threads is greater than the minimum required, then kill
// off one of them.
if ( ( CallThreadCount - ActiveCallCount > 1 )
&& ( ( CallThreadCount > MinimumCallThreads )
|| ( CallThreadCount > MINIMUM_CALL_THREADS ) ) )
{
CallThreadCount--;
AddressMutex.Clear();
return;
}
AddressMutex.Clear();
}
}
RPC_STATUS
OSF_ADDRESS::ServerStartingToListen (
IN unsigned int MinimumCallThreads,
IN unsigned int MaximumConcurrentCalls,
IN int ServerThreadsStarted
)
/*++
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 RpcStatus;
UNUSED(MaximumConcurrentCalls);
this->MinimumCallThreads = MinimumCallThreads;
if (ServerThreadsStarted == 0)
{
AddressMutex.Request();
#if defined(NTENV) || defined(WIN96)
if(CreateThread)
{
#endif
while ( ( CallThreadCount < this->MinimumCallThreads )
&& ( CallThreadCount < MINIMUM_CALL_THREADS ) )
{
RpcStatus = RPCSTATUS_GET_CREATETHREAD(this);
if ( RpcStatus != RPC_S_OK )
{
AddressMutex.Clear();
ASSERT( RpcStatus == RPC_S_OUT_OF_THREADS );
return(RpcStatus);
}
CallThreadCount += 1;
}
#if defined(NTENV) || defined(WIN96)
}
#endif
AddressMutex.Clear();
}
ServerListeningFlag = 1;
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;
MinimumCallThreads = 2;
}
unsigned int
OSF_ADDRESS::InqNumberOfActiveCalls (
)
/*++
Return Value:
The number of active calls on this address will be returned.
--*/
{
return(ActiveCallCount);
}
RPC_STATUS
OSF_ADDRESS::FireUpManager (
IN unsigned int MinimumConcurrentCalls
)
/*++
Routine Description:
We fire up the manager in this method. To even get started, we need
to create at least one threads; we will do this now.
Arguments:
MinimumConcurrentCalls - Unused.
Return Value:
RPC_S_OK - We successfully fired up the manager.
RPC_S_OUT_OF_THREADS - We could not create one thread.
--*/
{
RPC_STATUS RpcStatus;
UNUSED(MinimumConcurrentCalls);
// We will go ahead and create one thread right now.
AddressMutex.Request();
RpcStatus = RPCSTATUS_GET_CREATETHREAD(this);
if ( RpcStatus != RPC_S_OK )
{
AddressMutex.Clear();
ASSERT( RpcStatus == RPC_S_OUT_OF_THREADS );
return(RpcStatus);
}
CallThreadCount += 1;
AddressMutex.Clear();
return(RPC_S_OK);
}
OSF_ASSOCIATION *
OSF_ADDRESS::RemoveAssociation (
IN int Key
)
{
// The AddressMutex has already been requested.
return(Associations.Delete(Key));
}
int
OSF_ADDRESS::AddAssociation (
IN OSF_ASSOCIATION * TheAssociation
)
{
// The AddressMutex has already been requested.
return(Associations.Insert(TheAssociation));
}
OSF_ASSOCIATION *
OSF_ADDRESS::FindAssociation (
IN unsigned long AssociationGroupId,
IN RPC_CLIENT_PROCESS_IDENTIFIER * ClientProcess
)
// The AddressMutex has already been requested.
{
OSF_ASSOCIATION * Association;
Associations.Reset();
while ( (Association = Associations.Next()) != 0 )
{
if ( Association->IsMyAssocGroupId(AssociationGroupId,
ClientProcess) != 0 )
{
Association->AddConnection();
return(Association);
}
}
return(0);
}
void
OSF_ADDRESS::MaybeMakeReceiveDirect (
IN OSF_SCONNECTION * SConnection,
OUT unsigned int PAPI * ReceiveDirectFlag
)
/*++
Routine Description:
The transport interface layer is inquiring whether the connection should
be receive direct or receive any.
Arguments:
SConnection - Supplies the connection for which we need to decide.
ReceiveDirectFlag - Returns an indication of whether the connection is
receive direct or receive any. A value of zero indicates receive
any; otherwise, the connection is receive direct.
--*/
{
RPC_STATUS RpcStatus;
AddressMutex.Request();
if ( ReceiveDirectCount + 2 < MinimumCallThreads )
{
*ReceiveDirectFlag = 1;
SConnection->ReceiveDirectAddress = this;
RpcStatus = Server->CreateThread(
(THREAD_PROC)&RecvDirectWrapper,
SConnection
);
if ( RpcStatus != RPC_S_OK )
{
*ReceiveDirectFlag = 0;
}
else
{
ReceiveDirectCount += 1;
}
}
else
{
*ReceiveDirectFlag = 0;
}
AddressMutex.Clear();
}
/* --------------------------------------------------------------------
-------------------------------------------------------------------- */
#define FIRST_CACHED_BUFFER_AVAILABLE 0x1
#define SECOND_CACHED_BUFFER_AVAILABLE 0x2
#define THIRD_CACHED_BUFFER_AVAILABLE 0x4
#define CACHED_BUFFERS_ALLOCATED 0x8
#define CACHED_BUFFER_AVAILABLE_MASK 0x7
#define ALIGN_POWER2 3
#define ALIGN_REQUIRED (1 << ALIGN_POWER2)
#ifdef NTENV
#define UnAlignBuffer(Buffer) \
(void PAPI *) (Buffer)
#else // NTENV
#define UnAlignBuffer(Buffer) \
(void PAPI *) ((char PAPI *)Buffer - ((int PAPI *)Buffer)[-1])
#endif // NTENV
#ifdef NTENV
#define CACHED_BUFFER_LENGTH 1024
#else // NTENV
#define CACHED_BUFFER_LENGTH 512
#endif // NTENV
OSF_SCONNECTION::OSF_SCONNECTION (
IN OUT RPC_STATUS PAPI * RpcStatus
)
: CachedBufferMutex(RpcStatus)
{
#ifndef NTENV
int AmountOfPad;
#endif // NTENV
MaxFrag = 512;
OutstandingBuffers = 0;
CallId = 0;
CallStack = 0;
Association = 0;
CurrentBinding = 0;
AuthContextId = 0;
Thread = 0;
CallOrphaned = 0;
CancelPending = 0;
AdditionalSpaceForSecurity = 0;
ImpersonatedClientFlag = 0;
ReceiveDirectReady = 0;
DceSecurityInfo.SendSequenceNumber = 0;
DceSecurityInfo.ReceiveSequenceNumber = 0;
// Ok, try and allocate the cached buffers.
CachedBufferLength = CACHED_BUFFER_LENGTH;
CurrentSecurityContext = 0;
RpcSecurityBeingUsed = 0;
SecurityContextAltered = 0;
#ifdef NTENV
FirstCachedBuffer = (int PAPI *) RpcpFarAllocate(CACHED_BUFFER_LENGTH * 3);
#else // NTENV
FirstCachedBuffer = (int PAPI *) RpcpFarAllocate(CACHED_BUFFER_LENGTH * 3
+ ALIGN_REQUIRED);
#endif // NTENV
if ( FirstCachedBuffer == 0 )
{
BufferCacheFlags = 0;
SecondCachedBuffer = 0;
ThirdCachedBuffer = 0;
}
else
{
#ifndef NTENV
ASSERT( (((long) FirstCachedBuffer) % sizeof(int)) == 0 );
AmountOfPad = Pad((char PAPI *)FirstCachedBuffer + 1, ALIGN_REQUIRED) + 1;
FirstCachedBuffer = (void PAPI *)
(((char PAPI *) FirstCachedBuffer) + AmountOfPad);
((int PAPI *) FirstCachedBuffer)[-1] = AmountOfPad;
#endif // NTENV
SecondCachedBuffer = (void PAPI *)
(((char PAPI *) FirstCachedBuffer) + CACHED_BUFFER_LENGTH);
ThirdCachedBuffer = (void PAPI *)
(((char PAPI *) SecondCachedBuffer) + CACHED_BUFFER_LENGTH);
BufferCacheFlags = FIRST_CACHED_BUFFER_AVAILABLE
| SECOND_CACHED_BUFFER_AVAILABLE
| THIRD_CACHED_BUFFER_AVAILABLE | CACHED_BUFFERS_ALLOCATED;
ASSERT(Pad8(ThirdCachedBuffer) == 0);
}
SavedHeader = 0;
SavedHeaderSize = 0;
BufferComplete = 0;
}
OSF_SCONNECTION::~OSF_SCONNECTION (
)
{
OSF_SBINDING * SBinding;
SSECURITY_CONTEXT * SecurityContext;
Bindings.Reset();
while (SBinding = Bindings.Next())
delete SBinding;
if (Association)
Association->RemoveConnection();
ASSERT( AuthInfo.AuthIdentity == 0 );
if ( CurrentSecurityContext && AuthInfo.AuthIdentity )
{
CurrentSecurityContext->DeletePac( AuthInfo.AuthIdentity );
}
SecurityContextDict.Reset();
while ( (SecurityContext = SecurityContextDict.Next()) != 0 )
delete SecurityContext;
if ( BufferCacheFlags & CACHED_BUFFERS_ALLOCATED )
{
RpcpFarFree(UnAlignBuffer(FirstCachedBuffer));
}
if (SavedHeader != 0)
{
ASSERT(AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE);
ASSERT(SavedHeaderSize != 0) ;
RpcpFarFree(SavedHeader);
}
}
RPC_STATUS
OSF_SCONNECTION::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 RpcStatus, ExceptionCode;
unsigned int RemoteFaultOccured = 0;
RPC_MESSAGE RpcMessage ;
RPC_RUNTIME_INFO RuntimeInfo ;
CallStack += 1;
Association->TheAddress()->Server->OutgoingCallback();
RpcStatus = SendRequestOrResponse(Message, rpc_request);
for (; RpcStatus == RPC_S_OK ;)
{
RpcStatus = ReceiveMessage(Message, &RemoteFaultOccured);
if ( RpcStatus != RPC_P_OK_REQUEST )
{
break;
}
Message->TransferSyntax = CurrentBinding->TransferSyntax();
RuntimeInfo.Length = sizeof(RPC_RUNTIME_INFO) ;
RpcMessage = *Message ;
RpcMessage.ReservedForRuntime = &RuntimeInfo ;
if ( ObjectUuidSpecified != 0 )
{
RpcStatus = CurrentBinding->GetInterface()
->DispatchToStubWithObject(&RpcMessage, &ObjectUuid, 1,
&ExceptionCode);
}
else
{
RpcStatus = CurrentBinding->GetInterface()->DispatchToStub(
&RpcMessage, 1, &ExceptionCode);
}
*Message = RpcMessage ;
if ( RpcStatus != RPC_S_OK )
{
ASSERT( (RpcStatus == RPC_P_EXCEPTION_OCCURED)
|| (RpcStatus == RPC_S_PROCNUM_OUT_OF_RANGE));
if ( RpcStatus == RPC_S_PROCNUM_OUT_OF_RANGE )
{
SendFault(RPC_S_PROCNUM_OUT_OF_RANGE, 1);
}
else
{
SendFault(ExceptionCode, 0);
}
RpcStatus = TransReceive(&(Message->Buffer),
&(Message->BufferLength), 0);
if ( RpcStatus != RPC_S_OK )
{
if ( ( RpcStatus == RPC_P_RECEIVE_FAILED )
|| ( RpcStatus == RPC_P_CONNECTION_CLOSED ) )
{
RpcStatus = RPC_S_CALL_FAILED;
}
else
{
ASSERT( ( RpcStatus == RPC_S_OUT_OF_MEMORY )
|| ( RpcStatus == RPC_S_OUT_OF_RESOURCES ) );
}
break;
}
}
else
{
RpcStatus = SendRequestOrResponse(Message, rpc_response);
if ( RpcStatus == RPC_S_CALL_FAILED_DNE )
{
RpcStatus = RPC_S_CALL_FAILED;
}
}
}
CallStack -= 1;
if ( RpcStatus == RPC_S_OK )
{
Message->Handle = (RPC_BINDING_HANDLE) this;
}
return(RpcStatus);
}
RPC_STATUS
OSF_SCONNECTION::GetBuffer (
IN OUT PRPC_MESSAGE Message
)
{
Message->Handle = (RPC_BINDING_HANDLE) this;
if (Message->RpcFlags & RPC_BUFFER_PARTIAL &&
Message->BufferLength < MaxFrag)
{
CurrentBufferLength = MaxFrag ;
}
else
{
CurrentBufferLength = Message->BufferLength ;
}
// In addition to saving space for the request (or response) header,
// we want to save space for security information if necessary.
if (TransGetBuffer(&Message->Buffer,CurrentBufferLength
+ sizeof(rpcconn_request) + (2*AdditionalSpaceForSecurity)))
{
CurrentBufferLength = 0 ;
return(RPC_S_OUT_OF_MEMORY);
}
Message->Buffer = (unsigned char *) Message->Buffer
+ sizeof(rpcconn_request);
return(RPC_S_OK);
}
RPC_STATUS
OSF_SCONNECTION::GetBufferDo (
IN PRPC_MESSAGE Message,
IN unsigned int culRequiredLength,
OUT void ** ppBuffer,
IN unsigned long Extra
)
{
if (TransGetBuffer(ppBuffer,culRequiredLength + sizeof(rpcconn_request)))
return(RPC_S_OUT_OF_MEMORY);
*ppBuffer = (((unsigned char *) (*ppBuffer)) + sizeof(rpcconn_request));
if (Extra)
{
ASSERT(Message->ReservedForRuntime) ;
((PRPC_RUNTIME_INFO)Message->ReservedForRuntime)->OldBuffer = *ppBuffer;
}
return(RPC_S_OK);
}
void
OSF_SCONNECTION::FreeBuffer (
IN PRPC_MESSAGE Message
)
{
TransFreeBuffer((unsigned char *) Message->Buffer
- sizeof(rpcconn_request));
CurrentBufferLength = 0;
}
void
OSF_SCONNECTION::FreePipeBuffer (
IN PRPC_MESSAGE Message
)
{
TransFreeBuffer((unsigned char *) Message->Buffer
- sizeof(rpcconn_request));
}
RPC_STATUS
OSF_SCONNECTION::ReallocPipeBuffer (
IN PRPC_MESSAGE Message,
IN unsigned int NewSize
)
{
void *TempBuffer ;
RPC_STATUS RpcStatus ;
unsigned int SizeToAlloc ;
if (NewSize > CurrentBufferLength)
{
SizeToAlloc = (NewSize > MaxFrag) ? NewSize:MaxFrag ;
RpcStatus = TransGetBuffer(&TempBuffer,
SizeToAlloc + sizeof(rpcconn_request) + sizeof(UUID)
+ (2*AdditionalSpaceForSecurity) );
if ( RpcStatus != RPC_S_OK )
{
ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY );
return(RPC_S_OUT_OF_MEMORY);
}
if (CurrentBufferLength > 0)
{
RpcpMemoryCopy((char PAPI *) TempBuffer+sizeof(rpcconn_request),
Message->Buffer, Message->BufferLength) ;
FreePipeBuffer(Message) ;
}
//BUGBUG: Think about changing this to return CurrentBufferLength
Message->Buffer = (char PAPI *) TempBuffer + sizeof(rpcconn_request);
CurrentBufferLength = SizeToAlloc ;
}
Message->BufferLength = NewSize ;
return (RPC_S_OK) ;
}
RPC_STATUS
OSF_SCONNECTION::MonitorAssociation (
IN PRPC_RUNDOWN RundownRoutine,
IN void * pContext
)
{
return(Association->MonitorAssociation(RundownRoutine,pContext));
}
RPC_STATUS
OSF_SCONNECTION::StopMonitorAssociation (
)
{
return(Association->StopMonitorAssociation());
}
RPC_STATUS
OSF_SCONNECTION::GetAssociationContext (
OUT void ** AssociationContext
)
{
*AssociationContext = Association->AssociationContext();
return(RPC_S_OK);
}
RPC_STATUS
OSF_SCONNECTION::SetAssociationContext (
IN void * pContext
)
{
Association->SetAssociationContext(pContext);
return(RPC_S_OK);
}
RPC_STATUS
OSF_SCONNECTION::ImpersonateClient (
)
// 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.
{
RPC_STATUS Status;
if ( !RpcSecurityBeingUsed )
{
Status = SetThreadSecurityContext((SSECURITY_CONTEXT *) ~0UL, &CachedBufferMutex);
if (RPC_S_OK != Status)
{
return Status;
}
return TransImpersonateClient();
}
SSECURITY_CONTEXT * SecurityContext = CurrentSecurityContext;
if (!SecurityContext)
{
ASSERT(SecurityContextAltered);
return RPC_S_NO_CONTEXT_AVAILABLE;
}
Status = SetThreadSecurityContext(SecurityContext, &CachedBufferMutex);
if (RPC_S_OK != Status)
{
return Status;
}
Status = SecurityContext->ImpersonateClient();
if (RPC_S_OK != Status)
{
ClearThreadSecurityContext(&CachedBufferMutex);
}
return Status;
}
RPC_STATUS
OSF_SCONNECTION::RevertToSelf (
)
// 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.
{
SSECURITY_CONTEXT * SecurityContext = ClearThreadSecurityContext(&CachedBufferMutex);
if (!RpcSecurityBeingUsed)
{
if (SecurityContext)
{
ASSERT(SecurityContext == (SSECURITY_CONTEXT *) ~0UL);
TransRevertToSelf();
}
return RPC_S_OK;
}
if (SecurityContext)
{
SecurityContext->RevertToSelf();
}
return(RPC_S_OK);
}
RPC_STATUS
OSF_SCONNECTION::IsClientLocal (
OUT unsigned int PAPI * 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;
TransQueryClientProcess(&ClientProcess);
if ( ClientProcess.FirstPart == 0 )
{
if(ClientProcess.SecondPart == 0)
return (RPC_S_CANNOT_SUPPORT) ;
else
*ClientLocalFlag = 1;
}
else
{
*ClientLocalFlag = 0;
}
return(RPC_S_OK);
}
RPC_STATUS
OSF_SCONNECTION::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 RpcStatus;
RPC_CHAR * StringBinding;
RpcStatus = TransQueryClientNetworkAddress(&NetworkAddress);
if ( RpcStatus != RPC_S_OK )
{
return(RpcStatus);
}
RpcStatus = RpcStringBindingComposeW(0, Association->TheAddress()->InqRpcProtocolSequence(),
NetworkAddress, 0, 0, &StringBinding);
delete NetworkAddress;
if ( RpcStatus != RPC_S_OK )
{
return(RpcStatus);
}
RpcStatus = RpcBindingFromStringBindingW(StringBinding, ServerBinding);
if ( ObjectUuidSpecified != 0 && RPC_S_OK == RpcStatus)
{
RpcStatus = RpcBindingSetObject(*ServerBinding, (UUID *) &ObjectUuid);
}
RpcStringFreeW(&StringBinding);
return(RpcStatus);
}
/* --------------------------------------------------------------------
-------------------------------------------------------------------- */
RPC_STATUS
OSF_SCONNECTION::TransGetBuffer (
OUT void PAPI * PAPI * 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.
--*/
{
int PAPI * Memory;
#ifndef NTENV
int AmountOfPad;
#endif // NTENV
// First we need to check to see if we can use one of the cached
// buffers.
if ( BufferLength <= CachedBufferLength )
{
CachedBufferMutex.Request();
if ( BufferCacheFlags & FIRST_CACHED_BUFFER_AVAILABLE )
{
BufferCacheFlags &= ~FIRST_CACHED_BUFFER_AVAILABLE;
*Buffer = FirstCachedBuffer;
OutstandingBuffers += 1;
CachedBufferMutex.Clear();
return(RPC_S_OK);
}
if ( BufferCacheFlags & SECOND_CACHED_BUFFER_AVAILABLE )
{
BufferCacheFlags &= ~SECOND_CACHED_BUFFER_AVAILABLE;
*Buffer = SecondCachedBuffer;
OutstandingBuffers += 1;
CachedBufferMutex.Clear();
return(RPC_S_OK);
}
if ( BufferCacheFlags & THIRD_CACHED_BUFFER_AVAILABLE )
{
BufferCacheFlags &= ~THIRD_CACHED_BUFFER_AVAILABLE;
*Buffer = ThirdCachedBuffer;
OutstandingBuffers += 1;
CachedBufferMutex.Clear();
return(RPC_S_OK);
}
CachedBufferMutex.Clear();
}
#ifdef NTENV
// The NT memory allocator returns memory which is aligned by at least
// 8, so we dont need to worry about aligning it.
Memory = (int PAPI *) RpcpFarAllocate(BufferLength);
if ( Memory == 0 )
{
return(RPC_S_OUT_OF_MEMORY);
}
ASSERT( (((long) Memory) % ALIGN_REQUIRED) == 0 );
#else // NTENV
// We will allocate an extra 8 bytes of memory, so we have enough
// space to pad the buffer. We will place an integer just before
// the pointer we return. The integer will specify the amount we
// had to pad the buffer to make it 8 byte aligned. We need this
// information when we free the buffer. As a result, the original
// buffer must be allocated to at least sizeof(int) alignment.
Memory = (int PAPI *) RpcpFarAllocate(BufferLength + ALIGN_REQUIRED);
if ( Memory == 0 )
{
return(RPC_S_OUT_OF_MEMORY);
}
ASSERT( (((long) Memory) % sizeof(int)) == 0 );
AmountOfPad = Pad((char PAPI *)Memory + 1, ALIGN_REQUIRED) + 1;
Memory = (int PAPI *) (((char PAPI *) Memory) + AmountOfPad);
Memory[-1] = AmountOfPad;
ASSERT(Pad8(Memory) == 0);
#endif // NTENV
*Buffer = Memory;
OutstandingBuffers += 1;
return(RPC_S_OK);
}
void
OSF_SCONNECTION::TransFreeBuffer (
IN void PAPI * 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.
--*/
{
CachedBufferMutex.Request();
if ( Buffer == FirstCachedBuffer )
{
BufferCacheFlags |= FIRST_CACHED_BUFFER_AVAILABLE;
}
else if ( Buffer == SecondCachedBuffer )
{
BufferCacheFlags |= SECOND_CACHED_BUFFER_AVAILABLE;
}
else if ( Buffer == ThirdCachedBuffer )
{
BufferCacheFlags |= THIRD_CACHED_BUFFER_AVAILABLE;
}
else
{
RpcpFarFree(UnAlignBuffer(Buffer));
}
OutstandingBuffers -= 1;
CachedBufferMutex.Clear();
}
/* --------------------------------------------------------------------
-------------------------------------------------------------------- */
int
OSF_SCONNECTION::SendBindNak (
IN p_reject_reason_t reject_reason
)
{
rpcconn_bind_nak * pBindNak = (rpcconn_bind_nak *) 0;
unsigned int cBindNak = sizeof(rpcconn_bind_nak);
if (TransGetBuffer((void **) &pBindNak,cBindNak))
return(-1);
ConstructPacket((rpcconn_common *) pBindNak,rpc_bind_nak,cBindNak);
pBindNak->provider_reject_reason = reject_reason;
pBindNak->versions.n_protocols = 1;
pBindNak->versions.p_protocols[0].major = OSF_RPC_V20_VERS;
pBindNak->versions.p_protocols[0].minor = OSF_RPC_V20_VERS_MINOR;
pBindNak->common.call_id = CallId;
pBindNak->common.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG ;
if (TransSend(pBindNak,cBindNak))
{
TransFreeBuffer(pBindNak);
return(-1);
}
TransFreeBuffer(pBindNak);
return(0);
}
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;
RPC_INTERFACE * Interface;
OSF_SBINDING * SBinding;
RPC_STATUS Status;
if (*PContextListLength < sizeof(p_cont_list_t))
{
return(1);
}
*PContextListLength -= (sizeof(p_cont_list_t) - sizeof(p_cont_elem_t));
ResultList->n_results = PContextList->n_context_elem;
ResultList->reserved = 0;
ResultList->reserved2 = 0;
for (PContextListIndex = 0, PContextElem = PContextList->p_cont_elem;
PContextListIndex < (unsigned int) PContextList->n_context_elem;
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 )
{
ByteSwapShort(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),
&Interface);
if (Status == RPC_S_OK)
{
ResultList->p_results[PContextListIndex].result = acceptance;
ResultList->p_results[PContextListIndex].reason = 0;
SBinding = new OSF_SBINDING(Interface, (RPC_SYNTAX_IDENTIFIER *)
&(PContextElem->abstract_syntax), (RPC_SYNTAX_IDENTIFIER *)
&(ResultList->p_results[PContextListIndex].transfer_syntax),
PContextElem->p_cont_id);
if ( (SBinding == 0)
|| (Bindings.Insert(SBinding) == -1))
{
ResultList->p_results[PContextListIndex].result =
provider_rejection;
ResultList->p_results[PContextListIndex].reason =
local_limit_exceeded;
memset(&(ResultList->p_results[PContextListIndex].
transfer_syntax.if_uuid.Data1),0,sizeof(GUID));
ResultList->p_results[PContextListIndex].
transfer_syntax.if_version = 0;
}
}
else if (Status == RPC_S_UNSUPPORTED_TRANS_SYN)
{
ResultList->p_results[PContextListIndex].result =
provider_rejection;
ResultList->p_results[PContextListIndex].reason =
proposed_transfer_syntaxes_not_supported;
memset(&(ResultList->p_results[PContextListIndex].
transfer_syntax.if_uuid.Data1),0,sizeof(GUID));
ResultList->p_results[PContextListIndex].
transfer_syntax.if_version = 0;
}
else
{
ASSERT(Status == RPC_S_UNKNOWN_IF);
ResultList->p_results[PContextListIndex].result = provider_rejection;
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 *) &(PContextElem->transfer_syntaxes[
PContextElem->n_transfer_syn]);
}
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 OSF_ADDRESS * Address,
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, AuthContinueNeeded = 0;
unsigned int BindAckLength, TokenLength = 0, AuthPadLength;
rpcconn_bind_ack * BindAck;
RPC_STATUS RpcStatus;
sec_trailer PAPI * SecurityTrailer, PAPI * NewSecurityTrailer;
SECURITY_CREDENTIALS * SecurityCredentials = 0;
rpcconn_auth3 PAPI * AuthThirdLegPacket;
unsigned int AuthThirdLegPacketLength;
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];
DCE_INIT_SECURITY_INFO InitSecurityInfo;
if ( BindPacketLength < sizeof(rpcconn_bind) )
{
TransFreeBuffer(BindPacket);
SendBindNak(reason_not_specified_reject);
return(1);
}
if ( DataConvertEndian(BindPacket->common.drep) != 0 )
{
ByteSwapShort(BindPacket->max_xmit_frag);
ByteSwapShort(BindPacket->max_recv_frag);
ByteSwapLong(BindPacket->assoc_group_id);
}
// 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 PAPI *)
(((unsigned char PAPI *) 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) )
{
SendBindNak(reason_not_specified_reject);
return(1);
}
AuthInfo.AuthenticationService = SecurityTrailer->auth_type;
AuthContextId = SecurityTrailer->auth_context_id;
if ( DataConvertEndian(BindPacket->common.drep) != 0 )
{
ByteSwapLong(AuthContextId);
}
RPC_STATUS Status = RPC_S_OK;
CurrentSecurityContext = new SSECURITY_CONTEXT(
&AuthInfo,
AuthContextId,
FALSE,
&Status
);
if ( (CurrentSecurityContext == 0)
|| RPC_S_OK != Status
||(SecurityContextDict.Insert(CurrentSecurityContext) == -1) )
{
SendBindNak(local_limit_exceeded_reject);
return(1);
}
RpcSecurityBeingUsed = 1;
RpcStatus = Address->Server->AcquireCredentials(
AuthInfo.AuthenticationService, AuthInfo.AuthenticationLevel,
&SecurityCredentials);
if ( RpcStatus == RPC_S_OUT_OF_MEMORY )
{
SendBindNak(local_limit_exceeded_reject);
return(1);
}
if ( RpcStatus != RPC_S_OK )
{
SendBindNak(authentication_type_not_recognized);
return(1);
}
ASSERT( SecurityCredentials != 0 );
}
PContextList = (p_cont_list_t *) (BindPacket + 1);
// 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.
RpcStatus = TransGetBuffer((void **) &BindAck, BindAckLength);
if ( RpcStatus != RPC_S_OK )
{
ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY );
Address->Server->FreeCredentials(SecurityCredentials);
TransFreeBuffer(BindPacket);
SendBindNak(local_limit_exceeded_reject);
return(1);
}
// Finally we get to do something about that authentication that the
// client sent us.
if ( SecurityCredentials != 0 )
{
NewSecurityTrailer = (sec_trailer PAPI *)
(((unsigned char PAPI *) 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 PAPI*)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;
RpcStatus = CurrentSecurityContext->AcceptFirstTime(SecurityCredentials,
&InputBufferDescriptor, &OutputBufferDescriptor,
SecurityTrailer->auth_level,
*((unsigned long PAPI *) BindPacket->common.drep),
0
);
TokenLength = (unsigned int) OutputBuffers[2].cbBuffer;
if ( ( RpcStatus == RPC_P_CONTINUE_NEEDED )
|| ( RpcStatus == RPC_S_OK )
|| ( RpcStatus == RPC_P_COMPLETE_NEEDED )
|| ( RpcStatus == RPC_P_COMPLETE_AND_CONTINUE ) )
{
if ( RpcStatus == RPC_P_CONTINUE_NEEDED )
{
AuthContinueNeeded = 1;
}
else if ( RpcStatus == RPC_P_COMPLETE_AND_CONTINUE )
{
AuthContinueNeeded = 1;
CompleteNeeded = 1;
}
else if ( RpcStatus == 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 = AuthPadLength;
NewSecurityTrailer->auth_reserved = 0;
NewSecurityTrailer->auth_context_id = AuthContextId;
Address->Server->FreeCredentials(SecurityCredentials);
}
else
{
ASSERT ( ( RpcStatus == RPC_S_OUT_OF_MEMORY )
|| ( RpcStatus == RPC_S_ACCESS_DENIED )
|| ( RpcStatus == RPC_S_UNKNOWN_AUTHN_SERVICE) );
TransFreeBuffer(BindPacket);
TransFreeBuffer(BindAck);
Address->Server->FreeCredentials(SecurityCredentials);
if (RpcStatus == RPC_S_OUT_OF_MEMORY)
{
SendBindNak(local_limit_exceeded_reject);
}
else
if (RpcStatus == RPC_S_UNKNOWN_AUTHN_SERVICE)
{
SendBindNak(authentication_type_not_recognized);
}
else
{
SendBindNak(invalid_checksum);
}
return(1);
}
}
TransQueryClientProcess(&ClientProcess);
if ( BindPacket->assoc_group_id != 0 )
{
// This means this is a connection on an existing association.
Address->AddressMutex.Request();
Association = Address->FindAssociation(
(int) BindPacket->assoc_group_id, &ClientProcess);
Address->AddressMutex.Clear();
if ( Association == 0 )
{
TransFreeBuffer(BindPacket);
TransFreeBuffer(BindAck);
SendBindNak(reason_not_specified_reject);
return(1);
}
}
if ( Association == 0 )
{
Association = new OSF_ASSOCIATION(Address, &ClientProcess, &RpcStatus);
if ( (Association == 0) || (RpcStatus != RPC_S_OK) )
{
delete Association;
Association = Nil;
TransFreeBuffer(BindPacket);
TransFreeBuffer(BindAck);
SendBindNak(local_limit_exceeded_reject);
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);
return(1);
}
// Fill in the header of the rpc_bind_ack packet.
ConstructPacket((rpcconn_common *) BindAck, rpc_bind_ack, BindAckLength);
MaxFrag = MinOf(BindPacket->max_xmit_frag, BindPacket->max_recv_frag,
TransMaximumSend());
if ( MaxFrag < MUST_RECV_FRAG_SIZE )
MaxFrag = MUST_RECV_FRAG_SIZE;
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;
((rpcconn_common PAPI *) BindAck)->pfc_flags |=
(PFC_FIRST_FRAG | PFC_LAST_FRAG);
DceSecurityInfo.ReceiveSequenceNumber += 1;
if ( SecondaryAddressLength != 0 )
{
RpcStatus = Address->TransSecondary((unsigned char *) (BindAck + 1),
SecondaryAddressLength);
if (RpcStatus != RPC_S_OK)
{
ASSERT(RpcStatus == RPC_S_OUT_OF_MEMORY);
TransFreeBuffer(BindPacket);
TransFreeBuffer(BindAck);
SendBindNak(reason_not_specified_reject);
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 = TokenLength;
// Send the rpc_bind_ack packet back to the client.
TransFreeBuffer(BindPacket);
if ( CompleteNeeded != 0 )
{
RpcStatus = CurrentSecurityContext->CompleteSecurityToken(
&OutputBufferDescriptor);
if (RpcStatus != RPC_S_OK)
{
TransFreeBuffer(BindAck);
SendBindNak(invalid_checksum);
return(1);
}
}
RpcStatus = TransSend(BindAck, BindAckLength);
TransFreeBuffer(BindAck);
if ( RpcStatus != RPC_S_OK )
{
return(1);
}
// We may need to do third leg AuthInfo.Authentication.
if ( AuthContinueNeeded != 0 )
{
// This means that the client is sending us back a third leg
// AuthInfo.Authentication packet.
RpcStatus = TransReceive((void **) &AuthThirdLegPacket,
&AuthThirdLegPacketLength, 0);
if ( RpcStatus != RPC_S_OK )
{
return(1);
}
// Save the unbyteswapped header
ASSERT(AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE);
if (SavedHeaderSize < AuthThirdLegPacketLength)
{
if (SavedHeader != 0)
{
ASSERT(SavedHeaderSize != 0);
RpcpFarFree(SavedHeader);
}
SavedHeader = RpcpFarAllocate(AuthThirdLegPacketLength);
if (SavedHeader == 0)
{
TransFreeBuffer(AuthThirdLegPacket);
return(1);
}
SavedHeaderSize = AuthThirdLegPacketLength;
RpcpMemoryCopy(SavedHeader, AuthThirdLegPacket,
AuthThirdLegPacketLength);
}
else
{
RpcpMemoryCopy(SavedHeader, AuthThirdLegPacket,
AuthThirdLegPacketLength);
}
RpcStatus = ValidatePacket((rpcconn_common PAPI *) AuthThirdLegPacket,
AuthThirdLegPacketLength);
if ( RpcStatus != RPC_S_OK )
{
TransFreeBuffer(AuthThirdLegPacket);
return(1);
}
if ( AuthThirdLegPacket->common.PTYPE != rpc_auth_3 )
{
TransFreeBuffer(AuthThirdLegPacket);
return(1);
}
NewSecurityTrailer = (sec_trailer PAPI *)
(((unsigned char PAPI *) AuthThirdLegPacket)
+ AuthThirdLegPacket->common.frag_length - sizeof(sec_trailer)
- AuthThirdLegPacket->common.auth_length);
if ( (NewSecurityTrailer->auth_type != AuthInfo.AuthenticationService)
|| (NewSecurityTrailer->auth_level != AuthInfo.AuthenticationLevel) )
{
TransFreeBuffer(AuthThirdLegPacket);
return(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 PAPI *)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;
RpcStatus = CurrentSecurityContext->AcceptThirdLeg(
*((unsigned long PAPI *) AuthThirdLegPacket->common.drep),
&InputBufferDescriptor, 0);
TransFreeBuffer(AuthThirdLegPacket);
if ( RpcStatus != RPC_S_OK )
{
return(1);
}
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);
}
return(0);
}
int
OSF_SCONNECTION::AlterContextRequested (
IN rpcconn_alter_context * AlterContext,
IN unsigned int AlterContextLength,
IN OSF_ADDRESS * Address
)
/*++
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 RpcStatus;
sec_trailer PAPI * SecurityTrailer, PAPI * 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;
SSECURITY_CONTEXT * SecId;
// 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.
if ( AlterContextLength < sizeof(rpcconn_alter_context) )
{
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 PAPI *)
(((unsigned char PAPI *) 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)
{
ByteSwapLong(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 SSECURITY_CONTEXT(&NewClientInfo, NewId, FALSE, &Status);
if ( (SecId == 0)
|| RPC_S_OK != Status
||(SecurityContextDict.Insert(SecId) == -1) )
{
SendFault(RPC_S_OUT_OF_MEMORY, 1);
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;
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);
return(1);
}
RpcStatus = Address->Server->AcquireCredentials(
AuthInfo.AuthenticationService,
AuthInfo.AuthenticationLevel,
&SecurityCredentials
);
if ( RpcStatus == RPC_S_OUT_OF_MEMORY )
{
SendFault(RPC_S_OUT_OF_MEMORY, 1);
return(1);
}
if ( RpcStatus != RPC_S_OK )
{
if (SecurityCredentials != 0)
{
Address->Server->FreeCredentials(SecurityCredentials);
}
SendFault(RPC_S_ACCESS_DENIED, 1);
return(1);
}
ASSERT( SecurityCredentials != 0 );
} //if secure alter context
PContextList = (p_cont_list_t *) (AlterContext + 1);
// BUGBUG - This particular expression is a work around for a
// C6 compiler bug.
AlterContextRespLength = sizeof(rpcconn_alter_context_resp);
AlterContextRespLength += sizeof(p_result_list_t);
AlterContextRespLength += 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);
}
RpcStatus = TransGetBuffer((void **) &AlterContextResp,
AlterContextRespLength);
if ( RpcStatus != RPC_S_OK )
{
ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY );
TransFreeBuffer(AlterContext);
if (SecurityCredentials != 0)
{
Address->Server->FreeCredentials(SecurityCredentials);
}
SendFault(RPC_S_OUT_OF_MEMORY, 1);
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)
{
Address->Server->FreeCredentials(SecurityCredentials);
}
SendFault(RPC_S_PROTOCOL_ERROR, 1);
return(1);
}
if ( SecureAlterContext != 0 )
{
ASSERT(SecurityCredentials != 0);
NewSecurityTrailer = (sec_trailer PAPI *)
(((unsigned char PAPI *) 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 PAPI *)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 )
{
RpcStatus = CurrentSecurityContext->AcceptFirstTime(
SecurityCredentials,
&InputBufferDescriptor,
&OutputBufferDescriptor,
SecurityTrailer->auth_level,
*((unsigned long *) AlterContext->common.drep),
NewContextRequired
);
//
// 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
{
RpcStatus = CurrentSecurityContext->AcceptThirdLeg(
*((unsigned long PAPI *) AlterContext->common.drep),
&InputBufferDescriptor,
&OutputBufferDescriptor
);
}
TokenLength = (unsigned int) OutputBuffers[2].cbBuffer;
if ( ( RpcStatus == RPC_S_OK )
|| ( RpcStatus == RPC_P_COMPLETE_NEEDED ) )
{
if ( RpcStatus == RPC_P_COMPLETE_NEEDED )
{
CompleteNeeded = 1;
}
AlterContextRespLength = AlterContextRespLength +
TokenLength -
SecurityCredentials->MaximumTokenLength();
NewSecurityTrailer->auth_type = SecurityTrailer->auth_type;
NewSecurityTrailer->auth_level = SecurityTrailer->auth_level;
NewSecurityTrailer->auth_pad_length = AuthPadLength;
NewSecurityTrailer->auth_reserved = 0;
NewSecurityTrailer->auth_context_id = AuthContextId;
/*SecurityTrailer->auth_context_id */
if (SecurityCredentials != 0)
{
Address->Server->FreeCredentials(SecurityCredentials);
}
}
else
{
ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY );
TransFreeBuffer(AlterContext);
TransFreeBuffer(AlterContextResp);
if (SecurityCredentials != 0)
{
ASSERT(NewContextRequired != 0);
Address->Server->FreeCredentials(SecurityCredentials);
}
SendFault(RPC_S_ACCESS_DENIED, 1);
return(1);
}
SecurityCredentials = 0;
}
DceSecurityInfo.ReceiveSequenceNumber++;
ConstructPacket((rpcconn_common *) AlterContextResp,
rpc_alter_context_resp, AlterContextRespLength);
TransFreeBuffer(AlterContext);
if ( Association == 0 )
{
TransFreeBuffer(AlterContextResp);
SendFault(RPC_S_PROTOCOL_ERROR, 1);
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.auth_length = TokenLength;
if (CompleteNeeded != 0)
{
CurrentSecurityContext->CompleteSecurityToken(&OutputBufferDescriptor);
}
RpcStatus= TransSend(AlterContextResp, AlterContextRespLength);
TransFreeBuffer(AlterContextResp);
if ( RpcStatus != RPC_S_OK )
{
return(1);
}
return(0);
}
unsigned int
OSF_SCONNECTION::GuessBufferSize (
)
{
return(MaxFrag/2);
}
RPC_STATUS
OSF_SCONNECTION::Receive (
IN OUT PRPC_MESSAGE Message,
IN unsigned int Size
)
{
RPC_STATUS RpcStatus ;
if (BufferComplete)
{
Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
return (RPC_S_OK) ;
}
RpcStatus = ReceiveNextChunk(Message, Size) ;
if (RpcStatus == RPC_S_OK
&& NOT_MULTIPLE_OF_EIGHT(Message->BufferLength)
&& (Message->RpcFlags & RPC_BUFFER_COMPLETE) == 0)
{
SaveRemainingData(Message) ;
}
return RpcStatus ;
}
int
OSF_SCONNECTION::ReceiveOriginalCall (
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.
Address - Supplies the address which owns the connection.
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 RpcStatus, ExceptionCode;
RPC_MESSAGE Message;
RPC_RUNTIME_INFO RuntimeInfo ;
RuntimeInfo.Length = sizeof(RPC_RUNTIME_INFO) ;
Message.Buffer = Packet;
Message.BufferLength = PacketLength;
Message.RpcFlags = 0 ;
Message.ReservedForRuntime = &RuntimeInfo ;
CallStack = 1;
ObjectUuidSpecified = 0;
AlertCount = 0;
CallOrphaned = 0;
ExtendedError = RPC_S_ACCESS_DENIED;
CurrentBufferLength = 0 ;
RpcStatus = ReceiveFirstFrag(&Message, 0);
if ( RpcStatus != RPC_S_OK )
{
if (RpcStatus == RPC_S_PROTOCOL_ERROR)
{
SendFault(RPC_S_PROTOCOL_ERROR,1);
}
else if (RpcStatus == RPC_S_ACCESS_DENIED)
{
SendFault(ExtendedError, 1);
}
else if ( (RpcStatus == RPC_S_OUT_OF_MEMORY)
|| (RpcStatus == RPC_S_OUT_OF_RESOURCES))
{
SendFault(RPC_S_OUT_OF_MEMORY, 1);
}
else if ( RpcStatus == RPC_S_CALL_FAILED_DNE )
{
return (0);
}
#ifdef DEBUGRPC
else
{
ASSERT( RpcStatus == RPC_S_CALL_FAILED );
}
#endif // DEBUGRPC
this->Delete();
return(1);
}
ASSERT( ImpersonatedClientFlag == 0);
Message.Handle = (RPC_BINDING_HANDLE) this;
RpcpSetThreadContext(this);
ASSERT(Thread == 0);
Thread = ThreadSelf();
Message.TransferSyntax = CurrentBinding->TransferSyntax();
//
// 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 (CurrentBinding->GetInterface()->IsSecurityCallbackReqd() != 0)
{
if (CurrentSecurityContext == 0)
{
SendFault(RPC_S_ACCESS_DENIED, 1);
RpcpSetThreadContext(0) ;
//Thread = 0;
this->Delete() ;
return (1);
}
RpcStatus = CurrentBinding->CheckSecurity(
this, CurrentSecurityContext->AuthContextId
);
if (RpcStatus != RPC_S_OK)
{
SendFault(RPC_S_ACCESS_DENIED, 1);
RpcpSetThreadContext(0) ;
//Thread = 0;
this->Delete() ;
return (1);
}
}
FirstFrag = 1;
if ( ObjectUuidSpecified != 0 )
{
RpcStatus = CurrentBinding->GetInterface()->DispatchToStubWithObject(
&Message, &ObjectUuid, 0, &ExceptionCode);
}
else
{
RpcStatus = CurrentBinding->GetInterface()->DispatchToStub(&Message,
0, &ExceptionCode);
}
RpcpSetThreadContext(0);
Thread = 0;
BufferComplete = 0;
if ( (CurrentSecurityContext != 0) && (AuthInfo.AuthIdentity != 0) )
{
CurrentSecurityContext->DeletePac( AuthInfo.AuthIdentity );
AuthInfo.AuthIdentity = 0;
}
// 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.
RevertToSelf();
ASSERT( CallStack == 1 );
CallStack = 0;
if ( RpcStatus != RPC_S_OK )
{
ASSERT( ( RpcStatus == RPC_S_PROCNUM_OUT_OF_RANGE )
|| ( RpcStatus == RPC_S_UNKNOWN_IF )
|| ( RpcStatus == RPC_S_NOT_LISTENING )
|| ( RpcStatus == RPC_S_SERVER_TOO_BUSY )
|| ( RpcStatus == RPC_S_UNSUPPORTED_TYPE )
|| ( RpcStatus == RPC_P_EXCEPTION_OCCURED ) );
if ( RpcStatus == RPC_P_EXCEPTION_OCCURED )
{
SendFault(ExceptionCode, 0);
}
else if ( RpcStatus == RPC_S_PROCNUM_OUT_OF_RANGE )
{
SendFault(RPC_S_PROCNUM_OUT_OF_RANGE,1);
}
else if ( RpcStatus == RPC_S_UNKNOWN_IF )
{
SendFault(RPC_S_UNKNOWN_IF,1);
}
else if ( RpcStatus == RPC_S_UNSUPPORTED_TYPE )
{
SendFault(RPC_S_UNSUPPORTED_TYPE, 1);
}
else
{
ASSERT( ( RpcStatus == RPC_S_NOT_LISTENING )
|| ( RpcStatus == RPC_S_SERVER_TOO_BUSY ) );
SendFault(RPC_S_SERVER_TOO_BUSY,1);
}
return(0);
}
ASSERT( Message.Buffer != 0 );
if ( CallOrphaned )
{
CallOrphaned = 0;
RpcTestCancel(); // clear cancel if thread didn\'t notice it.
return (0);
}
RpcStatus = SendRequestOrResponse(&Message, rpc_response);
if ( RpcStatus != RPC_S_OK )
{
this->Delete();
return(1);
}
return(0);
}
int
OSF_SCONNECTION::DispatchPacket (
IN rpcconn_common * Packet,
IN unsigned int PacketLength,
IN OSF_ADDRESS * Address
)
/*++
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.
Address - Supplies the address which owns the connection.
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 RpcStatus;
unsigned long SizeofHeaderToSave = 0;
int retval ;
//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]
//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_bind)||(Packet->PTYPE == rpc_alter_context) )
{
SizeofHeaderToSave = PacketLength;
}
else
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)
{
if ( Association == 0 )
{
TransFreeBuffer(Packet);
SendBindNak(protocol_version_not_supported);
this->Delete();
return(1);
}
TransFreeBuffer(Packet);
SendFault(RPC_S_PROTOCOL_ERROR, 1);
this->Delete();
return(1);
}
SavedHeaderSize = SizeofHeaderToSave;
RpcpMemoryCopy(SavedHeader, Packet, SizeofHeaderToSave);
}
else
if (SizeofHeaderToSave != 0)
{
RpcpMemoryCopy(SavedHeader, Packet, SizeofHeaderToSave);
}
}
RpcStatus = ValidatePacket(Packet, PacketLength);
CallId = Packet->call_id;
if ( RpcStatus != RPC_S_OK )
{
ASSERT( RpcStatus == 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 )
{
TransFreeBuffer(Packet);
SendBindNak(protocol_version_not_supported);
this->Delete();
return(1);
}
// It is not the first packet, so we need to send a fault instead,
// and then we will blow the connection away.
TransFreeBuffer(Packet);
SendFault(RPC_S_PROTOCOL_ERROR, 1);
this->Delete();
return(1);
}
// Ok, now check and make sure that if this is the first packet on this
// connection that it is a bind packet.
if ( (Packet->PTYPE != rpc_bind)
&& (Association == 0))
{
TransFreeBuffer(Packet);
SendBindNak(protocol_version_not_supported);
this->Delete();
return(1);
}
switch (Packet->PTYPE)
{
case rpc_bind :
DataRep = * (unsigned long PAPI *) Packet->drep;
if ( AssociationRequested(Address, (rpcconn_bind *) Packet,
PacketLength) != 0 )
{
this->Delete();
return(1);
}
break;
case rpc_alter_context :
DataRep = * (unsigned long PAPI *) Packet->drep;
if ( AlterContextRequested((rpcconn_alter_context *) Packet,
PacketLength, Address) != 0 )
{
this->Delete();
return(1);
}
break;
case rpc_request :
Bindings.Reset();
while ((CurrentBinding = Bindings.Next()))
{
if (CurrentBinding->GetPresentationContext() ==
((rpcconn_request *)Packet)->p_cont_id)
{
if (CurrentBinding->GetInterface()->IsAutoListenInterface())
{
CurrentBinding->GetInterface()->BeginAutoListenCall() ;
Address->BeginAutoListenCall() ;
retval = ReceiveOriginalCall(Packet, PacketLength) ;
CurrentBinding->GetInterface()->EndAutoListenCall() ;
Address->EndAutoListenCall() ;
return retval ;
}
return(ReceiveOriginalCall(Packet, PacketLength));
}
}
// We did not find a binding, which indicates the client tried
// to make a remote procedure call on an unknown interface.
SendFault(RPC_S_UNKNOWN_IF,1);
TransFreeBuffer(Packet);
this->Delete();
return(1);
default :
SendFault(RPC_S_PROTOCOL_ERROR,1);
this->Delete();
return(1);
}
CurrentBinding = Nil;
return(0);
}
void
OSF_SCONNECTION::SendFault (
IN RPC_STATUS Status,
IN int DidNotExecute
)
{
rpcconn_fault Fault;
memset(&Fault, 0, sizeof(Fault));
ConstructPacket((rpcconn_common *) &Fault,rpc_fault, sizeof(rpcconn_fault));
if (DidNotExecute != 0)
{
DidNotExecute = PFC_DID_NOT_EXECUTE;
}
Fault.common.pfc_flags |= PFC_FIRST_FRAG | PFC_LAST_FRAG | DidNotExecute;
Fault.status = MapToNcaStatusCode(Status);
Fault.common.call_id = CallId;
if (CurrentBinding)
Fault.p_cont_id = (unsigned char)
CurrentBinding->GetPresentationContext();
TransSend(&Fault, sizeof(rpcconn_fault));
}
RPC_STATUS
OSF_SCONNECTION::ReceiveMessage (
IN OUT PRPC_MESSAGE Message,
OUT unsigned int PAPI * RemoteFaultOccured
)
/*++
Routine Description:
Arguments:
Message - Supplies the first fragment of the message and returns the
complete message.
RemoteFaultOccured - Returns an indication of whether or not a remote
fault occured. A non-zero value indicates that a remote fault
occured.
Return Value:
RPC_S_OK - We successfully received a response message.
RPC_P_OK_REQUEST - We successfully received a request message.
RPC_S_PROTOCOL_ERROR - A protocol error occured; this is likely due
to a protocol mismatch with the server.
RPC_S_CALL_FAILED - The request failed, and may or may not have
executed.
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 RpcStatus;
rpcconn_common PAPI * pFragment = (rpcconn_common PAPI *) Message->Buffer;
*RemoteFaultOccured = 0;
RpcStatus = ValidatePacket(pFragment, Message->BufferLength);
if ( RpcStatus != RPC_S_OK )
{
ASSERT( RpcStatus == RPC_S_PROTOCOL_ERROR );
return(RpcStatus);
}
switch (pFragment->PTYPE)
{
case rpc_request :
if ( pFragment->call_id != CallId )
{
return(RPC_S_PROTOCOL_ERROR);
}
if ( ((rpcconn_request PAPI *) pFragment)->p_cont_id
!= CurrentBinding->GetPresentationContext() )
{
SendFault(RPC_S_UNKNOWN_IF, 0);
RpcStatus = TransReceive(&(Message->Buffer),
&(Message->BufferLength), 0);
if ( RpcStatus != RPC_S_OK )
{
if ( ( RpcStatus == RPC_P_RECEIVE_FAILED )
|| ( RpcStatus == RPC_P_CONNECTION_CLOSED ) )
{
return(RPC_S_CALL_FAILED);
}
ASSERT( ( RpcStatus == RPC_S_OUT_OF_MEMORY )
|| ( RpcStatus == RPC_S_OUT_OF_RESOURCES ) );
return(RpcStatus);
}
return(ReceiveMessage(Message, RemoteFaultOccured));
}
RpcStatus = ReceiveRequestOrResponse(Message);
if ( RpcStatus == RPC_S_OK )
{
return(RPC_P_OK_REQUEST);
}
return(RpcStatus);
case rpc_response :
if ( pFragment->call_id != CallId )
{
return(RPC_S_PROTOCOL_ERROR);
}
return(ReceiveRequestOrResponse(Message));
case rpc_fault :
RpcStatus = ((rpcconn_fault PAPI *)pFragment)->status;
if ( (RpcStatus == 0) &&
(pFragment->frag_length >= sizeof(rpcconn_fault) + 4) )
{
// DCE 1.0.x style fault status:
// Zero status and stub data contains the fault.
RpcStatus = *(unsigned long PAPI *)
(((rpcconn_fault PAPI *)pFragment)+1);
}
if (DataConvertEndian(pFragment->drep) != 0 )
{
ByteSwapLong(RpcStatus);
}
if (RpcStatus == 0)
{
RpcStatus = RPC_S_CALL_FAILED;
}
RpcStatus = MapFromNcaStatusCode(RpcStatus);
*RemoteFaultOccured = 1;
TransFreeBuffer(Message->Buffer);
Message->Buffer = 0;
return(RpcStatus);
case rpc_orphaned :
case rpc_remote_alert :
// For the first release, we will just ignore these messages.
TransFreeBuffer(Message->Buffer);
Message->Buffer = 0;
RpcStatus = TransReceive(&Message->Buffer,
&Message->BufferLength, 0) ;
if ( RpcStatus != RPC_S_OK )
{
if ( ( RpcStatus == RPC_P_RECEIVE_FAILED )
|| ( RpcStatus == RPC_P_CONNECTION_CLOSED ))
{
return(RPC_S_CALL_FAILED);
}
ASSERT( (RpcStatus == RPC_S_OUT_OF_MEMORY)
|| (RpcStatus == RPC_S_OUT_OF_RESOURCES));
return(RpcStatus);
}
return(ReceiveMessage(Message, RemoteFaultOccured));
default :
return(RPC_S_PROTOCOL_ERROR);
}
// This will never be reached.
return(RPC_S_INTERNAL_ERROR);
}
RPC_STATUS
OSF_SCONNECTION::Send (
IN OUT PRPC_MESSAGE Message
)
/*++
Routine Description:
Used by pipes, this is always a partial send.
Arguments:
Message - Supplies the buffer containing the request or response to be
sent, and returns the first fragment received from the server.
--*/
{
return SendRequestOrResponse(Message, rpc_response, 1) ;
}
RPC_STATUS
OSF_SCONNECTION::SendRequestOrResponse (
IN OUT PRPC_MESSAGE Message,
IN unsigned char PacketType,
IN int IsPartial
)
/*++
Routine Description:
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.
--*/
{
rpcconn_common PAPI * pFragment;
unsigned int LastFragmentFlag = 0;
unsigned int HeaderSize = sizeof(rpcconn_request);
RPC_MESSAGE SendBuffer;
unsigned int LengthLeft = Message->BufferLength;
RPC_STATUS RpcStatus;
void PAPI * ReceiveBuffer = 0;
unsigned int ReceiveBufferLength;
unsigned int MaxSecuritySize = 0;
unsigned char PAPI * ReservedForSecurity = NULL ;
unsigned int MaximumFragmentLength = MaxFrag;
unsigned int tocopy, leftover ;
ASSERT( sizeof(rpcconn_response) == sizeof(rpcconn_request) );
ASSERT( (PacketType == rpc_request)
|| (PacketType == rpc_response));
SendBuffer.Buffer = Message->Buffer;
// 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_SCONNECTION::GetBuffer)
// we saved space for security information. We did this for two reasons:
// so that for the last fragment, we could just stick the authentication
// information into there without having to copy anything. And so that
// we have space to save the contents of the buffer which will be
// overwritten with authentication information (for all but the last
// fragment).
if ( AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE )
{
MaxSecuritySize = AdditionalSpaceForSecurity
- MAXIMUM_SECURITY_BLOCK_SIZE;
if (MaxSecuritySize == sizeof(sec_trailer))
{
MaxSecuritySize = 0;
}
else
{
ReservedForSecurity = ((unsigned char PAPI *) Message->Buffer)
+ Message->BufferLength + AdditionalSpaceForSecurity;
// 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);
}
}
if (IsPartial && (LengthLeft + HeaderSize + MaxSecuritySize
<= MaximumFragmentLength))
{
return (RPC_S_SEND_INCOMPLETE) ;
}
pFragment = (rpcconn_common PAPI *)
((char PAPI *) 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 + HeaderSize + MaxSecuritySize
<= MaximumFragmentLength )
{
if (IsPartial)
{
ASSERT(PacketType == rpc_response) ;
Message->BufferLength = LengthLeft ;
RpcpMemoryCopy(Message->Buffer,
(unsigned char PAPI *) pFragment+HeaderSize,
LengthLeft) ;
return (RPC_S_SEND_INCOMPLETE) ;
}
else
{
LastFragmentFlag = 1;
}
}
ConstructPacket(pFragment, PacketType,
(LastFragmentFlag != 0 ? LengthLeft + HeaderSize
+ MaxSecuritySize : MaximumFragmentLength));
if ( (LengthLeft == Message->BufferLength) )
{
if (IsPartial == 0 || FirstFrag)
{
FirstFrag = 0;
pFragment->pfc_flags |= PFC_FIRST_FRAG;
if (RpcTestCancel() == RPC_S_OK)
{
pFragment->pfc_flags |= PFC_PENDING_ALERT;
}
}
}
if ( PacketType == rpc_request )
{
((rpcconn_request PAPI *) pFragment)->alloc_hint = LengthLeft;
((rpcconn_request PAPI *) pFragment)->p_cont_id =
CurrentBinding->GetPresentationContext();
((rpcconn_request PAPI *) pFragment)->opnum =
(unsigned short) Message->ProcNum;
}
else
{
((rpcconn_response PAPI *) pFragment)->alloc_hint = LengthLeft;
((rpcconn_response PAPI *) pFragment)->p_cont_id =
CurrentBinding->GetPresentationContext();
((rpcconn_response PAPI *) pFragment)->alert_count = AlertCount;
((rpcconn_response PAPI *) pFragment)->reserved = 0;
}
pFragment->call_id = CallId;
RpcStatus = SendFragment(pFragment, LastFragmentFlag, HeaderSize,
MaxSecuritySize, LengthLeft, MaximumFragmentLength,
ReservedForSecurity, &ReceiveBuffer, &ReceiveBufferLength) ;
if (RpcStatus != RPC_S_OK)
{
FreeBuffer(&SendBuffer);
return (RpcStatus) ;
}
if (LastFragmentFlag)
{
if (CallStack != 0)
{
Message->Buffer = ReceiveBuffer ;
Message->BufferLength = ReceiveBufferLength ;
}
FreeBuffer(&SendBuffer) ;
return (RpcStatus) ;
}
pFragment = (rpcconn_common PAPI *)
(((unsigned char PAPI *) pFragment) + MaximumFragmentLength
- (HeaderSize + MaxSecuritySize));
LengthLeft -= (MaximumFragmentLength - (HeaderSize + MaxSecuritySize));
}
}
inline RPC_STATUS
OSF_SCONNECTION::SendFragment(
IN OUT rpcconn_common PAPI *pFragment,
IN unsigned int LastFragmentFlag,
IN unsigned int HeaderSize,
IN unsigned int MaxSecuritySize,
IN unsigned int DataLength,
IN unsigned int MaximumFragmentLength,
IN unsigned char PAPI *ReservedForSecurity,
OUT void PAPI * PAPI *ReceiveBuffer,
OUT unsigned int *ReceiveBufferLength
)
{
sec_trailer PAPI * SecurityTrailer;
unsigned int SecurityLength;
unsigned int AuthPadLength;
SECURITY_BUFFER_DESCRIPTOR BufferDescriptor;
SECURITY_BUFFER SecurityBuffers[5];
DCE_MSG_SECURITY_INFO MsgSecurityInfo;
RPC_STATUS RpcStatus;
if ( ((AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
&& (AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_CONNECT))
|| ((AuthInfo.AuthenticationLevel == RPC_C_AUTHN_LEVEL_CONNECT)
&&(MaxSecuritySize != 0)) )
{
if ( LastFragmentFlag == 0 )
{
SecurityTrailer = (sec_trailer PAPI *)
(((unsigned char PAPI *) 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(ReservedForSecurity, 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 PAPI *)
(((unsigned char PAPI *) pFragment) + DataLength
+ HeaderSize);
pFragment->pfc_flags |= PFC_LAST_FRAG;
}
SecurityTrailer->auth_type = (unsigned char) AuthInfo.AuthenticationService;
SecurityTrailer->auth_level = (unsigned char) AuthInfo.AuthenticationLevel;
SecurityTrailer->auth_pad_length = 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 PAPI *) pFragment);
SecurityBuffers[1].cbBuffer = (LastFragmentFlag != 0 ?
DataLength
: (MaximumFragmentLength - HeaderSize
- MaxSecuritySize ));
SecurityBuffers[1].BufferType = SECBUFFER_DATA;
SecurityBuffers[1].pvBuffer = ((unsigned char PAPI *) 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 = SecurityLength = (unsigned short)
SecurityBuffers[3].cbBuffer;
SecurityLength += sizeof(sec_trailer);
if ( LastFragmentFlag != 0 )
{
pFragment->frag_length = HeaderSize + DataLength
+ SecurityLength;
}
else
{
pFragment->frag_length += SecurityLength - MaxSecuritySize;
}
RpcStatus = CurrentSecurityContext->SignOrSeal(
MsgSecurityInfo.SendSequenceNumber,
AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
&BufferDescriptor);
ASSERT( pFragment->auth_length == SecurityBuffers[3].cbBuffer);
if (RpcStatus != RPC_S_OK)
{
if ( LastFragmentFlag == 0 )
{
RpcpMemoryCopy(SecurityTrailer, ReservedForSecurity,
MaxSecuritySize);
}
if ( (RpcStatus == SEC_E_CONTEXT_EXPIRED)
|| (RpcStatus == 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;
if ( CallStack == 0)
{
// If this is the response to the original call; we
// just send it, rather than doing a TransSendReceive.
ASSERT( pFragment->PTYPE == rpc_response );
RpcStatus = TransSend(pFragment, DataLength + HeaderSize
+ SecurityLength);
}
else
{
RpcStatus = TransSendReceive(pFragment, DataLength + HeaderSize
+ SecurityLength, ReceiveBuffer, ReceiveBufferLength);
}
if ( RpcStatus != RPC_S_OK )
{
if ( (RpcStatus == RPC_P_CONNECTION_CLOSED)
|| (RpcStatus == RPC_P_SEND_FAILED))
{
return(RPC_S_CALL_FAILED_DNE);
}
if ( RpcStatus == RPC_P_RECEIVE_FAILED)
{
return(RPC_S_CALL_FAILED);
}
ASSERT( (RpcStatus == RPC_S_OUT_OF_MEMORY)
|| (RpcStatus == RPC_S_OUT_OF_RESOURCES));
return(RpcStatus);
}
return(RPC_S_OK);
}
RpcStatus = TransSend(pFragment, MaximumFragmentLength
- MaxSecuritySize + SecurityLength);
// We need to restore the part of the buffer which we overwrote
// with authentication information.
if ( (AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
&&(MaxSecuritySize != 0) )
{
RpcpMemoryCopy(SecurityTrailer, ReservedForSecurity,
MaxSecuritySize);
}
if ( RpcStatus != RPC_S_OK )
{
if ( (RpcStatus == RPC_P_CONNECTION_CLOSED)
|| (RpcStatus == RPC_P_SEND_FAILED))
{
return(RPC_S_CALL_FAILED_DNE);
}
ASSERT( (RpcStatus == RPC_S_OUT_OF_MEMORY)
|| (RpcStatus == RPC_S_OUT_OF_RESOURCES));
return(RpcStatus);
}
return RpcStatus ;
}
RPC_STATUS
OSF_SCONNECTION::EatAuthInfoFromPacket (
IN rpcconn_request PAPI * Request,
IN OUT unsigned int PAPI * RequestLength
)
/*++
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 PAPI * SecurityTrailer;
RPC_STATUS RpcStatus;
SECURITY_BUFFER_DESCRIPTOR BufferDescriptor;
SECURITY_BUFFER SecurityBuffers[5];
DCE_MSG_SECURITY_INFO MsgSecurityInfo;
unsigned long Id, Level, Service;
SSECURITY_CONTEXT * SecId;
unsigned int HeaderSize = sizeof(rpcconn_request);
if ( Request->common.auth_length != 0 )
{
SecurityTrailer = (sec_trailer PAPI *) (((unsigned char PAPI *)
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)
{
ByteSwapLong(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:
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;
MsgSecurityInfo.SendSequenceNumber =
DceSecurityInfo.SendSequenceNumber;
MsgSecurityInfo.ReceiveSequenceNumber =
DceSecurityInfo.ReceiveSequenceNumber;
MsgSecurityInfo.PacketType = Request->common.PTYPE;
BufferDescriptor.ulVersion = 0;
BufferDescriptor.cBuffers = 5;
BufferDescriptor.pBuffers = SecurityBuffers;
if ( (Request->common.pfc_flags & PFC_OBJECT_UUID) != 0 )
{
HeaderSize += sizeof(UUID);
}
SecurityBuffers[0].cbBuffer = HeaderSize;
SecurityBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
SecurityBuffers[0].pvBuffer = (unsigned char PAPI *) SavedHeader;
SecurityBuffers[1].cbBuffer = *RequestLength - HeaderSize -
sizeof(sec_trailer);
SecurityBuffers[1].BufferType = SECBUFFER_DATA;
SecurityBuffers[1].pvBuffer = ((unsigned char PAPI *) 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;
RpcStatus = CurrentSecurityContext->VerifyOrUnseal(
MsgSecurityInfo.ReceiveSequenceNumber,
AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
&BufferDescriptor);
if ( RpcStatus != RPC_S_OK )
{
ASSERT( RpcStatus == RPC_S_ACCESS_DENIED );
return(RpcStatus);
}
*RequestLength -= (sizeof(sec_trailer) +
SecurityTrailer->auth_pad_length);
}
else
{
//
// We are doing a nonsecure rpc -
// it doesnt matter that previously we did a secure rpc..
//
AuthInfo.AuthenticationLevel = RPC_C_AUTHN_LEVEL_NONE;
CurrentSecurityContext = 0;
if (SavedHeader != 0)
{
ASSERT(SavedHeaderSize != 0);
RpcpFarFree(SavedHeader);
SavedHeader = 0;
SavedHeaderSize = 0;
}
}
DceSecurityInfo.ReceiveSequenceNumber += 1;
return(RPC_S_OK);
}
RPC_STATUS
OSF_SCONNECTION::ReceiveRequestOrResponse (
IN OUT PRPC_MESSAGE Message
)
/*++
Routine Description:
Arguments:
Message - Supplies the first fragment of a request or a response, and
returns the completed message.
Return Value:
RPC_S_OK - We successfully received the entire message.
RPC_S_PROTOCOL_ERROR - A protocol error occured; this is typically
because of a protocol version mismatch between the client and
the server.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to receive
all of the message.
RPC_S_CALL_FAILED - The receive operation failed part way through.
RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to
receive all of the message.
RPC_S_ACCESS_DENIED - The security check of one of the received packets
failed.
Notes:
This method is very similar to OSF_CCONNECTION::ReceiveRequestOrResponse
in osfclnt.cxx.
--*/
{
return ReceiveFirstFrag(Message, 1) ;
}
inline RPC_STATUS
OSF_SCONNECTION::ReceiveFirstFrag(
IN OUT PRPC_MESSAGE Message,
IN int Callback
)
/*++
Routine Description:
Arguments:
Message - Supplies the first fragment of a request or a response, and
returns either the complete message or a buffer equal to alloc hint
Return Value:
RPC_S_OK - We successfully received the entire message.
RPC_S_PROTOCOL_ERROR - A protocol error occured; this is typically
because of a protocol version mismatch between the client and
the server.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to receive
all of the message.
RPC_S_CALL_FAILED - The receive operation failed part way through.
RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to
receive all of the message.
RPC_S_ACCESS_DENIED - The security check of one of the received packets
failed.
--*/
{
rpcconn_request PAPI * Request = (rpcconn_request PAPI *) Message->Buffer;
unsigned char PacketType = Request->common.PTYPE;
RPC_STATUS RpcStatus;
unsigned int BufferLengthUsed = 0;
void PAPI * NewBuffer;
int SecurityFailureOccured = 0;
unsigned long size = Request->alloc_hint ;
// Upon entry, the packet will have already been validated (and data
// converted) by whomever called us.
if ( (Request->common.pfc_flags & PFC_FIRST_FRAG) == 0 )
{
TransFreeBuffer(Request);
return(RPC_S_PROTOCOL_ERROR);
}
if ( (Request->common.pfc_flags & PFC_PENDING_ALERT))
{
RpcCancelThread(GetCurrentThread());
}
Message->ProcNum = Request->opnum;
DataRep = Message->DataRepresentation =
*((unsigned long PAPI *) Request->common.drep);
RpcStatus = EatAuthInfoFromPacket(Request, &(Message->BufferLength));
if ( RpcStatus != RPC_S_OK )
{
ASSERT( (RpcStatus == RPC_S_PROTOCOL_ERROR)
|| (RpcStatus == RPC_S_ACCESS_DENIED) );
/*
TransFreeBuffer(Request);
return(RpcStatus);
*/
if (RpcStatus == RPC_S_ACCESS_DENIED)
{
ExtendedError = GetLastError();
}
if (ExtendedError == 0)
{
ExtendedError = RPC_S_ACCESS_DENIED;
}
SecurityFailureOccured = 1;
}
if ( (Request->common.pfc_flags & PFC_OBJECT_UUID) != 0 )
{
if ( CallStack != 1 )
{
// There can not be an object uuid in the message. This is an
// error.
TransFreeBuffer(Request);
return(RPC_S_PROTOCOL_ERROR);
}
// 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 *) &DataRep)) != 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 PAPI *) (Request + 1))
+ sizeof(UUID), Message->BufferLength - sizeof(rpcconn_request)
- sizeof(UUID));
Message->BufferLength -= sizeof(UUID);
}
if ( (Request->common.pfc_flags & PFC_LAST_FRAG) != 0 )
{
if (SecurityFailureOccured != 0)
{
TransFreeBuffer(Request);
return(RPC_S_ACCESS_DENIED);
}
else
{
Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
Message->Buffer = (void PAPI *) (Request + 1);
Message->BufferLength -= sizeof(rpcconn_request);
// I am adding this to get around the problem that
// Message->RpcFlags might be whacked before
// NdrServerInitialize is called
BufferComplete = 1 ;
return (RPC_S_OK) ;
}
}
if ((Callback == 0) && CurrentBinding->GetInterface()->IsPipeInterface())
{
Message->RpcFlags = RPC_BUFFER_PARTIAL ;
}
RpcStatus = ReceiveNextChunk(Message, size, 1, SecurityFailureOccured) ;
Message->RpcFlags &= ~RPC_BUFFER_PARTIAL ;
if (((Message->RpcFlags & RPC_BUFFER_COMPLETE) == 0)
&& RpcStatus == RPC_S_OK
&& NOT_MULTIPLE_OF_EIGHT(Message->BufferLength))
{
SaveRemainingData(Message) ;
}
return RpcStatus ;
}
RPC_STATUS
OSF_SCONNECTION::ReceiveNextChunk (
IN OUT PRPC_MESSAGE Message,
IN unsigned int Size,
IN int FirstReceive,
IN int SecurityFailureOccured
)
/*++
Routine Description:
Arguments:
Message - Supplies the first fragment or more of a request or a response, and
based on Message->RpcFlags, returns the requested number of bytes, or the
complete message.
Return Value:
RPC_S_OK - We successfully received the entire message.
RPC_S_PROTOCOL_ERROR - A protocol error occured; this is typically
because of a protocol version mismatch between the client and
the server.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to receive
all of the message.
RPC_S_CALL_FAILED - The receive operation failed part way through.
RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to
receive all of the message.
RPC_S_ACCESS_DENIED - The security check of one of the received packets
failed.
Notes:
This method is very similar to OSF_CCONNECTION::ReceiveRequestOrResponse
in osfclnt.cxx.
--*/
{
rpcconn_request PAPI * Request ;
unsigned char PacketType ;
unsigned int BufferLengthUsed;
RPC_STATUS RpcStatus;
void PAPI * NewBuffer;
unsigned long Extra = Message->RpcFlags & RPC_BUFFER_EXTRA ;
unsigned long Partial = Message->RpcFlags & RPC_BUFFER_PARTIAL ;
if (FirstReceive)
{
Request = (rpcconn_request PAPI *) Message->Buffer ;
PacketType = Request->common.PTYPE;
Message->Buffer = 0;
BufferLengthUsed = 0 ;
FragmentLength = Message->BufferLength;
Message->BufferLength = (unsigned int) Request->alloc_hint ;
// use the alloc hint to allocate the buffer so that even in the
// pipe case, after the first receive, we have at least all the
// non pipe data
if ( Request->alloc_hint != 0 )
{
RpcStatus = GetBufferDo(Message, Request->alloc_hint,
&Message->Buffer, Extra);
if ( RpcStatus != RPC_S_OK )
{
ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY );
// Oops, we cant allocate a buffer as large as the allocation
// hint, so we will just not bother allocating one.
Message->BufferLength = 0;
}
}
}
else
{
Request = 0;
PacketType = rpc_request ; //BUGBUG
if (Extra == 0)
{
BufferLengthUsed = 0 ;
if (Message->Buffer == 0)
{
Message->BufferLength = MaxFrag ;
RpcStatus = GetBufferDo(Message, MaxFrag, &Message->Buffer, Extra) ;
if (RpcStatus != RPC_S_OK)
{
Message->BufferLength = 0;
return (RPC_S_OUT_OF_MEMORY) ;
}
}
}
else
{
BufferLengthUsed = Message->BufferLength ;
}
if (RemainingData[0])
{
if (Message->BufferLength < BufferLengthUsed + RemainingData[0])
{
RpcStatus = GetBufferDo(Message, BufferLengthUsed+MaxFrag,
&NewBuffer, Extra) ;
if (RpcStatus != RPC_S_OK)
{
FreeBuffer(Message) ;
Message->Buffer = 0;
return (RPC_S_OUT_OF_MEMORY) ;
}
if (BufferLengthUsed)
{
RpcpMemoryCopy(NewBuffer, Message->Buffer, BufferLengthUsed) ;
}
FreeBuffer(Message) ;
Message->Buffer = NewBuffer ;
}
RpcpMemoryCopy((char PAPI *) Message->Buffer+BufferLengthUsed,
&RemainingData[1], RemainingData[0]) ;
BufferLengthUsed += RemainingData[0] ;
RemainingData[0] = 0 ;
}
}
for (;;)
{
if (Message->BufferLength - BufferLengthUsed
< FragmentLength - sizeof(rpcconn_request))
{
// The message buffer is too small, so we need to grow it
// to hold the new fragment as well as those that we have
// already received.
RpcStatus = GetBufferDo(Message, FragmentLength + Message->BufferLength,
&NewBuffer, Extra);
if ( RpcStatus != RPC_S_OK )
{
ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY );
TransFreeBuffer(Request);
if (Message->Buffer != 0)
{
FreeBuffer(Message);
Message->Buffer = 0;
}
return(RpcStatus);
}
if ( BufferLengthUsed != 0 )
{
RpcpMemoryCopy(NewBuffer, Message->Buffer, BufferLengthUsed);
FreeBuffer(Message);
}
Message->Buffer = NewBuffer;
Message->BufferLength += FragmentLength;
}
// We have enough space in the buffer for the next fragment; all we
// have got to do is to copy it in.
if (Request)
{
RpcpMemoryCopy((unsigned char PAPI *)
Message->Buffer + BufferLengthUsed,
((unsigned char PAPI *) Request) + sizeof(rpcconn_request),
FragmentLength - sizeof(rpcconn_request));
BufferLengthUsed += FragmentLength - sizeof(rpcconn_request);
// If this is the last fragment, then we are all done receiving
// the request or response. We just need to free the last fragment
// and then return.
if ( (Request->common.pfc_flags & PFC_LAST_FRAG) != 0 )
{
TransFreeBuffer(Request);
if (SecurityFailureOccured != 0)
{
FreeBuffer(Message);
Message->Buffer = 0;
return (RPC_S_ACCESS_DENIED);
}
Message->BufferLength = BufferLengthUsed;
Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
// I am adding this to get around the problem that
// Message->RpcFlags might be whacked before
// NdrServerInitialize is called
BufferComplete = 1 ;
return(RPC_S_OK);
}
// Otherwise, we need to try and receive another fragment.
TransFreeBuffer(Request);
Request = 0;
if (Partial && (BufferLengthUsed >= Size))
{
Message->BufferLength = BufferLengthUsed ;
return (RPC_S_OK) ;
}
}
RpcStatus = TransReceive((void PAPI * PAPI *) &Request,
&FragmentLength, 0);
if ( RpcStatus != RPC_S_OK )
{
FreeBuffer(Message);
Message->Buffer = 0;
if ( (RpcStatus == RPC_P_RECEIVE_FAILED)
|| (RpcStatus == RPC_P_CONNECTION_CLOSED))
{
return(RPC_S_CALL_FAILED);
}
ASSERT( (RpcStatus == RPC_S_OUT_OF_MEMORY)
|| (RpcStatus == RPC_S_OUT_OF_RESOURCES));
return(RpcStatus);
}
//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( (AuthInfo.AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE)
|| (SavedHeaderSize >= sizeof(rpcconn_request)) );
if (AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
{
RpcpMemoryCopy(SavedHeader, Request, sizeof(rpcconn_request));
}
RpcStatus = ValidatePacket((rpcconn_common PAPI *) Request,
FragmentLength);
ASSERT( (RpcStatus == RPC_S_OK)
|| (RpcStatus == RPC_S_PROTOCOL_ERROR));
if ( Request->common.PTYPE == rpc_orphaned )
{
CallOrphaned = 1;
TransFreeBuffer(Request);
FreeBuffer(Message);
Message->Buffer = 0;
return (RPC_S_CALL_FAILED_DNE);
}
if ( (RpcStatus != RPC_S_OK)
|| (Request->common.PTYPE != PacketType)
|| (Request->common.call_id != CallId))
{
TransFreeBuffer(Request);
FreeBuffer(Message);
Message->Buffer = 0;
return(RPC_S_PROTOCOL_ERROR);
}
// 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.
RpcStatus = EatAuthInfoFromPacket(Request, &FragmentLength);
if ( RpcStatus != RPC_S_OK )
{
ASSERT( (RpcStatus == RPC_S_PROTOCOL_ERROR)
|| (RpcStatus == RPC_S_ACCESS_DENIED) );
/*
TransFreeBuffer(Request);
FreeBuffer(Message);
return(RpcStatus);
*/
SecurityFailureOccured = 1;
}
if ( (Request->common.pfc_flags & PFC_OBJECT_UUID) != 0 )
{
if ( CallStack != 1 )
{
// There can not be an object uuid in the message. This is an
// error.
TransFreeBuffer(Request);
return(RPC_S_PROTOCOL_ERROR);
}
// 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 PAPI *) (Request + 1))
+ sizeof(UUID), FragmentLength
- sizeof(rpcconn_request) - sizeof(UUID));
FragmentLength -= sizeof(UUID);
}
}
return (RPC_S_PROTOCOL_ERROR) ;
}
int
OSF_SCONNECTION::fCanDiscard (
)
{
return(OutstandingBuffers == 0 && Association &&
(Association->pContext == Nil || Association->TheConnectionCount() > 1));
}
/* --------------------------------------------------------------------
-------------------------------------------------------------------- */
OSF_ASSOCIATION::OSF_ASSOCIATION (
IN OSF_ADDRESS *TheAddress,
IN RPC_CLIENT_PROCESS_IDENTIFIER * ClientProcess,
OUT RPC_STATUS * Status
)
{
*Status = RPC_S_OK;
ConnectionCount = 1;
Address = TheAddress;
this->ClientProcess.FirstPart = ClientProcess->FirstPart;
this->ClientProcess.SecondPart = ClientProcess->SecondPart;
#ifdef NTENV
AssociationGroupId = InterlockedExchangeAdd(&GroupIdCounter, 1);
#else
RequestGlobalMutex();
AssociationGroupId = GroupIdCounter;
GroupIdCounter += 1;
ClearGlobalMutex();
#endif
Address->AddressMutex.Request();
AssociationDictKey = Address->AddAssociation(this);
Address->AddressMutex.Clear();
if (AssociationDictKey == -1)
{
*Status = RPC_S_OUT_OF_MEMORY;
}
}
OSF_ASSOCIATION::~OSF_ASSOCIATION (
)
{
ASSERT(AssociationDictKey == -1);
if (AssociationDictKey != -1)
{
Address->AddressMutex.Request();
Address->RemoveAssociation(AssociationDictKey);
Address->AddressMutex.Clear();
}
}
inline void
OSF_ASSOCIATION::AddConnection (
)
{
/*
Bumps up a refcount, indicating another connection has a reference to
this Association.
Previously this method acquires AddressMutex. Now - the caller needs to
ensure that is true.
*/
ConnectionCount += 1;
}
int
OSF_ASSOCIATION::RemoveConnection (
)
{
Address->AddressMutex.Request();
ConnectionCount -= 1;
if (ConnectionCount == 0)
{
Address->RemoveAssociation(AssociationDictKey);
AssociationDictKey = -1;
Address->AddressMutex.Clear();
delete this;
}
else
Address->AddressMutex.Clear();
return(0);
}
void
OSF_SCONNECTION::InquireObjectUuid (
OUT RPC_UUID PAPI * 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));
}
RPC_STATUS
OSF_SCONNECTION::ToStringBinding (
OUT RPC_CHAR PAPI * PAPI * 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 = Association->TheAddress()->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);
}
RPC_STATUS
OSF_SCONNECTION::InquireAuthClient (
OUT RPC_AUTHZ_HANDLE PAPI * Privileges,
OUT RPC_CHAR PAPI * PAPI * ServerPrincipalName, OPTIONAL
OUT unsigned long PAPI * AuthenticationLevel,
OUT unsigned long PAPI * AuthenticationService,
OUT unsigned long PAPI * AuthorizationService
)
/*++
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 RpcStatus;
SSECURITY_CONTEXT * SecurityContext;
SecurityContext = CurrentSecurityContext;
if ( !SecurityContext )
{
return(RPC_S_BINDING_HAS_NO_AUTH);
}
*AuthenticationLevel = SecurityContext->AuthenticationLevel;
*AuthenticationService = SecurityContext->AuthenticationService;
if (AuthInfo.AuthIdentity == 0)
{
SecurityContext->GetDceInfo(
&AuthInfo.AuthIdentity,
&AuthInfo.AuthorizationService
);
}
if ( ARGUMENT_PRESENT(Privileges) )
{
*Privileges = AuthInfo.AuthIdentity;
}
if ( ARGUMENT_PRESENT(AuthorizationService) )
{
*AuthorizationService = AuthInfo.AuthorizationService;
}
if ( ARGUMENT_PRESENT(ServerPrincipalName) )
{
RpcStatus = Association->TheAddress()->Server->InquirePrincipalName(
*AuthenticationService, ServerPrincipalName);
ASSERT( (RpcStatus == RPC_S_OK)
|| (RpcStatus == RPC_S_OUT_OF_MEMORY) );
return(RpcStatus);
}
return(RPC_S_OK);
}
void
OSF_SCONNECTION::Delete (
)
/*++
Routine Description:
The only reason we need this is to keep the compiler happy. The actual
implementation is TRANS_SCONNECTION::Delete which is defined in
transvr.cxx.
--*/
{
UNUSED(this);
}
void
OSF_SCONNECTION::ReceiveDirect (
)
/*++
Routine Description:
Each receive direct connection will have a new thread created which will
call this routine.
--*/
{
RPC_STATUS RpcStatus;
void PAPI * Buffer;
unsigned int BufferLength;
OSF_ADDRESS * Address = this->ReceiveDirectAddress;
int flag ;
#ifndef NTENV
int AmountOfPad;
#endif
if ( BufferCacheFlags & CACHED_BUFFERS_ALLOCATED )
{
RpcpFarFree(UnAlignBuffer(FirstCachedBuffer));
CachedBufferLength = TransMaximumSend();
#ifdef NTENV
FirstCachedBuffer = RpcpFarAllocate(CachedBufferLength * 2);
#else // NTENV
FirstCachedBuffer = RpcpFarAllocate(CachedBufferLength * 2
+ ALIGN_REQUIRED);
#endif // NTENV
if ( FirstCachedBuffer == 0 )
{
BufferCacheFlags = 0;
SecondCachedBuffer = 0;
}
else
{
#ifndef NTENV
ASSERT( (((long) FirstCachedBuffer) % sizeof(int)) == 0 );
AmountOfPad = Pad((char PAPI *)FirstCachedBuffer + 1, ALIGN_REQUIRED) + 1;
FirstCachedBuffer = (void PAPI *)
(((char PAPI *) FirstCachedBuffer) + AmountOfPad);
((int PAPI *) FirstCachedBuffer)[-1] = AmountOfPad;
#endif // NTENV
SecondCachedBuffer = (void PAPI *)
(((char PAPI *) FirstCachedBuffer) + CachedBufferLength);
BufferCacheFlags = FIRST_CACHED_BUFFER_AVAILABLE
| SECOND_CACHED_BUFFER_AVAILABLE | CACHED_BUFFERS_ALLOCATED;
ASSERT(Pad8(SecondCachedBuffer) == 0);
}
ThirdCachedBuffer = 0;
}
while ( ReceiveDirectReady == 0 )
{
PauseExecution(0L);
}
for (;;)
{
RpcStatus = TransReceive(&Buffer, &BufferLength, 1);
if ( RpcStatus == RPC_P_CONNECTION_CLOSED )
{
break;
}
#if defined(NTENV) || defined(WIN96)
if( RpcStatus == RPC_P_TIMEOUT)
{
break;
}
#endif
Address->BeginCall() ;
if ( DispatchPacket((rpcconn_common *) Buffer, BufferLength, Address) != 0)
{
Address->EndCall() ;
break;
}
Address->EndCall() ;
}
Address->NotifyReceiveDirectClosed();
if (RpcStatus == RPC_P_CONNECTION_CLOSED)
{
delete this ;
}
}
void
OSF_SCONNECTION::NotifyReceiveDirectReady (
)
/*++
Routine Description:
The transport will call this routine to notify the runtime that a
receive direct connection has been setup and is ready to start receiving
remote procedure calls.
--*/
{
ReceiveDirectReady = 1;
}
#if defined(NTENV) || defined(WIN96)
void
OSF_SCONNECTION::NotifyReceiveDirectCancelled(
)
/*++
When the transport times out on a ReceiveDirect, it needs to revert back to
doing a receive any on that connection. The transport will call this routine to
notify the runtime about that
--*/
{
ReceiveDirectReady = 0 ;
}
#endif
void PAPI *
OsfServerMapRpcProtocolSequence (
IN RPC_CHAR * RpcProtocolSequence,
OUT RPC_STATUS PAPI * Status
)
/*++
Routine Description:
This routine is used to determine whether a given rpc protocol sequence
is supported, and to get a pointer to the transport interface, so we
do not have to keep looking it up.
Arguments:
RpcProtocolSequence - Supplies the rpc protocol sequence.
Status - Returns the status of the operation. This will be one
of the following values.
RPC_S_OK - The rpc protocol sequence is supported.
RPC_S_PROTSEQ_NOT_SUPPORTED - The rpc protocol sequence is
not supported.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to
map the rpc protocol sequence to a transport.
Return Value:
A pointer to the transport interface is returned. This pointer
must not be dereferenced by the caller.
--*/
{
RPC_CHAR * DllName;
RPC_SERVER_TRANSPORT_INFO PAPI * RpcServerInfo;
*Status = RpcConfigMapRpcProtocolSequence(1, RpcProtocolSequence, &DllName);
if ( *Status != RPC_S_OK )
{
return(0);
}
RpcServerInfo = LoadableTransportServerInfo(DllName, RpcProtocolSequence,
Status);
delete DllName;
if ( *Status != RPC_S_OK )
{
return(0);
}
return(RpcServerInfo);
}
RPC_ADDRESS *
OsfCreateRpcAddress (
IN void PAPI * 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 RpcStatus = RPC_S_OK;
RpcAddress = new (0,
((RPC_SERVER_TRANSPORT_INFO *)TransportInfo)->SizeOfAddress)
TRANS_ADDRESS((RPC_SERVER_TRANSPORT_INFO PAPI *) TransportInfo,
&RpcStatus);
if ( RpcStatus != RPC_S_OK )
{
return(0);
}
return(RpcAddress);
}
RPC_STATUS
OSF_SCONNECTION::Cancel(
void * ThreadHandle
)
{
InterlockedIncrement(&CancelPending);
return RPC_S_OK;
}
unsigned
OSF_SCONNECTION::TestCancel(
)
{
return InterlockedExchange(&CancelPending, 0);
}