windows-nt/Source/XPSP1/NT/com/rpc/runtime/mtrt/epclnt.cxx

882 lines
22 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (C) Microsoft Corporation, 1991 - 1999
Module Name:
epclnt.cxx
Abstract:
This file contains the client runtime entry points into the
endpoint mapper dll.
Author:
Michael Montague (mikemon) 06-Jan-1992
Revision History:
--*/
#include <precomp.hxx>
#include <epmp.h>
#include <epmap.h>
#include <twrproto.h>
#include <CharConv.hxx>
#include <OsfPcket.hxx>
#include <BitSet.hxx>
#include <ProtBind.hxx>
#include <OsfClnt.hxx>
extern RPC_STATUS __RPC_FAR
MapFromNcaStatusCode (
IN unsigned long NcaStatus
);
static ProtseqEndpointPair EpMapperTable[] =
{
"ncacn_np", "\\pipe\\epmapper",
"ncalrpc", "epmapper",
"ncacn_ip_tcp", "135",
"ncadg_ip_udp", "135",
#ifdef NETBIOS_ON
"ncacn_nb_nb", "135",
"ncacn_nb_tcp", "135",
"ncacn_nb_ipx", "135",
#endif
#ifdef SPX_ON
"ncacn_spx", "34280",
#endif
#ifdef IPX_ON
"ncadg_ipx", "34280",
#endif
#ifdef APPLETALK_ON
"ncacn_at_dsp", "Endpoint Mapper",
#endif
#ifdef NCADG_MQ_ON
"ncadg_mq", "EpMapper",
#endif
"ncacn_http", "593"
};
unsigned long PartialRetries=0;
unsigned long ReallyTooBusy=0;
typedef struct _EP_LOOKUP_DATA
{
unsigned int NumberOfEndpoints;
unsigned int MaximumEndpoints;
unsigned int CurrentEndpoint;
RPC_CHAR * PAPI * Endpoints;
} EP_LOOKUP_DATA;
RPC_STATUS RPC_ENTRY
EpResolveEndpoint (
IN UUID PAPI * ObjectUuid, OPTIONAL
IN RPC_SYNTAX_IDENTIFIER PAPI * IfId,
IN RPC_SYNTAX_IDENTIFIER PAPI * XferId,
IN RPC_CHAR PAPI * RpcProtocolSequence,
IN RPC_CHAR PAPI * NetworkAddress,
IN RPC_CHAR PAPI * Options,
IN OUT void PAPI * PAPI * EpLookupHandle,
IN unsigned ConnTimeout,
IN ULONG CallTimeout,
IN CLIENT_AUTH_INFO *AuthInfo, OPTIONAL
OUT RPC_CHAR * PAPI * Endpoint
)
/*++
Routine Description:
The runtime will call this routine to resolve an endpoint.
Arguments:
ObjectUuid - Optional specifies the object uuid in the binding
for which we are trying to resolve an endpoint.
Ifid - Pointer to the Syntax Identifier for the Interface
Xferid - Pointer to the Syntax Identifier for the Transfer Syntax.
RpcProtocolSequence - Supplies the rpc protocol sequence contained
in the binding.
NetworkAddress - Supplies the network address. This will be used
to contact the endpoint mapper on that machine in order to
resolve the endpoint.
EpLookupHandle - Supplies the current version of the lookup handle
for this iteration through the endpoint mapper. A new value
for the lookup handle will be returned. If RPC_S_NO_ENDPOINT_FOUND
is returned, this parameter will be set to its initial value,
zero.
ConnTimeout - the connection timeout
CallTimeout - the call timeout
AutInfo - any auth info that needs to be used during the resolution process
Endpoint - Returns the endpoint resolved by the endpoint mapper on
the machine specified by the network address argument. The
storage for the endpoint must have been allocated using the
runtime API I_RpcAllocate.
Return Value:
RPC_S_OK - The endpoint was successfully resolved.
EP_S_NOT_REGISTERED - There are no more endpoints to be found
for the specified combination of interface, network address,
and lookup handle.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allow
resolution of the endpoint.
EP_S_CANT_PERFORM_OP - The operation failed due to misc. error e.g.
unable to bind to the EpMapper.
--*/
{
RPC_BINDING_HANDLE MapperHandle;
RPC_STATUS RpcStatus;
twr_p_t InputTower = 0;
twr_p_t OutputTower[4];
unsigned long Returned;
error_status ErrorStatus;
ept_lookup_handle_t ContextHandle = 0;
EP_LOOKUP_DATA PAPI * EpLookupData = (EP_LOOKUP_DATA PAPI *)
*EpLookupHandle;
unsigned long RetryCount, i;
unsigned char PAPI * EPoint;
CHeapAnsi AnsiNWAddr, AnsiOptions;
CStackAnsi AnsiProtseq;
CNlUnicode nlEndpoint;
ASSERT(*Endpoint == 0);
// We have already taken all of the endpoints from the endpoint mapper;
// now we just return them back to the runtime one at a time.
ReturnEndpointFromList:
if ( EpLookupData != 0 )
{
// When we reach the end of the list of endpoints, return an error,
// and set things up so that we will start at the beginning again.
if ( EpLookupData->CurrentEndpoint == EpLookupData->NumberOfEndpoints )
{
RpcpErrorAddRecord(EEInfoGCRuntime,
EPT_S_NOT_REGISTERED,
EEInfoDLEpResolveEndpoint10,
RpcProtocolSequence,
NetworkAddress,
IfId->SyntaxGUID.Data1,
(ULONG)((EpLookupData->CurrentEndpoint << 16) | EpLookupData->NumberOfEndpoints));
EpLookupData->CurrentEndpoint = 0;
return(EPT_S_NOT_REGISTERED);
}
*Endpoint = DuplicateString(
EpLookupData->Endpoints[EpLookupData->CurrentEndpoint]);
EpLookupData->CurrentEndpoint += 1;
if ( *Endpoint == 0 )
{
return(RPC_S_OUT_OF_MEMORY);
}
return(RPC_S_OK);
}
// Otherwise, we need to take the list of endpoints from the endpoint
// mapper.
EpLookupData = (EP_LOOKUP_DATA PAPI *) RpcpFarAllocate(
sizeof(EP_LOOKUP_DATA));
if ( EpLookupData == 0 )
{
return(RPC_S_OUT_OF_MEMORY);
}
EpLookupData->MaximumEndpoints = 64;
EpLookupData->Endpoints = (RPC_CHAR * PAPI *) RpcpFarAllocate(
sizeof(RPC_CHAR PAPI *) * EpLookupData->MaximumEndpoints);
if ( EpLookupData->Endpoints == 0 )
{
RpcpFarFree(EpLookupData);
EpLookupData = 0;
return(RPC_S_OUT_OF_MEMORY);
}
EpLookupData->NumberOfEndpoints = 0;
EpLookupData->CurrentEndpoint = 0;
RpcStatus = AnsiNWAddr.Attach(NetworkAddress);
if ( RpcStatus != RPC_S_OK )
{
ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY );
RpcpFarFree(EpLookupData);
EpLookupData = 0;
return(RpcStatus);
}
i = 1+RpcpStringLength(RpcProtocolSequence);
*(AnsiProtseq.GetPAnsiString()) = (char *)_alloca(i);
RpcStatus = AnsiProtseq.Attach(RpcProtocolSequence, i, i * 2);
if ( RpcStatus != RPC_S_OK )
{
ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY );
RpcpFarFree(EpLookupData);
EpLookupData = 0;
return(RpcStatus);
}
RpcStatus = AnsiOptions.Attach(Options);
if ( RpcStatus != RPC_S_OK )
{
ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY );
RpcpFarFree(EpLookupData);
EpLookupData = 0;
return(RpcStatus);
}
RpcStatus = BindToEpMapper(&MapperHandle,
NetworkAddress,
RpcProtocolSequence,
Options,
ConnTimeout,
CallTimeout,
AuthInfo
);
if ( RpcStatus != RPC_S_OK )
{
MapperHandle = 0;
goto CleanupAndReturn;
}
RpcStatus = TowerConstruct((RPC_IF_ID PAPI *) IfId,
(RPC_TRANSFER_SYNTAX PAPI *) XferId, (char PAPI *) AnsiProtseq,
NULL, (char PAPI *) AnsiNWAddr, &InputTower);
if ( RpcStatus != RPC_S_OK )
{
goto CleanupAndReturn;
}
for (RetryCount = 0;;)
{
OutputTower[0] = 0;
OutputTower[1] = 0;
OutputTower[2] = 0;
OutputTower[3] = 0;
RpcTryExcept
{
ept_map(MapperHandle, ObjectUuid, InputTower, &ContextHandle, 4L,
&Returned, &OutputTower[0], &ErrorStatus);
}
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
{
ErrorStatus = RpcExceptionCode();
}
RpcEndExcept
if ( ErrorStatus == RPC_S_SERVER_TOO_BUSY)
{
if (RetryCount < 3)
{
RetryCount ++;
PartialRetries++;
continue;
}
else
{
ReallyTooBusy++;
}
}
if ( ErrorStatus != 0 )
{
// For DCE interop the endpoint mapper returns DCE errors on the
// wire. We need to map some of them to the MS RPC ones.
switch (ErrorStatus)
{
case EP_S_CANT_PERFORM_OP :
RpcStatus = EPT_S_CANT_PERFORM_OP;
break;
case EP_S_NOT_REGISTERED :
RpcpErrorAddRecord(EEInfoGCRuntime,
EPT_S_NOT_REGISTERED,
EEInfoDLEpResolveEndpoint20,
RpcProtocolSequence,
NetworkAddress,
IfId->SyntaxGUID.Data1,
(ULONGLONG)MapperHandle);
RpcStatus = EPT_S_NOT_REGISTERED;
break;
default :
RpcStatus = MapFromNcaStatusCode(ErrorStatus);
break;
}
break;
}
ASSERT( ((Returned != 0) || (ContextHandle == 0)) && (Returned <= 4) );
for (i = 0; i < Returned; i++)
{
if (OutputTower[i] == 0)
{
return RPC_S_OUT_OF_MEMORY ;
}
RpcStatus = TowerExplode(
OutputTower[i],
NULL,
NULL,
NULL,
(char PAPI * PAPI *) &EPoint,
NULL
);
if ( RpcStatus != RPC_S_OK )
{
break;
}
RpcStatus = nlEndpoint.Attach((char *)EPoint);
*Endpoint = nlEndpoint;
I_RpcFree(EPoint);
if ( *Endpoint == 0 )
{
RpcStatus = RPC_S_OUT_OF_MEMORY;
break;
}
EpLookupData->Endpoints[EpLookupData->NumberOfEndpoints] =
*Endpoint;
EpLookupData->NumberOfEndpoints += 1;
if ( EpLookupData->NumberOfEndpoints ==
EpLookupData->MaximumEndpoints )
{
goto OutsideTheLoop;
}
}//..for Loop over parse all towers/eps in this loop
for (i = 0; i < Returned; i++)
{
MIDL_user_free(OutputTower[i]);
}
if ( (ContextHandle == 0) || (RpcStatus != RPC_S_OK) )
{
break;
}
} //..for loop over get all endpoints
OutsideTheLoop:
ASSERT( InputTower != 0 );
I_RpcFree(InputTower);
CleanupAndReturn:
if ( MapperHandle != 0 )
{
RPC_STATUS Status = RpcBindingFree(&MapperHandle);
ASSERT( Status == RPC_S_OK );
}
if ( ContextHandle != 0 )
{
RpcSsDestroyClientContext(&ContextHandle);
}
if ( ( RpcStatus == EPT_S_NOT_REGISTERED )
|| ( RpcStatus == RPC_S_OK ) )
{
if ( EpLookupData->NumberOfEndpoints != 0 )
{
*EpLookupHandle = EpLookupData;
goto ReturnEndpointFromList;
}
RpcStatus = EPT_S_NOT_REGISTERED;
}
if ( EpLookupData != 0 )
{
if ( EpLookupData->Endpoints != 0 )
{
while ( EpLookupData->NumberOfEndpoints > 0 )
{
EpLookupData->NumberOfEndpoints -= 1;
delete EpLookupData->Endpoints[EpLookupData->NumberOfEndpoints];
}
RpcpFarFree(EpLookupData->Endpoints);
}
RpcpFarFree(EpLookupData);
}
return(RpcStatus);
}
RPC_STATUS RPC_ENTRY
EpGetEpmapperEndpoint(
IN OUT RPC_CHAR * PAPI * Endpoint,
IN RPC_CHAR PAPI * Protseq
)
/*+
Routine Description:
Returns the Endpoint mappers well known endpoint for a given
protocol sequence.
Arguments:
Endpoint - Place to store the epmappers well known endpoint.
Protsq - Protocol sequence the client wishes to use.
Return Value:
RPC_S_OK - Found the protocol sequence in the epmapper table and
am returning the associated well known endpoint.
EPT_S_CANT_PERFORM_OP - Protocol sequence not found.
--*/
{
RPC_STATUS Status = EPT_S_CANT_PERFORM_OP;
RPC_STATUS rc;
unsigned int i, Count;
CStackAnsi AnsiProtseq;
CNlUnicode nlEndpoint;
unsigned char PAPI * Epoint;
if (Protseq != NULL)
{
#ifdef UNICODE
//Must convert the protocol sequence into an ansi string from unicode
i = 1 + RpcpStringLength(Protseq);
*(AnsiProtseq.GetPAnsiString()) = (char *)_alloca(i);
rc = AnsiProtseq.Attach(Protseq, i, i * 2);
if ( rc != RPC_S_OK )
{
ASSERT( rc == RPC_S_OUT_OF_MEMORY );
return(Status);
}
#else
AnsiProtseq = Protseq;
#endif
Count = sizeof(EpMapperTable)/sizeof(EpMapperTable[0]);
for (i = 0; i < Count; i++)
{
//Search for the protocol sequence client is using.
if ( RpcpStringCompareA((char PAPI *)AnsiProtseq,
(char PAPI *)EpMapperTable[i].Protseq) )
{
//Not yet found.
continue;
}
else
{
//Found a match. Grab the epmappers known endpoint.
Epoint = (unsigned char __RPC_FAR *)(EpMapperTable[i].Endpoint);
rc = nlEndpoint.Attach((char *)Epoint);
*Endpoint = nlEndpoint;
Status = RPC_S_OK;
break;
}
} //for
}//if
return(Status);
}
RPC_STATUS RPC_ENTRY
BindToEpMapper(
OUT RPC_BINDING_HANDLE PAPI * MapperHandle,
IN RPC_CHAR * NWAddress OPTIONAL,
IN RPC_CHAR * Protseq OPTIONAL,
IN RPC_CHAR * Options OPTIONAL,
IN unsigned ConnTimeout,
IN ULONG CallTimeout,
IN CLIENT_AUTH_INFO *AuthInfo OPTIONAL
)
/*+
Routine Description:
This helper routine is used to by RpcEpRegister[NoReplace],
RpcEpUnRegister and EpResolveEndpoint(epclnt.cxx) to bind to
the EpMapper. If a Protseq is supplied, that particular protseq
is tried, otherwise lrpc is used to connect to the local epmapper.
If a NW Address is specified EpMapper at that host is contacted, else
local Endpoint mapper is used.
Arguments:
MapperHandle- Returns binding handle to the Endpoint mapper
NWAddress - NW address of the Endpoint mapper to bind to.
Ignored if protseq is NULL.
Protseq - Protocol sequence the client wishes to use.
NULL indicates a call to the local endpoint mapper.
ConnTimeout - the connection timeout
CallTimeout - the call timeout
AuthInfo - authentication information for the resolution
Return Value:
RPC_S_OK - The ansi string was successfully converted into a unicode
string.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available for the unicode
string.
EP_S_CANT_PERFORM_OP - The binding was unsuccessful, possibly because
the protocol sequence is not supported.
--*/
{
RPC_STATUS Status = EPT_S_CANT_PERFORM_OP;
RPC_CHAR * BindingString = NULL;
unsigned int i, Count;
BOOL fHttp = FALSE;
Count = sizeof(EpMapperTable)/sizeof(EpMapperTable[0]);
// If Protseq == NULL use lrpc.
if (NULL == Protseq)
{
ASSERT(NWAddress == 0);
BindingString = RPC_STRING_LITERAL("ncalrpc:[epmapper]");
}
else
{
char * AnsiProtseq;
AnsiProtseq = (char *) _alloca(1+RpcpStringLength(Protseq));
if (!AnsiProtseq)
{
return RPC_S_OUT_OF_MEMORY;
}
SimpleUnicodeToAnsi(Protseq, AnsiProtseq);
if (Options)
{
fHttp = (0 == RpcpStringCompare(Protseq, RPC_STRING_LITERAL("ncacn_http")));
}
for (i = 0; i < Count; i++)
{
if (RpcpStringCompareA(AnsiProtseq,
(char PAPI *) EpMapperTable[i].Protseq) )
continue;
// Found it.
RPC_CHAR * Endpoint;
Endpoint = (RPC_CHAR *) _alloca(sizeof(RPC_CHAR) * (1+strlen(EpMapperTable[i].Endpoint)));
if (!Endpoint)
{
return RPC_S_OUT_OF_MEMORY;
}
SimpleAnsiToPlatform(EpMapperTable[i].Endpoint, Endpoint);
Status = RpcStringBindingCompose( NULL,
Protseq,
NWAddress,
Endpoint,
(fHttp ? Options : 0),
&BindingString);
break;
}
}
if (BindingString)
{
Status = RpcBindingFromStringBinding(BindingString, MapperHandle);
}
if (BindingString != NULL && Protseq != NULL)
{
RpcStringFree(&BindingString);
}
if (Status != RPC_S_OK)
{
return(EPT_S_CANT_PERFORM_OP);
}
if (AuthInfo && (RpcpStringNCompare(Protseq, RPC_STRING_LITERAL("ncacn_"), 6) == 0))
{
Status = SetAuthInformation (*MapperHandle, AuthInfo);
if (Status != RPC_S_OK)
return Status;
}
Status = RpcMgmtSetComTimeout(*MapperHandle, ConnTimeout);
if (Status != RPC_S_OK)
{
return(EPT_S_CANT_PERFORM_OP);
}
return(RPC_S_OK);
}
void RPC_ENTRY
EpFreeLookupHandle (
IN void PAPI * EpLookupHandle
)
{
EP_LOOKUP_DATA PAPI * EpLookupData = (EP_LOOKUP_DATA PAPI *) EpLookupHandle;
if ( EpLookupData->Endpoints != 0 )
{
while ( EpLookupData->NumberOfEndpoints > 0 )
{
EpLookupData->NumberOfEndpoints -= 1;
delete EpLookupData->Endpoints[EpLookupData->NumberOfEndpoints];
}
RpcpFarFree(EpLookupData->Endpoints);
}
RpcpFarFree(EpLookupData);
}
HPROCESS hRpcssContext = 0;
RPC_STATUS RPC_ENTRY
I_RpcServerAllocateIpPort(
IN DWORD Flags,
OUT USHORT *pPort
)
{
USHORT Port;
RPC_STATUS status;
RPC_BINDING_HANDLE hServer;
PORT_TYPE type;
*pPort = 0;
// Figure out what sort of port to allocate
if (Flags & RPC_C_USE_INTERNET_PORT)
{
type = PORT_INTERNET;
Flags &= ~RPC_C_USE_INTERNET_PORT;
}
else if (Flags & RPC_C_USE_INTRANET_PORT)
{
type = PORT_INTRANET;
Flags &= ~RPC_C_USE_INTRANET_PORT;
}
else
{
type = PORT_DEFAULT;
}
// Setup process context in the endpoint mapper if needed.
if (hRpcssContext == 0)
{
HPROCESS hProcess;
status = RpcBindingFromStringBinding(RPC_STRING_LITERAL("ncalrpc:[epmapper]"),
&hServer);
if (status != RPC_S_OK)
{
return(status);
}
hProcess = 0;
status = OpenEndpointMapper(hServer,
&hProcess);
RPC_STATUS statust =
RpcBindingFree(&hServer);
ASSERT(statust == RPC_S_OK);
if (status != RPC_S_OK)
{
return(status);
}
GlobalMutexRequest();
if (hRpcssContext != 0)
{
ASSERT(hRpcssContext != hProcess);
RpcSmDestroyClientContext(&hProcess);
}
else
{
hRpcssContext = hProcess;
}
GlobalMutexClear();
}
// Actually allocate a port.
RPC_STATUS allocstatus;
status = AllocateReservedIPPort(hRpcssContext,
type,
&allocstatus,
pPort);
if (status != RPC_S_OK)
{
ASSERT(*pPort == 0);
return(status);
}
return(allocstatus);
}
// Very special code for our older (NT 3.1 Era) servers.
//
// These server send out unique pointers which will confuse our
// stubs while unmarshalling. Here we go through and fixup the
// node id's to look like full pointers.
//
// This code can be removed when support for NT 3.1 era servers
// is no longer required.
extern "C"
void FixupForUniquePointerServers(PRPC_MESSAGE pMessage)
{
int CurrentPointer = 3;
unsigned int NumberOfPointers;
unsigned int i;
unsigned long __RPC_FAR *pBuffer;
pBuffer = (unsigned long __RPC_FAR *) pMessage->Buffer;
// The output buffer looks like:
// [ out-context handle (20b) ]
// [ count (4b) ]
// [ max (4b) ]
// [ min (4b) ]
// [ length (4b) ] // should be the same as count
// [ pointer node (count of them) ]
ASSERT(pBuffer[5] == pBuffer[8]);
NumberOfPointers = pBuffer[5];
ASSERT(pMessage->BufferLength >= 4 * 9 + 4 * NumberOfPointers);
for(i = 0; i < NumberOfPointers; i++)
{
if (pBuffer[9 + i] != 0)
{
pBuffer[9 + i] = CurrentPointer;
CurrentPointer++;
}
}
return;
}
#if defined(WIN) || defined(WIN32)
void __RPC_FAR * __RPC_API
MIDL_user_allocate(
size_t Size
)
/*++
Routine Description:
MIDL generated stubs need this routine.
Arguments:
Size - Supplies the length of the memory to allocate in bytes.
Return Value:
The buffer allocated will be returned, if there is sufficient memory,
otherwise, zero will be returned.
--*/
{
void PAPI * pvBuf;
pvBuf = I_RpcAllocate(Size);
return(pvBuf);
}
void __RPC_API
MIDL_user_free (
void __RPC_FAR *Buf
)
{
I_RpcFree(Buf);
}
#endif