Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1279 lines
39 KiB

/*++
Copyright (C) Microsoft Corporation, 1991 - 1999
Module Name:
dcebind.cxx
Abstract:
This module contains the code implementing the Binding Object DCE RPC
runtime APIs. APIs which are used only by server applications do not
live here.
Author:
Michael Montague (mikemon) 25-Sep-1991
Revision History:
--*/
#include <precomp.hxx>
#include <rpccfg.h>
#include <CharConv.hxx>
RPC_STATUS RPC_ENTRY
RpcBindingCopy (
IN RPC_BINDING_HANDLE SourceBinding,
OUT RPC_BINDING_HANDLE PAPI * DestinationBinding
)
/*++
Routine Description:
This routine copies binding information and creates a new binding
handle.
Arguments:
SourceBinding - Supplies the binding to be duplicated.
DestinationBinding - Returns a new binding which is a duplicate of
SourceBinding.
Return Value:
The status for the operation is returned.
--*/
{
MESSAGE_OBJECT * Binding;
THREAD *Thread;
InitializeIfNecessary();
Thread = ThreadSelf();
if (Thread == NULL)
return RPC_S_OUT_OF_MEMORY;
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
Binding = (MESSAGE_OBJECT *) SourceBinding;
if (Binding->InvalidHandle(BINDING_HANDLE_TYPE))
{
return NDRCCopyContextHandle(SourceBinding, DestinationBinding);
}
return(Binding->BindingCopy((BINDING_HANDLE *PAPI *) DestinationBinding, 0));
}
RPC_STATUS RPC_ENTRY
I_RpcBindingCopy (
IN RPC_BINDING_HANDLE SourceBinding,
OUT RPC_BINDING_HANDLE PAPI * DestinationBinding
)
/*++
Routine Description:
This routine copies binding information and creates a new binding
handle. In addition, context is being maintained by the server over
this binding handle.
Arguments:
SourceBinding - Supplies the binding to be duplicated.
DestinationBinding - Returns a new binding which is a duplicate of
SourceBinding.
Return Value:
The status for the operation is returned.
--*/
{
MESSAGE_OBJECT * Binding;
InitializeIfNecessary();
Binding = (MESSAGE_OBJECT *) SourceBinding;
if (Binding->InvalidHandle(BINDING_HANDLE_TYPE))
return(RPC_S_INVALID_BINDING);
return(Binding->BindingCopy((BINDING_HANDLE * PAPI *) DestinationBinding, 1));
}
RPC_STATUS RPC_ENTRY
RpcBindingFree (
IN OUT RPC_BINDING_HANDLE PAPI * Binding
)
/*++
Routine Description :
RpcBindingFree releases binding handle resources.
Arguments:
Binding - Supplies the binding handle to be freed, and returns zero.
Return Value:
The status of the operation is returned.
--*/
{
BINDING_HANDLE * BindingHandle;
RPC_STATUS Status;
// if we're shutting down, don't bother
// Since our other threads have been nuked, data structures may
// be in half modified state. Therefore it is unsafe to proceed
// with freeing the binding handle during shutdown
if (RtlDllShutdownInProgress())
{
*Binding = 0;
return RPC_S_OK;
}
InitializeIfNecessary();
// here it will be more efficient if we succeed, but other code will manage fine
// even if we don't, so we don't really care about return value
ThreadSelf();
ASSERT(!RpcpCheckHeap());
BindingHandle = (BINDING_HANDLE *) *Binding;
if (BindingHandle->InvalidHandle(BINDING_HANDLE_TYPE))
return(RPC_S_INVALID_BINDING);
Status = BindingHandle->BindingFree();
*Binding = 0;
return(Status);
}
RPC_STATUS RPC_ENTRY
RpcBindingReset (
IN RPC_BINDING_HANDLE Binding
)
/*++
Routine Description:
This routine sets the endpoint in the supplied binding handle to
zero. This makes the binding handle a partiallly bound binding
handle. NOTE: this routine will fail if the binding handle has
already been used to make remote procedure calls. Based on how
this routine will be used (to iterate through the entries in the
endpoint mapper database), this should not be a problem.
Arguments:
Binding - Supplies the binding handle for which the endpoint will
be set to zero, hence making it a partially bound binding handle.
Return Value:
RPC_S_OK - The operation completed successfully.
RPC_S_INVALID_BINDING - The supplied argument is not a valid binding.
RPC_S_WRONG_KIND_OF_BINDING - Either the supplied binding is not a
client binding handle or it is a client binding handle which has
already been used to make remote procedure calls.
--*/
{
BINDING_HANDLE * BindingHandle;
THREAD *Thread;
Thread = ThreadSelf();
if (Thread == NULL)
return RPC_S_OUT_OF_MEMORY;
BindingHandle = (BINDING_HANDLE *) Binding;
if (BindingHandle->InvalidHandle(BINDING_HANDLE_TYPE))
return(RPC_S_INVALID_BINDING);
return(BindingHandle->BindingReset());
}
RPC_STATUS RPC_ENTRY
RpcBindingFromStringBinding (
IN unsigned short PAPI * StringBinding,
OUT RPC_BINDING_HANDLE PAPI * Binding
)
/*++
Routine Description:
This routine returns a binding handle from a string representation
of a binding handle.
Arguments:
StringBinding - Supplies the string representation of a binding handle.
Binding - Returns a binding handle constructed from the string
representation.
Return Value:
The status of the operation is returned.
--*/
{
DCE_BINDING * DceBinding;
RPC_STATUS Status;
BINDING_HANDLE * BindingHandle;
RPC_CHAR __RPC_FAR * CopiedStringBinding;
THREAD *Thread;
InitializeIfNecessary();
ASSERT(!RpcpCheckHeap());
Thread = ThreadSelf();
if (!Thread)
return RPC_S_OUT_OF_MEMORY;
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
*Binding = 0;
CopiedStringBinding = (RPC_CHAR *)
_alloca( (RpcpStringLength(StringBinding)+1)*(sizeof(RPC_CHAR)) );
if (CopiedStringBinding == 0)
{
return (RPC_S_OUT_OF_MEMORY);
}
RpcpStringCopy(CopiedStringBinding, StringBinding);
DceBinding = new DCE_BINDING(CopiedStringBinding, &Status);
if (DceBinding == 0)
Status = RPC_S_OUT_OF_MEMORY;
if (Status == RPC_S_OK)
{
BindingHandle = DceBinding->CreateBindingHandle(&Status);
if (Status == RPC_S_OK)
*Binding = BindingHandle;
//
// DceBinding gets deleted by the callee, if the above call fails
//
}
else
{
delete DceBinding;
}
return(Status);
}
RPC_STATUS RPC_ENTRY
RpcBindingSetObject (
IN RPC_BINDING_HANDLE Binding,
IN UUID PAPI * ObjectUuid
)
/*++
Routine Description:
This routine sets the object UUID value in a binding handle.
Arguments:
Binding - Supplies the binding handle for which the object UUID is
to be set.
ObjectUuid - Supplies the UUID value to put into the binding handle.
Return Values:
RPC_S_OK - The operation completed successfully.
RPC_S_INVALID_BINDING - The binding argument does not specify a binding
handle.
RPC_S_WRONG_KIND_OF_BINDING - The binding argument does specify a
binding handle, but it is not a client binding handle (ie. one
owned by the client side rpc runtime).
--*/
{
BINDING_HANDLE * BindingHandle;
InitializeIfNecessary();
BindingHandle = (BINDING_HANDLE *) Binding;
if (BindingHandle->InvalidHandle(BINDING_HANDLE_TYPE))
return(RPC_S_INVALID_BINDING);
BindingHandle->SetObjectUuid((RPC_UUID PAPI *) ObjectUuid);
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
RpcBindingVectorFree (
IN OUT RPC_BINDING_VECTOR PAPI * PAPI * BindingVector
)
/*++
Routine Description:
This routine frees the binding handles contained in the vector, and
the vector itself.
Arguments:
BindingVector - Supplies a vector of binding handles which will be
freed. On return, the pointer to the binding vector will be
set to zero.
Return Value:
The status of the operation will be returned.
--*/
{
unsigned int Index, Count;
RPC_BINDING_VECTOR PAPI * Vector;
RPC_STATUS Status;
InitializeIfNecessary();
for (Index = 0, Vector = *BindingVector,
Count = (unsigned int) Vector->Count;
Index < Count; Index++)
if (Vector->BindingH[Index] != 0)
{
Status = RpcBindingFree(&(Vector->BindingH[Index]));
if (Status != RPC_S_OK)
return(Status);
}
RpcpFarFree(*BindingVector);
*BindingVector = 0;
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
RpcEpResolveBinding (
IN RPC_BINDING_HANDLE Binding,
IN RPC_IF_HANDLE IfSpec
)
/*++
Routine Description:
This routine is used to resolve a partially-bound binding handle
into a fully-bound binding handle. A partially-bound binding
handle is one in which the endpoint is not specified. To make
the binding handle fully-bound, we need to determine the endpoint.
Arguments:
Binding - Supplies a partially-bound binding handle to resolve into
a fully bound one. Specifying a fully-bound binding handle to
this routine is not an error; it has no effect on the binding
handle.
IfSpec - Supplies a handle to the description of the interface for
which we wish to resolve the endpoint. This information will
be used to find the correct server on the machine specified by
the network address in the binding handle.
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.
RPC_S_INVALID_BINDING - The binding argument does not specify a binding
handle.
RPC_S_WRONG_KIND_OF_BINDING - The binding argument does specify a
binding handle, but it is not a client binding handle (ie. one
owned by the client side rpc runtime).
--*/
{
BINDING_HANDLE * BindingHandle;
InitializeIfNecessary();
BindingHandle = (BINDING_HANDLE *) Binding;
if (BindingHandle->InvalidHandle(BINDING_HANDLE_TYPE))
return(RPC_S_INVALID_BINDING);
return(BindingHandle->ResolveBinding((PRPC_CLIENT_INTERFACE) IfSpec));
}
RPC_STATUS RPC_ENTRY
RpcNsBindingInqEntryName (
IN RPC_BINDING_HANDLE Binding,
IN unsigned long EntryNameSyntax,
OUT unsigned short PAPI * PAPI * EntryName
)
/*++
Routine Description:
Arguments:
Return Value:
RPC_S_OK - The entry name for the binding handle has been successfully
inquired and returned.
RPC_S_INVALID_BINDING - The binding argument does not specify a binding
handle.
RPC_S_WRONG_KIND_OF_BINDING - The binding argument does specify a
binding handle, but it is not a client binding handle (ie. one
owned by the client side rpc runtime).
--*/
{
#if !defined(NO_LOCATOR_CODE)
BINDING_HANDLE * BindingHandle;
InitializeIfNecessary();
BindingHandle = (BINDING_HANDLE *) Binding;
if (BindingHandle->InvalidHandle(BINDING_HANDLE_TYPE))
return(RPC_S_INVALID_BINDING);
if (gfRPCVerifierEnabledWithBreaks)
{
// Locator is an unsafe feature to use. We should flag it in the verifier.
RPC_VERIFIER_WARNING_MSG("Possible security threat: Client is using the locator name service",
RPC_VERIFIER_UNSAFE_FEATURE);
RPC_VERIFIER_PRINT_OFFENDING_STACK(1, 4);
}
return(BindingHandle->InquireEntryName(EntryNameSyntax, EntryName));
#else
return RPC_S_CANNOT_SUPPORT;
#endif
}
RPC_STATUS RPC_ENTRY
THUNK_FN(I_RpcNsBindingSetEntryName) (
IN RPC_BINDING_HANDLE,
IN unsigned long,
IN unsigned char *
)
{
return RPC_S_CANNOT_SUPPORT;
}
RPC_STATUS RPC_ENTRY
I_RpcNsBindingSetEntryName (
IN RPC_BINDING_HANDLE Binding,
IN unsigned long EntryNameSyntax,
IN unsigned short PAPI * EntryName
)
/*++
Routine Description:
This routine is a private entry point for use by name service support
dlls; it allows them to set the entry name in a binding handle
before returning it from import or lookup. If an entry name already
exists in the binding handle, we just go ahead and overwrite the
old one with new one.
Arguments:
Binding - Supplies the binding handle for which we want to set the
entry name.
EntryNameSyntax - Supplies the syntax used by the entry name. We need
to save this information for when the entry name is inquired.
EntryName - Supplies the entry name for this binding handle.
Return Value:
RPC_S_OK - The entry name has been successfully set for the binding
handle.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete
the operation.
RPC_S_INVALID_BINDING - The binding argument does not specify a binding
handle.
RPC_S_WRONG_KIND_OF_BINDING - The binding argument does specify a
binding handle, but it is not a client binding handle (ie. one
owned by the client side rpc runtime).
--*/
{
#if !defined(NO_LOCATOR_CODE)
BINDING_HANDLE * BindingHandle;
InitializeIfNecessary();
BindingHandle = (BINDING_HANDLE *) Binding;
if (BindingHandle->InvalidHandle(BINDING_HANDLE_TYPE))
return(RPC_S_INVALID_BINDING);
if (gfRPCVerifierEnabledWithBreaks)
{
// Locator is an unsafe feature to use. We should flag it in the verifier.
RPC_VERIFIER_WARNING_MSG("Possible security threat: Client is using the locator name service",
RPC_VERIFIER_UNSAFE_FEATURE);
RPC_VERIFIER_PRINT_OFFENDING_STACK(1, 4);
}
return(BindingHandle->SetEntryName(EntryNameSyntax, EntryName));
#else
return RPC_S_CANNOT_SUPPORT;
#endif
}
RPC_STATUS RPC_ENTRY
RpcBindingInqAuthInfo (
IN RPC_BINDING_HANDLE Binding,
OUT unsigned short PAPI * PAPI * ServerPrincName, OPTIONAL
OUT unsigned long PAPI * AuthnLevel, OPTIONAL
OUT unsigned long PAPI * AuthnSvc, OPTIONAL
OUT RPC_AUTH_IDENTITY_HANDLE PAPI * AuthIdentity, OPTIONAL
OUT unsigned long PAPI * AuthzSvc OPTIONAL
)
/*++
Routine Description:
This routine is used to return the authentication and authorization for
a binding handle. You should also see RpcBindingSetAuthInfoW.
Arguments:
Binding - Supplies the binding handle for which we wish to query the
authentication and authorization information.
ServerPrincName - Optionally returns the server principal name set for
the binding handle.
AuthnLevel - Optionally returns the authentication level set for the
binding handle.
AuthnSvc - Optionally returns the authentication service set for the
binding handle.
AuthIdentity - Optionally returns a handle to the security context
being used for authentication and authorization.
AuthzSvc - Optionally returns the authorization service set for the
binding handle.
Return Value:
RPC_S_OK - We successfully returned the information requested.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete
the operation.
RPC_S_INVALID_BINDING - The value supplied as the binding argument is
not a valid binding handle.
RPC_S_WRONG_KIND_OF_BINDING - A binding handle on the client side must
be specified as the binding argument.
RPC_S_BINDING_HAS_NO_AUTH - RpcBindingInqAuthInfo has not yet been
called on the binding handle, so there is not authentication or
authorization to be returned.
--*/
{
BINDING_HANDLE * BindingObject;
CLIENT_AUTH_INFO * ClientAuthInfo;
InitializeIfNecessary();
return( RpcBindingInqAuthInfoEx(
Binding,
ServerPrincName,
AuthnLevel,
AuthnSvc,
AuthIdentity,
AuthzSvc,
0,
0
) );
}
RPC_STATUS RPC_ENTRY
RpcBindingInqAuthInfoEx (
IN RPC_BINDING_HANDLE Binding,
OUT unsigned short PAPI * PAPI * ServerPrincName, OPTIONAL
OUT unsigned long PAPI * AuthnLevel, OPTIONAL
OUT unsigned long PAPI * AuthnSvc, OPTIONAL
OUT RPC_AUTH_IDENTITY_HANDLE PAPI * AuthIdentity, OPTIONAL
OUT unsigned long PAPI * AuthzSvc, OPTIONAL
IN unsigned long RpcSecurityQosVersion,
OUT RPC_SECURITY_QOS * SecurityQos
)
/*++
Routine Description:
This routine is used to return the authentication and authorization for
a binding handle. You should also see RpcBindingSetAuthInfoW.
Arguments:
Binding - Supplies the binding handle for which we wish to query the
authentication and authorization information.
ServerPrincName - Optionally returns the server principal name set for
the binding handle.
AuthnLevel - Optionally returns the authentication level set for the
binding handle.
AuthnSvc - Optionally returns the authentication service set for the
binding handle.
AuthIdentity - Optionally returns a handle to the security context
being used for authentication and authorization.
AuthzSvc - Optionally returns the authorization service set for the
binding handle.
RpcSecurityQosVersion - Indicates a version for RPC_SECURITY_QOS structure,
that optionally can be inquired. If SecurityQOS passes in is 0, this
is ignored.
SecurityQOS - is the version of the Security Quality Of Service
Return Value:
RPC_S_OK - We successfully returned the information requested.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete
the operation.
RPC_S_INVALID_BINDING - The value supplied as the binding argument is
not a valid binding handle.
RPC_S_WRONG_KIND_OF_BINDING - A binding handle on the client side must
be specified as the binding argument.
RPC_S_BINDING_HAS_NO_AUTH - RpcBindingInqAuthInfo has not yet been
called on the binding handle, so there is not authentication or
authorization to be returned.
--*/
{
BINDING_HANDLE * BindingObject;
CLIENT_AUTH_INFO * ClientAuthInfo;
InitializeIfNecessary();
BindingObject = (BINDING_HANDLE *) Binding;
if ( BindingObject->InvalidHandle(BINDING_HANDLE_TYPE) )
{
return(RPC_S_INVALID_BINDING);
}
ClientAuthInfo = BindingObject->InquireAuthInformation();
if ( ClientAuthInfo == 0
|| ClientAuthInfo->AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE)
{
return(RPC_S_BINDING_HAS_NO_AUTH);
}
if (ARGUMENT_PRESENT(AuthnLevel))
{
*AuthnLevel = ClientAuthInfo->AuthenticationLevel;
}
if (ARGUMENT_PRESENT(AuthnSvc))
{
*AuthnSvc = ClientAuthInfo->AuthenticationService;
}
if (ARGUMENT_PRESENT(AuthIdentity))
{
*AuthIdentity = ClientAuthInfo->AuthIdentity;
}
if (ARGUMENT_PRESENT(AuthzSvc))
{
*AuthzSvc = ClientAuthInfo->AuthorizationService;
}
if (ARGUMENT_PRESENT(ServerPrincName))
{
if ( ClientAuthInfo->ServerPrincipalName == 0 )
{
*ServerPrincName = 0;
}
else
{
*ServerPrincName = DuplicateStringPAPI(
ClientAuthInfo->ServerPrincipalName);
if ( *ServerPrincName == 0 )
{
return(RPC_S_OUT_OF_MEMORY);
}
}
}
if (ARGUMENT_PRESENT(SecurityQos))
{
if (RpcSecurityQosVersion != RPC_C_SECURITY_QOS_VERSION)
{
if (ARGUMENT_PRESENT(ServerPrincName))
delete *ServerPrincName;
return (RPC_S_INVALID_ARG);
}
SecurityQos->Version = RPC_C_SECURITY_QOS_VERSION;
SecurityQos->Capabilities = ClientAuthInfo->Capabilities;
SecurityQos->ImpersonationType = ClientAuthInfo->ImpersonationType;
SecurityQos->IdentityTracking = ClientAuthInfo->IdentityTracking;
}
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
RpcBindingSetAuthInfo (
IN RPC_BINDING_HANDLE Binding,
IN unsigned short PAPI * ServerPrincName,
IN unsigned long AuthnLevel,
IN unsigned long AuthnSvc,
IN RPC_AUTH_IDENTITY_HANDLE AuthIdentity, OPTIONAL
IN unsigned long AuthzSvc
)
/*++
Routine Description:
A client application will use this routine to specify the authentication
and authorization information in a binding handle, so that the binding
handle can be used to make authenticated remote procedure calls. If
the this routine is not used, then all remote procedure calls on the
binding handle will be unauthenticated.
Arguments:
Binding - Supplies binding handle for which we want to set authentication
and authorization information.
ServerPrincName - Supplies the expected principal name of the server
referenced by the binding handle (that is supplied as the binding
argument). This information is necessary for some security services
to be able to authenticate with the server.
AuthnLevel - Supplies a value indicating the amount (or level) of
authentication to be performed on remote procedure calls using
the binding handle. If we do not support the requested level,
we will upgrade to the next highest supported level.
RPC_C_AUTHN_LEVEL_DEFAULT - Indicates that the default level for
authentication service being used should be used.
RPC_C_AUTHN_LEVEL_NONE - Do not perform any authentication.
RPC_C_AUTHN_LEVEL_CONNECT - Authentication will be performed only
when the client first talks to the server.
RPC_C_AUTHN_LEVEL_CALL - For connection based protocols, we will
use RPC_C_AUTHN_LEVEL_PKT instead; for datagram based protocols,
authentication will be performed at the beginning of each
remote procedure call.
RPC_C_AUTHN_LEVEL_PKT - All data will be authenticated to insure that
the data it is received from the expected client.
RPC_C_AUTHN_LEVEL_PKT_INTEGRITY - In addition, to authenticating that
the data is from the expected client, we will verify that none
of it has been modified.
RPC_C_AUTHN_LEVEL_PKT_PRIVACY - Finally, this includes all of the
support in packet integrity, as well as encrypting all remote
procedure call data.
AuthnSvc - Supplies the authentication service to use.
AuthIdentify - Optionally supplies authentication and authorization
credentials to use; if this argument is not specified, the security
context for the current address space will be used.
AuthzSvc - Supplies the authorization service being used by the
server. The client must know this so that the correct authorization
information can be sent to the server.
Return Value:
RPC_S_OK - The supplied authentication and authorization information has
been set in the binding handle.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
operation.
RPC_S_INVALID_BINDING - The value supplied as the binding argument is
not a valid binding handle.
RPC_S_WRONG_KIND_OF_BINDING - A binding handle on the client side must
be specified as the binding argument.
RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
not supported.
RPC_S_UNKNOWN_AUTHN_LEVEL - The specified authentication level is
not supported.
RPC_S_INVALID_AUTH_IDENTITY - The specified security context (supplied
by the auth identity argument) is invalid.
RPC_S_UNKNOWN_AUTHZ_SERVICE - The specified authorization service is
not supported.
--*/
{
return ( RpcBindingSetAuthInfoEx(
Binding,
ServerPrincName,
AuthnLevel,
AuthnSvc,
AuthIdentity,
AuthzSvc,
0 ) );
}
RPC_STATUS RPC_ENTRY
RpcBindingSetAuthInfoEx (
IN RPC_BINDING_HANDLE Binding,
IN unsigned short PAPI * ServerPrincName,
IN unsigned long AuthnLevel,
IN unsigned long AuthnSvc,
IN RPC_AUTH_IDENTITY_HANDLE AuthIdentity, OPTIONAL
IN unsigned long AuthzSvc,
IN RPC_SECURITY_QOS *SecurityQOS
)
/*++
Routine Description:
A client application will use this routine to specify the authentication
and authorization information in a binding handle, so that the binding
handle can be used to make authenticated remote procedure calls. If
the this routine is not used, then all remote procedure calls on the
binding handle will be unauthenticated.
Arguments:
Binding - Supplies binding handle for which we want to set authentication
and authorization information.
ServerPrincName - Supplies the expected principal name of the server
referenced by the binding handle (that is supplied as the binding
argument). This information is necessary for some security services
to be able to authenticate with the server.
AuthnLevel - Supplies a value indicating the amount (or level) of
authentication to be performed on remote procedure calls using
the binding handle. If we do not support the requested level,
we will upgrade to the next highest supported level.
RPC_C_AUTHN_LEVEL_DEFAULT - Indicates that the default level for
authentication service being used should be used.
RPC_C_AUTHN_LEVEL_NONE - Do not perform any authentication.
RPC_C_AUTHN_LEVEL_CONNECT - Authentication will be performed only
when the client first talks to the server.
RPC_C_AUTHN_LEVEL_CALL - For connection based protocols, we will
use RPC_C_AUTHN_LEVEL_PKT instead; for datagram based protocols,
authentication will be performed at the beginning of each
remote procedure call.
RPC_C_AUTHN_LEVEL_PKT - All data will be authenticated to insure that
the data it is received from the expected client.
RPC_C_AUTHN_LEVEL_PKT_INTEGRITY - In addition, to authenticating that
the data is from the expected client, we will verify that none
of it has been modified.
RPC_C_AUTHN_LEVEL_PKT_PRIVACY - Finally, this includes all of the
support in packet integrity, as well as encrypting all remote
procedure call data.
AuthnSvc - Supplies the authentication service to use.
AuthIdentify - Optionally supplies authentication and authorization
credentials to use; if this argument is not specified, the security
context for the current address space will be used.
AuthzSvc - Supplies the authorization service being used by the
server. The client must know this so that the correct authorization
information can be sent to the server.
SecurityQOS - a security QOS stucture. Currently accepting RPC_C_SECURITY_QOS_VERSION_2
and RPC_C_SECURITY_QOS_VERSION_1
Return Value:
RPC_S_OK - The supplied authentication and authorization information has
been set in the binding handle.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
operation.
RPC_S_INVALID_BINDING - The value supplied as the binding argument is
not a valid binding handle.
RPC_S_WRONG_KIND_OF_BINDING - A binding handle on the client side must
be specified as the binding argument.
RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
not supported.
RPC_S_UNKNOWN_AUTHN_LEVEL - The specified authentication level is
not supported.
RPC_S_INVALID_AUTH_IDENTITY - The specified security context (supplied
by the auth identity argument) is invalid.
RPC_S_UNKNOWN_AUTHZ_SERVICE - The specified authorization service is
not supported.
--*/
{
BINDING_HANDLE * BindingObject;
RPC_STATUS Status;
RPC_CHAR __RPC_FAR * ServerName;
unsigned long ImpersonationType;
unsigned long IdentityTracking;
unsigned long Capabilities;
void *AdditionalCredentials;
ULONG AdditionalTransportCredentialsType;
THREAD *Thread;
RPC_HTTP_TRANSPORT_CREDENTIALS_W *HttpCredentials;
unsigned int i;
PSID Sid;
InitializeIfNecessary();
Thread = ThreadSelf();
if (Thread)
{
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
}
BindingObject = (BINDING_HANDLE *) Binding;
if ((SecurityQOS != 0) &&
( (SecurityQOS->Version < RPC_C_SECURITY_QOS_VERSION_1) ||
(SecurityQOS->Version > RPC_C_SECURITY_QOS_VERSION_3) ) )
{
return(RPC_S_INVALID_ARG);
}
if ( BindingObject->InvalidHandle(BINDING_HANDLE_TYPE) )
{
return(RPC_S_INVALID_BINDING);
}
//
// For no authentication, bail out now.
//
if (AuthnSvc == RPC_C_AUTHN_NONE)
{
if ((AuthnLevel != RPC_C_AUTHN_LEVEL_NONE) &&
(AuthnLevel != RPC_C_AUTHN_LEVEL_DEFAULT))
{
return(RPC_S_UNKNOWN_AUTHN_LEVEL);
}
// fall through - we will set all defaults
}
if (AuthnSvc == RPC_C_AUTHN_DEFAULT)
{
RpcpGetDefaultSecurityProviderInfo();
AuthnSvc = DefaultProviderId;
}
if (AuthnSvc == RPC_C_AUTHN_GSS_SCHANNEL)
{
if (AuthnLevel < RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
{
AuthnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
}
}
Sid = NULL;
if (SecurityQOS != 0)
{
IdentityTracking = SecurityQOS->IdentityTracking;
ImpersonationType= SecurityQOS->ImpersonationType;
Capabilities = SecurityQOS->Capabilities;
// if we were given the hint for lightweight local MA,
// we must have been told to use MA in the first place
if (Capabilities & RPC_C_QOS_CAPABILITIES_LOCAL_MA_HINT)
{
if ((Capabilities & RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH) == 0)
return RPC_S_INVALID_ARG;
// doesn't work for datagrams
if (((BINDING_HANDLE *)Binding)->InvalidHandle(DG_BINDING_HANDLE_TYPE) == FALSE)
return RPC_S_INVALID_ARG;
}
// by the condition above, we know we can't have the local MA hint only -
// if we have local MA hint, we must have full MA also. Thus we can check
// for full MA only and effectively address both
if (Capabilities & RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH)
{
// if we were asked for full MA, either SID of SPN must be supplied
if (((ServerPrincName == NULL)
||
(ServerPrincName[0] == '\0') )
&&
(
(SecurityQOS->Version < RPC_C_SECURITY_QOS_VERSION_3)
||
(((RPC_SECURITY_QOS_V3 *)SecurityQOS)->Sid == NULL)
)
)
{
#if DBG
DbgPrint("RPCRT4: %X: Rejecting invalid arguments to RpcBindingSetAuthInfoEx\n",
GetCurrentProcessId());
#endif
return RPC_S_INVALID_ARG;
}
}
if (SecurityQOS->Version == RPC_C_SECURITY_QOS_VERSION_1)
{
AdditionalTransportCredentialsType = 0;
AdditionalCredentials = NULL;
}
else
{
AdditionalTransportCredentialsType = ((RPC_SECURITY_QOS_V2 *)SecurityQOS)->AdditionalSecurityInfoType;
AdditionalCredentials = ((RPC_SECURITY_QOS_V2 *)SecurityQOS)->u.HttpCredentials;
if (AdditionalTransportCredentialsType != RPC_C_AUTHN_INFO_TYPE_HTTP)
{
if (AdditionalTransportCredentialsType != 0)
return(RPC_S_INVALID_ARG);
if (AdditionalCredentials != NULL)
return(RPC_S_INVALID_ARG);
}
else if (AdditionalCredentials == NULL)
return(RPC_S_INVALID_ARG);
else
{
HttpCredentials = (RPC_HTTP_TRANSPORT_CREDENTIALS_W *)AdditionalCredentials;
if (HttpCredentials->TransportCredentials)
{
if (HttpCredentials->TransportCredentials->User)
{
if (RpcpStringLength(HttpCredentials->TransportCredentials->User)
!= HttpCredentials->TransportCredentials->UserLength)
{
return(RPC_S_INVALID_ARG);
}
}
else if (HttpCredentials->TransportCredentials->UserLength)
return(RPC_S_INVALID_ARG);
if (HttpCredentials->TransportCredentials->Domain)
{
if (RpcpStringLength(HttpCredentials->TransportCredentials->Domain)
!= HttpCredentials->TransportCredentials->DomainLength)
{
return(RPC_S_INVALID_ARG);
}
}
else if (HttpCredentials->TransportCredentials->DomainLength)
return(RPC_S_INVALID_ARG);
if (HttpCredentials->TransportCredentials->Password)
{
if (RpcpStringLength(HttpCredentials->TransportCredentials->Password)
!= HttpCredentials->TransportCredentials->PasswordLength)
{
return(RPC_S_INVALID_ARG);
}
}
else if (HttpCredentials->TransportCredentials->PasswordLength)
return(RPC_S_INVALID_ARG);
if (HttpCredentials->TransportCredentials->Flags != SEC_WINNT_AUTH_IDENTITY_UNICODE)
return(RPC_S_INVALID_ARG);
}
// if you don't want to authenticate against anyone, you can't authenticate
if (HttpCredentials->AuthenticationTarget == 0)
return(RPC_S_INVALID_ARG);
// if you don't support any method of authentication, you can't authenticate
if (HttpCredentials->NumberOfAuthnSchemes == 0)
return(RPC_S_INVALID_ARG);
// if you don't support any method of authentication, you can't authenticate
if (HttpCredentials->AuthnSchemes == NULL)
return(RPC_S_INVALID_ARG);
// check whether Negotiate, Passport or Digest are in the list of auth scehemes. If yes,
// reject the call since we don't support them yet.
for (i = 0; i < HttpCredentials->NumberOfAuthnSchemes; i ++)
{
if (HttpCredentials->AuthnSchemes[i] == RPC_C_HTTP_AUTHN_SCHEME_PASSPORT)
return RPC_S_CANNOT_SUPPORT;
if (HttpCredentials->AuthnSchemes[i] == RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE)
return RPC_S_CANNOT_SUPPORT;
if (HttpCredentials->AuthnSchemes[i] == RPC_C_HTTP_AUTHN_SCHEME_DIGEST)
return RPC_S_CANNOT_SUPPORT;
}
}
if (SecurityQOS->Version == RPC_C_SECURITY_QOS_VERSION_3)
{
// doesn't work for datagrams
if ((((BINDING_HANDLE *)Binding)->InvalidHandle(DG_BINDING_HANDLE_TYPE) == FALSE)
&& ((RPC_SECURITY_QOS_V3 *)SecurityQOS)->Sid)
return RPC_S_INVALID_ARG;
Sid = ((RPC_SECURITY_QOS_V3 *)SecurityQOS)->Sid;
}
}
}
else
{
IdentityTracking = RPC_C_QOS_IDENTITY_STATIC;
ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE;
Capabilities = RPC_C_QOS_CAPABILITIES_DEFAULT;
AdditionalTransportCredentialsType = 0;
AdditionalCredentials = NULL;
}
if (AuthnSvc == RPC_C_AUTHN_NONE)
{
Status = BindingObject->SetAuthInformation(
ServerPrincName,
AuthnLevel,
AuthnSvc,
AuthIdentity,
AuthzSvc,
0,
ImpersonationType,
IdentityTracking,
Capabilities,
FALSE, // Acquire new credentials
AdditionalTransportCredentialsType,
AdditionalCredentials,
Sid
);
}
else
{
Status = BindingObject->SetAuthInformation(
ServerPrincName,
AuthnLevel,
AuthnSvc,
AuthIdentity,
AuthzSvc,
0,
ImpersonationType,
IdentityTracking,
Capabilities,
TRUE, // Acquire new credentials
AdditionalTransportCredentialsType,
AdditionalCredentials,
Sid
);
}
return (Status);
}
RPC_STATUS RPC_ENTRY
I_RpcBindingInqSecurityContext (
IN RPC_BINDING_HANDLE Binding,
OUT void **SecurityContextHandle
)
/*++
Routine Description:
Arguments:
Return Value:
The status for the operation is returned.
--*/
{
CALL * Call;
InitializeIfNecessary();
Call = (CALL *) Binding;
if (Call->InvalidHandle(CALL_TYPE))
return(RPC_S_INVALID_BINDING);
return(Call->InqSecurityContext(SecurityContextHandle));
}
RPC_STATUS RPC_ENTRY
I_RpcTurnOnEEInfoPropagation (
void
)
/*++
Routine Description:
Turns on extended error info propagation for this process.
Arguments:
Return Value:
RPC_S_OK.
--*/
{
g_fSendEEInfo = TRUE;
return RPC_S_OK;
}