mirror of https://github.com/lianthony/NT4.0
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.
5699 lines
159 KiB
5699 lines
159 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
osfclnt.cxx
|
|
|
|
Abstract:
|
|
|
|
This file contains the client 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 <osfpcket.hxx>
|
|
#include <sdict2.hxx>
|
|
#include <bitset.hxx>
|
|
#include <osfclnt.hxx>
|
|
#include <tranclnt.hxx>
|
|
#include <rpccfg.h>
|
|
#include <epmap.h>
|
|
#include <twrtypes.h>
|
|
|
|
//Maximum retries in light of getting a shutdown
|
|
//or closed in doing a bind or shutdown
|
|
#define MAX_RETRIES 3
|
|
|
|
OSF_BINDING_HANDLE::OSF_BINDING_HANDLE (
|
|
IN OUT RPC_STATUS PAPI * RpcStatus
|
|
) : BindingMutex(RpcStatus)
|
|
{
|
|
ALLOCATE_THIS(OSF_BINDING_HANDLE);
|
|
|
|
Association = 0;
|
|
ReferenceCount = 1;
|
|
DceBinding = 0;
|
|
TransportInterface = 0;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_BINDING_HANDLE::GetBuffer (
|
|
IN OUT PRPC_MESSAGE Message
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Message - Supplies the length of the buffer required, and returns the
|
|
new buffer.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - The operation completed successfully.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete
|
|
the operation.
|
|
|
|
RPC_S_NO_ENDPOINT_FOUND - The endpoint can not be resolved.
|
|
|
|
RPC_S_OUT_OF_RESOURCES - The transport has insufficient resources
|
|
inorder to make a connection with the server.
|
|
|
|
RPC_S_SERVER_TOO_BUSY - The server is there, but it is too busy to
|
|
talk with us right now.
|
|
|
|
RPC_S_ACCESS_DENIED - The client is unable to make a connection with
|
|
the server for security reasons.
|
|
|
|
RPC_S_INVALID_NETWORK_OPTIONS - The supplied network options are
|
|
invalid; see a description of the particular transport interface
|
|
module for an explination.
|
|
|
|
RPC_S_CALL_FAILED_DNE - The call failed and is guaranteed not to have
|
|
executed.
|
|
|
|
RPC_S_PROTOCOL_ERROR - A protocol error occured; this will typically
|
|
be because of a protocol mismatch with the server.
|
|
|
|
RPC_S_UNSUPPORTED_TRANS_SYN - The transfer syntax supplied by the client
|
|
is not supported by the server.
|
|
|
|
RPC_S_UNKNOWN_IF - The interface to which the client wished to bind is not
|
|
supported by the server.
|
|
|
|
RPC_S_UNKNOWN_AUTHN_TYPE - The server does not support the authentication
|
|
type specified by the client.
|
|
|
|
RPC_S_INVALID_ENDPOINT_FORMAT - The endpoint supplied is in an incorrect
|
|
format for the particular protocol sequence.
|
|
|
|
EPT_S_NOT_REGISTERED - There are no more endpoints to be found
|
|
for the specified combination of interface, network address,
|
|
and lookup handle.
|
|
|
|
EPT_S_CANT_PERFORM_OP - The operation failed due to misc. error e.g.
|
|
unable to bind to the EpMapper.
|
|
|
|
--*/
|
|
{
|
|
OSF_CCONNECTION * CConnection;
|
|
RPC_STATUS RpcStatus;
|
|
unsigned int NotChangedRetry = 0;
|
|
unsigned int Retry;
|
|
|
|
#ifdef WIN
|
|
ASSERT( GetCurrentTask() == TaskId );
|
|
|
|
// Verify that a there isn't a call already in progress
|
|
RpcStatus = I_RpcWinCallInProgress();
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
VALIDATE((RpcStatus, RPC_S_CALL_IN_PROGRESS, RPC_S_OUT_OF_MEMORY, 0));
|
|
return(RpcStatus);
|
|
}
|
|
#endif
|
|
|
|
for (;;)
|
|
{
|
|
|
|
Retry = 0;
|
|
for (;;)
|
|
{
|
|
RpcStatus = AllocateConnection(&CConnection,
|
|
(RPC_CLIENT_INTERFACE PAPI *) Message->RpcInterfaceInformation);
|
|
if ( (RpcStatus != RPC_P_CONNECTION_SHUTDOWN)
|
|
&&(RpcStatus != RPC_P_CONNECTION_CLOSED) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (this->Association != 0)
|
|
{
|
|
Association->ShutdownRequested();
|
|
}
|
|
|
|
Retry++;
|
|
if (Retry == MAX_RETRIES)
|
|
break;
|
|
}
|
|
|
|
if ( RpcStatus != RPC_S_SERVER_UNAVAILABLE )
|
|
{
|
|
break;
|
|
}
|
|
if ( *InquireEpLookupHandle() == 0 )
|
|
{
|
|
break;
|
|
}
|
|
|
|
// If we reach here, it means that we are iterating through the list
|
|
// of endpoints obtained from the endpoint mapper.
|
|
|
|
BindingMutex.Request();
|
|
|
|
if ( ( ReferenceCount == 1 )
|
|
&& ( Association != 0 ) )
|
|
{
|
|
DceBinding = Association->DuplicateDceBinding();
|
|
Association->UnBind();
|
|
Association = 0;
|
|
DceBinding->MakePartiallyBound();
|
|
NotChangedRetry = 0;
|
|
}
|
|
else
|
|
{
|
|
NotChangedRetry += 1;
|
|
if ( NotChangedRetry > 4 )
|
|
{
|
|
BindingMutex.Clear();
|
|
return(RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
}
|
|
|
|
BindingMutex.Clear();
|
|
}
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
if ( (RpcStatus == RPC_P_CONNECTION_CLOSED)
|
|
||(RpcStatus == RPC_P_CONNECTION_SHUTDOWN) )
|
|
{
|
|
return(RPC_S_CALL_FAILED_DNE);
|
|
}
|
|
return(RpcStatus);
|
|
}
|
|
|
|
RpcStatus = CConnection->GetBuffer(Message);
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY );
|
|
CConnection->AbortConnection();
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
OSF_BINDING_HANDLE::~OSF_BINDING_HANDLE (
|
|
)
|
|
{
|
|
OSF_ACTIVE_ENTRY *ActiveEntry ;
|
|
|
|
if ( Association != 0 )
|
|
{
|
|
Association->UnBind();
|
|
}
|
|
else
|
|
{
|
|
delete DceBinding;
|
|
}
|
|
|
|
ActiveConnections.Reset();
|
|
|
|
while ((ActiveEntry = ActiveConnections.Next()))
|
|
{
|
|
delete ActiveEntry->CConnection;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_BINDING_HANDLE::BindingCopy (
|
|
OUT BINDING_HANDLE * PAPI * DestinationBinding,
|
|
IN unsigned int MaintainContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We need to copy this binding handle. This is relatively easy to
|
|
do: we just need to point the copied binding handle to the same
|
|
association as this binding handle. We also need to tell the
|
|
association about the new binding handle.
|
|
|
|
Arguments:
|
|
|
|
DestinationBinding - Returns a copy of this binding handle.
|
|
|
|
MaintainContext - Supplies a flag that indicates whether or not context
|
|
is being maintained over this binding handle. A non-zero value
|
|
indicates that context is being maintained.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OUT_OF_MEMORY - This indicates that there is not enough memory
|
|
to allocate a new binding handle.
|
|
|
|
RPC_S_OK - We successfully copied this binding handle.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus = RPC_S_OK;
|
|
OSF_BINDING_HANDLE * Binding;
|
|
RPC_UUID Uuid;
|
|
CLIENT_AUTH_INFO * AuthInfo;
|
|
|
|
Binding = new OSF_BINDING_HANDLE(&RpcStatus);
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
delete Binding;
|
|
Binding = 0;
|
|
}
|
|
if ( Binding == 0 )
|
|
{
|
|
*DestinationBinding = 0;
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
RequestGlobalMutex();
|
|
InquireObjectUuid(&Uuid);
|
|
Binding->SetObjectUuid(&Uuid);
|
|
|
|
if ((AuthInfo = InquireAuthInformation()) != 0)
|
|
{
|
|
RpcStatus = Binding->SetAuthInformation(
|
|
AuthInfo->ServerPrincipalName,
|
|
AuthInfo->AuthenticationLevel,
|
|
AuthInfo->AuthenticationService,
|
|
AuthInfo->AuthIdentity,
|
|
AuthInfo->AuthorizationService,
|
|
#ifndef NTENV
|
|
AuthInfo->Credentials
|
|
#else
|
|
AuthInfo->Credentials,
|
|
AuthInfo->ImpersonationType,
|
|
AuthInfo->IdentityTracking,
|
|
AuthInfo->Capabilities
|
|
#endif
|
|
);
|
|
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
ASSERT (RpcStatus == RPC_S_OUT_OF_MEMORY);
|
|
delete Binding;
|
|
Binding = 0;
|
|
*DestinationBinding = 0 ;
|
|
|
|
ClearGlobalMutex();
|
|
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
}
|
|
|
|
Binding->Association = Association;
|
|
if ( DceBinding != 0 )
|
|
{
|
|
ASSERT( MaintainContext == 0 );
|
|
|
|
Binding->DceBinding = DceBinding->DuplicateDceBinding();
|
|
}
|
|
else
|
|
{
|
|
Binding->DceBinding = 0;
|
|
}
|
|
|
|
Binding->TransportInterface = TransportInterface;
|
|
|
|
if ( Association != 0 )
|
|
{
|
|
Association->IncrementCount();
|
|
if ( MaintainContext != 0 )
|
|
{
|
|
Association->MaintainingContext();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ClearGlobalMutex();
|
|
*DestinationBinding = (BINDING_HANDLE *) Binding;
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_BINDING_HANDLE::BindingFree (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This method gets called when the application calls RpcBindingFree.
|
|
All we have got to do is to decrement the reference count, and if
|
|
it has reached zero, delete the binding handle.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - This operation always succeeds.
|
|
|
|
--*/
|
|
{
|
|
BindingMutex.Request();
|
|
ReferenceCount -= 1;
|
|
|
|
if ( ReferenceCount == 0 )
|
|
{
|
|
BindingMutex.Clear();
|
|
delete this;
|
|
}
|
|
else
|
|
{
|
|
BindingMutex.Clear();
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
void
|
|
OSF_BINDING_HANDLE::PrepareBindingHandle (
|
|
IN void * TransportInterface,
|
|
IN DCE_BINDING * DceBinding
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This method will be called just before a new binding handle is returned
|
|
to the user. We just stash the transport interface and binding
|
|
information so we can use it later when the first remote procedure
|
|
call is made. At that time, we will actually bind to the interface.
|
|
|
|
Arguments:
|
|
|
|
TransportInterface - Supplies a pointer to a data structure describing
|
|
a loadable transport.
|
|
|
|
DceBinding - Supplies the binding information for this binding handle.
|
|
|
|
--*/
|
|
{
|
|
this->TransportInterface = (RPC_CLIENT_TRANSPORT_INFO *) TransportInterface;
|
|
this->DceBinding = DceBinding;
|
|
Association = 0;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_BINDING_HANDLE::ToStringBinding (
|
|
OUT RPC_CHAR PAPI * PAPI * StringBinding
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We need to convert the binding handle into a string binding. If the
|
|
binding handle has not yet been used to make a remote procedure
|
|
call, then we can just use the information in the binding handle to
|
|
create the string binding. Otherwise, we need to ask the association
|
|
to do it for us.
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
if ( Association == 0 )
|
|
{
|
|
*StringBinding = DceBinding->StringBindingCompose(
|
|
InqPointerAtObjectUuid());
|
|
if (*StringBinding == 0)
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
return(RPC_S_OK);
|
|
}
|
|
return(Association->ToStringBinding(StringBinding,
|
|
InqPointerAtObjectUuid()));
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_BINDING_HANDLE::BindingReset (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will set the endpoint of this binding handle to zero,
|
|
if possible. The binding handle will become partially bound as a
|
|
result. If a remote procedure call has been made on this binding
|
|
handle, it will fail as well.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - The binding handle has successfully been made partially
|
|
bound.
|
|
|
|
RPC_S_WRONG_KIND_OF_BINDING - The binding handle currently has remote
|
|
procedure calls active.
|
|
|
|
--*/
|
|
{
|
|
BindingMutex.Request();
|
|
|
|
if ( Association != 0 )
|
|
{
|
|
if ( ReferenceCount != 1 )
|
|
{
|
|
BindingMutex.Clear();
|
|
return(RPC_S_WRONG_KIND_OF_BINDING);
|
|
}
|
|
|
|
DceBinding = Association->DuplicateDceBinding();
|
|
Association->UnBind();
|
|
Association = 0;
|
|
}
|
|
|
|
DceBinding->MakePartiallyBound();
|
|
|
|
if ( *InquireEpLookupHandle() != 0 )
|
|
{
|
|
EpFreeLookupHandle(*InquireEpLookupHandle());
|
|
*InquireEpLookupHandle() = 0;
|
|
}
|
|
|
|
BindingMutex.Clear();
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
unsigned long
|
|
OSF_BINDING_HANDLE::MapAuthenticationLevel (
|
|
IN unsigned long AuthenticationLevel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The connection oriented protocol module supports all authentication
|
|
levels except for RPC_C_AUTHN_LEVEL_CALL. We just need to map it
|
|
to RPC_C_AUTHN_LEVEL_PKT.
|
|
|
|
--*/
|
|
{
|
|
UNUSED(this);
|
|
|
|
if ( AuthenticationLevel == RPC_C_AUTHN_LEVEL_CALL )
|
|
{
|
|
return(RPC_C_AUTHN_LEVEL_PKT);
|
|
}
|
|
|
|
return(AuthenticationLevel);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_BINDING_HANDLE::ResolveBinding (
|
|
IN PRPC_CLIENT_INTERFACE RpcClientInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We need to try and resolve the endpoint for this binding handle
|
|
if necessary (the binding handle is partially-bound). We check
|
|
to see if an association has been obtained for this binding
|
|
handle; if so, we need to do nothing since the binding handle is
|
|
fully-bound, otherwise, we try and resolve an endpoint for it.
|
|
|
|
Arguments:
|
|
|
|
RpcClientInterface - Supplies interface information to be used
|
|
in resolving the endpoint.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - The binding handle is now fully-bound.
|
|
|
|
RPC_S_NO_ENDPOINT_FOUND - We were unable to resolve the endpoint
|
|
for this particular combination of binding handle (network address)
|
|
and interface.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to resolve
|
|
the endpoint.
|
|
|
|
--*/
|
|
{
|
|
if ( Association == 0 )
|
|
{
|
|
return(DceBinding->ResolveEndpointIfNecessary(
|
|
RpcClientInterface, InqPointerAtObjectUuid(),
|
|
InquireEpLookupHandle(), FALSE, InqComTimeout()));
|
|
|
|
}
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_BINDING_HANDLE::AllocateConnection (
|
|
OUT OSF_CCONNECTION * PAPI * CConnection,
|
|
IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This method will allocate a connection which has been bound to the
|
|
interface specified by the interface information. First, we have got
|
|
to see if we have an association for this binding. If not, we need
|
|
to find or create one. Before we can find or create an association,
|
|
we need to resolve the endpoint if necessary. Next we need to see
|
|
if there is already a connection allocated for this interface and thread.
|
|
Otherwise, we need to ask the association to allocate a connection
|
|
for us.
|
|
|
|
Arguments:
|
|
|
|
CConnection - Returns the allocated connection which has been bound
|
|
to the interface specified by the rpc interface information.
|
|
|
|
RpcInterfaceInformation - Supplies information describing the
|
|
interface to which we wish to bind.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - The operation completed successfully.
|
|
|
|
RPC_S_NO_ENDPOINT_FOUND - The endpoint can not be resolved.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
|
|
a connection.
|
|
|
|
EPT_S_NOT_REGISTERED - There are no more endpoints to be found
|
|
for the specified combination of interface, network address,
|
|
and lookup handle.
|
|
|
|
EPT_S_CANT_PERFORM_OP - The operation failed due to misc. error e.g.
|
|
unable to bind to the EpMapper.
|
|
|
|
All the return values from OSF_CASSOCIATION::AllocateConnection will
|
|
be passed through unchanged.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS Status;
|
|
OSF_ACTIVE_ENTRY * ActiveEntry;
|
|
#ifdef NTENV
|
|
CLIENT_AUTH_INFO * AuthInfo;
|
|
#endif
|
|
|
|
BindingMutex.Request();
|
|
|
|
// To start off, see if the binding handle points to an association
|
|
// yet. If not, we have got to get one.
|
|
|
|
if (Association == 0)
|
|
{
|
|
Status = DceBinding->ResolveEndpointIfNecessary(
|
|
RpcInterfaceInformation, InqPointerAtObjectUuid(),
|
|
InquireEpLookupHandle(), FALSE, InqComTimeout());
|
|
if ( Status != RPC_S_OK )
|
|
{
|
|
BindingMutex.Clear();
|
|
return(Status);
|
|
}
|
|
|
|
Association = FindOrCreateAssociation(DceBinding,TransportInterface);
|
|
|
|
if ( Association == 0 )
|
|
{
|
|
BindingMutex.Clear();
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
// Ownership of the DCE binding passes to the association. We are
|
|
// going to set the field to zero so that no one screws with them.
|
|
|
|
DceBinding = 0;
|
|
|
|
// Ok, when we reach here, we go ahead and fall through to
|
|
// see if we have an active connection (which we will not),
|
|
// and then request the association to allocate one for us.
|
|
|
|
}
|
|
|
|
// First we need to check if there is already a connection active
|
|
// for this thread and interface. To make the common case quicker,
|
|
// we will check to see if there are any connections in the dictionary
|
|
// first.
|
|
|
|
if ( ActiveConnections.Size() != 0 )
|
|
{
|
|
ActiveConnections.Reset();
|
|
while ( (ActiveEntry = ActiveConnections.Next()) != 0 )
|
|
{
|
|
*CConnection = ActiveEntry->IsThisMyActiveConnection(
|
|
GetThreadIdentifier(), RpcInterfaceInformation);
|
|
if ( *CConnection != 0 )
|
|
{
|
|
BindingMutex.Clear();
|
|
return(RPC_S_OK);
|
|
}
|
|
}
|
|
}
|
|
|
|
// We will assume that we are successfully able to allocate a connection,
|
|
// so we bump the reference count now.
|
|
|
|
ReferenceCount += 1;
|
|
|
|
BindingMutex.Clear();
|
|
|
|
#ifdef NTENV
|
|
//
|
|
// If this is a secure BH and it requires DYNAMIC TRACKING, check if
|
|
// LogonID has changed. If it has changed, get new Credential Handle
|
|
//
|
|
|
|
AuthInfo = InquireAuthInformation();
|
|
if ((AuthInfo != 0) && (AuthInfo->AuthenticationLevel !=
|
|
RPC_C_AUTHN_LEVEL_NONE))
|
|
{
|
|
if (AuthInfo->IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC)
|
|
{
|
|
Status = ReAcquireCredentialsIfNecessary();
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
BindingMutex.Request();
|
|
ReferenceCount -=1;
|
|
BindingMutex.Clear();
|
|
return (Status);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// There is not a connection active, so we need to ask the association
|
|
// for one.
|
|
|
|
Status = Association->AllocateConnection(RpcInterfaceInformation,
|
|
#ifdef NTENV
|
|
CConnection, InqComTimeout(), AuthInfo);
|
|
#else
|
|
CConnection, InqComTimeout(), InquireAuthInformation());
|
|
#endif
|
|
|
|
if ( Status == RPC_S_OK )
|
|
{
|
|
(*CConnection)->SetCurrentBinding(this);
|
|
}
|
|
else
|
|
{
|
|
BindingMutex.Request();
|
|
ReferenceCount -= 1;
|
|
ASSERT( ReferenceCount != 0 );
|
|
BindingMutex.Clear();
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
RPC_STATUS
|
|
OSF_BINDING_HANDLE::AddActiveEntry (
|
|
IN OSF_CCONNECTION * CConnection,
|
|
IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
When a callback occurs, we need to add an entry for the thread and
|
|
interface being using for the callback to the binding handle. This
|
|
is so that we can later turn original calls into callbacks if they
|
|
are from the same thread (as the original call) and to the same
|
|
interface (as the original call).
|
|
|
|
Arguments:
|
|
|
|
CConnection - Supplies the connection on which the original call was
|
|
sent.
|
|
|
|
RpcInterfaceInformation - Supplies the interface used by the original
|
|
call.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - An active entry has been added to the binding handle for
|
|
the supplied connection and interface.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to perform the
|
|
operation.
|
|
|
|
--*/
|
|
{
|
|
OSF_ACTIVE_ENTRY * ActiveEntry;
|
|
|
|
BindingMutex.Request();
|
|
ActiveEntry = new OSF_ACTIVE_ENTRY(GetThreadIdentifier(),
|
|
RpcInterfaceInformation, CConnection);
|
|
if ( ActiveEntry == 0 )
|
|
{
|
|
BindingMutex.Clear();
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
CConnection->ActiveConnectionsKey = ActiveConnections.Insert(
|
|
ActiveEntry);
|
|
if ( CConnection->ActiveConnectionsKey == -1 )
|
|
{
|
|
BindingMutex.Clear();
|
|
delete ActiveEntry;
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
ReferenceCount += 1;
|
|
BindingMutex.Clear();
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
void
|
|
OSF_BINDING_HANDLE::FreeConnection (
|
|
IN OSF_CCONNECTION * CConnection
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
When the original call completes on an active connection, the
|
|
connection notifies the binding handle using it that the connection
|
|
can be freed. (This does not mean that the connection is deleted,
|
|
only that it is no longer active).
|
|
|
|
Arguments:
|
|
|
|
CConnection - Supplies an active connection which should be made
|
|
inactive.
|
|
|
|
--*/
|
|
{
|
|
BindingMutex.Request();
|
|
ReferenceCount -= 1;
|
|
if (ReferenceCount == 0)
|
|
{
|
|
|
|
// No one points at this binding handle, so we can go ahead
|
|
// and clean it up.
|
|
|
|
BindingMutex.Clear();
|
|
if ( Association->FreeConnection(CConnection) != 0 )
|
|
{
|
|
delete CConnection;
|
|
}
|
|
delete this;
|
|
}
|
|
else
|
|
{
|
|
BindingMutex.Clear();
|
|
if ( Association->FreeConnection(CConnection) != 0 )
|
|
delete CConnection;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
OSF_BINDING_HANDLE::AbortConnection (
|
|
IN OSF_CCONNECTION * CConnection
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
An error occured in the specified connection, so we need to abort
|
|
it. The caller will delete the connection after this call returns,
|
|
so all we have got to do is to remove the connection from our
|
|
dictionary of active connections.
|
|
|
|
Arguments:
|
|
|
|
CConnection - Supplies the connection to be removed from the
|
|
dictionary of active connections.
|
|
|
|
--*/
|
|
{
|
|
UNUSED(CConnection);
|
|
|
|
BindingMutex.Request();
|
|
ReferenceCount -= 1;
|
|
|
|
if (ReferenceCount == 0)
|
|
{
|
|
|
|
// No one points to this binding, so we go ahead and delete it.
|
|
|
|
BindingMutex.Clear();
|
|
delete this;
|
|
}
|
|
else
|
|
BindingMutex.Clear();
|
|
}
|
|
|
|
void
|
|
OSF_BINDING_HANDLE::RemoveActiveConnection (
|
|
IN OSF_CCONNECTION * CConnection
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The specified connection is removed from the dictionary of active
|
|
connections for this binding handle.
|
|
|
|
Arguments:
|
|
|
|
CConnection - Supplies the connection to be removed from the
|
|
dictionary of active connections.
|
|
|
|
--*/
|
|
{
|
|
OSF_ACTIVE_ENTRY * ActiveEntry;
|
|
|
|
BindingMutex.Request();
|
|
ActiveEntry = ActiveConnections.Delete(CConnection->ActiveConnectionsKey);
|
|
if ( ActiveEntry != 0 )
|
|
{
|
|
delete ActiveEntry;
|
|
}
|
|
ReferenceCount -= 1;
|
|
BindingMutex.Clear();
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::Send (
|
|
IN PRPC_MESSAGE Message
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine is used in conjunction with pipes. If it is the first send, it retries,
|
|
otherwise, it simply sends the data. If the RPC_BUFFER_PARTIAL bit is not set,
|
|
it waits for the first reply.
|
|
|
|
Return Value:
|
|
RPC_S_OK: All the data was sent across
|
|
RPC_S_SEND_INCOMPLETE: Some of the data still remains to be sent.
|
|
Message->Buffer points to this data and Message->BufferLength is the length
|
|
of the remaining data
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
|
|
// Apart from sending the data, SendRecur and SendNext Chunk check
|
|
// Message->Flags for the RPC_BUFFER_PARTIAL bit. If it is not set,
|
|
// the first fragment of the response is receive as a side effect of the send.
|
|
// this is done to take advantage to the sendreceive feature of some
|
|
// transports.
|
|
if (FirstFrag)
|
|
{
|
|
if (EnableCancels == 0)
|
|
{
|
|
RpcStatus = DoPreSendProcessing() ;
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
AbortTheConnection(Message, Message->Buffer) ;
|
|
return RpcStatus ;
|
|
}
|
|
}
|
|
|
|
RpcStatus = SendRecur(Message, 0);
|
|
}
|
|
else
|
|
{
|
|
RpcStatus = SendNextChunk(Message) ;
|
|
}
|
|
|
|
//
|
|
// WARNING! Do not touch any member privates of the this pointer directly
|
|
// after this point! The *this* pointer could have been deleted [see auto retry logic
|
|
// in SendRecur!
|
|
//
|
|
|
|
return (RpcStatus);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::SendNextChunk(
|
|
IN OUT PRPC_MESSAGE Message
|
|
)
|
|
{
|
|
RPC_STATUS RpcStatus ;
|
|
|
|
if ( ConnectionAbortedFlag != 0 )
|
|
{
|
|
return(RPC_S_CALL_FAILED);
|
|
}
|
|
|
|
if ( (CurrentBinding->InqIfNullObjectUuid() == 0) )
|
|
{
|
|
RpcStatus = SendRequestOrResponse(Message, rpc_request,
|
|
CurrentBinding->InqPointerAtObjectUuid(), 1);
|
|
}
|
|
else
|
|
{
|
|
RpcStatus = SendRequestOrResponse(Message, rpc_request, 0, 1);
|
|
}
|
|
|
|
// temporary fix
|
|
if (RpcStatus == RPC_S_CALL_FAILED_DNE)
|
|
{
|
|
RpcStatus = RPC_S_CALL_FAILED ;
|
|
}
|
|
|
|
|
|
if ((RpcStatus != RPC_S_OK)
|
|
&& (RpcStatus != RPC_S_SEND_INCOMPLETE))
|
|
{
|
|
DoConnectionCleanup(Message, NULL, RpcStatus, 0, 0) ;
|
|
|
|
DoPostReceiveProcessing(Message, RpcStatus) ;
|
|
}
|
|
return (RpcStatus) ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::SendRecur (
|
|
IN OUT PRPC_MESSAGE Message,
|
|
IN unsigned int RecursionCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Message - Supplies the request to send to the server. This is used only on the
|
|
first send.
|
|
|
|
RecursionCount - Supplies the number of times that this routine has
|
|
been recursively called. We need this to prevent infinite recursion
|
|
in some rather weird cases.
|
|
|
|
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;
|
|
RPC_MESSAGE OriginalMessage;
|
|
unsigned int ActiveEntrySet = 0;
|
|
unsigned int BufferOffset = 0;
|
|
|
|
if ( ConnectionAbortedFlag != 0 )
|
|
{
|
|
return(RPC_S_CALL_FAILED_DNE);
|
|
}
|
|
|
|
// Arbitrarly allow OSF_CCONNECTION::SendRecur to be recursively
|
|
// called a maximum of eight times.
|
|
|
|
if ( RecursionCount > 8 )
|
|
{
|
|
return(RPC_S_CALL_FAILED_DNE);
|
|
}
|
|
|
|
CallStack = 1 ;
|
|
AlertMsgsSent = 0;
|
|
|
|
OriginalMessage = *Message;
|
|
if (CurrentBinding->InqIfNullObjectUuid() == 0)
|
|
{
|
|
RpcStatus = SendRequestOrResponse(Message, rpc_request,
|
|
CurrentBinding->InqPointerAtObjectUuid(), 1);
|
|
}
|
|
else
|
|
{
|
|
RpcStatus = SendRequestOrResponse(Message, rpc_request, 0, 1);
|
|
}
|
|
|
|
if ( ( (RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
|
|
|| (RpcStatus == RPC_S_CALL_FAILED_DNE) )
|
|
&& ( ClientSecurityContext.AuthenticationLevel !=
|
|
RPC_C_AUTHN_LEVEL_PKT_PRIVACY ) )
|
|
{
|
|
*Message = OriginalMessage;
|
|
Message->Handle = (RPC_BINDING_HANDLE) CurrentBinding;
|
|
if (RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
|
|
{
|
|
Association->ShutdownRequested();
|
|
RpcStatus = RPC_S_CALL_FAILED_DNE;
|
|
}
|
|
|
|
AbortConnection();
|
|
|
|
RpcStatus = CurrentBinding->GetBuffer(Message);
|
|
|
|
if ( RpcStatus == RPC_S_OK )
|
|
{
|
|
if (CurrentBinding->InqIfNullObjectUuid() == 0)
|
|
BufferOffset = sizeof(UUID);
|
|
|
|
RpcpMemoryCopy(
|
|
Message->Buffer,
|
|
(void PAPI *)((char PAPI *)(OriginalMessage.Buffer)+BufferOffset),
|
|
OriginalMessage.BufferLength
|
|
);
|
|
}
|
|
FreeBuffer(&OriginalMessage);
|
|
CurrentBinding->AbortConnection(this) ;
|
|
CallStack = 0 ;
|
|
|
|
if ( RpcStatus == RPC_S_OK )
|
|
{
|
|
delete this;
|
|
|
|
((OSF_CCONNECTION *) Message->Handle)->DoPreSendProcessing() ;
|
|
|
|
return(((OSF_CCONNECTION *) Message->Handle)->SendRecur(
|
|
Message, RecursionCount + 1));
|
|
}
|
|
else
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
Message->Handle = 0;
|
|
return(RpcStatus);
|
|
}
|
|
|
|
CallStack = 0 ;
|
|
|
|
if ((RpcStatus != RPC_S_OK)
|
|
&& (RpcStatus != RPC_S_SEND_INCOMPLETE))
|
|
{
|
|
DoConnectionCleanup(Message, NULL, RpcStatus, 0, 1) ;
|
|
|
|
DoPostReceiveProcessing(Message, RpcStatus) ;
|
|
}
|
|
|
|
return(RpcStatus);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::Receive (
|
|
IN PRPC_MESSAGE Message,
|
|
IN unsigned int Size
|
|
)
|
|
{
|
|
RPC_STATUS RpcStatus ;
|
|
unsigned int RemoteFaultOccured = 0;
|
|
unsigned int ActiveEntrySet = 0;
|
|
unsigned long Partial = Message->RpcFlags & RPC_BUFFER_PARTIAL ;
|
|
unsigned int DidNotExecute = 0;
|
|
|
|
if (Message->RpcFlags & RPC_BUFFER_COMPLETE)
|
|
{
|
|
return RPC_S_OK ;
|
|
}
|
|
|
|
CallStack = 1;
|
|
|
|
// First Receive is set in the constructor for OSF_CCONNECTION
|
|
if (FirstReceive)
|
|
{
|
|
RpcStatus = ReceiveMessage(Message, &RemoteFaultOccured,
|
|
Size, &DidNotExecute) ;
|
|
FirstReceive = 0 ;
|
|
}
|
|
else
|
|
{
|
|
Request = 0 ;
|
|
RpcStatus = ReceiveNextChunk(Message, Size) ;
|
|
}
|
|
|
|
#if 0
|
|
// need to understand the ramifications of cancelling in the middle of partial
|
|
// receives. This is disabled for the initial checkin..
|
|
#ifdef NTENV
|
|
if (RpcStatus == RPC_S_OK)
|
|
{
|
|
if ( ((OSF_CCONNECTION *) Message->Handle)->PendingAlert == TRUE )
|
|
{
|
|
RpcCancelThread(GetCurrentThread());
|
|
((OSF_CCONNECTION *)Message->Handle)->PendingAlert = FALSE;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
if (RpcStatus == RPC_S_OK
|
|
&& NOT_MULTIPLE_OF_EIGHT(Message->BufferLength)
|
|
&& (Message->RpcFlags & RPC_BUFFER_COMPLETE) == 0)
|
|
{
|
|
SaveRemainingData(Message) ;
|
|
}
|
|
|
|
CallStack = 0;
|
|
|
|
if ((Message->RpcFlags & RPC_BUFFER_COMPLETE)
|
|
|| RpcStatus != RPC_S_OK)
|
|
{
|
|
if ( ActiveEntrySet != 0 )
|
|
{
|
|
CurrentBinding->RemoveActiveConnection(this);
|
|
}
|
|
|
|
ASSERT(CallStack == 0) ;
|
|
|
|
DoConnectionCleanup(Message, NULL, RpcStatus,
|
|
RemoteFaultOccured, DidNotExecute) ;
|
|
|
|
DoPostReceiveProcessing(Message, RpcStatus) ;
|
|
}
|
|
|
|
return(RpcStatus);
|
|
}
|
|
|
|
|
|
/* --------------------------------------------------------------------
|
|
-------------------------------------------------------------------- */
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::SendReceive (
|
|
IN PRPC_MESSAGE Message
|
|
)
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
|
|
RpcStatus = DoPreSendProcessing() ;
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
AbortTheConnection(Message, Message->Buffer) ;
|
|
return RpcStatus ;
|
|
}
|
|
|
|
RpcStatus = SendReceiveRecur(Message, 0);
|
|
|
|
//
|
|
// WARNING! Do not touch any member privates of the this pointer directly
|
|
// after this point! The *this* pointer could have been deleted [see auto retry logic
|
|
// in SendReceiveRecur!
|
|
//
|
|
DoPostReceiveProcessing(Message, RpcStatus) ;
|
|
|
|
return (RpcStatus);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::SendReceiveRecur (
|
|
IN OUT PRPC_MESSAGE Message,
|
|
IN unsigned int RecursionCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Message - Supplies the request to send to the server and returns the
|
|
response received from the server.
|
|
|
|
RecursionCount - Supplies the number of times that this routine has
|
|
been recursively called. We need this to prevent infinite recursion
|
|
in some rather weird cases.
|
|
|
|
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;
|
|
RPC_MESSAGE OriginalMessage;
|
|
unsigned int RemoteFaultOccured = 0;
|
|
unsigned int ActiveEntrySet = 0;
|
|
unsigned int BufferOffset = 0;
|
|
unsigned int DidNotExecute = 0;
|
|
unsigned int InShutdownRecoveryMode = 0;
|
|
|
|
if ( ConnectionAbortedFlag != 0 )
|
|
{
|
|
return(RPC_S_CALL_FAILED_DNE);
|
|
}
|
|
|
|
// Arbitrarly allow OSF_CCONNECTION::SendReceiveRecur to be recursively
|
|
// called a maximum of eight times.
|
|
|
|
if ( RecursionCount > 8 )
|
|
{
|
|
return(RPC_S_CALL_FAILED_DNE);
|
|
}
|
|
|
|
if ( CallStack == 0 )
|
|
{
|
|
AlertMsgsSent = 0;
|
|
}
|
|
|
|
OriginalMessage = *Message;
|
|
CallStack += 1;
|
|
if ( (CallStack == 1)
|
|
&& (CurrentBinding->InqIfNullObjectUuid() == 0) )
|
|
{
|
|
RpcStatus = SendRequestOrResponse(Message, rpc_request,
|
|
CurrentBinding->InqPointerAtObjectUuid());
|
|
}
|
|
else
|
|
{
|
|
RpcStatus = SendRequestOrResponse(Message, rpc_request, 0);
|
|
}
|
|
|
|
if ( ( (RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
|
|
||(RpcStatus == RPC_S_CALL_FAILED_DNE) )
|
|
&& ( CallStack == 1 )
|
|
&& ( ClientSecurityContext.AuthenticationLevel !=
|
|
RPC_C_AUTHN_LEVEL_PKT_PRIVACY ) )
|
|
{
|
|
*Message = OriginalMessage;
|
|
Message->Handle = (RPC_BINDING_HANDLE) CurrentBinding;
|
|
if (RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
|
|
{
|
|
/* Association->ShutdownRequested(); */
|
|
//
|
|
// We cannot shutdown all the connections ..
|
|
// OSF servrs keep Associations that have marshalled out
|
|
// Context Handles active.. Active
|
|
// We retry with alternate connections .. over and over
|
|
// till we endup blowing off all previously active connections
|
|
// and get a *new* connection .. or endup using an old one
|
|
// that has a context active.
|
|
InShutdownRecoveryMode = 1;
|
|
RpcStatus = RPC_S_CALL_FAILED_DNE;
|
|
}
|
|
|
|
AbortConnection();
|
|
|
|
while ( 1 )
|
|
{
|
|
RpcStatus = CurrentBinding->GetBuffer(Message);
|
|
if (RpcStatus != RPC_P_CONNECTION_SHUTDOWN)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( RpcStatus == RPC_S_OK )
|
|
{
|
|
if (CurrentBinding->InqIfNullObjectUuid() == 0)
|
|
BufferOffset = sizeof(UUID);
|
|
|
|
RpcpMemoryCopy(
|
|
Message->Buffer,
|
|
(void PAPI *)((char PAPI *)(OriginalMessage.Buffer)+BufferOffset),
|
|
OriginalMessage.BufferLength
|
|
);
|
|
}
|
|
FreeBuffer(&OriginalMessage);
|
|
CurrentBinding->AbortConnection(this);
|
|
CallStack -= 1;
|
|
|
|
if ( RpcStatus == RPC_S_OK )
|
|
{
|
|
if ( InShutdownRecoveryMode == 0 )
|
|
{
|
|
RecursionCount++;
|
|
}
|
|
|
|
delete this;
|
|
|
|
((OSF_CCONNECTION *) Message->Handle)->DoPreSendProcessing() ;
|
|
|
|
return(((OSF_CCONNECTION *) Message->Handle)->SendReceiveRecur(
|
|
Message, RecursionCount));
|
|
}
|
|
else
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
Message->Handle = 0;
|
|
return(RpcStatus);
|
|
}
|
|
|
|
for (; RpcStatus == RPC_S_OK ;)
|
|
{
|
|
// Sent message okay, original buffer has been freed.
|
|
OriginalMessage.Buffer = 0;
|
|
|
|
RpcStatus = ReceiveMessage(Message, &RemoteFaultOccured,
|
|
0, &DidNotExecute);
|
|
if ( RpcStatus != RPC_P_OK_REQUEST )
|
|
{
|
|
break;
|
|
}
|
|
OriginalMessage.Buffer = Message->Buffer;
|
|
Message->TransferSyntax = 0;
|
|
|
|
if ( ( CallStack == 1 )
|
|
&& ( ActiveEntrySet == 0 ) )
|
|
{
|
|
RpcStatus = CurrentBinding->AddActiveEntry(this,
|
|
(RPC_CLIENT_INTERFACE PAPI *)
|
|
Message->RpcInterfaceInformation);
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
break;
|
|
}
|
|
ActiveEntrySet = 1;
|
|
}
|
|
|
|
RpcStatus = DispatchCallback(DispatchTableCallback, Message,
|
|
&ExceptionCode);
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
ASSERT( (RpcStatus == RPC_P_EXCEPTION_OCCURED)
|
|
|| (RpcStatus == RPC_S_PROCNUM_OUT_OF_RANGE));
|
|
|
|
FreeBuffer(&OriginalMessage);
|
|
|
|
if ( RpcStatus == RPC_S_PROCNUM_OUT_OF_RANGE )
|
|
{
|
|
SendFault(RPC_S_PROCNUM_OUT_OF_RANGE, 0);
|
|
}
|
|
else
|
|
{
|
|
SendFault(ExceptionCode, 0);
|
|
}
|
|
|
|
RpcStatus = TransReceive(&(Message->Buffer),
|
|
&(Message->BufferLength));
|
|
ASSERT( (RpcStatus != RPC_S_CALL_CANCELLED)
|
|
&&(RpcStatus != RPC_P_RECEIVE_ALERTED) );
|
|
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 ) );
|
|
}
|
|
OriginalMessage.Buffer = 0;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FreeBuffer(&OriginalMessage);
|
|
|
|
OriginalMessage = *Message;
|
|
RpcStatus = SendRequestOrResponse(Message, rpc_response, 0);
|
|
if ( (RpcStatus == RPC_S_CALL_FAILED_DNE)
|
|
||(RpcStatus == RPC_P_CONNECTION_SHUTDOWN) )
|
|
{
|
|
RpcStatus = RPC_S_CALL_FAILED;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ActiveEntrySet != 0 )
|
|
{
|
|
CurrentBinding->RemoveActiveConnection(this);
|
|
}
|
|
|
|
CallStack -= 1;
|
|
|
|
|
|
DoConnectionCleanup(Message, OriginalMessage.Buffer, RpcStatus,
|
|
RemoteFaultOccured, DidNotExecute) ;
|
|
|
|
return(RpcStatus);
|
|
}
|
|
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::ReceiveMessage (
|
|
IN OUT PRPC_MESSAGE Message,
|
|
OUT unsigned int PAPI * RemoteFaultOccured,
|
|
IN unsigned int Size,
|
|
OUT unsigned int PAPI * DidNotExecute
|
|
)
|
|
/*++
|
|
|
|
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.
|
|
|
|
Contract:
|
|
|
|
On Entry Message->Buffer points to the first fragment [or complete response]
|
|
On Successful return Message->Buffer points to the complete response.
|
|
On Failure, Message->Buffer [first frag] is *freed* and Message->Buffer==0
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
unsigned long FaultStatus;
|
|
rpcconn_common PAPI * pFragment = (rpcconn_common PAPI *) Message->Buffer;
|
|
rpcconn_response PAPI * pResponse = (rpcconn_response PAPI *) Message->Buffer;
|
|
|
|
*RemoteFaultOccured = 0;
|
|
*DidNotExecute = 0;
|
|
|
|
//If there is security save the rpc header
|
|
if ( ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE )
|
|
{
|
|
if (SavedHeaderSize < sizeof(rpcconn_response))
|
|
{
|
|
|
|
if (SavedHeader != 0)
|
|
{
|
|
ASSERT(SavedHeaderSize != 0);
|
|
RpcpFarFree(SavedHeader);
|
|
}
|
|
|
|
SavedHeader = RpcpFarAllocate(sizeof(rpcconn_response));
|
|
if (SavedHeader == 0)
|
|
{
|
|
TransFreeBuffer(Message->Buffer);
|
|
Message->Buffer = 0;
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
SavedHeaderSize = sizeof(rpcconn_response);
|
|
RpcpMemoryCopy(SavedHeader, Message->Buffer,
|
|
sizeof(rpcconn_response));
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
RpcpMemoryCopy(SavedHeader, Message->Buffer,sizeof(rpcconn_response));
|
|
}
|
|
}
|
|
|
|
RpcStatus = ValidatePacket(pFragment, Message->BufferLength);
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
ASSERT( RpcStatus == RPC_S_PROTOCOL_ERROR );
|
|
TransFreeBuffer(Message->Buffer);
|
|
Message->Buffer = 0;
|
|
return(RpcStatus);
|
|
}
|
|
|
|
switch (pFragment->PTYPE)
|
|
{
|
|
case rpc_request :
|
|
if ( pFragment->call_id != CallId )
|
|
{
|
|
TransFreeBuffer(Message->Buffer);
|
|
Message->Buffer = 0;
|
|
return(RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
if ( ((rpcconn_request PAPI *) pFragment)->p_cont_id
|
|
!= PresentationContext )
|
|
{
|
|
SendFault(RPC_S_UNKNOWN_IF, 0);
|
|
|
|
RpcStatus = TransReceive(&(Message->Buffer),
|
|
&(Message->BufferLength));
|
|
ASSERT( (RpcStatus != RPC_S_CALL_CANCELLED)
|
|
&&(RpcStatus != RPC_P_RECEIVE_ALERTED) );
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
if ( ( RpcStatus == RPC_P_RECEIVE_FAILED )
|
|
|| ( RpcStatus == RPC_P_CONNECTION_CLOSED ) )
|
|
{
|
|
TransFreeBuffer(Message->Buffer);
|
|
Message->Buffer = 0;
|
|
return(RPC_S_CALL_FAILED);
|
|
}
|
|
TransFreeBuffer(Message->Buffer);
|
|
Message->Buffer = 0;
|
|
return(RpcStatus);
|
|
}
|
|
|
|
return(ReceiveMessage(Message, RemoteFaultOccured,
|
|
Size, DidNotExecute));
|
|
}
|
|
|
|
RpcStatus = ReceiveRequestOrResponse(Message, Size);
|
|
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);
|
|
}
|
|
|
|
if (pResponse->alert_count != AlertMsgsSent)
|
|
{
|
|
PendingAlert = TRUE;
|
|
}
|
|
else if (pResponse->common.pfc_flags & PFC_PENDING_ALERT)
|
|
{
|
|
PendingAlert = TRUE;
|
|
}
|
|
else
|
|
{
|
|
PendingAlert = FALSE;
|
|
}
|
|
|
|
return(ReceiveRequestOrResponse(Message, Size));
|
|
|
|
case rpc_fault :
|
|
FaultStatus = ((rpcconn_fault PAPI *)pFragment)->status;
|
|
|
|
if ( (FaultStatus == 0) &&
|
|
(pFragment->frag_length >= sizeof(rpcconn_fault) + 4) )
|
|
{
|
|
// DCE 1.0.x style fault status:
|
|
// Zero status and stub data contains the fault.
|
|
|
|
FaultStatus = *(unsigned long PAPI *)
|
|
(((rpcconn_fault PAPI *)pFragment)+1);
|
|
}
|
|
|
|
if (DataConvertEndian(pFragment->drep) != 0 )
|
|
{
|
|
ByteSwapLong(FaultStatus);
|
|
}
|
|
|
|
ASSERT(FaultStatus != 0);
|
|
|
|
RpcStatus = MapFromNcaStatusCode(FaultStatus);
|
|
*RemoteFaultOccured = 1;
|
|
if (pFragment->pfc_flags & PFC_DID_NOT_EXECUTE)
|
|
{
|
|
*DidNotExecute = 1 ;
|
|
}
|
|
TransFreeBuffer(Message->Buffer);
|
|
Message->Buffer = 0;
|
|
|
|
|
|
// In 3.5 we didnt Sign/Seal Faults. So .. Unsign/UnSeal doesnt
|
|
// get called and hence Client side and Server side Seq# are
|
|
// out of Sync.. So cheat ..
|
|
|
|
DceSecurityInfo.ReceiveSequenceNumber += 1;
|
|
|
|
return(RpcStatus);
|
|
|
|
case rpc_orphaned :
|
|
case rpc_remote_alert :
|
|
case rpc_shutdown :
|
|
// For the first release, we will just ignore these messages.
|
|
|
|
TransFreeBuffer(Message->Buffer);
|
|
Message->Buffer = 0;
|
|
|
|
RpcStatus = TransReceive(&Message->Buffer, &Message->BufferLength);
|
|
ASSERT( (RpcStatus != RPC_S_CALL_CANCELLED)
|
|
&&(RpcStatus != RPC_P_RECEIVE_ALERTED) );
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
if ( ( RpcStatus == RPC_P_RECEIVE_FAILED )
|
|
|| ( RpcStatus == RPC_P_CONNECTION_CLOSED ))
|
|
{
|
|
return(RPC_S_CALL_FAILED);
|
|
}
|
|
else
|
|
if ( RpcStatus == RPC_P_CONNECTION_SHUTDOWN )
|
|
{
|
|
return (RPC_S_CALL_FAILED_DNE);
|
|
}
|
|
return(RpcStatus);
|
|
}
|
|
return(ReceiveMessage(Message, RemoteFaultOccured, Size, DidNotExecute));
|
|
|
|
default :
|
|
return(RPC_S_PROTOCOL_ERROR);
|
|
|
|
}
|
|
|
|
// This will never be reached.
|
|
|
|
return(RPC_S_INTERNAL_ERROR);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::SendRequestOrResponse (
|
|
IN OUT PRPC_MESSAGE Message,
|
|
IN unsigned char PacketType,
|
|
IN RPC_UUID * ObjectUuid OPTIONAL,
|
|
IN int PipeSend OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Message - Supplies the buffer containing the request or response to be
|
|
sent. Returns the first fragment received from the server, if
|
|
the partial bit is not set in the message.
|
|
|
|
PacketType - Supplies the packet type; this must be rpc_request or
|
|
rpc_response.
|
|
|
|
ObjectUuid - Optionally supplies the object UUID to use for this request.
|
|
|
|
Note: If this function returns an error the input (request/response)
|
|
Message->Buffer is not freed. If it completes successfully, the
|
|
Message->buffer is freed.
|
|
|
|
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;
|
|
RPC_MESSAGE SendBuffer;
|
|
unsigned int LengthLeft = Message->BufferLength;
|
|
RPC_STATUS RpcStatus;
|
|
void PAPI * ReceiveBuffer = 0;
|
|
unsigned int ReceiveBufferLength;
|
|
unsigned char PAPI * Source, PAPI * Destination;
|
|
unsigned int Count;
|
|
unsigned int MaxSecuritySize = 0;
|
|
unsigned char PAPI * ReservedForSecurity;
|
|
unsigned int MaximumFragmentLength = MaxFrag;
|
|
int Partial = (Message->RpcFlags & RPC_BUFFER_PARTIAL) ;
|
|
|
|
ASSERT( sizeof(rpcconn_response) == sizeof(rpcconn_request) );
|
|
ASSERT( (PacketType == rpc_request)
|
|
|| (PacketType == rpc_response));
|
|
|
|
SendBuffer.Buffer = Message->Buffer;
|
|
|
|
if ( ObjectUuid != 0 )
|
|
{
|
|
HeaderSize = sizeof(rpcconn_request) + sizeof(UUID);
|
|
|
|
// We saved space for an object uuid when we allocated the buffer,
|
|
// so we can shift the stub data to make room for an object uuid
|
|
// at the front.
|
|
|
|
// BUGBUG - There has got to be a more efficient way to do this.
|
|
|
|
Destination = ((unsigned char PAPI *) Message->Buffer) + sizeof(UUID)
|
|
+ Message->BufferLength;
|
|
Source = ((unsigned char PAPI *) Message->Buffer)
|
|
+ Message->BufferLength;
|
|
Count = Message->BufferLength;
|
|
while ( Count-- != 0 )
|
|
{
|
|
*--Destination = *--Source;
|
|
}
|
|
|
|
Message->Buffer = ((unsigned char PAPI *) Message->Buffer)
|
|
+ sizeof(UUID);
|
|
}
|
|
else
|
|
{
|
|
HeaderSize = sizeof(rpcconn_request);
|
|
}
|
|
|
|
|
|
// 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_CCONNECTION::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 (ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
|
|
{
|
|
ASSERT(ClientSecurityContext.AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY ||
|
|
ClientSecurityContext.AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY ||
|
|
ClientSecurityContext.AuthenticationLevel == RPC_C_AUTHN_LEVEL_CONNECT ||
|
|
ClientSecurityContext.AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT);
|
|
|
|
MaxSecuritySize = AdditionalSpaceForSecurity
|
|
- MAXIMUM_SECURITY_BLOCK_SIZE;
|
|
|
|
if (MaxSecuritySize <= sizeof(sec_trailer) &&
|
|
ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_CONNECT)
|
|
{
|
|
return(RPC_S_CALL_FAILED_DNE);
|
|
}
|
|
|
|
if (MaxSecuritySize <= sizeof(sec_trailer))
|
|
{
|
|
MaxSecuritySize = 0;
|
|
ASSERT(ClientSecurityContext.AuthenticationLevel ==
|
|
RPC_C_AUTHN_LEVEL_CONNECT);
|
|
}
|
|
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 (Partial &&
|
|
(LengthLeft + HeaderSize + MaxSecuritySize < MaximumFragmentLength))
|
|
{
|
|
ASSERT(PacketType == rpc_request) ;
|
|
|
|
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 (Partial)
|
|
{
|
|
ASSERT(PacketType == rpc_request) ;
|
|
|
|
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 ( ObjectUuid != 0 )
|
|
{
|
|
pFragment->pfc_flags |= PFC_OBJECT_UUID;
|
|
RpcpMemoryCopy(((unsigned char PAPI *) pFragment)
|
|
+ sizeof(rpcconn_request),
|
|
ObjectUuid, sizeof(UUID));
|
|
}
|
|
|
|
if ( LengthLeft == Message->BufferLength)
|
|
{
|
|
if (PipeSend == 0 || FirstFrag)
|
|
{
|
|
pFragment->pfc_flags |= PFC_FIRST_FRAG;
|
|
FirstFrag = 0;
|
|
|
|
if (PendingAlert)
|
|
{
|
|
pFragment->pfc_flags |= PFC_PENDING_ALERT;
|
|
PendingAlert = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( PacketType == rpc_request )
|
|
{
|
|
((rpcconn_request PAPI *) pFragment)->alloc_hint = LengthLeft;
|
|
((rpcconn_request PAPI *) pFragment)->p_cont_id =
|
|
PresentationContext;
|
|
((rpcconn_request PAPI *) pFragment)->opnum =
|
|
(unsigned short) Message->ProcNum;
|
|
}
|
|
else
|
|
{
|
|
((rpcconn_response PAPI *) pFragment)->alloc_hint = LengthLeft;
|
|
((rpcconn_response PAPI *) pFragment)->p_cont_id =
|
|
(unsigned short) PresentationContext;
|
|
((rpcconn_response PAPI *) pFragment)->alert_count = 0;
|
|
((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)
|
|
{
|
|
return (RpcStatus) ;
|
|
}
|
|
|
|
if (LastFragmentFlag)
|
|
{
|
|
Message->Buffer = ReceiveBuffer;
|
|
Message->BufferLength = ReceiveBufferLength;
|
|
|
|
FreeBuffer(&SendBuffer) ;
|
|
return (RPC_S_OK) ;
|
|
}
|
|
|
|
pFragment = (rpcconn_common PAPI *)
|
|
(((unsigned char PAPI *) pFragment) + MaximumFragmentLength
|
|
- (HeaderSize + MaxSecuritySize));
|
|
|
|
LengthLeft -= (MaximumFragmentLength - (HeaderSize + MaxSecuritySize));
|
|
}
|
|
}
|
|
|
|
inline RPC_STATUS
|
|
OSF_CCONNECTION::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 PAPI *ReceiveBufferLength
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Sends on fragment
|
|
--*/
|
|
|
|
{
|
|
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 ( ((ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
|
|
&&(ClientSecurityContext.AuthenticationLevel
|
|
!= RPC_C_AUTHN_LEVEL_CONNECT))
|
|
||((ClientSecurityContext.AuthenticationLevel == RPC_C_AUTHN_LEVEL_CONNECT)
|
|
&& (MaxSecuritySize != 0)) )
|
|
{
|
|
|
|
ASSERT
|
|
(
|
|
(ClientSecurityContext.AuthenticationLevel
|
|
== RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
|
|
|| (ClientSecurityContext.AuthenticationLevel
|
|
== RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
|
|| (ClientSecurityContext.AuthenticationLevel
|
|
== RPC_C_AUTHN_LEVEL_PKT)
|
|
|| (ClientSecurityContext.AuthenticationLevel
|
|
== RPC_C_AUTHN_LEVEL_CONNECT)
|
|
);
|
|
|
|
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( ((HeaderSize+DataLength+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)
|
|
ClientSecurityContext.AuthenticationService;
|
|
SecurityTrailer->auth_level = (unsigned char)
|
|
ClientSecurityContext.AuthenticationLevel;
|
|
SecurityTrailer->auth_pad_length = AuthPadLength;
|
|
SecurityTrailer->auth_reserved = 0;
|
|
SecurityTrailer->auth_context_id = (unsigned long)(this);
|
|
|
|
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].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
|
SecurityBuffers[2].cbBuffer = sizeof(sec_trailer);
|
|
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;
|
|
|
|
//DCE computes check sums for Header also
|
|
//Make sure Header remains intact
|
|
//Infact may need to extend security interface if
|
|
//some packages return dynamic size seals/signatures
|
|
|
|
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 = ClientSecurityContext.SignOrSeal(
|
|
MsgSecurityInfo.SendSequenceNumber,
|
|
ClientSecurityContext.AuthenticationLevel
|
|
!= RPC_C_AUTHN_LEVEL_PKT_PRIVACY, &BufferDescriptor);
|
|
|
|
ASSERT(SecurityBuffers[3].cbBuffer <= pFragment->auth_length);
|
|
|
|
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 )
|
|
{
|
|
|
|
ASSERT(!RpcpCheckHeap());
|
|
AlertsEnabled = 1;
|
|
|
|
pFragment->pfc_flags |= PFC_LAST_FRAG;
|
|
|
|
RpcStatus = TransSendReceive(pFragment, DataLength + HeaderSize
|
|
+ SecurityLength, ReceiveBuffer, ReceiveBufferLength);
|
|
|
|
AlertsEnabled = 0;
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
if ( (RpcStatus == RPC_P_CONNECTION_CLOSED)
|
|
|| (RpcStatus == RPC_P_SEND_FAILED))
|
|
{
|
|
return(RPC_S_CALL_FAILED_DNE);
|
|
}
|
|
#ifdef NTENV
|
|
if ( RpcStatus == RPC_S_CALL_CANCELLED )
|
|
{
|
|
return (RPC_S_CALL_CANCELLED);
|
|
}
|
|
#endif
|
|
if ( RpcStatus == RPC_P_RECEIVE_FAILED)
|
|
{
|
|
return(RPC_S_CALL_FAILED);
|
|
}
|
|
|
|
ASSERT( (RpcStatus == RPC_S_OUT_OF_MEMORY)
|
|
|| (RpcStatus == RPC_S_OUT_OF_RESOURCES)
|
|
|| (RpcStatus == RPC_P_CONNECTION_SHUTDOWN));
|
|
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 (ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
|
|
{
|
|
ASSERT(
|
|
(ClientSecurityContext.AuthenticationLevel
|
|
== RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
|
|
|| (ClientSecurityContext.AuthenticationLevel
|
|
== RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
|
|| (ClientSecurityContext.AuthenticationLevel
|
|
== RPC_C_AUTHN_LEVEL_PKT)
|
|
|| (ClientSecurityContext.AuthenticationLevel
|
|
== RPC_C_AUTHN_LEVEL_CONNECT)
|
|
);
|
|
|
|
RpcpMemoryCopy(SecurityTrailer, ReservedForSecurity,
|
|
MaxSecuritySize);
|
|
}
|
|
|
|
#if 0
|
|
// BUGBUG - Due to a bug in NT named pipes, if you do not delay,
|
|
// the receive operation will fail in weird and wonderful ways.
|
|
// We only need to do it if we are sending authentication information.
|
|
|
|
if ( MaxSecuritySize != 0 )
|
|
{
|
|
PauseExecution(50L);
|
|
}
|
|
#endif
|
|
|
|
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)
|
|
|| (RpcStatus == RPC_P_CONNECTION_SHUTDOWN));
|
|
return(RpcStatus);
|
|
}
|
|
|
|
return RpcStatus ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::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;
|
|
|
|
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 ( (ClientSecurityContext.AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE) )
|
|
|
|
/*
|
|
Cannot test this here
|
|
|| (ClientSecurityContext.AuthenticationLevel
|
|
!= SecurityTrailer->auth_level)
|
|
|| (ClientSecurityContext.AuthenticationService
|
|
!= SecurityTrailer->auth_type) )
|
|
*/
|
|
{
|
|
return(RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
*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;
|
|
|
|
SecurityBuffers[0].cbBuffer = sizeof(rpcconn_request);
|
|
SecurityBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
|
SecurityBuffers[0].pvBuffer = ((unsigned char PAPI *) SavedHeader);
|
|
|
|
SecurityBuffers[1].cbBuffer = *RequestLength - sizeof(rpcconn_request)
|
|
-sizeof (sec_trailer);
|
|
SecurityBuffers[1].BufferType = SECBUFFER_DATA;
|
|
SecurityBuffers[1].pvBuffer = ((unsigned char PAPI *) Request)
|
|
+ sizeof(rpcconn_request);
|
|
|
|
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 = ClientSecurityContext.VerifyOrUnseal(
|
|
MsgSecurityInfo.ReceiveSequenceNumber,
|
|
ClientSecurityContext.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
|
|
{
|
|
/*
|
|
if (ClientSecurityContext.AuthenticationLevel
|
|
!= RPC_C_AUTHN_LEVEL_NONE)
|
|
{
|
|
return(RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
*/
|
|
if ( (ClientSecurityContext.AuthenticationLevel
|
|
== RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
|
|
||(ClientSecurityContext.AuthenticationLevel
|
|
== RPC_C_AUTHN_LEVEL_PKT_PRIVACY) )
|
|
{
|
|
return(RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
}
|
|
DceSecurityInfo.ReceiveSequenceNumber += 1;
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::ReceiveRequestOrResponse (
|
|
IN OUT PRPC_MESSAGE Message,
|
|
IN unsigned int Size
|
|
)
|
|
/*++
|
|
|
|
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.
|
|
|
|
Notes:
|
|
|
|
This method is very similar to OSF_SCONNECTION::ReceiveRequestOrResponse
|
|
in osfsvr.cxx.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
void PAPI * NewBuffer;
|
|
int SecurityFailureOccured = 0;
|
|
|
|
Request = (rpcconn_request PAPI *) Message->Buffer;
|
|
PacketType = Request->common.PTYPE;
|
|
|
|
FragmentLength = 0 ;
|
|
Message->Buffer = 0;
|
|
|
|
// 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);
|
|
}
|
|
|
|
Message->ProcNum = Request->opnum;
|
|
Message->DataRepresentation =
|
|
(Request->common.drep[0] | (Request->common.drep[1] << 8));
|
|
|
|
if ( (Request->common.pfc_flags & PFC_OBJECT_UUID) != 0 )
|
|
{
|
|
// There can not be an object uuid in the message. This is an
|
|
// error.
|
|
|
|
TransFreeBuffer(Request);
|
|
return(RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
|
|
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);
|
|
*/
|
|
SecurityFailureOccured = 1;
|
|
}
|
|
|
|
if ( (Request->common.pfc_flags & PFC_LAST_FRAG) != 0 )
|
|
{
|
|
if (SecurityFailureOccured != 0)
|
|
{
|
|
TransFreeBuffer(Request);
|
|
return(RPC_S_ACCESS_DENIED);
|
|
}
|
|
Message->Buffer = (void PAPI *) (Request + 1);
|
|
Message->BufferLength -= sizeof(rpcconn_request);
|
|
Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
FragmentLength = Message->BufferLength;
|
|
|
|
// If the server specified an allocation hint, we will go ahead and
|
|
// use it. On Dos and Win 3.1, only use allocation hints which are
|
|
// less than 63.5K.
|
|
|
|
Message->BufferLength = (unsigned int) Request->alloc_hint;
|
|
|
|
#ifdef DOS
|
|
|
|
if ( Request->alloc_hint > 0xFE00L )
|
|
{
|
|
Message->BufferLength = 0;
|
|
}
|
|
|
|
#endif // DOS
|
|
|
|
if ( Message->BufferLength != 0 )
|
|
{
|
|
RpcStatus = GetBufferDo(Message->BufferLength, &Message->Buffer);
|
|
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;
|
|
}
|
|
}
|
|
|
|
return ReceiveNextChunk(Message, Size, SecurityFailureOccured) ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::ReceiveNextChunk(
|
|
IN OUT PRPC_MESSAGE Message,
|
|
IN unsigned int Size,
|
|
IN int SecurityFailureOccured
|
|
)
|
|
{
|
|
unsigned int BufferLengthUsed ;
|
|
RPC_STATUS RpcStatus;
|
|
void PAPI * NewBuffer;
|
|
unsigned long Partial = Message->RpcFlags & RPC_BUFFER_PARTIAL ;
|
|
unsigned long Extra = Message->RpcFlags & RPC_BUFFER_EXTRA ;
|
|
|
|
if (Extra)
|
|
{
|
|
BufferLengthUsed = Message->BufferLength ;
|
|
}
|
|
else
|
|
{
|
|
BufferLengthUsed = 0 ;
|
|
}
|
|
|
|
if (RemainingData[0])
|
|
{
|
|
if (Message->BufferLength < BufferLengthUsed + RemainingData[0])
|
|
{
|
|
// we allocate enough to hold a fragment
|
|
RpcStatus = GetBufferDo(BufferLengthUsed+FragmentLength, &NewBuffer) ;
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
if (Request)
|
|
{
|
|
TransFreeBuffer(Request) ;
|
|
}
|
|
|
|
TransFreeBuffer(Message->Buffer) ;
|
|
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 (;;)
|
|
{
|
|
// check if the remaining data buffer can fit a fragment
|
|
if (Message->BufferLength - BufferLengthUsed
|
|
< FragmentLength - sizeof(rpcconn_request))
|
|
{
|
|
|
|
// For Dos and Win 3.1, make sure that the buffer length does
|
|
// not overflow the size of an integer.
|
|
#ifdef DOS
|
|
|
|
if ( Message->BufferLength > 0xFE00 - FragmentLength )
|
|
{
|
|
TransFreeBuffer(Request);
|
|
FreeBuffer(Message);
|
|
Message->Buffer = 0;
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
#endif // DOS
|
|
|
|
// 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(FragmentLength + Message->BufferLength,
|
|
&NewBuffer);
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY );
|
|
if (Request)
|
|
{
|
|
TransFreeBuffer(Request);
|
|
}
|
|
|
|
if (Message->Buffer)
|
|
{
|
|
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 ;
|
|
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);
|
|
ASSERT( (RpcStatus != RPC_S_CALL_CANCELLED)
|
|
&&(RpcStatus != RPC_P_RECEIVE_ALERTED) );
|
|
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);
|
|
}
|
|
|
|
|
|
if ( ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE )
|
|
{
|
|
|
|
//
|
|
//Save the new request_header..
|
|
//note we already should have enough memory saved
|
|
//
|
|
ASSERT ((SavedHeaderSize >= sizeof(rpcconn_response))
|
|
&& (FragmentLength >= sizeof(rpcconn_response)));
|
|
RpcpMemoryCopy(SavedHeader, Request, sizeof(rpcconn_response));
|
|
|
|
}
|
|
|
|
RpcStatus = ValidatePacket((rpcconn_common PAPI *) Request,
|
|
FragmentLength);
|
|
ASSERT( (RpcStatus == RPC_S_OK)
|
|
|| (RpcStatus == RPC_S_PROTOCOL_ERROR));
|
|
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);
|
|
}
|
|
|
|
RpcStatus = EatAuthInfoFromPacket(Request, &FragmentLength);
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
ASSERT( (RpcStatus == RPC_S_PROTOCOL_ERROR)
|
|
|| (RpcStatus == RPC_S_ACCESS_DENIED) );
|
|
|
|
SecurityFailureOccured = 1;
|
|
}
|
|
}
|
|
|
|
if (Partial)
|
|
{
|
|
ASSERT(Size <= Message->BufferLength) ;
|
|
return (RPC_S_OK) ;
|
|
}
|
|
else
|
|
{
|
|
return (RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
OSF_CCONNECTION::SendFault (
|
|
IN RPC_STATUS Status,
|
|
IN int DidNotExecute
|
|
)
|
|
{
|
|
rpcconn_fault Fault;
|
|
|
|
// BUGBUG this should be a #define in sysinc.h
|
|
#if WIN
|
|
_fmemset(&Fault, 0, sizeof(Fault));
|
|
#else
|
|
memset(&Fault, 0, sizeof(Fault));
|
|
#endif
|
|
|
|
ConstructPacket((rpcconn_common PAPI *) &Fault,rpc_fault,
|
|
sizeof(rpcconn_fault));
|
|
|
|
if (DidNotExecute)
|
|
Fault.common.pfc_flags |= PFC_DID_NOT_EXECUTE;
|
|
|
|
Fault.common.pfc_flags |= PFC_FIRST_FRAG | PFC_LAST_FRAG;
|
|
Fault.p_cont_id = (unsigned short) PresentationContext;
|
|
Fault.status = MapToNcaStatusCode(Status);
|
|
TransSend(&Fault,sizeof(rpcconn_fault));
|
|
}
|
|
|
|
void
|
|
OSF_CCONNECTION::SendOrphan (
|
|
)
|
|
{
|
|
rpcconn_common Orphan;
|
|
|
|
ConstructPacket((rpcconn_common PAPI *) &Orphan, rpc_orphaned,
|
|
sizeof(rpcconn_common));
|
|
|
|
Orphan.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
|
|
|
|
TransSend(&Orphan, sizeof(rpcconn_common));
|
|
}
|
|
|
|
void
|
|
OSF_CCONNECTION::SendAlert(
|
|
)
|
|
{
|
|
rpcconn_common Alert;
|
|
|
|
ConstructPacket((rpcconn_common PAPI *) &Alert, rpc_remote_alert,
|
|
sizeof(rpcconn_common));
|
|
|
|
Alert.pfc_flags = PFC_LAST_FRAG | PFC_PENDING_ALERT;
|
|
|
|
TransSend(&Alert, sizeof(rpcconn_common));
|
|
AlertMsgsSent++;
|
|
}
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::GetBuffer (
|
|
IN OUT PRPC_MESSAGE Message
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Message - Supplies a description containing the length of buffer to be
|
|
allocated, and returns the allocated buffer.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - A buffer of the requested size has successfully been allocated.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
|
|
Message->Handle = (RPC_BINDING_HANDLE) this;
|
|
|
|
// In addition to saving space for the request (or response) header
|
|
// and an object UUID, we want to save space for security information
|
|
// if necessary.
|
|
|
|
if ((Message->RpcFlags & RPC_BUFFER_PARTIAL) &&
|
|
(Message->BufferLength < MaxFrag))
|
|
{
|
|
CurrentBufferLength = MaxFrag ;
|
|
}
|
|
else
|
|
{
|
|
CurrentBufferLength = Message->BufferLength ;
|
|
}
|
|
|
|
RpcStatus = TransGetBuffer(&Message->Buffer,
|
|
CurrentBufferLength + 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);
|
|
}
|
|
|
|
Message->Buffer = (char PAPI *)Message->Buffer + sizeof(rpcconn_request);
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::GetBufferDo (
|
|
IN unsigned int culRequiredLength,
|
|
OUT void PAPI *PAPI * ppBuffer
|
|
)
|
|
{
|
|
if (TransGetBuffer(ppBuffer,culRequiredLength + sizeof(rpcconn_request)
|
|
+ sizeof(UUID)))
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
|
|
*ppBuffer = (((unsigned char PAPI *) *ppBuffer) + sizeof(rpcconn_request));
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
void
|
|
OSF_CCONNECTION::FreeBuffer (
|
|
IN PRPC_MESSAGE Message
|
|
)
|
|
{
|
|
TransFreeBuffer((char PAPI *)Message->Buffer - sizeof(rpcconn_request));
|
|
CurrentBufferLength = 0 ;
|
|
|
|
if (CallStack == 0 &&
|
|
OutstandingBuffers == 0)
|
|
{
|
|
FreeConnection();
|
|
}
|
|
}
|
|
|
|
void OSF_CCONNECTION::FreePipeBuffer (
|
|
IN PRPC_MESSAGE Message
|
|
)
|
|
{
|
|
TransFreeBuffer((char PAPI *)Message->Buffer - sizeof(rpcconn_request));
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::ReallocPipeBuffer (
|
|
IN PRPC_MESSAGE Message,
|
|
IN unsigned int NewSize
|
|
)
|
|
{
|
|
void PAPI *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 (Message->BufferLength > 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_CCONNECTION::BindingCopy (
|
|
OUT BINDING_HANDLE * PAPI * DestinationBinding,
|
|
IN unsigned int MaintainContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We check to see if this connection has an active binding, if
|
|
so, we tell the binding using this connection to copy itself.
|
|
Otherwise, it is an error.
|
|
|
|
Arguments:
|
|
|
|
DestinationBinding - Returns a copy of the current binding handle
|
|
for this connection.
|
|
|
|
MaintainContext - Supplies a flag that indicates whether or not context
|
|
is being maintained over this binding handle. A non-zero value
|
|
indicates that context is being maintained.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_INVALID_HANDLE - This connection does not have a current
|
|
binding to be copied.
|
|
|
|
--*/
|
|
{
|
|
if (CurrentBinding == 0)
|
|
{
|
|
return(RPC_S_INVALID_BINDING);
|
|
}
|
|
|
|
return(CurrentBinding->BindingCopy(DestinationBinding, MaintainContext));
|
|
}
|
|
|
|
#define FIRST_CACHED_BUFFER_AVAILABLE 0x1
|
|
#define SECOND_CACHED_BUFFER_AVAILABLE 0x2
|
|
#define CACHED_BUFFERS_ALLOCATED 0x4
|
|
|
|
#define CACHED_BUFFER_AVAILABLE_MASK 0x3
|
|
|
|
#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
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::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 <= CACHED_BUFFER_LENGTH )
|
|
{
|
|
if ( BufferCacheFlags & FIRST_CACHED_BUFFER_AVAILABLE )
|
|
{
|
|
BufferCacheFlags &= ~FIRST_CACHED_BUFFER_AVAILABLE;
|
|
*Buffer = FirstCachedBuffer;
|
|
OutstandingBuffers += 1;
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
if ( BufferCacheFlags & SECOND_CACHED_BUFFER_AVAILABLE )
|
|
{
|
|
BufferCacheFlags &= ~SECOND_CACHED_BUFFER_AVAILABLE;
|
|
*Buffer = SecondCachedBuffer;
|
|
OutstandingBuffers += 1;
|
|
return(RPC_S_OK);
|
|
}
|
|
}
|
|
|
|
#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(Memory + 1, ALIGN_REQUIRED) + sizeof(int);
|
|
Memory = (int PAPI *) (((char PAPI *) Memory) + AmountOfPad);
|
|
Memory[-1] = AmountOfPad;
|
|
|
|
#endif // NTENV
|
|
|
|
*Buffer = Memory;
|
|
OutstandingBuffers += 1;
|
|
|
|
ASSERT(Pad8(*Buffer) == 0);
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
void
|
|
OSF_CCONNECTION::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.
|
|
|
|
--*/
|
|
{
|
|
if ( Buffer == FirstCachedBuffer )
|
|
{
|
|
BufferCacheFlags |= FIRST_CACHED_BUFFER_AVAILABLE;
|
|
}
|
|
else if ( Buffer == SecondCachedBuffer )
|
|
{
|
|
BufferCacheFlags |= SECOND_CACHED_BUFFER_AVAILABLE;
|
|
}
|
|
else
|
|
{
|
|
RpcpFarFree(UnAlignBuffer(Buffer));
|
|
}
|
|
|
|
OutstandingBuffers -= 1;
|
|
}
|
|
|
|
void
|
|
ConstructPContextList ( // Construct the presentation context list in the
|
|
// rpc_bind packet (and implicitly rpc_alter_context)
|
|
// packet.
|
|
OUT p_cont_list_t PAPI * pCon, // Place the list here.
|
|
IN PRPC_SYNTAX_IDENTIFIER Interface,
|
|
IN PRPC_SYNTAX_IDENTIFIER TransferSyntaxes,
|
|
IN unsigned int TransferSyntaxCount,
|
|
IN unsigned char PresentContext
|
|
)
|
|
{
|
|
pCon->n_context_elem = 1;
|
|
pCon->reserved = 0;
|
|
pCon->reserved2 = 0;
|
|
pCon->p_cont_elem[0].p_cont_id = (unsigned char) PresentContext;
|
|
pCon->p_cont_elem[0].n_transfer_syn = TransferSyntaxCount;
|
|
pCon->p_cont_elem[0].reserved = 0;
|
|
|
|
RpcpMemoryCopy(&pCon->p_cont_elem[0].abstract_syntax, Interface,
|
|
sizeof(RPC_SYNTAX_IDENTIFIER));
|
|
|
|
RpcpMemoryCopy(pCon->p_cont_elem[0].transfer_syntaxes, TransferSyntaxes,
|
|
sizeof(RPC_SYNTAX_IDENTIFIER) * TransferSyntaxCount);
|
|
|
|
|
|
#ifdef MAC
|
|
|
|
// Our RPC_SYNTAX_IDENTIFIER structure contains a RPC_VERSION structure
|
|
// which is defined as two shorts making a little endian formatted long.
|
|
// We need to send the versions as a big endian formatted long.
|
|
// Rather then changing the stubs, we'll be swap it here.
|
|
|
|
// Since the shorts are correct (big endian), we just need to swap
|
|
// them.
|
|
|
|
#define SWAP_WORDS_OF_DWORD(x) \
|
|
x = (( (x & 0x0000FFFF) << 16 ) | ( (x & 0xFFFF0000) >> 16 ))
|
|
|
|
SWAP_WORDS_OF_DWORD(pCon->p_cont_elem[0].abstract_syntax.if_version);
|
|
|
|
|
|
// If we move to a multiple transfer syntaxes we'll should take the
|
|
// time to fix it so that this byte swap is not necessary at all.
|
|
|
|
ASSERT(TransferSyntaxCount == 1);
|
|
|
|
SWAP_WORDS_OF_DWORD(pCon->p_cont_elem[0].transfer_syntaxes[0].if_version);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::PingServer(
|
|
)
|
|
{
|
|
return Association->PingServer() ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::SendBindPacket (
|
|
IN PRPC_SYNTAX_IDENTIFIER InterfaceSyntax,
|
|
IN PRPC_SYNTAX_IDENTIFIER TransferSyntaxes,
|
|
IN unsigned int TransferSyntaxCount,
|
|
IN unsigned char PresentContext,
|
|
IN unsigned long AssocGroup,
|
|
IN unsigned char PacketType,
|
|
OUT void PAPI * PAPI * Buffer,
|
|
OUT unsigned int PAPI * BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to send a bind or alter context packet. It
|
|
will allocate a buffer, fill in the packet, and then send it and
|
|
receive a reply. The reply buffer is just returned to the caller.
|
|
|
|
Arguments:
|
|
|
|
InterfaceSyntax - Supplies the interface UUID and version to which
|
|
we want to bind. This information will be placed in the packet.
|
|
|
|
TransferSyntax - Supplies one or more transfer syntaxes which the
|
|
client stub supports. The server will select one, if possible,
|
|
which the server stub supports.
|
|
|
|
TransferSyntaxCount - Supplies the number of transfer syntaxes.
|
|
|
|
PresentContext - Supplies the presentation context to be used for
|
|
this particular binding.
|
|
|
|
AssocGroup - Supplies the association group id for the association
|
|
group of which this connection is a new member.
|
|
|
|
PacketType - Supplies the packet type which must be one of rpc_bind
|
|
or rpc_alter_context.
|
|
|
|
Buffer - Returns the reply buffer.
|
|
|
|
BufferLength - Returns the length of the reply buffer.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - The operation completed successfully.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete
|
|
the operation.
|
|
|
|
RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to
|
|
complete the operation.
|
|
|
|
RPC_S_ACCESS_DENIED - The security package won't allow this.
|
|
|
|
RPC_P_CONNECTION_CLOSED - The connection has been closed and the
|
|
receive operation failed. The send operation may or may not
|
|
have succeeded.
|
|
|
|
--*/
|
|
{
|
|
rpcconn_bind PAPI * BindPacket = 0;
|
|
unsigned int BindPacketLength, AuthPadLength, SecurityTokenLength;
|
|
RPC_STATUS RpcStatus;
|
|
sec_trailer PAPI * SecurityTrailer;
|
|
SECURITY_BUFFER_DESCRIPTOR BufferDescriptor;
|
|
SECURITY_BUFFER SecurityBuffers[4];
|
|
DCE_INIT_SECURITY_INFO InitSecurityInfo;
|
|
unsigned int CompleteNeeded = 0;
|
|
|
|
BindPacketLength = sizeof(rpcconn_bind) + sizeof(p_cont_list_t) +
|
|
(TransferSyntaxCount - 1) * sizeof(p_syntax_id_t);
|
|
|
|
// If we need to send authentication information in the packet, we
|
|
// need to save space for it. This method prepares and sends both
|
|
// rpc_bind and rpc_alter_context packets; we will only send
|
|
// authentication information in rpc_bind packets. This is due to
|
|
// a design decision that each connection supports only a single
|
|
// security context, which is determined when the connection is
|
|
// created.
|
|
|
|
if ( ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE )
|
|
{
|
|
ASSERT( (ClientSecurityContext.AuthenticationLevel
|
|
== RPC_C_AUTHN_LEVEL_CONNECT)
|
|
|| (ClientSecurityContext.AuthenticationLevel
|
|
== RPC_C_AUTHN_LEVEL_PKT)
|
|
|| (ClientSecurityContext.AuthenticationLevel
|
|
== RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
|
|
|| (ClientSecurityContext.AuthenticationLevel
|
|
== RPC_C_AUTHN_LEVEL_PKT_PRIVACY) );
|
|
|
|
RpcStatus = UuidCreate(&(DceSecurityInfo.AssociationUuid));
|
|
if ( (RpcStatus != RPC_S_OK )
|
|
&& (RpcStatus != RPC_S_UUID_LOCAL_ONLY) )
|
|
{
|
|
return(RpcStatus);
|
|
}
|
|
|
|
// We align the packet length to a four byte boundary, and then
|
|
// save space for the token and the sec_trailer. We also need
|
|
// to save the length of the token because we will need it later
|
|
// if we do third leg authentication.
|
|
|
|
AuthPadLength = Pad4(BindPacketLength);
|
|
BindPacketLength += AuthPadLength;
|
|
TokenLength = ClientSecurityContext.Credentials->MaximumTokenLength();
|
|
BindPacketLength += TokenLength + sizeof(sec_trailer);
|
|
}
|
|
|
|
RpcStatus = TransGetBuffer((void PAPI * PAPI *) &BindPacket,
|
|
BindPacketLength);
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY );
|
|
if ( ( PacketType == rpc_bind )
|
|
&& ( ClientSecurityContext.AuthenticationLevel
|
|
!= RPC_C_AUTHN_LEVEL_NONE ) )
|
|
{
|
|
;
|
|
}
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
ConstructPacket((rpcconn_common PAPI *) BindPacket, PacketType,
|
|
BindPacketLength);
|
|
|
|
BindPacket->max_xmit_frag = BindPacket->max_recv_frag
|
|
= (unsigned short) TransMaximumSend();
|
|
BindPacket->assoc_group_id = AssocGroup;
|
|
|
|
ConstructPContextList((p_cont_list_t PAPI *) (BindPacket + 1),
|
|
InterfaceSyntax, TransferSyntaxes, TransferSyntaxCount,
|
|
PresentContext);
|
|
|
|
// If this connection is using security, we need to stick the
|
|
// authentication information into the packet.
|
|
|
|
if ( ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE )
|
|
{
|
|
InitSecurityInfo.DceSecurityInfo = DceSecurityInfo;
|
|
InitSecurityInfo.AuthorizationService =
|
|
ClientSecurityContext.AuthorizationService;
|
|
InitSecurityInfo.PacketType = PacketType;
|
|
BufferDescriptor.ulVersion = 0;
|
|
BufferDescriptor.cBuffers = 4;
|
|
BufferDescriptor.pBuffers = SecurityBuffers;
|
|
SecurityBuffers[0].cbBuffer = sizeof(rpcconn_bind);
|
|
SecurityBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
|
SecurityBuffers[0].pvBuffer = BindPacket;
|
|
SecurityBuffers[1].cbBuffer = BindPacketLength - sizeof(rpcconn_bind)
|
|
- ClientSecurityContext.Credentials->MaximumTokenLength();
|
|
SecurityBuffers[1].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
|
SecurityBuffers[1].pvBuffer = ((unsigned char PAPI *) BindPacket)
|
|
+ sizeof(rpcconn_bind);
|
|
SecurityBuffers[2].cbBuffer =
|
|
ClientSecurityContext.Credentials->MaximumTokenLength();
|
|
SecurityBuffers[2].BufferType = SECBUFFER_TOKEN;
|
|
SecurityBuffers[2].pvBuffer = ((unsigned char PAPI *) BindPacket)
|
|
+ BindPacketLength -
|
|
ClientSecurityContext.Credentials->MaximumTokenLength();
|
|
SecurityBuffers[3].cbBuffer = sizeof(DCE_INIT_SECURITY_INFO);
|
|
SecurityBuffers[3].BufferType = SECBUFFER_PKG_PARAMS | SECBUFFER_READONLY;
|
|
SecurityBuffers[3].pvBuffer = &InitSecurityInfo;
|
|
|
|
// Let the security packet take care of sticking appropriate stuff
|
|
// into the packet for us.
|
|
|
|
if (PacketType == rpc_bind)
|
|
{
|
|
RpcStatus = ClientSecurityContext.InitializeFirstTime(
|
|
ClientSecurityContext.Credentials,
|
|
ClientSecurityContext.ServerPrincipalName,
|
|
ClientSecurityContext.AuthenticationLevel,
|
|
&BufferDescriptor);
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// a third leg auth may not be needed with some packages
|
|
// on an alter context [where only pcon is changed as opposed
|
|
// to an alternative client principal
|
|
//
|
|
ThirdLegAuthNeeded = 0;
|
|
|
|
RpcStatus = ClientSecurityContext.InitializeThirdLeg(
|
|
*((unsigned long PAPI *)&(BindPacket->common.drep[0])),
|
|
0L,
|
|
&BufferDescriptor);
|
|
}
|
|
|
|
if ( RpcStatus == RPC_P_CONTINUE_NEEDED )
|
|
{
|
|
// Remember the fact that the security package requested that
|
|
// it be called again. This will be important later: see
|
|
// OSF_CASSOCIATION::ActuallyDoBinding.
|
|
|
|
ThirdLegAuthNeeded = 1;
|
|
}
|
|
else if ( RpcStatus == RPC_P_COMPLETE_NEEDED )
|
|
{
|
|
CompleteNeeded = 1;
|
|
}
|
|
else if ( RpcStatus == RPC_P_COMPLETE_AND_CONTINUE )
|
|
{
|
|
ThirdLegAuthNeeded = 1;
|
|
CompleteNeeded = 1;
|
|
}
|
|
else if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
ASSERT( (RpcStatus == RPC_S_OUT_OF_MEMORY)
|
|
|| (RpcStatus == RPC_S_ACCESS_DENIED)
|
|
|| (RpcStatus == RPC_S_SEC_PKG_ERROR) );
|
|
TransFreeBuffer(BindPacket);
|
|
return(RpcStatus);
|
|
}
|
|
SecurityTokenLength = (unsigned int) SecurityBuffers[2].cbBuffer;
|
|
|
|
// We need to fill in the fields of the security trailer.
|
|
|
|
SecurityTrailer = (sec_trailer PAPI *)
|
|
(((unsigned char PAPI *) BindPacket) + BindPacketLength
|
|
- ClientSecurityContext.Credentials->MaximumTokenLength()
|
|
- sizeof(sec_trailer));
|
|
|
|
SecurityTrailer->auth_type = (unsigned char)
|
|
ClientSecurityContext.AuthenticationService;
|
|
SecurityTrailer->auth_level = (unsigned char)
|
|
ClientSecurityContext.AuthenticationLevel;
|
|
SecurityTrailer->auth_pad_length = AuthPadLength;
|
|
SecurityTrailer->auth_reserved = 0;
|
|
SecurityTrailer->auth_context_id = (unsigned long)(this);
|
|
|
|
// Ok, finally, we need to adjust the length of the packet,
|
|
// and set the length of the authentication information.
|
|
|
|
BindPacket->common.auth_length = SecurityTokenLength;
|
|
BindPacketLength = BindPacketLength
|
|
- ClientSecurityContext.Credentials->MaximumTokenLength()
|
|
+ SecurityTokenLength;
|
|
BindPacket->common.frag_length = BindPacketLength;
|
|
BindPacket->assoc_group_id = AssocGroup;
|
|
|
|
if ( CompleteNeeded != 0 )
|
|
{
|
|
RpcStatus = ClientSecurityContext.CompleteSecurityToken(
|
|
&BufferDescriptor);
|
|
if (RpcStatus != 0)
|
|
{
|
|
TransFreeBuffer(BindPacket);
|
|
return(RpcStatus);
|
|
}
|
|
}
|
|
}
|
|
|
|
RpcStatus = TransSendReceiveWithTimeout(BindPacket, BindPacketLength,
|
|
Buffer, BufferLength, RPC_BIND_TIMEOUT);
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
ASSERT( (RpcStatus == RPC_S_OUT_OF_MEMORY)
|
|
|| (RpcStatus == RPC_S_ACCESS_DENIED)
|
|
|| (RpcStatus == RPC_S_OUT_OF_RESOURCES)
|
|
|| (RpcStatus == RPC_P_CONNECTION_CLOSED)
|
|
|| (RpcStatus == RPC_P_RECEIVE_FAILED)
|
|
|| (RpcStatus == RPC_P_SEND_FAILED));
|
|
|
|
TransFreeBuffer(BindPacket);
|
|
if ( (RpcStatus == RPC_P_RECEIVE_FAILED)
|
|
|| (RpcStatus == RPC_P_SEND_FAILED))
|
|
{
|
|
return(RPC_P_CONNECTION_CLOSED);
|
|
}
|
|
return(RpcStatus);
|
|
}
|
|
|
|
TransFreeBuffer(BindPacket);
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
void
|
|
OSF_CCONNECTION::SetMaxFrag (
|
|
IN unsigned short max_xmit_frag,
|
|
IN unsigned short max_recv_frag
|
|
)
|
|
{
|
|
UNUSED(max_recv_frag);
|
|
|
|
unsigned short TranMax = TransMaximumSend();
|
|
|
|
MaxFrag = max_xmit_frag;
|
|
|
|
if (MaxFrag > TranMax || MaxFrag == 0)
|
|
{
|
|
MaxFrag = TranMax;
|
|
}
|
|
|
|
#ifndef WIN
|
|
ASSERT( MaxFrag >= MUST_RECV_FRAG_SIZE );
|
|
#endif // WIN
|
|
}
|
|
|
|
|
|
void
|
|
OSF_CCONNECTION::FreeConnection (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to free a connection when the original remote
|
|
procedure call using it completes.
|
|
|
|
--*/
|
|
{
|
|
OSF_BINDING_HANDLE * Binding;
|
|
|
|
ASSERT(CurrentBinding != 0);
|
|
|
|
Binding = CurrentBinding;
|
|
CurrentBinding = 0;
|
|
Binding->FreeConnection(this);
|
|
}
|
|
|
|
|
|
void
|
|
OSF_CCONNECTION::AbortConnection (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Any time that an error occurs while a remote procedure call is using
|
|
this connection, this routine will be called. We need to indicate that
|
|
the connection has been aborted, and in addition, if all calls using
|
|
this connection have completed, we need to delete it.
|
|
|
|
--*/
|
|
{
|
|
OSF_BINDING_HANDLE * Binding;
|
|
|
|
if ( ConnectionAbortedFlag == 0 )
|
|
{
|
|
ConnectionAbortedFlag = 1;
|
|
Association->NotifyConnectionClosed();
|
|
}
|
|
|
|
if (CallStack == 0 )
|
|
{
|
|
ASSERT( CurrentBinding != 0 );
|
|
ASSERT( OutstandingBuffers == 0);
|
|
#ifdef DEBUGRPC
|
|
if ( OutstandingBuffers != 0 )
|
|
{
|
|
PrintToDebugger("RPCCLNT: OutstandingBuffers != 0\n");
|
|
}
|
|
#endif // DEBUGRPC
|
|
|
|
Binding = CurrentBinding;
|
|
CurrentBinding = 0;
|
|
Binding->AbortConnection(this);
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
|
|
OSF_CCONNECTION::OSF_CCONNECTION (
|
|
CLIENT_AUTH_INFO * ClientAuthInfo,
|
|
RPC_STATUS __RPC_FAR * pStatus
|
|
)
|
|
: CCONNECTION(ClientAuthInfo, pStatus),
|
|
ClientSecurityContext(ClientAuthInfo, pStatus)
|
|
{
|
|
#ifndef NTENV
|
|
|
|
int AmountOfPad;
|
|
|
|
#endif // NTENV
|
|
|
|
Association = 0;
|
|
MaxFrag = 512;
|
|
AssociationKey = -1;
|
|
CurrentBinding = Nil;
|
|
OutstandingBuffers = 0;
|
|
CallStack = 0;
|
|
CallId = 0xFFFFFFFF;
|
|
ConnectionAbortedFlag = 0;
|
|
|
|
ThirdLegAuthNeeded = 0;
|
|
AdditionalSpaceForSecurity = 0;
|
|
LastTimeUsed = 0;
|
|
|
|
PendingAlert = FALSE;
|
|
AlertsEnabled = 0;
|
|
DceSecurityInfo.SendSequenceNumber = 0;
|
|
DceSecurityInfo.ReceiveSequenceNumber = 0;
|
|
|
|
// Ok, try and allocate the cached buffers.
|
|
|
|
#ifdef NTENV
|
|
|
|
FirstCachedBuffer = (int PAPI *) RpcpFarAllocate(CACHED_BUFFER_LENGTH * 2);
|
|
|
|
#else // NTENV
|
|
|
|
FirstCachedBuffer = (int PAPI *) RpcpFarAllocate(CACHED_BUFFER_LENGTH * 2
|
|
+ ALIGN_REQUIRED);
|
|
|
|
#endif // NTENV
|
|
|
|
if ( FirstCachedBuffer == 0 )
|
|
{
|
|
BufferCacheFlags = 0;
|
|
SecondCachedBuffer = 0;
|
|
}
|
|
else
|
|
{
|
|
#ifndef NTENV
|
|
|
|
ASSERT( (((long) FirstCachedBuffer) % sizeof(int)) == 0 );
|
|
|
|
AmountOfPad = Pad((char __RPC_FAR *)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);
|
|
BufferCacheFlags = FIRST_CACHED_BUFFER_AVAILABLE
|
|
| SECOND_CACHED_BUFFER_AVAILABLE | CACHED_BUFFERS_ALLOCATED;
|
|
ASSERT(Pad8(SecondCachedBuffer) == 0);
|
|
}
|
|
|
|
SavedHeader = 0;
|
|
SavedHeaderSize = 0;
|
|
FirstFrag = 1 ;
|
|
FirstReceive = 1 ;
|
|
EnableCancels = 0;
|
|
}
|
|
|
|
OSF_CCONNECTION::~OSF_CCONNECTION (
|
|
)
|
|
{
|
|
if ( ConnectionAbortedFlag == 0 )
|
|
{
|
|
if ( Association != 0 )
|
|
{
|
|
Association->NotifyConnectionClosed();
|
|
}
|
|
}
|
|
if ( BufferCacheFlags & CACHED_BUFFERS_ALLOCATED )
|
|
{
|
|
RpcpFarFree(UnAlignBuffer(FirstCachedBuffer));
|
|
}
|
|
|
|
if (SavedHeader != 0)
|
|
{
|
|
ASSERT(SavedHeaderSize != 0);
|
|
RpcpFarFree(SavedHeader);
|
|
}
|
|
|
|
if (EnableCancels)
|
|
{
|
|
EVAL_AND_ASSERT(RPC_S_OK == UnregisterForCancels());
|
|
}
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::MaybeDo3rdLegAuth (
|
|
IN void PAPI * Buffer,
|
|
IN unsigned int BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We use this method to deal with third leg authentication if necessary.
|
|
In addition, we do error checking for whether or not there should be
|
|
security information in the packet.
|
|
|
|
Arguments:
|
|
|
|
Buffer - Supplies an rpc_bind_ack or rpc_bind_nak packet which may or
|
|
may not contain some authentication information.
|
|
|
|
BufferLength - Supplies the length of the buffer in bytes.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - Everything proceeded as expected.
|
|
|
|
RPC_S_PROTOCOL_ERROR - The server either specified authentication
|
|
information when none was expected, or did not specify some when
|
|
we expected some.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient space is available to allocate
|
|
the third leg
|
|
|
|
RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to
|
|
send the third leg authentication packet to the server.
|
|
|
|
RPC_S_ACCESS_DENIED - We are unable to access the server for security
|
|
related reasons.
|
|
|
|
RPC_P_CONNECTION_CLOSED - The connection has closed.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
unsigned int AuthThirdLegPacketLength, SecurityTokenLength;
|
|
rpcconn_auth3 PAPI * AuthThirdLegPacket;
|
|
sec_trailer PAPI * SecurityTrailer;
|
|
SECURITY_BUFFER_DESCRIPTOR InputBufferDescriptor;
|
|
SECURITY_BUFFER_DESCRIPTOR OutputBufferDescriptor;
|
|
SECURITY_BUFFER InputBuffers[4];
|
|
SECURITY_BUFFER OutputBuffers[4];
|
|
DCE_INIT_SECURITY_INFO InitSecurityInfo;
|
|
unsigned int CompleteNeeded = 0;
|
|
|
|
// To begin with, check to see if there is not authentication information
|
|
// in the packet; if there is not, we need to check to see if there
|
|
// should have been some.
|
|
|
|
if ( ((rpcconn_common PAPI *) Buffer)->auth_length == 0 )
|
|
{
|
|
if ( ThirdLegAuthNeeded != 0 )
|
|
{
|
|
// We have got a problem: there should have been some
|
|
// authentication information in this packet, but there is not.
|
|
|
|
return(RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
// Now we need to allocate an rpc_auth3 packet to send the security
|
|
// information back to the server. We do not need padding, because
|
|
// the rpc_auth3 packet is already aligned.
|
|
|
|
ASSERT( Pad4(sizeof(rpcconn_auth3)) == 0 );
|
|
AuthThirdLegPacketLength = sizeof(rpcconn_auth3) + sizeof(sec_trailer)
|
|
+ TokenLength;
|
|
|
|
RpcStatus = TransGetBuffer((void PAPI * PAPI *) &AuthThirdLegPacket,
|
|
AuthThirdLegPacketLength);
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY );
|
|
return(RpcStatus);
|
|
}
|
|
|
|
ConstructPacket((rpcconn_common PAPI *) AuthThirdLegPacket, rpc_auth_3,
|
|
AuthThirdLegPacketLength);
|
|
|
|
SecurityTrailer = (sec_trailer PAPI *) (AuthThirdLegPacket + 1);
|
|
|
|
InitSecurityInfo.DceSecurityInfo = DceSecurityInfo;
|
|
InitSecurityInfo.AuthorizationService = AuthInfo.AuthorizationService;
|
|
InitSecurityInfo.PacketType = ((rpcconn_common PAPI *) Buffer)->PTYPE;
|
|
InputBufferDescriptor.ulVersion = 0;
|
|
InputBufferDescriptor.cBuffers = 4;
|
|
InputBufferDescriptor.pBuffers = InputBuffers;
|
|
ASSERT((SavedHeader != 0) && (SavedHeaderSize != 0));
|
|
|
|
InputBuffers[0].cbBuffer = sizeof(rpcconn_bind_ack)
|
|
- sizeof(unsigned short);
|
|
InputBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
|
InputBuffers[0].pvBuffer = SavedHeader;
|
|
|
|
InputBuffers[1].cbBuffer = BufferLength - (sizeof(rpcconn_bind_ack)
|
|
- sizeof(unsigned short))
|
|
- ((rpcconn_common PAPI *) Buffer)->auth_length;
|
|
InputBuffers[1].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
|
InputBuffers[1].pvBuffer = ((unsigned char PAPI *) SavedHeader)
|
|
+ sizeof(rpcconn_bind_ack) - sizeof(unsigned short);
|
|
|
|
InputBuffers[2].cbBuffer = ((rpcconn_common PAPI *) Buffer)->auth_length;
|
|
InputBuffers[2].BufferType = SECBUFFER_TOKEN;
|
|
InputBuffers[2].pvBuffer = ((unsigned char PAPI *) Buffer)
|
|
+ BufferLength - ((rpcconn_common PAPI *) Buffer)->auth_length;
|
|
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_auth3);
|
|
OutputBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
|
OutputBuffers[0].pvBuffer = AuthThirdLegPacket;
|
|
OutputBuffers[1].cbBuffer = sizeof(sec_trailer);
|
|
OutputBuffers[1].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
|
OutputBuffers[1].pvBuffer = ((unsigned char PAPI *) AuthThirdLegPacket)
|
|
+ sizeof(rpcconn_auth3);
|
|
OutputBuffers[2].cbBuffer = TokenLength;
|
|
OutputBuffers[2].BufferType = SECBUFFER_TOKEN;
|
|
OutputBuffers[2].pvBuffer = SecurityTrailer + 1;
|
|
OutputBuffers[3].cbBuffer = sizeof(DCE_INIT_SECURITY_INFO);
|
|
OutputBuffers[3].BufferType = SECBUFFER_PKG_PARAMS | SECBUFFER_READONLY;
|
|
OutputBuffers[3].pvBuffer = &InitSecurityInfo;
|
|
|
|
RpcStatus = ClientSecurityContext.InitializeThirdLeg(
|
|
*((unsigned long PAPI *) ((rpcconn_common PAPI *)
|
|
Buffer)->drep), &InputBufferDescriptor, &OutputBufferDescriptor);
|
|
|
|
SecurityTokenLength = (unsigned int) OutputBuffers[2].cbBuffer;
|
|
|
|
if ( RpcStatus == RPC_P_COMPLETE_NEEDED )
|
|
{
|
|
CompleteNeeded = 1;
|
|
}
|
|
else if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
TransFreeBuffer(AuthThirdLegPacket);
|
|
|
|
ASSERT( (RpcStatus == RPC_S_ACCESS_DENIED)
|
|
|| (RpcStatus == RPC_S_OUT_OF_MEMORY)
|
|
|| (RpcStatus == RPC_S_SEC_PKG_ERROR));
|
|
return(RpcStatus);
|
|
}
|
|
//Now that we accepted the packet bump up the recv #
|
|
DceSecurityInfo.ReceiveSequenceNumber += 1;
|
|
|
|
if ( ThirdLegAuthNeeded != 0 )
|
|
{
|
|
SecurityTrailer->auth_type = (unsigned char)
|
|
AuthInfo.AuthenticationService;
|
|
SecurityTrailer->auth_level = (unsigned char)
|
|
AuthInfo.AuthenticationLevel;
|
|
SecurityTrailer->auth_pad_length = 0;
|
|
SecurityTrailer->auth_reserved = 0;
|
|
SecurityTrailer->auth_context_id = (unsigned long) this;
|
|
|
|
AuthThirdLegPacket->common.auth_length = SecurityTokenLength;
|
|
AuthThirdLegPacketLength = AuthThirdLegPacketLength - TokenLength
|
|
+ SecurityTokenLength;
|
|
AuthThirdLegPacket->common.frag_length = AuthThirdLegPacketLength;
|
|
|
|
if ( CompleteNeeded != 0 )
|
|
{
|
|
ClientSecurityContext.CompleteSecurityToken(
|
|
&OutputBufferDescriptor);
|
|
}
|
|
RpcStatus = TransSend(AuthThirdLegPacket, AuthThirdLegPacketLength);
|
|
|
|
// BUGBUG - Due to a bug in NT named pipes, if you do not delay, the
|
|
// receive operation will fail.
|
|
|
|
#ifdef NTENV
|
|
|
|
PauseExecution(0L);
|
|
|
|
#endif // NTENV
|
|
TransFreeBuffer(AuthThirdLegPacket);
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
if ( (RpcStatus == RPC_P_CONNECTION_CLOSED)
|
|
|| (RpcStatus == RPC_P_SEND_FAILED) )
|
|
{
|
|
return(RPC_P_CONNECTION_CLOSED);
|
|
}
|
|
ASSERT( (RpcStatus == RPC_S_OUT_OF_MEMORY)
|
|
|| (RpcStatus == RPC_S_OUT_OF_RESOURCES) );
|
|
return(RpcStatus);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TransFreeBuffer(AuthThirdLegPacket);
|
|
}
|
|
|
|
// This is as good a place as any to figure out how much additional
|
|
// space we need to reserve in each buffer for security information.
|
|
|
|
|
|
ASSERT( AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE );
|
|
|
|
// 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.
|
|
|
|
switch ( AuthInfo.AuthenticationLevel )
|
|
{
|
|
|
|
case RPC_C_AUTHN_LEVEL_CONNECT:
|
|
case RPC_C_AUTHN_LEVEL_PKT:
|
|
case RPC_C_AUTHN_LEVEL_PKT_INTEGRITY:
|
|
AdditionalSpaceForSecurity = MAXIMUM_SECURITY_BLOCK_SIZE +
|
|
ClientSecurityContext.MaximumSignatureLength()
|
|
+ sizeof(sec_trailer);
|
|
break;
|
|
|
|
case RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
|
|
AdditionalSpaceForSecurity = MAXIMUM_SECURITY_BLOCK_SIZE +
|
|
ClientSecurityContext.MaximumHeaderLength()
|
|
+ sizeof(sec_trailer);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(!"Unknown Security Level\n");
|
|
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
inline int
|
|
OSF_CCONNECTION::SupportedAuthInfo (
|
|
IN CLIENT_AUTH_INFO * ClientAuthInfo
|
|
)
|
|
/*++
|
|
|
|
Arguments:
|
|
|
|
ClientAuthInfo - Supplies the authentication and authorization information
|
|
required of this connection. A value of zero (the pointer is
|
|
zero) indicates that we want an unauthenticated connection.
|
|
|
|
Return Value:
|
|
|
|
Non-zero indicates that the connection has the requested authentication
|
|
and authorization information; otherwise, zero will be returned.
|
|
|
|
--*/
|
|
{
|
|
return (ClientSecurityContext.IsSupportedAuthInfo(ClientAuthInfo));
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::SetAuthInformation (
|
|
IN CLIENT_AUTH_INFO * ClientAuthInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We need to use this routine to initialize the authentication and
|
|
authorization information for this connection.
|
|
|
|
Arguments:
|
|
|
|
ClientAuthInfo - Supplies the authentication and authorization information
|
|
to use.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - Everybody's happy.
|
|
|
|
RPC_S_OUT_OF_MEMORY - We were unable to make a copy of the server
|
|
principal name.
|
|
|
|
--*/
|
|
{
|
|
AuthInfo = *ClientAuthInfo;
|
|
if ( ClientAuthInfo->ServerPrincipalName != 0 )
|
|
{
|
|
AuthInfo.ServerPrincipalName = DuplicateString(
|
|
ClientAuthInfo->ServerPrincipalName);
|
|
if ( AuthInfo.ServerPrincipalName == 0 )
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
/* --------------------------------------------------------------------
|
|
-------------------------------------------------------------------- */
|
|
|
|
NEW_SDICT(OSF_CASSOCIATION);
|
|
|
|
static OSF_CASSOCIATION_DICT * AssociationDict;
|
|
|
|
/* --------------------------------------------------------------------
|
|
-------------------------------------------------------------------- */
|
|
|
|
|
|
OSF_CASSOCIATION::OSF_CASSOCIATION (
|
|
IN DCE_BINDING * DceBinding,
|
|
IN RPC_CLIENT_TRANSPORT_INFO * RpcClientInfo,
|
|
IN OUT RPC_STATUS PAPI * RpcStatus
|
|
) : AssociationMutex(RpcStatus), CallIdCounter(1)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We construct a OSF_CASSOCIATION object in this routine. This consists
|
|
of initializing some instance variables, and saving the parameters
|
|
away.
|
|
|
|
Arguments:
|
|
|
|
DceBinding - Supplies the binding information for this association.
|
|
Ownership of this data passes to this object.
|
|
|
|
RpcClientInfo - Supplies the information necessary to use the loadable
|
|
transport corresponding to the network interface type used by
|
|
this association.
|
|
|
|
--*/
|
|
{
|
|
ALLOCATE_THIS(OSF_CASSOCIATION);
|
|
|
|
BindHandleCount = 1;
|
|
AssocGroupId = 0;
|
|
|
|
this->DceBinding = DceBinding;
|
|
this->RpcClientInfo = RpcClientInfo;
|
|
|
|
SecondaryEndpoint = 0;
|
|
OpenConnectionCount = 0;
|
|
|
|
MaintainContext = 0;
|
|
|
|
#ifdef WIN
|
|
TaskId = GetCurrentTask();
|
|
#endif
|
|
AssociationValid = TRUE ;
|
|
FailureCount = 0;
|
|
}
|
|
|
|
OSF_CASSOCIATION::~OSF_CASSOCIATION (
|
|
)
|
|
{
|
|
OSF_BINDING * Binding;
|
|
OSF_CCONNECTION * CConnection;
|
|
|
|
if (DceBinding != 0)
|
|
{
|
|
delete DceBinding;
|
|
}
|
|
|
|
Bindings.Reset();
|
|
while ((Binding = Bindings.Next()))
|
|
delete Binding;
|
|
|
|
FreeConnections.Reset();
|
|
while ((CConnection = FreeConnections.Next()))
|
|
{
|
|
delete CConnection;
|
|
}
|
|
|
|
if ( SecondaryEndpoint != 0 )
|
|
{
|
|
delete SecondaryEndpoint;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
OSF_CASSOCIATION::NotifyConnectionClosed (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is necessary so that we can know when to set the association
|
|
group id back to zero. We do this when no more connections owned by
|
|
this association can possibly be connected with the server.
|
|
|
|
--*/
|
|
{
|
|
RequestGlobalMutex();
|
|
|
|
ASSERT( OpenConnectionCount > 0 );
|
|
|
|
OpenConnectionCount -= 1;
|
|
if ( OpenConnectionCount == 0 )
|
|
{
|
|
AssocGroupId = 0;
|
|
}
|
|
|
|
ClearGlobalMutex();
|
|
}
|
|
|
|
RPC_STATUS
|
|
OSF_CASSOCIATION::ProcessBindAckOrNak (
|
|
IN rpcconn_common PAPI * Buffer,
|
|
IN unsigned int BufferLength,
|
|
IN OSF_CCONNECTION * CConnection
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Buffer - Supplies the buffer containing either the bind_ack, bind_nak,
|
|
or alter_context_resp packet.
|
|
|
|
BufferLength - Supplies the length of the buffer, less the length of
|
|
the authorization information.
|
|
|
|
CConnection - Supplies the connection from which we received the packet.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - The client has successfully bound with the server.
|
|
|
|
RPC_S_PROTOCOL_ERROR - The packet received from the server does not
|
|
follow the protocol.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to make a
|
|
copy of the secondary endpoint.
|
|
|
|
RPC_S_UNSUPPORTED_TRANS_SYN - The transfer syntax supplied by the client
|
|
is not supported by the server.
|
|
|
|
RPC_S_UNKNOWN_IF - The interface to which the client wished to bind is not
|
|
supported by the server.
|
|
|
|
RPC_S_SERVER_TOO_BUSY - The server is too busy to accept the clients
|
|
bind request.
|
|
|
|
RPC_S_UNKNOWN_AUTHN_TYPE - The server does not support the authentication
|
|
type specified by the client.
|
|
|
|
--*/
|
|
{
|
|
rpcconn_bind_ack PAPI *pBindAck;
|
|
rpcconn_bind_nak PAPI *pBindNak;
|
|
p_result_list_t PAPI *pResults;
|
|
int port_spec_plus_pad;
|
|
unsigned int SecondaryEndpointLength;
|
|
unsigned char PAPI * Pointer;
|
|
|
|
// The common header of the packet has already been validated and data
|
|
// converted, if necessary, by whoever called this method.
|
|
|
|
if ( (Buffer->PTYPE == rpc_bind_ack)
|
|
|| (Buffer->PTYPE == rpc_alter_context_resp))
|
|
{
|
|
FailureCount = 0;
|
|
|
|
// The bind_ack and alter_context_resp packets are the same.
|
|
|
|
pBindAck = (rpcconn_bind_ack PAPI *) Buffer;
|
|
|
|
// We need to convert the max_xmit_frag, max_recv_frag, and
|
|
// assoc_group_id fields of the packet.
|
|
|
|
if ( DataConvertEndian(Buffer->drep) != 0 )
|
|
{
|
|
ByteSwapShort(pBindAck->max_xmit_frag);
|
|
ByteSwapShort(pBindAck->max_recv_frag);
|
|
ByteSwapLong(pBindAck->assoc_group_id);
|
|
ByteSwapShort(pBindAck->sec_addr_length);
|
|
}
|
|
|
|
if ( Buffer->PTYPE == rpc_bind_ack )
|
|
{
|
|
CConnection->SetMaxFrag(pBindAck->max_xmit_frag,
|
|
pBindAck->max_recv_frag);
|
|
}
|
|
|
|
BufferLength -= sizeof(rpcconn_bind_ack);
|
|
Pointer = (unsigned char PAPI *) (pBindAck + 1);
|
|
|
|
if ( pBindAck->sec_addr_length )
|
|
{
|
|
SecondaryEndpointLength = pBindAck->sec_addr_length;
|
|
|
|
// The secondary address length is two bytes long. We want
|
|
// to align the total of the secondary address length itself,
|
|
// the the secondary address. Hence, the length of the secondary
|
|
// address and the necessary pad is calculated below. Think
|
|
// very carefully before changing this piece of code.
|
|
|
|
port_spec_plus_pad = SecondaryEndpointLength +
|
|
Pad4(SecondaryEndpointLength + 2);
|
|
|
|
if ( BufferLength < (unsigned int) port_spec_plus_pad )
|
|
{
|
|
return(RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
|
|
if ( SecondaryEndpoint != 0 )
|
|
{
|
|
delete SecondaryEndpoint;
|
|
}
|
|
|
|
SecondaryEndpoint = new unsigned char[SecondaryEndpointLength];
|
|
|
|
if ( SecondaryEndpoint == 0 )
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
|
|
RpcpMemoryCopy(SecondaryEndpoint, Pointer, SecondaryEndpointLength);
|
|
if ( DataConvertCharacter(Buffer->drep) != 0 )
|
|
{
|
|
ConvertStringEbcdicToAscii(SecondaryEndpoint);
|
|
}
|
|
|
|
BufferLength -= port_spec_plus_pad;
|
|
Pointer = Pointer + port_spec_plus_pad;
|
|
}
|
|
else
|
|
{
|
|
Pointer = Pointer + 2;
|
|
BufferLength -= 2;
|
|
}
|
|
|
|
pResults = (p_result_list_t PAPI*) Pointer;
|
|
if ( BufferLength < sizeof(p_result_list_t) )
|
|
{
|
|
return(RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
|
|
if ( DataConvertEndian(Buffer->drep) != 0 )
|
|
{
|
|
ByteSwapShort(pResults->p_results[0].result);
|
|
ByteSwapShort(pResults->p_results[0].reason);
|
|
ByteSwapSyntaxId(&(pResults->p_results[0].transfer_syntax));
|
|
}
|
|
|
|
if ( pResults->n_results != 1 )
|
|
{
|
|
return(RPC_S_UNSUPPORTED_TRANS_SYN);
|
|
}
|
|
|
|
if ( pResults->p_results[0].result != acceptance )
|
|
{
|
|
if ( pResults->p_results[0].result != provider_rejection )
|
|
{
|
|
return(RPC_S_CALL_FAILED_DNE);
|
|
}
|
|
|
|
if ( pResults->p_results[0].reason
|
|
== abstract_syntax_not_supported)
|
|
{
|
|
return(RPC_S_UNKNOWN_IF);
|
|
}
|
|
|
|
if ( pResults->p_results[0].reason ==
|
|
proposed_transfer_syntaxes_not_supported )
|
|
{
|
|
return(RPC_S_UNSUPPORTED_TRANS_SYN);
|
|
}
|
|
|
|
if ( pResults->p_results[0].reason == local_limit_exceeded )
|
|
{
|
|
return(RPC_S_SERVER_TOO_BUSY);
|
|
}
|
|
|
|
return(RPC_S_CALL_FAILED_DNE);
|
|
}
|
|
|
|
// Once we reach here, we know that the binding has been excepted,
|
|
// so we can go ahead and set the association group id.
|
|
// warning: as soon as the AssocGroupId is set, threads
|
|
// will start sending the bind without acquiring the mutex
|
|
if ( Buffer->PTYPE == rpc_bind_ack )
|
|
{
|
|
AssocGroupId = pBindAck->assoc_group_id;
|
|
}
|
|
}
|
|
else if (Buffer->PTYPE == rpc_bind_nak)
|
|
{
|
|
|
|
//
|
|
// BUGBUG: Fix Osfpcket.cxx to pack!
|
|
// 21 bytes is the minimum BINDNAK
|
|
//
|
|
if (BufferLength < 21)
|
|
{
|
|
return(RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
|
|
pBindNak = (rpcconn_bind_nak PAPI *) Buffer;
|
|
|
|
if ( DataConvertEndian(Buffer->drep) != 0 )
|
|
{
|
|
ByteSwapShort(pBindNak->provider_reject_reason);
|
|
}
|
|
|
|
if ( (pBindNak->provider_reject_reason == temporary_congestion)
|
|
|| (pBindNak->provider_reject_reason
|
|
== local_limit_exceeded_reject))
|
|
{
|
|
return(RPC_S_SERVER_TOO_BUSY);
|
|
}
|
|
|
|
if ( pBindNak->provider_reject_reason
|
|
== protocol_version_not_supported )
|
|
{
|
|
return(RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
|
|
if ( pBindNak->provider_reject_reason
|
|
== authentication_type_not_recognized )
|
|
{
|
|
return(RPC_S_UNKNOWN_AUTHN_SERVICE);
|
|
}
|
|
|
|
if ( pBindNak->provider_reject_reason
|
|
== invalid_checksum )
|
|
{
|
|
return(RPC_S_ACCESS_DENIED);
|
|
}
|
|
|
|
FailureCount++ ;
|
|
if (FailureCount >= 5)
|
|
{
|
|
AssociationValid = FALSE ;
|
|
}
|
|
|
|
return(RPC_S_CALL_FAILED_DNE);
|
|
}
|
|
else
|
|
{
|
|
return(RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CASSOCIATION::PingServer(
|
|
)
|
|
{
|
|
RPC_STATUS RpcStatus ;
|
|
OSF_CCONNECTION * CConnection;
|
|
|
|
RpcStatus = RPC_S_OK;
|
|
|
|
CConnection = new(0, RpcClientInfo->SizeOfConnection)
|
|
TRANS_CCONNECTION(
|
|
RpcClientInfo,
|
|
DceBinding->InqNetworkAddress(),
|
|
DceBinding->InqEndpoint(),
|
|
DceBinding->InqNetworkOptions(),
|
|
DceBinding->InqRpcProtocolSequence(),
|
|
&RpcStatus,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if (CConnection != 0)
|
|
{
|
|
delete CConnection ;
|
|
}
|
|
|
|
return RpcStatus ;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CASSOCIATION::ActuallyDoBinding (
|
|
IN PRPC_SYNTAX_IDENTIFIER InterfaceSyntax,
|
|
IN PRPC_SYNTAX_IDENTIFIER TransferSyntaxes,
|
|
IN unsigned int TransferSyntaxCount,
|
|
OUT OSF_CCONNECTION * PAPI * TheCConnection,
|
|
IN int PresentContext,
|
|
IN unsigned int Timeout,
|
|
IN CLIENT_AUTH_INFO * ClientAuthInfo,
|
|
IN unsigned long MyAssocGroupId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We need to find or create a connection which supports the specified
|
|
interface and transfer syntax(es).
|
|
|
|
Arguments:
|
|
|
|
InterfaceSyntax - Supplies a description of the interface to which
|
|
we wish to bind.
|
|
|
|
TransferSyntaxes - Supplies a list of one or more transfer syntaxes
|
|
which the client stub is willing to talk with the server stub.
|
|
|
|
TransferSyntaxCount - Supplies the number of transfer syntaxes; this
|
|
must be at least one.
|
|
|
|
TheCConnection - Returns the allocated connection assuming that a
|
|
connection was obtained and binding occured successfully.
|
|
|
|
PresentContext - Supplies the presentation context to be used for
|
|
the binding.
|
|
|
|
Timeout - Supplies the timeout to be used if an attempt is made to
|
|
create a new connection. See the documentation for
|
|
RpcMgmtSetComTimeout for a description of the possible values
|
|
for the timeout.
|
|
|
|
ClientAuthInfo - Supplies the authentication and authorization
|
|
information required for the connection.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - We successfully bound with the server. Things should
|
|
be all ready now to make remote procedure calls.
|
|
|
|
RPC_S_SERVER_UNAVAILABLE - We are unable to connect with the server.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to bind.
|
|
|
|
RPC_S_OUT_OF_RESOURCES - The transport has insufficient resources
|
|
inorder to make a connection with the server.
|
|
|
|
RPC_S_SERVER_TOO_BUSY - The server is there, but it is too busy to
|
|
talk with us right now.
|
|
|
|
RPC_S_ACCESS_DENIED - The client is unable to make a connection with
|
|
the server for security reasons.
|
|
|
|
RPC_S_INVALID_NETWORK_OPTIONS - The supplied network options are
|
|
invalid; see a description of the particular transport interface
|
|
module for an explination.
|
|
|
|
RPC_P_CONNECTION_CLOSED - The connection closed while the client was
|
|
attempting to send the bind packet or waiting to receive the
|
|
response.
|
|
|
|
RPC_S_PROTOCOL_ERROR - A protocol error occured; this will typically
|
|
be because of a protocol mismatch with the server.
|
|
|
|
RPC_S_UNSUPPORTED_TRANS_SYN - The transfer syntax supplied by the client
|
|
is not supported by the server.
|
|
|
|
RPC_S_UNKNOWN_IF - The interface to which the client wished to bind is not
|
|
supported by the server.
|
|
|
|
RPC_S_UNKNOWN_AUTHN_TYPE - The server does not support the authentication
|
|
type specified by the client.
|
|
|
|
RPC_S_INVALID_ENDPOINT_FORMAT - The endpoint supplied is in an incorrect
|
|
format for the particular protocol sequence.
|
|
|
|
--*/
|
|
{
|
|
OSF_CCONNECTION * CConnection;
|
|
int NewConnectionFlag = 0;
|
|
RPC_STATUS RpcStatus;
|
|
void PAPI * Buffer = 0;
|
|
unsigned int BufferLength = 0;
|
|
|
|
ASSERT( TransferSyntaxCount >= 1 );
|
|
|
|
// To start off with, we want to try and find an existing connection
|
|
// to use. We need to try and find one which supports the requested
|
|
// authentication and authorization information.
|
|
|
|
*TheCConnection = Nil;
|
|
RequestGlobalMutex();
|
|
FreeConnections.Reset();
|
|
while ( (CConnection = FreeConnections.Next()) != 0 )
|
|
{
|
|
if ( CConnection->SupportedAuthInfo(ClientAuthInfo) != 0 )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( CConnection == 0 )
|
|
{
|
|
// There are no free connections, so we go ahead and try to
|
|
// create one.
|
|
|
|
NewConnectionFlag = 1;
|
|
|
|
// Once an initial connection has been established, calls will
|
|
// not be timed out any more aggressively than the default.
|
|
|
|
if ( OpenConnectionCount > 0 )
|
|
{
|
|
if ( Timeout < RPC_C_BINDING_DEFAULT_TIMEOUT )
|
|
{
|
|
Timeout = RPC_C_BINDING_DEFAULT_TIMEOUT;
|
|
}
|
|
}
|
|
ClearGlobalMutex();
|
|
|
|
// If the timeout specified is RPC_C_BINDING_INFINITE_TIMEOUT, we
|
|
// need to loop trying to connect as long as the result is
|
|
// RPC_S_SERVER_UNAVAILABLE or RPC_S_SERVER_TOO_BUSY.
|
|
|
|
for (;;)
|
|
{
|
|
// BUGBUG - Secondary endpoint support is needed.
|
|
|
|
RpcStatus = RPC_S_OK;
|
|
|
|
CConnection = new(0, RpcClientInfo->SizeOfConnection)
|
|
TRANS_CCONNECTION(
|
|
RpcClientInfo,
|
|
DceBinding->InqNetworkAddress(),
|
|
DceBinding->InqEndpoint(),
|
|
DceBinding->InqNetworkOptions(),
|
|
DceBinding->InqRpcProtocolSequence(),
|
|
&RpcStatus,
|
|
Timeout,
|
|
ClientAuthInfo
|
|
);
|
|
|
|
ASSERT( (CConnection == 0)
|
|
|| (RpcStatus == RPC_S_PROTSEQ_NOT_SUPPORTED)
|
|
|| (RpcStatus == RPC_S_OK)
|
|
|| (RpcStatus == RPC_S_SERVER_UNAVAILABLE)
|
|
|| (RpcStatus == RPC_S_OUT_OF_MEMORY)
|
|
|| (RpcStatus == RPC_S_OUT_OF_RESOURCES)
|
|
|| (RpcStatus == RPC_S_SERVER_TOO_BUSY)
|
|
|| (RpcStatus == RPC_S_ACCESS_DENIED)
|
|
|| (RpcStatus == RPC_S_INVALID_NET_ADDR)
|
|
|| (RpcStatus == RPC_S_INVALID_ENDPOINT_FORMAT)
|
|
|| (RpcStatus == RPC_S_INVALID_NETWORK_OPTIONS));
|
|
|
|
if ( CConnection == 0 )
|
|
{
|
|
RpcStatus = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if ( RpcStatus == RPC_S_OK )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( CConnection != 0 )
|
|
{
|
|
delete CConnection;
|
|
}
|
|
|
|
if ( Timeout != RPC_C_BINDING_INFINITE_TIMEOUT )
|
|
{
|
|
return(RpcStatus);
|
|
}
|
|
|
|
if ( (RpcStatus != RPC_S_SERVER_UNAVAILABLE)
|
|
&& (RpcStatus != RPC_S_SERVER_TOO_BUSY) )
|
|
{
|
|
return(RpcStatus);
|
|
}
|
|
}
|
|
|
|
CConnection->SetAssociation(this);
|
|
}
|
|
else
|
|
{
|
|
// There is a connection available, so we grab it from the
|
|
// set of free connections.
|
|
|
|
FreeConnections.Delete(CConnection->AssociationKey);
|
|
ClearGlobalMutex();
|
|
}
|
|
|
|
RpcStatus = CConnection->SendBindPacket(InterfaceSyntax,
|
|
TransferSyntaxes, TransferSyntaxCount, PresentContext,
|
|
MyAssocGroupId, (NewConnectionFlag ? rpc_bind : rpc_alter_context),
|
|
&Buffer, &BufferLength);
|
|
|
|
//Now mark this connection as a part of the pool
|
|
if ( NewConnectionFlag != 0)
|
|
{
|
|
RequestGlobalMutex();
|
|
OpenConnectionCount += 1;
|
|
ClearGlobalMutex();
|
|
}
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
#if DBG
|
|
if ( (RpcStatus != RPC_S_OUT_OF_MEMORY)
|
|
&& (RpcStatus != RPC_S_OUT_OF_RESOURCES)
|
|
&& (RpcStatus != RPC_P_CONNECTION_SHUTDOWN)
|
|
&& (RpcStatus != RPC_P_CONNECTION_CLOSED)
|
|
&& (RpcStatus != RPC_S_UUID_NO_ADDRESS)
|
|
&& (RpcStatus != RPC_S_ACCESS_DENIED)
|
|
&& (RpcStatus != RPC_S_SEC_PKG_ERROR) )
|
|
{
|
|
PrintToDebugger("RPC SendBindPacket Returned [%x] \n",RpcStatus);
|
|
}
|
|
#endif
|
|
ASSERT( (RpcStatus == RPC_S_OUT_OF_MEMORY)
|
|
|| (RpcStatus == RPC_S_OUT_OF_RESOURCES)
|
|
|| (RpcStatus == RPC_P_CONNECTION_SHUTDOWN)
|
|
|| (RpcStatus == RPC_P_CONNECTION_CLOSED)
|
|
|| (RpcStatus == RPC_S_UUID_NO_ADDRESS)
|
|
|| (RpcStatus == RPC_S_ACCESS_DENIED)
|
|
|| (RpcStatus == RPC_S_SEC_PKG_ERROR) );
|
|
delete CConnection;
|
|
return(RpcStatus);
|
|
}
|
|
|
|
// We loop around ignoring shutdown packets until we get a response.
|
|
|
|
for (;;)
|
|
{
|
|
|
|
//If there is security, we need to save away the packet
|
|
//and the header. This is because we may have to byte swap stuff
|
|
//The correct check here should be
|
|
//if ((AluthLevel != NONE) && (ByteSwapEndian == TRUE))
|
|
//I am avoiding the second check for now so that we can test
|
|
//this code w/o a big endian machine
|
|
//another potential opt. is not saving the whole packet!
|
|
//but just header + result_list..
|
|
//again the opt. will be done once all this starts working well
|
|
|
|
|
|
if ( CConnection->AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE )
|
|
{
|
|
|
|
//Security is on.. save the packet before we byte swap
|
|
if (CConnection->SavedHeaderSize < BufferLength)
|
|
{
|
|
|
|
if (CConnection->SavedHeader != 0)
|
|
{
|
|
ASSERT(CConnection->SavedHeaderSize != 0);
|
|
RpcpFarFree(CConnection->SavedHeader);
|
|
}
|
|
|
|
CConnection->SavedHeader = RpcpFarAllocate(BufferLength);
|
|
if (CConnection->SavedHeader == 0)
|
|
{
|
|
CConnection->TransFreeBuffer(Buffer);
|
|
delete CConnection;
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
CConnection->SavedHeaderSize = BufferLength;
|
|
RpcpMemoryCopy(CConnection->SavedHeader, Buffer, BufferLength);
|
|
|
|
}
|
|
|
|
else
|
|
{
|
|
RpcpMemoryCopy(CConnection->SavedHeader, Buffer, BufferLength);
|
|
}
|
|
|
|
}
|
|
|
|
RpcStatus = ValidatePacket((rpcconn_common PAPI *) Buffer,
|
|
BufferLength);
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
ASSERT( RpcStatus == RPC_S_PROTOCOL_ERROR );
|
|
CConnection->TransFreeBuffer(Buffer);
|
|
delete CConnection;
|
|
return(RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
|
|
if ( NewConnectionFlag != 0 )
|
|
{
|
|
// Since this is a new connection, the packet we receive
|
|
// must be either a bind_ack or a bind_nak; anything else
|
|
// is an error.
|
|
|
|
if ( (((rpcconn_common PAPI *) Buffer)->PTYPE != rpc_bind_ack)
|
|
&& (((rpcconn_common PAPI *) Buffer)->PTYPE != rpc_bind_nak)
|
|
&& (((rpcconn_common PAPI *) Buffer)->PTYPE != rpc_shutdown))
|
|
{
|
|
return(RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
|
|
if (((rpcconn_common PAPI *) Buffer)->PTYPE != rpc_shutdown)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( ((rpcconn_common PAPI *) Buffer)->PTYPE == rpc_alter_context_resp )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( ((rpcconn_common PAPI *) Buffer)->PTYPE == rpc_shutdown )
|
|
{
|
|
ShutdownRequested();
|
|
}
|
|
else
|
|
{
|
|
CConnection->TransFreeBuffer(Buffer);
|
|
delete CConnection;
|
|
return(RPC_S_PROTOCOL_ERROR);
|
|
}
|
|
|
|
CConnection->TransFreeBuffer(Buffer);
|
|
|
|
RpcStatus = CConnection->TransReceive(&Buffer,&BufferLength);
|
|
ASSERT( (RpcStatus != RPC_S_CALL_CANCELLED)
|
|
&&(RpcStatus != RPC_P_RECEIVE_ALERTED) );
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
ASSERT( (RpcStatus == RPC_S_OUT_OF_MEMORY)
|
|
|| (RpcStatus == RPC_S_OUT_OF_RESOURCES)
|
|
|| (RpcStatus == RPC_P_RECEIVE_FAILED)
|
|
|| (RpcStatus == RPC_P_CONNECTION_CLOSED));
|
|
CConnection->TransFreeBuffer(Buffer);
|
|
delete CConnection;
|
|
if ( RpcStatus == RPC_P_RECEIVE_FAILED )
|
|
{
|
|
return(RPC_P_CONNECTION_CLOSED);
|
|
}
|
|
return(RpcStatus);
|
|
}
|
|
}
|
|
|
|
// We subtract from BufferLength the length of the authentication
|
|
// information; that way ProcessBinAckOrNak can check the length
|
|
// correctly, whether or not there is security information.
|
|
if (MyAssocGroupId == 0)
|
|
{
|
|
RpcStatus = ProcessBindAckOrNak((rpcconn_common PAPI *) Buffer,
|
|
BufferLength - ((rpcconn_common PAPI *) Buffer)->auth_length,
|
|
CConnection);
|
|
}
|
|
else
|
|
{
|
|
AssociationMutex.Request() ;
|
|
|
|
RpcStatus = ProcessBindAckOrNak((rpcconn_common PAPI *) Buffer,
|
|
BufferLength - ((rpcconn_common PAPI *) Buffer)->auth_length,
|
|
CConnection);
|
|
|
|
AssociationMutex.Clear() ;
|
|
}
|
|
|
|
// Let the connection deal with 3rd leg authentication if it is
|
|
// necessary. Note that OSF_CCONNECTION::MaybeDo3rdLegAuth knows
|
|
// that we are only doing authentication on the initial bind packets.
|
|
|
|
if ( RpcStatus == RPC_S_OK )
|
|
{
|
|
RpcStatus = CConnection->MaybeDo3rdLegAuth(Buffer, BufferLength);
|
|
|
|
ASSERT( (RpcStatus == RPC_S_OK)
|
|
|| (RpcStatus == RPC_S_PROTOCOL_ERROR)
|
|
|| (RpcStatus == RPC_S_OUT_OF_MEMORY)
|
|
|| (RpcStatus == RPC_S_OUT_OF_RESOURCES)
|
|
|| (RpcStatus == RPC_P_CONNECTION_CLOSED)
|
|
|| (RpcStatus == RPC_S_SEC_PKG_ERROR)
|
|
|| (RpcStatus == RPC_S_ACCESS_DENIED) );
|
|
}
|
|
|
|
CConnection->TransFreeBuffer(Buffer);
|
|
|
|
if ( RpcStatus == RPC_S_OK )
|
|
{
|
|
if ( CConnection->AddPContext(PresentContext) != 0 )
|
|
RpcStatus = RPC_S_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
if ( NewConnectionFlag == 0 )
|
|
{
|
|
// We failed to bind, but since the connection is not a new
|
|
// connection, we can stick it back into the pool of free
|
|
// connections.
|
|
|
|
if ( FreeConnection(CConnection) != 0 )
|
|
{
|
|
delete CConnection;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// If RpcStatus == DNE, it means that we probably got a B-NAK
|
|
// [Also note this is a new connection]
|
|
// If we were using security, [Auth Level != NONE]
|
|
// delete this connection, and return RPC_P_CONNECTION_SHUTDOWN
|
|
// which will cause BH->GetBuffer code to retry 2 more times
|
|
//
|
|
if (RpcStatus == RPC_S_CALL_FAILED_DNE)
|
|
/*
|
|
What the hell .. retry failures over non-authenticated
|
|
binds also.. the ones we retry over are bind naks with
|
|
unspecifed reason .. one day we can get OSF to send
|
|
bind_nk with reason assoc_group_shutdown..
|
|
&& (CConnection->AuthInfo.AuthenticationLevel
|
|
!= RPC_C_AUTHN_LEVEL_NONE))
|
|
*/
|
|
{
|
|
RpcStatus = RPC_P_CONNECTION_SHUTDOWN;
|
|
}
|
|
|
|
delete CConnection;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*TheCConnection = CConnection;
|
|
#ifdef NTENV
|
|
if (CConnection->PendingAlert)
|
|
{
|
|
RpcCancelThread(GetCurrentThread());
|
|
CConnection->PendingAlert = FALSE;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return(RpcStatus);
|
|
}
|
|
|
|
#if 0
|
|
|
|
void
|
|
OSF_CASSOCIATION::CleanupAuthenticatedConnections(
|
|
IN CLIENT_AUTH_INFO *ClientAuthInfo
|
|
)
|
|
{
|
|
OSF_CCONNECTION *CConnection;
|
|
OSF_BINDING *Binding;
|
|
|
|
//
|
|
// Temp fix for Digital, we need to cleanup Cconnections
|
|
// holding the security context associated with a binding
|
|
// when that binding is destroyed.
|
|
//
|
|
// This needs a better soln, this has holes with binding copy.
|
|
|
|
if (ClientAuthInfo == 0) return;
|
|
|
|
RequestGlobalMutex();
|
|
|
|
FreeConnections.Reset();
|
|
while ((CConnection = FreeConnections.Next()) != 0)
|
|
{
|
|
if (CConnection->SupportedAuthInfo(ClientAuthInfo) != 0)
|
|
{
|
|
FreeConnections.Delete(CConnection->AssociationKey);
|
|
delete CConnection;
|
|
}
|
|
}
|
|
|
|
ClearGlobalMutex();
|
|
}
|
|
|
|
#endif
|
|
|
|
void
|
|
OSF_CASSOCIATION::UnBind (
|
|
)
|
|
{
|
|
RequestGlobalMutex();
|
|
BindHandleCount -= 1;
|
|
|
|
if (BindHandleCount == 0)
|
|
{
|
|
AssociationDict->Delete(Key);
|
|
ClearGlobalMutex();
|
|
|
|
delete this ;
|
|
}
|
|
else
|
|
{
|
|
ClearGlobalMutex();
|
|
}
|
|
}
|
|
|
|
|
|
OSF_BINDING *
|
|
OSF_CASSOCIATION::FindOrCreateOsfBinding (
|
|
IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This method gets called to find the osf binding (a dictionary
|
|
entry) corresponding to the specified rpc interface information.
|
|
The caller of this routine must be holding (ie. requested) the
|
|
association mutex.
|
|
|
|
Arguments:
|
|
|
|
RpcInterfaceInformation - Supplies the interface information for
|
|
which we are looking for an osf binding object.
|
|
|
|
Return Value:
|
|
|
|
An osf binding object corresponding to the interface information
|
|
specified will be returned unless we run out of memory, in which
|
|
case zero will be returned.
|
|
|
|
--*/
|
|
{
|
|
OSF_BINDING * Binding;
|
|
|
|
// First we search for an existing presentation context
|
|
// corresponding to the specified interface information. Otherwise,
|
|
// we create a new presentation context.
|
|
|
|
Bindings.Reset();
|
|
while ((Binding = Bindings.Next()) != 0)
|
|
{
|
|
if (Binding->CompareWithRpcInterfaceInformation(
|
|
RpcInterfaceInformation) == 0)
|
|
return(Binding);
|
|
}
|
|
|
|
Binding = new OSF_BINDING(RpcInterfaceInformation);
|
|
|
|
if (Binding == 0)
|
|
return(0);
|
|
|
|
Binding->PresentContext = Bindings.Insert(Binding);
|
|
if (Binding->PresentContext == -1)
|
|
{
|
|
delete Binding;
|
|
return(0);
|
|
}
|
|
|
|
return(Binding);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CASSOCIATION::AllocateConnection (
|
|
IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation,
|
|
OUT OSF_CCONNECTION * PAPI * CConnection,
|
|
IN unsigned int Timeout,
|
|
IN CLIENT_AUTH_INFO * ClientAuthInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
In this method, we allocate a connection supporting the requested
|
|
interface information. This means that first we need to find the
|
|
presentation context corresponding to the requested interface
|
|
interface. Then we search for an existing connection supporting
|
|
the presentation context, and then we try and create a new
|
|
connection.
|
|
|
|
Arguments:
|
|
|
|
RpcInterfaceInformation - Supplies the information which describes
|
|
the interface so we can find or create a connection which has
|
|
been bound to the correct interface.
|
|
|
|
CConnection - Returns the allocated connection.
|
|
|
|
Timeout - Supplies the timeout to be used if an attempt is made to
|
|
create a new connection. See the documentation for
|
|
RpcMgmtSetComTimeout for a description of the possible values
|
|
for the timeout.
|
|
|
|
ClientAuthInfo - Supplies the authentication and authorization
|
|
information required for the connection.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - The operation completed successfully.
|
|
|
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to create
|
|
objects necessary to allocate a connection.
|
|
|
|
All of the return values from OSF_CASSOCIATION::ActuallyDoBinding will
|
|
be passed through unchanged.
|
|
|
|
--*/
|
|
{
|
|
OSF_BINDING * Binding;
|
|
RPC_STATUS RpcStatus;
|
|
unsigned long CallIdToUse;
|
|
int MutexHeld = 0;
|
|
unsigned long MyAssocGroupId ;
|
|
|
|
// To begin with, we need to obtain the presentation context
|
|
// corresponding to the specified interface information.
|
|
|
|
RequestGlobalMutex();
|
|
Binding = FindOrCreateOsfBinding(RpcInterfaceInformation);
|
|
if ( Binding == 0 )
|
|
{
|
|
ClearGlobalMutex();
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
// Ok, now we search for an available connection supporting the
|
|
// requested presentation context.
|
|
|
|
FreeConnections.Reset();
|
|
while ( (*CConnection = FreeConnections.Next()) != 0 )
|
|
{
|
|
if ( ((*CConnection)->SupportedAuthInfo(ClientAuthInfo) != 0)
|
|
&& ((*CConnection)->SupportedPContext(Binding->PresentContext)
|
|
!= 0) )
|
|
{
|
|
FreeConnections.Delete((*CConnection)->AssociationKey);
|
|
(*CConnection)->CallId = CallIdCounter++;
|
|
ClearGlobalMutex();
|
|
(*CConnection)->ActivateConnection(Binding->PresentContext,
|
|
(PRPC_DISPATCH_TABLE)
|
|
RpcInterfaceInformation->DispatchTable);
|
|
return(RPC_S_OK);
|
|
}
|
|
}
|
|
CallIdToUse = CallIdCounter++;
|
|
ClearGlobalMutex();
|
|
|
|
AssociationMutex.Request();
|
|
MyAssocGroupId = AssocGroupId ;
|
|
|
|
if (AssocGroupId != 0)
|
|
{
|
|
AssociationMutex.Clear() ;
|
|
}
|
|
else
|
|
{
|
|
MutexHeld = 1 ;
|
|
}
|
|
|
|
RpcStatus = ActuallyDoBinding(
|
|
&(Binding->RpcInterfaceInformation.InterfaceId),
|
|
&(Binding->RpcInterfaceInformation.TransferSyntax), 1,
|
|
CConnection, Binding->PresentContext,
|
|
Timeout, ClientAuthInfo, MyAssocGroupId);
|
|
|
|
if (MutexHeld)
|
|
{
|
|
AssociationMutex.Clear();
|
|
}
|
|
|
|
if ( RpcStatus == RPC_S_OK )
|
|
{
|
|
ASSERT((*CConnection) != 0);
|
|
(*CConnection)->ActivateConnection(Binding->PresentContext,
|
|
(PRPC_DISPATCH_TABLE) RpcInterfaceInformation->DispatchTable);
|
|
(*CConnection)->CallId = CallIdToUse;
|
|
}
|
|
return(RpcStatus);
|
|
}
|
|
|
|
int
|
|
OSF_CASSOCIATION::FreeConnection (
|
|
IN OSF_CCONNECTION * CConnection
|
|
)
|
|
{
|
|
if (!AssociationValid)
|
|
{
|
|
delete CConnection ;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if ( CConnection->InquireLastTimeUsed() != 0 )
|
|
{
|
|
CConnection->SetLastTimeUsedToNow();
|
|
}
|
|
|
|
RequestGlobalMutex();
|
|
if ((CConnection->AssociationKey =
|
|
FreeConnections.Insert(CConnection)) == -1)
|
|
{
|
|
ClearGlobalMutex();
|
|
return(-1);
|
|
}
|
|
|
|
ClearGlobalMutex();
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
void
|
|
OSF_CASSOCIATION::ShutdownRequested (
|
|
)
|
|
{
|
|
OSF_CCONNECTION * CConnection;
|
|
|
|
RequestGlobalMutex();
|
|
FreeConnections.Reset();
|
|
while ((CConnection = FreeConnections.Next()) != Nil)
|
|
{
|
|
FreeConnections.Delete(CConnection->AssociationKey);
|
|
delete CConnection;
|
|
}
|
|
|
|
//
|
|
// We have received a shutdown notice
|
|
// Just reset the AssocGrpId to 0 [looks like an over kill.. but...]
|
|
// We need this because If another thread is trying a bind
|
|
// he will [or she will] have bumped up the ConnectionCount
|
|
// On his/her retry
|
|
//
|
|
|
|
|
|
ClearGlobalMutex();
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CASSOCIATION::ToStringBinding (
|
|
OUT RPC_CHAR PAPI * PAPI * StringBinding,
|
|
IN RPC_UUID * ObjectUuid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We need to convert the binding handle into a string binding. If the
|
|
binding handle has not yet been used to make a remote procedure
|
|
call, then we can just use the information in the binding handle to
|
|
create the string binding. Otherwise, we need to ask the association
|
|
to do it for us.
|
|
|
|
Arguments:
|
|
|
|
StringBinding - Returns the string representation of the binding
|
|
handle.
|
|
|
|
ObjectUuid - Supplies the object uuid of the binding handle which
|
|
is requesting that we create a string binding.
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
*StringBinding = DceBinding->StringBindingCompose(ObjectUuid);
|
|
if (*StringBinding == 0)
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
/* --------------------------------------------------------------------
|
|
-------------------------------------------------------------------- */
|
|
|
|
// This value specifies the minimum amount of time in seconds to wait before
|
|
// deleting an idle connection.
|
|
|
|
#define CLIENT_DISCONNECT_TIME 10
|
|
|
|
|
|
OSF_CASSOCIATION *
|
|
FindOrCreateAssociation (
|
|
IN DCE_BINDING * DceBinding,
|
|
IN RPC_CLIENT_TRANSPORT_INFO * TransportInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine finds an existing association supporting the requested
|
|
DCE binding, or create a new association which supports the
|
|
requested DCE binding. Ownership of the passed DceBinding pass
|
|
to this routine.
|
|
|
|
Arguments:
|
|
|
|
DceBinding - Supplies binding information; ownership of this object
|
|
passes to this routine.
|
|
|
|
TransportInterface - Supplies a pointer to the data structure which
|
|
describes a loadable transport.
|
|
|
|
Return Value:
|
|
|
|
An association which supports the requested binding will be returned;
|
|
Otherwise, zero will be returned, indicating insufficient memory.
|
|
|
|
--*/
|
|
{
|
|
OSF_CASSOCIATION * CAssociation;
|
|
RPC_STATUS RpcStatus = RPC_S_OK;
|
|
|
|
// We start be looking in the dictionary of existing associations
|
|
// to see if there is one supporting the binding information specified.
|
|
|
|
RequestGlobalMutex();
|
|
AssociationDict->Reset();
|
|
while ( (CAssociation = AssociationDict->Next()) != 0 )
|
|
{
|
|
if (CAssociation->IsValid() &&
|
|
CAssociation->CompareWithDceBinding(DceBinding) == 0)
|
|
{
|
|
CAssociation->IncrementCount();
|
|
ClearGlobalMutex();
|
|
|
|
delete DceBinding;
|
|
|
|
return(CAssociation);
|
|
}
|
|
}
|
|
|
|
CAssociation = new OSF_CASSOCIATION(DceBinding, TransportInterface,
|
|
&RpcStatus);
|
|
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
ASSERT(CAssociation != 0);
|
|
CAssociation->DceBinding = 0;
|
|
delete CAssociation;
|
|
CAssociation = 0;
|
|
}
|
|
|
|
if (CAssociation != 0)
|
|
CAssociation->Key = AssociationDict->Insert(CAssociation);
|
|
|
|
ClearGlobalMutex();
|
|
|
|
// Finally, we need to notify the protocol independent layer that
|
|
// the code to delete idle connections should be executed periodically.
|
|
// We divide by two to reduce the amount of extra time an idle
|
|
// connection lives beyond the minimum.
|
|
|
|
GarbageCollectionNeeded(CLIENT_DISCONNECT_TIME / 2);
|
|
|
|
return(CAssociation);
|
|
}
|
|
|
|
|
|
int
|
|
OSF_CASSOCIATION::CompareWithDceBinding (
|
|
IN DCE_BINDING * DceBinding
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine compares the specified binding information with the
|
|
binding information in the object, this.
|
|
|
|
Arguments:
|
|
|
|
DceBinding - Supplies the binding information to compare against
|
|
the binding information in this.
|
|
|
|
Return Value:
|
|
|
|
Zero will be returned if the specified binding information,
|
|
DceBinding, is the same as in this. Otherwise, non-zero will be
|
|
returned.
|
|
|
|
--*/
|
|
{
|
|
int Result;
|
|
|
|
if ((Result = this->DceBinding->Compare(DceBinding)) != 0)
|
|
return(Result);
|
|
|
|
#ifdef WIN
|
|
|
|
if ( (Result = TaskId - GetCurrentTask()) != 0 )
|
|
{
|
|
return(Result);
|
|
}
|
|
|
|
#endif // WIN
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
OSF_CCONNECTION *
|
|
OSF_CASSOCIATION::FindIdleConnection (
|
|
IN unsigned long MinimumIdleSeconds,
|
|
IN unsigned long CurrentTime
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to find a connection which has been idle more
|
|
than the minimum number of seconds specified. If one is found, it
|
|
is removed from the set of free connections and returned. The
|
|
global mutex will be held when this routine is called.
|
|
|
|
Arguments:
|
|
|
|
MinimumIdleSeconds - Supplies the minimum number of seconds a connection
|
|
must be idle to be returned.
|
|
|
|
CurrentTime - Supplies the current time in seconds.
|
|
|
|
Return Value:
|
|
|
|
If an idle connection is found, it will be returned; otherwise, zero
|
|
will be returned.
|
|
|
|
--*/
|
|
{
|
|
OSF_CCONNECTION * CConnection;
|
|
|
|
// If we need to maintain context with server, we do not want to close
|
|
// the last open connection. To be on the safe side, we will make
|
|
// sure that there is at least one free connection.
|
|
|
|
if ( MaintainContext != 0 )
|
|
{
|
|
if ( FreeConnections.Size() <= 1 )
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
FreeConnections.Reset();
|
|
while ( (CConnection = FreeConnections.Next()) != 0 )
|
|
{
|
|
if ( CConnection->InquireLastTimeUsed() == 0 )
|
|
{
|
|
CConnection->SetLastTimeUsedToNow();
|
|
}
|
|
else if ( CurrentTime - CConnection->InquireLastTimeUsed()
|
|
> MinimumIdleSeconds )
|
|
{
|
|
FreeConnections.Delete(CConnection->AssociationKey);
|
|
|
|
return(CConnection);
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
void
|
|
OsfDeleteIdleConnections (
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will be called to delete connections which have been
|
|
idle for a certain amount of time. We need to be careful of a couple
|
|
of things in writing this routine:
|
|
|
|
(1) We dont want to grab the global mutex for too long, because this
|
|
will prevent threads which are trying to do real work from doing
|
|
it.
|
|
|
|
(2) We dont want to be holding the global mutex when we delete the
|
|
connection.
|
|
|
|
--*/
|
|
{
|
|
OSF_CASSOCIATION * Association;
|
|
OSF_CCONNECTION * CConnection;
|
|
unsigned int IdleConnectionFound;
|
|
unsigned long CurrentTime;
|
|
|
|
do
|
|
{
|
|
IdleConnectionFound = 0;
|
|
|
|
RequestGlobalMutex();
|
|
|
|
CurrentTime = CurrentTimeInSeconds();
|
|
|
|
AssociationDict->Reset();
|
|
while ( (Association = AssociationDict->Next()) != 0 )
|
|
{
|
|
// The architecture says that the client should disconnect
|
|
// connections which have been idle too long.
|
|
|
|
CConnection = Association->FindIdleConnection(
|
|
CLIENT_DISCONNECT_TIME, CurrentTime);
|
|
|
|
if ( CConnection != 0 )
|
|
{
|
|
ClearGlobalMutex();
|
|
|
|
delete CConnection;
|
|
IdleConnectionFound = 1;
|
|
|
|
RequestGlobalMutex();
|
|
break;
|
|
}
|
|
}
|
|
ClearGlobalMutex();
|
|
}
|
|
while ( IdleConnectionFound != 0);
|
|
}
|
|
|
|
|
|
int
|
|
InitializeRpcProtocolOfsClient (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We perform loadtime initialization necessary for the code in this
|
|
file. In particular, it means we allocate the association dictionary
|
|
and the association dictionary mutex.
|
|
|
|
Return Value:
|
|
|
|
Zero will be returned if initialization completes successfully;
|
|
otherwise, non-zero will be returned.
|
|
|
|
--*/
|
|
{
|
|
AssociationDict = new OSF_CASSOCIATION_DICT;
|
|
if (AssociationDict == 0)
|
|
return(1);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
void *
|
|
OsfClientMapRpcProtocolSequence (
|
|
IN RPC_CHAR PAPI * 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 - There is insufficient memory to perform
|
|
the operation.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the transport interface is returned. This pointer
|
|
must not be dereferenced by the caller.
|
|
|
|
--*/
|
|
{
|
|
RPC_CHAR * DllName;
|
|
RPC_CLIENT_TRANSPORT_INFO * RpcClientInfo;
|
|
|
|
*Status= RpcConfigMapRpcProtocolSequence(0, RpcProtocolSequence, &DllName);
|
|
if ( *Status != RPC_S_OK )
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
RpcClientInfo = LoadableTransportClientInfo(DllName, RpcProtocolSequence,
|
|
Status);
|
|
delete DllName;
|
|
|
|
if ( *Status != RPC_S_OK )
|
|
{
|
|
return(0);
|
|
}
|
|
return(RpcClientInfo);
|
|
}
|
|
|
|
|
|
BINDING_HANDLE *
|
|
OsfCreateBindingHandle (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine does exactly one thing: it creates a binding handle of
|
|
the appropriate type for the osf connection protocol module.
|
|
|
|
Return Value:
|
|
|
|
A new binding handle will be returned. Zero will be returned if
|
|
insufficient memory is available to create the binding handle.
|
|
|
|
--*/
|
|
{
|
|
BINDING_HANDLE * BindingHandle;
|
|
RPC_STATUS RpcStatus = RPC_S_OK;
|
|
|
|
BindingHandle = new OSF_BINDING_HANDLE(&RpcStatus);
|
|
if ( RpcStatus != RPC_S_OK )
|
|
{
|
|
delete BindingHandle;
|
|
return(0);
|
|
}
|
|
return(BindingHandle);
|
|
}
|
|
|
|
#ifdef NTENV
|
|
RPC_STATUS RPC_ENTRY
|
|
I_RpcIOAlerted (
|
|
IN RPC_TRANSPORT_CONNECTION TransConnection
|
|
)
|
|
{
|
|
|
|
|
|
unsigned long Timeout;
|
|
TRANS_CCONNECTION *Connection = InqTransCConnection(TransConnection);
|
|
|
|
//
|
|
//We dont send alerts/orphans or anything in certain states
|
|
//These states are marked by setting AlertsEnabled to 0.
|
|
//
|
|
if (Connection->AlertsEnabled == 0)
|
|
{
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
if ( (Timeout = ThreadGetRpcCancelTimeout()) == 0)
|
|
{
|
|
Connection->SendOrphan();
|
|
return(RPC_S_CALL_CANCELLED); //Ask Transport To Cancel IO
|
|
}
|
|
|
|
Connection->SendAlert();
|
|
Connection->PendingAlert = FALSE;
|
|
Connection->TransSetTimeout(Timeout);
|
|
|
|
return(RPC_S_OK);
|
|
|
|
}
|
|
#endif
|
|
|
|
extern "C" {
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
OsfTowerConstruct(
|
|
IN char PAPI * ProtocolSeq,
|
|
IN char PAPI * Endpoint,
|
|
IN char PAPI * NetworkAddress,
|
|
OUT unsigned short PAPI * Floors,
|
|
OUT unsigned long PAPI * ByteCount,
|
|
OUT unsigned char PAPI * PAPI * Tower
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine constructs and returns the upper floors of a tower.
|
|
It invokes the appropriate loadable transport and has them construct
|
|
it.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
RPC_CLIENT_TRANSPORT_INFO PAPI * ClientInfo;
|
|
RPC_STATUS Status = RPC_S_OK;
|
|
RPC_CHAR PAPI * Pseq;
|
|
#ifdef NTENV
|
|
UNICODE_STRING UnicodeStr;
|
|
#endif
|
|
|
|
#ifdef NTENV
|
|
|
|
if (Status = AnsiToUnicodeString((unsigned char PAPI *)ProtocolSeq,
|
|
&UnicodeStr))
|
|
{
|
|
return(Status);
|
|
}
|
|
|
|
Pseq = UnicodeStr.Buffer;
|
|
|
|
#else
|
|
|
|
Pseq = (RPC_CHAR PAPI * )ProtocolSeq;
|
|
|
|
#endif
|
|
|
|
#ifdef DEBUGRPC
|
|
|
|
char * CoOffset = (char *) &((( RPC_CLIENT_TRANSPORT_INFO *) 0)->TowerConstruct);
|
|
char * DgOffset = (char *) &(((DG_RPC_CLIENT_TRANSPORT_INFO *) 0)->TowerConstruct);
|
|
|
|
ASSERT( CoOffset == DgOffset);
|
|
|
|
if (CoOffset != DgOffset)
|
|
{
|
|
return RPC_S_INTERNAL_ERROR;
|
|
}
|
|
#endif
|
|
|
|
|
|
if (Status == RPC_S_OK)
|
|
{
|
|
ClientInfo = (RPC_CLIENT_TRANSPORT_INFO PAPI *)
|
|
OsfClientMapRpcProtocolSequence(Pseq, &Status);
|
|
}
|
|
|
|
if (Status == RPC_S_OK)
|
|
{
|
|
Status = ClientInfo->TowerConstruct(Endpoint,
|
|
NetworkAddress,
|
|
Floors,
|
|
ByteCount,
|
|
Tower,
|
|
ProtocolSeq);
|
|
}
|
|
|
|
#ifdef NTENV
|
|
RtlFreeUnicodeString(&UnicodeStr);
|
|
#endif
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
OsfTowerExplode(
|
|
IN unsigned char PAPI * Tower,
|
|
OUT char PAPI * PAPI * Protseq,
|
|
OUT char PAPI * PAPI * Endpoint,
|
|
OUT char PAPI * PAPI * NWAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine accepts upper floors of a tower [Floor 3 onwards]
|
|
It invokes the appropriate loadable transport based on the opcode
|
|
it finds in level 3 to return protocol sequence, endpoint and nwaddress.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS Status;
|
|
unsigned short TransportId;
|
|
unsigned char PAPI * Id;
|
|
unsigned char PAPI * ProtocolSequence;
|
|
RPC_CHAR PAPI * PSeq;
|
|
RPC_CLIENT_TRANSPORT_INFO PAPI * ClientInfo;
|
|
#ifdef NTENV
|
|
UNICODE_STRING UnicodeStr;
|
|
#endif
|
|
|
|
Id = (Tower + sizeof(unsigned short));
|
|
|
|
TransportId = (0x00FF & *Id);
|
|
|
|
ClientInfo = (RPC_CLIENT_TRANSPORT_INFO PAPI *)
|
|
GetLoadedClientTransportInfoFromId(TransportId);
|
|
if (ClientInfo != 0)
|
|
{
|
|
Status = ClientInfo->TowerExplode(
|
|
Tower,
|
|
Protseq,
|
|
Endpoint,
|
|
NWAddress);
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
//Unfortunately the transport was not loaded ..
|
|
//
|
|
|
|
Status = RpcGetAdditionalTransportInfo(TransportId, &ProtocolSequence);
|
|
|
|
if (Status == RPC_S_OK)
|
|
{
|
|
|
|
#ifdef NTENV
|
|
|
|
if (Status = AnsiToUnicodeString(
|
|
(unsigned char PAPI *)ProtocolSequence, &UnicodeStr) )
|
|
{
|
|
return(Status);
|
|
}
|
|
|
|
PSeq = UnicodeStr.Buffer;
|
|
|
|
#else
|
|
|
|
PSeq = (RPC_CHAR PAPI * )ProtocolSequence;
|
|
|
|
#endif
|
|
|
|
ClientInfo = (RPC_CLIENT_TRANSPORT_INFO PAPI *)
|
|
OsfClientMapRpcProtocolSequence(PSeq, &Status);
|
|
}
|
|
else
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
if (Status == RPC_S_OK)
|
|
{
|
|
if (ClientInfo != 0)
|
|
{
|
|
Status = ClientInfo->TowerExplode(
|
|
Tower,
|
|
Protseq,
|
|
Endpoint,
|
|
NWAddress);
|
|
}
|
|
else
|
|
{
|
|
Status = RPC_S_INVALID_RPC_PROTSEQ;
|
|
}
|
|
}
|
|
|
|
#ifdef NTENV
|
|
RtlFreeUnicodeString(&UnicodeStr);
|
|
#endif
|
|
|
|
return(Status);
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef NTENV
|
|
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::Cancel(
|
|
void * ThreadHandle
|
|
)
|
|
{
|
|
NTSTATUS NtStatus = NtAlertThread((HANDLE) ThreadHandle);
|
|
|
|
if (NT_SUCCESS(NtStatus))
|
|
{
|
|
return RPC_S_OK;
|
|
}
|
|
else
|
|
{
|
|
return RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
}
|
|
|
|
unsigned
|
|
OSF_CCONNECTION::TestCancel(
|
|
)
|
|
{
|
|
if (NtTestAlert() == STATUS_ALERTED)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#elif (DOSWIN32RPC)
|
|
|
|
RPC_STATUS
|
|
OSF_CCONNECTION::Cancel(
|
|
void * ThreadHandle
|
|
)
|
|
{
|
|
return (RPC_S_CANNOT_SUPPORT);
|
|
}
|
|
|
|
unsigned
|
|
OSF_CCONNECTION::TestCancel(
|
|
)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
#endif
|