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

1979 lines
50 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
binding.cxx
Abstract:
The implementation of the DCE binding class is contained in this
file.
Author:
Michael Montague (mikemon) 04-Nov-1991
Revision History:
--*/
#include <precomp.hxx>
#include <epmap.h>
#ifdef DOSWIN32RPC
#define DBCS_ENABLED 1
#endif
#ifdef WIN
//NotifyRegister writes over hTask:0x28.
//We sacrifice the 0x40 bytes to appease the Win31 gods here
//
char LeaveSomeRoom[0x30] = { 'x' };
#endif
#ifdef WIN32RPC
UUID MgmtIf = { 0xafa8bd80,0x7d8a,0x11c9,
{0xbe,0xf4,0x08,0x00,0x2b,0x10,0x29,0x89} };
UUID NullUuid = { 0L, 0, 0, {0,0,0,0,0,0,0,0} };
int
IsMgmtIfUuid(
UUID PAPI * IfId
)
{
if (RpcpMemoryCompare(IfId, &MgmtIf, sizeof(UUID)) == 0)
{
return 1;
}
return 0;
}
#endif
RPC_CHAR *
DuplicateString (
IN RPC_CHAR PAPI * String
)
/*++
Routine Description:
When this routine is called, it will duplicate the string into a fresh
string and return it.
Arguments, either:
String - Supplies the string to be duplicated.
Ansi String - Supplies the string to be duplicated.
Return Value:
The duplicated string is returned. If insufficient memory is available
to allocate a fresh string, zero will be returned.
--*/
{
RPC_CHAR * FreshString, * FreshStringScan;
RPC_CHAR PAPI * StringScan;
unsigned int Length;
Length = 1;
StringScan = String;
while (*StringScan++ != 0)
Length += 1;
FreshString = new RPC_CHAR[Length];
if (FreshString == 0)
return(0);
for (FreshStringScan = FreshString, StringScan = String;
*StringScan != 0; FreshStringScan++, StringScan++)
{
*FreshStringScan = *StringScan;
}
*FreshStringScan = *StringScan;
return(FreshString);
}
DCE_BINDING::DCE_BINDING (
IN RPC_CHAR PAPI * ObjectUuid OPTIONAL,
IN RPC_CHAR PAPI * RpcProtocolSequence OPTIONAL,
IN RPC_CHAR PAPI * NetworkAddress OPTIONAL,
IN RPC_CHAR PAPI * Endpoint OPTIONAL,
IN RPC_CHAR PAPI * Options OPTIONAL,
OUT RPC_STATUS PAPI * Status
)
/*++
Routine Description:
The constructor creates a DCE_BINDING object based on the pieces of
the string binding specified.
Arguments:
ObjectUuid - Optionally supplies the object uuid component of the
binding.
RpcProtocolSequence - Optionally supplies the rpc protocol sequence
component of the binding.
NetworkAddress - Optionally supplies the network address component
of the binding.
Endpoint - Optionally supplies the endpoint component of the binding.
Options - Optionally supplies the network options component of the
binding.
Status - Returns the status of the operation. This argument will
be set to one of the following values.
RPC_S_OK - The operation completed successfully.
RPC_S_INVALID_STRING_UUID - The specified object uuid does
not contain the valid string representation of a uuid.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to
complete the operation.
--*/
{
ALLOCATE_THIS(DCE_BINDING);
*Status = RPC_S_OK;
if ( ARGUMENT_PRESENT(ObjectUuid)
&& (ObjectUuid[0] != 0))
{
if (this->ObjectUuid.ConvertFromString(ObjectUuid))
{
*Status = RPC_S_INVALID_STRING_UUID;
this->ObjectUuid.SetToNullUuid();
}
}
else
this->ObjectUuid.SetToNullUuid();
if (ARGUMENT_PRESENT(RpcProtocolSequence))
{
this->RpcProtocolSequence = DuplicateString(RpcProtocolSequence);
if (this->RpcProtocolSequence == 0)
*Status = RPC_S_OUT_OF_MEMORY;
}
else
this->RpcProtocolSequence = 0;
if (ARGUMENT_PRESENT(NetworkAddress))
{
this->NetworkAddress = DuplicateString(NetworkAddress);
if (this->NetworkAddress == 0)
*Status = RPC_S_OUT_OF_MEMORY;
}
else
this->NetworkAddress = 0;
if (ARGUMENT_PRESENT(Endpoint))
{
this->Endpoint = DuplicateString(Endpoint);
if (this->Endpoint == 0)
*Status = RPC_S_OUT_OF_MEMORY;
}
else
this->Endpoint = 0;
if (ARGUMENT_PRESENT(Options))
{
this->Options = DuplicateString(Options);
if (this->Options == 0)
*Status = RPC_S_OUT_OF_MEMORY;
}
else
{
this->Options = AllocateEmptyString();
if (this->Options == 0)
*Status = RPC_S_OUT_OF_MEMORY;
}
}
/*static*/ RPC_CHAR PAPI *
StringCharSearchWithEscape (
IN RPC_CHAR PAPI * String,
IN unsigned int Character
)
/*++
Routine Description:
This routine is the same as the library routine, strchr, except that
the backslash character ('\') is treated as an escape character.
Arguments:
String - Supplies the string in which to search for the character.
Character - Supplies the character to search for in the string.
Return Value:
A pointer to the first occurance of Character in String is returned.
If Character does not exist in String, then 0 is returned.
--*/
{
#ifdef DBCS_ENABLED
ASSERT(IsDBCSLeadByte((RPC_CHAR)Character) == FALSE);
ASSERT(IsDBCSLeadByte(RPC_CONST_CHAR('\\')) == FALSE);
while(*String != (RPC_CHAR)Character)
{
if (*String == 0)
return(0);
if (*String == RPC_CONST_CHAR('\\'))
{
String = (RPC_CHAR *)CharNext((LPCSTR)String);
}
String = (RPC_CHAR *)CharNext((LPCSTR)String);
}
return(String);
#else
while (*String != (RPC_CHAR) Character)
{
if (*String == 0)
return(0);
if (*String == RPC_CONST_CHAR('\\'))
String++;
String++;
}
return(String);
#endif
}
/*static*/ void
StringCopyWithEscape (
OUT RPC_CHAR PAPI * Destination,
IN RPC_CHAR PAPI * Source
)
/*++
Routine Description:
This routine is the same as the library routine, strcpy, except that
the backslash character ('\') is treated as an escape character. When
a character is escaped, the backslash character is not copied to the
Destination.
Arguments:
Destination - Returns a duplicate of the string specified in Source,
but with out escaped characters escaped.
Source - Specifies the string to be copied.
Return Value:
None.
--*/
{
BOOL fLastQuote = FALSE;
#ifdef DBCS_ENABLED
ASSERT(IsDBCSLeadByte('\\') == FALSE);
#endif
while ((*Destination = *Source) != 0)
{
#ifdef DBCS_ENABLED
if (IsDBCSLeadByte(*Source))
{
// Copy the whole DBCS character; don't look for
// escapes within the character.
Destination++;
Source++;
*Destination = *Source;
if (*Source == 0)
{
ASSERT(0); // Bad string, NULL following a lead byte.
return;
}
Destination++;
Source++;
}
else
#endif
{
if ( *Source != RPC_CONST_CHAR('\\')
|| fLastQuote == TRUE)
{
Destination++;
fLastQuote = FALSE;
}
else
{
fLastQuote = TRUE;
}
Source++;
}
}
}
/*static*/ RPC_STATUS
ParseAndCopyEndpointField (
OUT RPC_CHAR ** Endpoint,
IN RPC_CHAR PAPI * String
)
/*++
Routine Description:
This routine parses and then copies the endpoint field in String. A
copy of the field is made into a newly allocated string and returned
in Endpoint. String is assumed to contain only the endpoint field;
the terminating ',' or ']' are not included.
Arguments:
Endpoint - Returns a copy of the endpoint field in a newly allocated
string.
String - Supplies the endpoint field to be parsed and copied.
Return Value:
RPC_S_OK - The operation completed successfully.
RPC_S_OUT_OF_MEMORY - There is no memory available to make a copy
of the string.
RPC_S_INVALID_ENDPOINT_FORMAT - The endpoint field is syntactically
incorrect. This error code will be returned if the endpoint field
does not match the following pattern.
[ <Endpoint> | "endpoint=" <Endpoint> ]
--*/
{
// Search will be used to scan along the string to find the end of
// the endpoint field and the '='.
RPC_CHAR PAPI * Search;
Search = StringCharSearchWithEscape(String,RPC_CONST_CHAR('='));
if (Search == 0)
{
// This means that we have the <Endpoint> pattern, so we just
// copy the endpoint field.
Search = StringCharSearchWithEscape(String,0);
*Endpoint = new RPC_CHAR[Search - String + 1];
if (*Endpoint == 0)
return(RPC_S_OUT_OF_MEMORY);
StringCopyWithEscape(*Endpoint,String);
return(RPC_S_OK);
}
// Otherwise, we have the "endpoint=" pattern. First we need to check
// that the string before the '=' is in fact "endpoint".
*Search = 0;
if ( RpcpStringCompare(String, RPC_CONST_STRING("endpoint")) != 0 )
{
*Search = RPC_CONST_CHAR('=');
return(RPC_S_INVALID_ENDPOINT_FORMAT);
}
*Search = RPC_CONST_CHAR('=');
String = Search + 1;
// Now we just need to allocate a new string and copy the endpoint into
// it.
Search = StringCharSearchWithEscape(String,0);
*Endpoint = new RPC_CHAR[Search - String + 1];
if (*Endpoint == 0)
return(RPC_S_OUT_OF_MEMORY);
StringCopyWithEscape(*Endpoint,String);
return(RPC_S_OK);
}
RPC_CHAR *
AllocateEmptyString (
void
)
/*++
Routine Description:
This routine allocates and returns an empty string ("").
Return Value:
A newly allocated empty string will be returned.
--*/
{
RPC_CHAR * String;
String = new RPC_CHAR[1];
if (String != 0)
*String = 0;
return(String);
}
DCE_BINDING::DCE_BINDING (
IN RPC_CHAR PAPI * StringBinding,
OUT RPC_STATUS PAPI * Status
)
/*++
Routine Description:
This constructor creates a DCE_BINDING object from a string binding,
which requires that the string binding be parsed into seperate
strings and validated.
Arguments:
StringBinding - Supplies the string being to be parsed.
Status - Returns the status of the operation. This parameter will
take on the following values:
RPC_S_OK - The operation completed successfully.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to
allocate space for the fields of the string binding.
RPC_S_INVALID_STRING_BINDING - The string binding is
syntactically invalid.
RPC_S_INVALID_ENDPOINT_FORMAT - The endpoint specified in
the string binding is syntactically incorrect.
RPC_S_INVALID_STRING_UUID - The specified object uuid does not
contain the valid string representation of a uuid.
--*/
{
// String will point to the beginning of the field we are trying to
// parse.
RPC_CHAR PAPI * String;
// Search will be used to scan along the string to find the end of
// the field we are trying to parse.
RPC_CHAR PAPI * Search;
// This will contain the string representation of the object uuid.
RPC_CHAR PAPI * ObjectUuidString;
ALLOCATE_THIS(DCE_BINDING);
// A string binding consists of an optional object uuid, an RPC protocol
// sequence, a network address, an optional endpoint, and zero or more
// option fields.
//
// [ <Object UUID> "@" ] <RPC Protocol Sequence> ":" <Network Address>
// [ "[" ( <Endpoint> | "endpoint=" <Endpoint> | ) [","]
// [ "," <Option Name> "=" <Option Value>
// ( <Option Name> "=" <Option Value> )* ] "]" ]
//
// If an object UUID is specified, then it will be followed by '@'.
// Likewise, if an endpoint and/or option(s) are specified, they will
// be in square brackets. Finally, one or more options are specified,
// then ',' must seperate the optional endpoint from the options. The
// backslash character '\' is treated as an escape character in all
// string binding fields.
// To begin with, we need to set all of the string pointers to zero.
// This is necessary so that when we do memory cleanup for error
// recovery, we know which pointers we allocated a string for.
ObjectUuidString = 0;
RpcProtocolSequence = 0;
NetworkAddress = 0;
Endpoint = 0;
Options = 0;
String = StringBinding;
// To begin with, we need to parse off the object UUID from the string
// if it exists.
Search = StringCharSearchWithEscape(String,RPC_CONST_CHAR('@'));
if (Search == 0)
{
// The string binding does not contain an object UUID.
ObjectUuid.SetToNullUuid();
}
else
{
// There is an object UUID in the string.
// We need to add one for the terminating zero in the
// string.
ObjectUuidString = (RPC_CHAR PAPI *) RpcpFarAllocate(
sizeof(RPC_CHAR)*(Search - String + 1));
if (ObjectUuidString == 0)
{
*Status = RPC_S_OUT_OF_MEMORY;
goto FreeMemoryAndReturn;
}
// Now copy the string.
*Search = 0;
StringCopyWithEscape(ObjectUuidString,String);
*Search = RPC_CONST_CHAR('@');
// Finally, update String so that we are ready to parse the next
// field.
String = Search + 1;
// Now convert the string representation of the object uuid
// into an actual uuid.
if (ObjectUuid.ConvertFromString(ObjectUuidString))
{
*Status = RPC_S_INVALID_STRING_UUID;
goto FreeMemoryAndReturn;
}
RpcpFarFree(ObjectUuidString);
ObjectUuidString = 0;
}
// The RPC protocol sequence field comes next; it is terminated by
// ':'. Both the RPC protocol sequence field and the ':' are required.
Search = StringCharSearchWithEscape(String,RPC_CONST_CHAR(':'));
if (Search == 0)
{
// This is an error, because the RPC protocol sequence field is
// required. We may need to free the string we allocated for
// the object UUID field.
*Status = RPC_S_INVALID_STRING_BINDING;
goto FreeMemoryAndReturn;
}
else
{
// The same comments which applied to copying the object UUID
// apply here as well.
RpcProtocolSequence = new RPC_CHAR[Search - String + 1];
if (RpcProtocolSequence == 0)
{
*Status = RPC_S_OUT_OF_MEMORY;
goto FreeMemoryAndReturn;
}
*Search = 0;
StringCopyWithEscape(RpcProtocolSequence,String);
*Search = RPC_CONST_CHAR(':');
// Finally, update String so that we are ready to parse the next
// field.
String = Search + 1;
}
// Next comes the network address field which is required. It is
// terminated by zero or '['.
Search = StringCharSearchWithEscape(String,RPC_CONST_CHAR('['));
if (Search == 0)
{
// This means that the network address is the last field, so we
// just copy it, and set the remaining fields to be empty strings.
Search = StringCharSearchWithEscape(String,0);
NetworkAddress = new RPC_CHAR[Search - String + 1];
if (NetworkAddress == 0)
{
*Status = RPC_S_OUT_OF_MEMORY;
goto FreeMemoryAndReturn;
}
StringCopyWithEscape(NetworkAddress,String);
Endpoint = AllocateEmptyString();
if (Endpoint == 0)
{
*Status = RPC_S_OUT_OF_MEMORY;
goto FreeMemoryAndReturn;
}
Options = AllocateEmptyString();
if (Options == 0)
{
*Status = RPC_S_OUT_OF_MEMORY;
goto FreeMemoryAndReturn;
}
*Status = RPC_S_OK;
return;
}
// Otherwise, if we reach here, there is an endpoint and/or options
// left to parse. But before we parse them, lets copy the network
// address field.
NetworkAddress = new RPC_CHAR [Search - String + 1];
if (NetworkAddress == 0)
{
*Status = RPC_S_OUT_OF_MEMORY;
goto FreeMemoryAndReturn;
}
*Search = 0;
StringCopyWithEscape(NetworkAddress,String);
*Search = RPC_CONST_CHAR('[');
String = Search + 1;
// Now we are ready to parse off the endpoint and/or options.
// To begin with, we check to see if there is a comma.
Search = StringCharSearchWithEscape(String,RPC_CONST_CHAR(','));
if (Search == 0)
{
// There is only one token in the string binding. See
// if its an endpoint, if not, it must be an option.
// Before we copy the endpoint field, we need to check
// for the closing square bracket.
Search = StringCharSearchWithEscape(String,RPC_CONST_CHAR(']'));
if (Search == 0)
{
// This is an error; the string binding is invalid. We need to
// clean everything up, and return an error.
*Status = RPC_S_INVALID_ENDPOINT_FORMAT;
goto FreeMemoryAndReturn;
}
*Search = 0;
*Status = ParseAndCopyEndpointField(&Endpoint,String);
*Search = RPC_CONST_CHAR(']');
// If the parse succeeded, allocate an empty option.
if (*Status == RPC_S_OK)
{
Options = AllocateEmptyString();
if (Options == 0)
{
*Status = RPC_S_OUT_OF_MEMORY;
goto FreeMemoryAndReturn;
}
}
// If the endpoint parse failed with RPC_S_INVALID_ENDPOINT_FORMAT,
// the token must be an option.
else if (*Status == RPC_S_INVALID_ENDPOINT_FORMAT)
{
Endpoint = AllocateEmptyString();
if (Endpoint == 0)
{
*Status = RPC_S_OUT_OF_MEMORY;
goto FreeMemoryAndReturn;
}
Options = new RPC_CHAR [Search - String + 1];
if (Options == 0)
{
*Status = RPC_S_OUT_OF_MEMORY;
goto FreeMemoryAndReturn;
}
*Search = 0;
StringCopyWithEscape(Options,String);
*Search = RPC_CONST_CHAR(']');
}
// Something bad must have happened, clean up.
else
goto FreeMemoryAndReturn;
*Status = RPC_S_OK;
return;
}
// When we reach here, we know that there are options. We have
// to see if there is an endpoint. If there is, copy it and then
// copy the options. If there isn't, allocate a null endpoint and
// copy the options.
*Search = 0;
*Status = ParseAndCopyEndpointField(&Endpoint,String);
*Search = RPC_CONST_CHAR(',');
// If there was an endpoint, skip that part of the string.
// Otherwise treat it as an option.
if (*Status == RPC_S_OK)
String = Search + 1;
else if (*Status != RPC_S_INVALID_ENDPOINT_FORMAT)
goto FreeMemoryAndReturn;
// There was no endpoint, so allocate an empty string.
else
{
Endpoint = AllocateEmptyString();
if (Endpoint == 0)
{
*Status = RPC_S_OUT_OF_MEMORY;
goto FreeMemoryAndReturn;
}
}
// Even if the caller did not specify the NetworkOptions argument,
// we still want to validate the rest of the string binding.
Search = StringCharSearchWithEscape(String,RPC_CONST_CHAR(']'));
if (Search == 0)
{
// This is an error; the string binding is invalid. We need
// to clean everything up, and return an error.
*Status = RPC_S_INVALID_STRING_BINDING;
goto FreeMemoryAndReturn;
}
// Go ahead and copy the network options field if we reach here.
Options = new RPC_CHAR [Search - String + 1];
if (Options == 0)
{
*Status = RPC_S_OUT_OF_MEMORY;
goto FreeMemoryAndReturn;
}
*Search = 0;
StringCopyWithEscape(Options,String);
*Search = RPC_CONST_CHAR(']');
// Everything worked out fine; we just fall through the memory
// cleanup code and return.
*Status = RPC_S_OK;
// If an error occured up above, we will have set status to the
// appropriate error code, and jumped here. We may also arrive
// here if an error did not occur, hence the check for an error status
// before we clean up the memory.
FreeMemoryAndReturn:
if (*Status != RPC_S_OK)
{
if (ObjectUuidString != 0)
RpcpFarFree(ObjectUuidString);
if (RpcProtocolSequence != 0)
delete RpcProtocolSequence;
if (NetworkAddress != 0)
delete NetworkAddress;
if (Endpoint != 0)
delete Endpoint;
if (Options != 0)
delete Options;
ObjectUuidString = 0;
RpcProtocolSequence = 0;
NetworkAddress = 0;
Endpoint = 0;
Options = 0;
}
}
DCE_BINDING::~DCE_BINDING (
)
/*++
Routine Description:
We cleaning things up here when a DCE_BINDING is getting deleted.
This consists of freeing the strings pointed to by the fields of
the class.
--*/
{
if (RpcProtocolSequence != 0)
delete RpcProtocolSequence;
if (NetworkAddress != 0)
delete NetworkAddress;
if (Endpoint != 0)
delete Endpoint;
if (Options != 0)
delete Options;
}
/*static*/ int
StringLengthWithEscape (
IN RPC_CHAR PAPI * String
)
/*++
Routine Description:
This routine is the same as the library routine, strlen, except that
for that following characters, '@', ':', '\', '[', and ',', are
counted as two characters (to save space for a \) rather than one.
Arguments:
String - Supplies a string whose length will be determined.
Return Value:
The length of the string will be returned including enough space to
escape certain characters.
--*/
{
// We use length to keep track of how long the string is so far.
int Length;
Length = 0;
while (*String != 0)
{
#ifdef DBCS_ENABLED
if (IsDBCSLeadByte(*String))
{
String += 2;
Length += 2;
}
else
#endif
{
if ( (*String == RPC_CONST_CHAR('@'))
|| (*String == RPC_CONST_CHAR(':'))
|| (*String == RPC_CONST_CHAR('\\'))
|| (*String == RPC_CONST_CHAR('['))
|| (*String == RPC_CONST_CHAR(']'))
|| (*String == RPC_CONST_CHAR(',')))
Length += 2;
else
Length += 1;
String += 1;
}
}
return(Length);
}
/*static*/ RPC_CHAR PAPI *
StringCopyEscapeCharacters (
OUT RPC_CHAR PAPI * Destination,
IN RPC_CHAR PAPI * Source
)
/*++
Routine Description:
Source is copied into destination. When coping into destination, the
following characters are escaped by prefixing them with a '\': '@',
':', '\', '[', ']', and ','.
Arguments:
Destination - Returns a copy of Source.
Source - Supplies a string to be copied into destination.
Return Value:
A pointer to the terminating zero in Destination is returned.
--*/
{
while ((*Destination = *Source) != 0)
{
#ifdef DBCS_ENABLED
if (IsDBCSLeadByte(*Source))
{
Destination++;
Source++;
*Destination = *Source;
}
else
#endif
{
if ( (*Source == RPC_CONST_CHAR('@'))
|| (*Source == RPC_CONST_CHAR(':'))
|| (*Source == RPC_CONST_CHAR('\\'))
|| (*Source == RPC_CONST_CHAR('['))
|| (*Source == RPC_CONST_CHAR(']'))
|| (*Source == RPC_CONST_CHAR(',')))
{
*Destination++ = RPC_CONST_CHAR('\\');
*Destination = *Source;
}
}
Destination++;
Source++;
}
*Destination = 0;
return(Destination);
}
RPC_CHAR PAPI *
DCE_BINDING::StringBindingCompose (
IN RPC_UUID PAPI * Uuid OPTIONAL
)
/*++
Routine Description:
This method creates a string binding from a DCE_BINDING by combining
the components of a string binding.
Arguments:
Uuid - Optionally supplies a uuid to use in composing the string
binding rather than the object uuid contained in the DCE_BINDING.
Return Value:
String Binding - A newly allocated and created (from the components)
is returned.
0 - Insufficient memory is available to allocate the string binding.
--*/
{
// We will use the following automatic variable to calculate the
// required length of the string.
int Length;
// Copy is used to copy the fields of the string binding into the
// string binding.
RPC_CHAR PAPI * Copy;
// StringBinding will contain the string binding we are supposed
// to be creating here.
RPC_CHAR PAPI * StringBinding;
// This routine is written as follows. First we need to calculate
// the amount of space required to hold the string binding. This
// is not quite straight forward as it seems: we need to escape
// '@', ':', '\', '[', ']', and ',' characters in the string binding
// we create. After allocating the string, we copy each piece in,
// escaping characters as necessary.
// Go through and figure out how much space each field of the string
// binding will take up.
if (!ARGUMENT_PRESENT(Uuid))
Uuid = &ObjectUuid;
if (Uuid->IsNullUuid() == 0)
{
// The extra plus one is to save space for the '@' which seperates
// the object UUID field from the RPC protocol sequence field. The
// length of the string representation of a uuid is always 36
// characters.
Length = 36 + 1;
}
else
{
Length = 0;
}
if (RpcProtocolSequence != 0)
{
Length += StringLengthWithEscape(RpcProtocolSequence);
}
// We need to save space for the ':' seperating the RPC protocol
// sequence field from the network address field.
Length += 1;
if (NetworkAddress != 0)
Length += StringLengthWithEscape(NetworkAddress);
if ( (Endpoint != 0)
&& (Endpoint[0] != 0))
{
// The plus two is to save space for the '[' and ']' surrounding
// the endpoint and options fields.
Length += StringLengthWithEscape(Endpoint) + 2;
if ( (Options != 0)
&& (Options[0] != 0))
{
// The extra plus one is for the ',' which goes before the
// options field.
Length += StringLengthWithEscape(Options) + 1;
}
}
else
{
if ( (Options != 0)
&& (Options[0] != 0))
{
// We need to add three to the length to save space for the
// '[' and ']' which will go around the options, and the ','
// which goes before the options.
Length += StringLengthWithEscape(Options) + 3;
}
}
// Finally, include space for the terminating zero in the string.
Length += 1;
// Now we allocate space for the string binding and copy all of the
// pieces into it.
StringBinding = (RPC_CHAR PAPI *)
RpcpFarAllocate(Length * sizeof(RPC_CHAR));
if (StringBinding == 0)
return(0);
if (Uuid->IsNullUuid() == 0)
{
Copy = Uuid->ConvertToString(StringBinding);
*Copy++ = RPC_CONST_CHAR('@');
}
else
{
Copy = StringBinding;
}
if (RpcProtocolSequence != 0)
{
Copy = StringCopyEscapeCharacters(Copy, RpcProtocolSequence);
}
*Copy++ = RPC_CONST_CHAR(':');
if (NetworkAddress != 0)
{
Copy = StringCopyEscapeCharacters(Copy, NetworkAddress);
}
if ( (Endpoint != 0)
&& (Endpoint[0] != 0))
{
*Copy++ = RPC_CONST_CHAR('[');
Copy = StringCopyEscapeCharacters(Copy, Endpoint);
if ( (Options != 0)
&& (Options[0] != 0))
{
*Copy++ = RPC_CONST_CHAR(',');
Copy = StringCopyEscapeCharacters(Copy, Options);
}
*Copy++ = RPC_CONST_CHAR(']');
}
else
{
if ( (Options != 0)
&& (Options[0] != 0))
{
*Copy++ = RPC_CONST_CHAR('[');
*Copy++ = RPC_CONST_CHAR(',');
Copy = StringCopyEscapeCharacters(Copy, Options);
*Copy++ = RPC_CONST_CHAR(']');
}
}
// And do not forget to terminate the string.
*Copy = 0;
return(StringBinding);
}
#if defined(WIN) || defined(MAC)
RPC_CHAR PAPI *
AllocateEmptyStringPAPI (
void
)
/*++
Routine Description:
This routine allocates and returns an empty string ("").
Return Value:
A newly allocated empty string will be returned.
--*/
{
RPC_CHAR PAPI * String;
String = (RPC_CHAR PAPI *) RpcpFarAllocate(sizeof(RPC_CHAR));
if (String != 0)
*String = 0;
return(String);
}
RPC_CHAR PAPI *
DuplicateStringPAPI (
IN RPC_CHAR * String
)
/*++
Routine Description:
When this routine is called, it will duplicate the string into a fresh
string and return it.
Arguments:
String - Supplies the string to be duplicated.
Return Value:
The duplicated string is returned. If insufficient memory is available
to allocate a fresh string, zero will be returned.
--*/
{
RPC_CHAR PAPI * FreshString, PAPI * FreshStringScan;
RPC_CHAR * StringScan;
unsigned int Length;
Length = 1;
StringScan = String;
while (*StringScan++ != 0)
Length += 1;
FreshString = (RPC_CHAR PAPI *) RpcpFarAllocate(Length * sizeof(RPC_CHAR));
if (FreshString == 0)
return(0);
for (FreshStringScan = FreshString, StringScan = String;
*StringScan != 0; FreshStringScan++, StringScan++)
*FreshStringScan = *StringScan;
*FreshStringScan = *StringScan;
return(FreshString);
}
#endif // WIN
RPC_CHAR PAPI *
DCE_BINDING::ObjectUuidCompose (
OUT RPC_STATUS PAPI * Status
)
/*++
Routine Description:
This method returns a string representation of the object UUID
component of the DCE_BINDING. The string representation is
suitable for using as the object UUID component of a string binding.
Arguments:
Status - Returns the status of the operation if there is insufficient
memory to allocate for the string to be returned.
Return Value:
The string representation of the object UUID is returned in a freshly
allocated string.
--*/
{
RPC_CHAR PAPI * String;
if (ObjectUuid.IsNullUuid() != 0)
return(AllocateEmptyStringPAPI());
// The string representation of a uuid is always 36 characters long
// (and the extra character is for the terminating zero).
String = (RPC_CHAR PAPI *) RpcpFarAllocate(37 * sizeof(RPC_CHAR));
if (String == 0)
*Status = RPC_S_OUT_OF_MEMORY;
else
{
ObjectUuid.ConvertToString(String);
String[36] = 0;
}
return(String);
}
RPC_CHAR PAPI *
DCE_BINDING::RpcProtocolSequenceCompose (
OUT RPC_STATUS PAPI * Status
)
/*++
Routine Description:
This method returns a string representation of the RPC protocol sequence
component of the DCE_BINDING. The string representation is
suitable for using as the RPC protocol sequence component of a
string binding.
Arguments:
Status - Returns the status of the operation if there is insufficient
memory to allocate for the string to be returned.
Return Value:
The string representation of the RPC protocol sequence is returned
in a freshly allocated string.
--*/
{
RPC_CHAR PAPI * String;
if (RpcProtocolSequence == 0)
return(AllocateEmptyStringPAPI());
String = DuplicateStringPAPI(RpcProtocolSequence);
if (String == 0)
*Status = RPC_S_OUT_OF_MEMORY;
return(String);
}
RPC_CHAR PAPI *
DCE_BINDING::NetworkAddressCompose (
OUT RPC_STATUS PAPI * Status
)
/*++
Routine Description:
This method returns a string representation of the network address
component of the DCE_BINDING. The string representation is
suitable for using as the network address component of a string binding.
Arguments:
Status - Returns the status of the operation if there is insufficient
memory to allocate for the string to be returned.
Return Value:
The string representation of the network address is returned in a freshly
allocated string.
--*/
{
RPC_CHAR PAPI * String;
if (NetworkAddress == 0)
return(AllocateEmptyStringPAPI());
String = DuplicateStringPAPI(NetworkAddress);
if (String == 0)
*Status = RPC_S_OUT_OF_MEMORY;
return(String);
}
RPC_CHAR PAPI *
DCE_BINDING::EndpointCompose (
OUT RPC_STATUS PAPI * Status
)
/*++
Routine Description:
This method returns a string representation of the endpoint
component of the DCE_BINDING. The string representation is
suitable for using as the endpoint component of a string binding.
Arguments:
Status - Returns the status of the operation if there is insufficient
memory to allocate for the string to be returned.
Return Value:
The string representation of the endpoint is returned in a freshly
allocated string.
--*/
{
RPC_CHAR PAPI * String;
if (Endpoint == 0)
return(AllocateEmptyStringPAPI());
String = DuplicateStringPAPI(Endpoint);
if (String == 0)
*Status = RPC_S_OUT_OF_MEMORY;
return(String);
}
RPC_CHAR PAPI *
DCE_BINDING::OptionsCompose (
OUT RPC_STATUS PAPI * Status
)
/*++
Routine Description:
This method returns a string representation of the options
component of the DCE_BINDING. The string representation is
suitable for using as the options component of a string binding.
Arguments:
Status - Returns the status of the operation if there is insufficient
memory to allocate for the string to be returned.
Return Value:
The string representation of the options is returned in a freshly
allocated string.
--*/
{
RPC_CHAR PAPI * String;
if (Options == 0)
return(AllocateEmptyStringPAPI());
String = DuplicateStringPAPI(Options);
if (String == 0)
*Status = RPC_S_OUT_OF_MEMORY;
return(String);
}
BINDING_HANDLE *
DCE_BINDING::CreateBindingHandle (
OUT RPC_STATUS PAPI * Status
)
/*++
Routine Description:
We will create a binding handle specific to the rpc protocol sequence
specified by the DCE_BINDING object. The object uuid will be
passed on to the created binding handle. Ownership of this
passes to this routine. If an error occurs, it will be deleted.
Arguments:
Status - Returns the status of the operation; this status will be
one of the following values.
RPC_S_OK - We had no trouble allocating the binding handle.
RPC_S_OUT_OF_MEMORY - Insufficient memory was available to
complete the operation.
RPC_S_INVALID_RPC_PROTSEQ - The rpc protocol sequence is
syntactically invalid.
RPC_S_PROTSEQ_NOT_SUPPORTED - The requested rpc protocol sequence
is not supported.
Return Value:
The created binding handle will be returned, or zero if an error
occured.
--*/
{
BINDING_HANDLE * BindingHandle;
void * TransportInterface;
#ifdef WIN32RPC
#ifndef NTENV
if ( RpcpMemoryCompare(RpcProtocolSequence, RPC_CONST_STRING("mswmsg"),
6) == 0 )
{
BindingHandle = WmsgCreateBindingHandle();
if (BindingHandle == 0)
{
delete this;
*Status = RPC_S_OUT_OF_MEMORY;
return(0);
}
}
else
#endif
if ( RpcpMemoryCompare(RpcProtocolSequence, RPC_CONST_STRING("ncalrpc"),
8 * sizeof(RPC_CHAR)) == 0 )
{
#ifdef NTENV
BindingHandle = WmsgCreateBindingHandle();
#else
BindingHandle = SpcCreateBindingHandle();
#endif
if (BindingHandle == 0)
{
delete this;
*Status = RPC_S_OUT_OF_MEMORY;
return(0);
}
}
#else // WIN32RPC
if ( RpcpMemoryCompare(RpcProtocolSequence, RPC_CONST_STRING("ncalrpc"),
8 * sizeof(RPC_CHAR)) == 0 )
{
*Status = RPC_S_PROTSEQ_NOT_SUPPORTED;
delete this;
return(0);
}
#endif // WIN32RPC
#if !defined(MAC) && (!defined(DOSWIN32RPC) || defined(WIN96))
else if ( RpcpMemoryCompare(RpcProtocolSequence,
RPC_CONST_STRING("ncadg_"), 6*sizeof(RPC_CHAR)) == 0)
{
BindingHandle = DgCreateBindingHandle();
if (BindingHandle == 0)
{
delete this;
*Status = RPC_S_OUT_OF_MEMORY;
return 0;
}
TransportInterface = OsfClientMapRpcProtocolSequence(
RpcProtocolSequence,
Status
);
if (*Status != RPC_S_OK)
{
delete BindingHandle;
delete this;
return 0;
}
}
#endif // DOSWIN32RPC
#ifdef MAC
else if ( RpcpMemoryCompare(RpcProtocolSequence,
RPC_CONST_STRING("ncadg_"), 6*sizeof(RPC_CHAR)) == 0)
{
delete this ;
*Status = RPC_S_PROTSEQ_NOT_SUPPORTED ;
return 0 ;
}
#endif
else if ( RpcpMemoryCompare(RPC_CONST_STRING("ncacn_"),
RpcProtocolSequence, 6 * sizeof(RPC_CHAR)) == 0 )
{
BindingHandle = OsfCreateBindingHandle();
if (BindingHandle == 0)
{
delete this;
*Status = RPC_S_OUT_OF_MEMORY;
return(0);
}
TransportInterface = OsfClientMapRpcProtocolSequence(
RpcProtocolSequence, Status);
if (*Status != RPC_S_OK)
{
delete BindingHandle;
delete this;
return(0);
}
}
else
{
*Status = RPC_S_INVALID_RPC_PROTSEQ;
delete this;
return(0);
}
BindingHandle->SetObjectUuid(&ObjectUuid);
BindingHandle->PrepareBindingHandle(TransportInterface,this);
*Status = RPC_S_OK;
return(BindingHandle);
}
void
DCE_BINDING::AddEndpoint(
IN RPC_CHAR *Endpoint
)
/*++
Routine Description:
This routine can be used to update the endpoint stored in the DCE_BINDING.
If the DCE_BINDING already has an endpoint it is deleted.
Arguments:
Endpoint - The new endpoint to store in this DCE_BINDING. Ownership
passes to this DCE_BINDING.
Return Value:
n/a
--*/
{
if (this->Endpoint)
delete this->Endpoint;
this->Endpoint = Endpoint;
}
RPC_STATUS
DCE_BINDING::ResolveEndpointIfNecessary (
IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation,
IN RPC_UUID * ObjectUuid,
IN OUT void PAPI * PAPI * EpLookupHandle,
IN BOOL UseEpMapperEp,
IN unsigned Timeout
)
/*++
Routine Description:
This routine will determine the endpoint if it is not specified.
The arguments specifies interface information necessary to resolve
the endpoint, as well as the object uuid.
Arguments:
RpcInterfaceInformation - Supplies the interface information necessary
to resolve the endpoint.
ObjectUuid - Supplies the object uuid in the binding.
EpLookupHandle - Supplies the current value of the endpoint mapper
lookup handle for a binding, and returns the new value.
Return Value:
RPC_S_OK - The endpoint is fully resolved.
RPC_S_NO_ENDPOINT_FOUND - The endpoint can not be resolved.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to resolve
the endpoint.
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.
--*/
{
unsigned int Index;
RPC_STATUS RpcStatus;
#ifdef NTENV
UNICODE_STRING UnicodeString;
#endif // NTENV
if ( (Endpoint == 0)
|| (Endpoint[0] == 0) )
{
// This binding does not have an endpoint, so we must perform
// binding resolution to obtain an endpoint. First we look
// in the interface information to see if an endpoint corresponding
// to the rpc protocol sequence for this binding is there.
for (Index = 0;
Index < RpcInterfaceInformation->RpcProtseqEndpointCount;
Index++)
{
#ifdef NTENV
RpcStatus = AnsiToUnicodeString(
RpcInterfaceInformation->RpcProtseqEndpoint[
Index].RpcProtocolSequence, &UnicodeString);
if (RpcStatus != RPC_S_OK)
return(RpcStatus);
if ( RpcpStringCompare(RpcProtocolSequence,
UnicodeString.Buffer) == 0 )
#else
if ( RpcpStringCompare(RpcProtocolSequence,
RpcInterfaceInformation->RpcProtseqEndpoint[
Index].RpcProtocolSequence) == 0 )
#endif // NTENV
{
#ifdef NTENV
RtlFreeUnicodeString(&UnicodeString);
#endif // NTENV
if (Endpoint != 0)
{
delete Endpoint;
Endpoint = 0;
}
#ifdef NTENV
RpcStatus = AnsiToUnicodeString(
RpcInterfaceInformation->RpcProtseqEndpoint[
Index].Endpoint, &UnicodeString);
if (RpcStatus != RPC_S_OK)
return(RpcStatus);
Endpoint = DuplicateString(UnicodeString.Buffer);
RtlFreeUnicodeString(&UnicodeString);
#else
Endpoint = DuplicateString(
RpcInterfaceInformation->RpcProtseqEndpoint[
Index].Endpoint);
#endif // NTENV
if (Endpoint == 0)
return(RPC_S_OUT_OF_MEMORY);
return(RPC_S_OK);
}
#ifdef NTENV
RtlFreeUnicodeString(&UnicodeString);
#endif // NTENV
}
//The endpoint has not been supplied so resolve the endpoint.
//CLH 2/17/94 If datagram and forward is required (that is
//RpcEpResolveBinding has not been called), then simply put
//the endpoint mapper's endpoint into this binding handles endpoint.
//The endpoint mapper on the destination node will resolve the
//endpoint and its runtime will forward the pkt.
if (Endpoint != 0)
{
delete Endpoint;
Endpoint = 0;
}
//
// We cannot allow management interfaces to be resolved if they dont contain
// an object uuid.
//
#ifdef WIN32RPC
if ( (IsMgmtIfUuid ((UUID PAPI * )
&RpcInterfaceInformation->InterfaceId.SyntaxGUID))
&&( (ObjectUuid == 0) ||
(RpcpMemoryCompare(ObjectUuid, &NullUuid, sizeof(UUID)) == 0) ) )
{
return(RPC_S_BINDING_INCOMPLETE);
}
#endif
if ( (RpcpMemoryCompare(RpcProtocolSequence,
RPC_CONST_STRING("ncadg_"), 6*sizeof(RPC_CHAR)) == 0)
&& (UseEpMapperEp != 0) )
{
RpcStatus = EpGetEpmapperEndpoint(
((RPC_CHAR * PAPI *) &Endpoint),
RpcProtocolSequence);
return((RpcStatus == RPC_S_OK) ?
RPC_P_EPMAPPER_EP : RpcStatus);
}
else
{
// Otherwise, we need to contact the endpoint mapper to
// resolve the endpoint.
return(EpResolveEndpoint((UUID PAPI *) ObjectUuid,
&RpcInterfaceInformation->InterfaceId,
&RpcInterfaceInformation->TransferSyntax,
RpcProtocolSequence, NetworkAddress, EpLookupHandle, Timeout,
(RPC_CHAR * PAPI *) &Endpoint));
}
}
return(RPC_S_OK);
}
DCE_BINDING::Compare (
IN DCE_BINDING * DceBinding
)
/*++
Routine Description:
This method compares two DCE_BINDING objects for equality.
Arguments:
DceBinding - Supplies a DCE_BINDING object to compare with this.
Return Value:
Zero will be returned if the specified DCE_BINDING object is the
same as this. Otherwise, non-zero will be returned.
--*/
{
int Result;
Result = memcmp(&(DceBinding->ObjectUuid), &ObjectUuid, sizeof(UUID));
if (Result != 0)
return(Result);
if (RpcProtocolSequence != 0)
{
if (DceBinding->RpcProtocolSequence != 0)
{
Result = RpcpStringCompare(DceBinding->RpcProtocolSequence,
RpcProtocolSequence);
if (Result != 0)
return(Result);
}
else
return(1);
}
else
{
if (DceBinding->RpcProtocolSequence != 0)
return(1);
}
if (NetworkAddress != 0)
{
if (DceBinding->NetworkAddress != 0)
{
Result = RpcpStringCompare(DceBinding->NetworkAddress,
NetworkAddress);
if (Result != 0)
return(Result);
}
else
return(1);
}
else
{
if (DceBinding->NetworkAddress != 0)
return(1);
}
if (Endpoint != 0)
{
if (DceBinding->Endpoint != 0)
{
Result = RpcpStringCompare(DceBinding->Endpoint, Endpoint);
if (Result != 0)
return(Result);
}
else
return(1);
}
else
{
if (DceBinding->Endpoint != 0)
return(1);
}
if (Options != 0)
{
if (DceBinding->Options != 0)
{
Result = RpcpStringCompare(DceBinding->Options, Options);
if (Result != 0)
return(Result);
}
else
return(1);
}
else
{
if (DceBinding->Options != 0)
return(1);
}
return(0);
}
DCE_BINDING *
DCE_BINDING::DuplicateDceBinding (
)
/*++
Routine Description:
We duplicate this DCE binding in this method.
Return Value:
A duplicate DCE_BINDING to this DCE_BINDING will be returned, if
everthing works correctly. Otherwise, zero will be returned
indicating an out of memory error.
--*/
{
DCE_BINDING * DceBinding;
RPC_STATUS Status;
RPC_CHAR ObjectUuidString[37];
ObjectUuid.ConvertToString(ObjectUuidString);
ObjectUuidString[36] = 0;
DceBinding = new DCE_BINDING(ObjectUuidString,RpcProtocolSequence,
NetworkAddress,Endpoint,Options,&Status);
if (Status != RPC_S_OK)
{
ASSERT(Status == RPC_S_OUT_OF_MEMORY);
return(0);
}
return(DceBinding);
}
void
DCE_BINDING::MakePartiallyBound (
)
/*++
Routine Description:
We need to make the binding into a partially bound one by setting the
endpoint to zero. This is really easy to do.
--*/
{
if (Endpoint != 0)
{
delete Endpoint;
Endpoint = 0;
}
}
RPC_STATUS
IsRpcProtocolSequenceSupported (
IN RPC_CHAR PAPI * RpcProtocolSequence
)
/*++
Routine Description:
This routine determines if the specified rpc protocol sequence is
supported. It will optionally return the parts of the rpc protocol
sequence (rpc protocol specifier, and address + interface specifiers).
Arguments:
RpcProtocolSequence - Supplies an rpc protocol sequence to check.
RpcProtocolPart - Optionally returns the rpc protocol part of the
rpc protocol sequence.
AddressAndInterfacePart - Optionally returns the address and interface
parts of the rpc protocol sequence.
Return Value:
RPC_S_OK - The specified rpc protocol sequence is supported.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to check
the rpc protocol sequence.
RPC_S_PROTSEQ_NOT_SUPPORTED - The specified rpc protocol sequence is not
supported (but it appears to be valid).
RPC_S_INVALID_RPC_PROTSEQ - The specified rpc protocol sequence is
syntactically invalid.
--*/
{
RPC_STATUS Status;
#ifdef WIN32
if ( RpcpMemoryCompare(RpcProtocolSequence, RPC_CONST_STRING("mswmsg"),
7 * sizeof(RPC_CHAR)) == 0 )
{
return(RPC_S_OK);
}
#else
if ( RpcpMemoryCompare(RpcProtocolSequence, RPC_CONST_STRING("mswmsg"),
7 * sizeof(RPC_CHAR)) == 0 )
{
return(RPC_S_PROTSEQ_NOT_SUPPORTED);
}
#endif
#ifdef WIN32
if ( RpcpMemoryCompare(RpcProtocolSequence, RPC_CONST_STRING("ncalrpc"),
8 * sizeof(RPC_CHAR)) == 0 )
{
return(RPC_S_OK);
}
#else // WIN32
if ( RpcpMemoryCompare(RpcProtocolSequence, RPC_CONST_STRING("ncalrpc"),
8 * sizeof(RPC_CHAR)) == 0 )
{
return(RPC_S_PROTSEQ_NOT_SUPPORTED);
}
#endif // NTENV
else if ( (RpcpMemoryCompare(RPC_CONST_STRING("ncacn_"),
RpcProtocolSequence, 6 * sizeof(RPC_CHAR)) == 0 )
|| ( RpcpMemoryCompare(RPC_CONST_STRING("ncadg_"), RpcProtocolSequence,
6 * sizeof(RPC_CHAR)) == 0 ) )
{
OsfClientMapRpcProtocolSequence(RpcProtocolSequence,&Status);
if (Status == RPC_S_OK)
{
return(RPC_S_OK);
}
return(RPC_S_PROTSEQ_NOT_SUPPORTED);
}
return(RPC_S_INVALID_RPC_PROTSEQ);
}