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.
 
 
 
 
 
 

3263 lines
90 KiB

/*++
Copyright (C) Microsoft Corporation, 1991 - 1999
Module Name:
dcesvr.cxx
Abstract:
This routine implements the server side DCE runtime APIs. The
routines in this file are used by server applications only.
Author:
Michael Montague (mikemon) 13-Nov-1991
Revision History:
--*/
#include <precomp.hxx>
#include <wincrypt.h>
#include <rpcssl.h>
#include <rpcobj.hxx>
#include <rpcasync.h>
#include <hndlsvr.hxx>
#include <mgmt.h>
#include <rpccfg.h>
#include <sidcache.hxx>
#include <CharConv.hxx>
long GroupIdCounter;
RPC_INTERFACE * GlobalManagementInterface = NULL;
RPC_STATUS RPC_ENTRY
RpcNetworkInqProtseqs (
OUT RPC_PROTSEQ_VECTOR PAPI * PAPI * ProtseqVector
)
/*++
Routine Description:
A server application will call this routine to obtain a list of the
rpc protocol sequences supported by this system configuration.
Arguments:
ProtseqVector - Returns a vector of the rpc protocol sequences
supported by this system configuration.
Return Value:
RPC_S_OK - The operation completed successfully.
RPC_S_NO_PROTSEQS - The current system configuration does not
support any rpc protocol sequences.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to inquire
the rpc protocol sequences supported by this system configuration.
--*/
{
InitializeIfNecessary();
return(RpcConfigInquireProtocolSequences(FALSE, ProtseqVector));
}
RPC_STATUS RPC_ENTRY
RpcObjectInqType (
IN UUID PAPI * ObjUuid,
OUT UUID PAPI * TypeUuid OPTIONAL
)
/*++
Routine Description:
A server application will use this routine to obtain the type uuid
for an object. This routine can also be used to determine whether
a given object is register with the runtime or not. This is done
by not specifying the optional type uuid argument.
Arguments:
ObjUuid - Supplies the object uuid for which we want look up the
type uuid.
TypeUuid - Optionally returns the type uuid of the specified object
uuid.
Return Value:
RPC_S_OK - The operation completed successfully; the object uuid
is registered with the runtime or the object inquiry function
knows the object uuid.
RPC_S_OBJECT_NOT_FOUND - The specified object uuid has not been
registered with the runtime and the object inquiry function
does not know about the object uuid.
--*/
{
RPC_UUID OptionalTypeUuid;
InitializeIfNecessary();
if (ARGUMENT_PRESENT(TypeUuid))
{
return(ObjectInqType(
(RPC_UUID PAPI *) ObjUuid, (RPC_UUID PAPI *) TypeUuid));
}
return(ObjectInqType(
(RPC_UUID PAPI *) ObjUuid, &OptionalTypeUuid));
}
RPC_STATUS RPC_ENTRY
RpcObjectSetInqFn (
IN RPC_OBJECT_INQ_FN PAPI * InquiryFn
)
/*++
Routine Description:
A function to be used to determine an object's type is specified
using this routine.
Arguments:
InquiryFn - Supplies a pointer to a function which will automatically
be called when an inquiry is made for the type of object which
has not yet been registered with the runtime.
Return Value:
RPC_S_OK - This value will always be returned.
--*/
{
InitializeIfNecessary();
return(ObjectSetInqFn(InquiryFn));
}
RPC_STATUS RPC_ENTRY
RpcObjectSetType (
IN UUID PAPI * ObjUuid,
IN UUID PAPI * TypeUuid OPTIONAL
)
/*++
Routine Description:
An application will call this routine to register an object and its
type with the runtime.
Arguments:
ObjUuid - Supplies the object uuid to be registered with the runtime.
TypeUuid - Supplies the type of the object being registered. The type
is registered with the object.
Return Value:
RPC_S_OK - The object uuid (and type uuid with it) were successfully
registered with the runtime.
RPC_S_ALREADY_REGISTERED - The object uuid specified has already
been registered with the runtime.
RPC_S_OUT_OF_MEMORY - There is insufficient memory available to
register the object with the runtime.
RPC_S_INVALID_OBJECT - The object uuid specified is the nil uuid.
--*/
{
InitializeIfNecessary();
return(ObjectSetType(
(RPC_UUID PAPI *) ObjUuid, (RPC_UUID PAPI *) TypeUuid));
}
RPC_STATUS RPC_ENTRY
RpcProtseqVectorFree (
IN OUT RPC_PROTSEQ_VECTOR PAPI * PAPI * ProtseqVector
)
/*++
Routine Description:
The protocol sequence vector obtained by calling RpcNetworkInqProtseqs
is freed using this routine. Each of the protocol sequences (they
are represented as strings) and the vector itself are all freed.
Arguments:
ProtseqVector - Supplies the rpc protocol sequence vector to be freed,
and returns zero in place of the pointer to the vector.
Return Value:
RPC_S_OK - This routine always completes successfully.
--*/
{
unsigned int Index, Count;
InitializeIfNecessary();
if ( *ProtseqVector == 0 )
{
return(RPC_S_OK);
}
for (Index = 0, Count = (*ProtseqVector)->Count; Index < Count; Index++)
{
delete((*ProtseqVector)->Protseq[Index]);
}
delete(*ProtseqVector);
*ProtseqVector = 0;
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
RpcServerInqBindings (
OUT RPC_BINDING_VECTOR PAPI * PAPI * BindingVector
)
/*++
Routine Description:
A server application will call this routine to obtain a vector of
binding handles. Each protocol sequence registered with the rpc
server will be used to create one binding handle.
Arguments:
BindingVector - Returns the vector of binding handles.
Return Value:
RPC_S_OK - At least one rpc protocol sequence has been registered
with the rpc server, and the operation completed successfully.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete
the operation.
RPC_S_NO_BINDINGS - No rpc protocol sequences have been successfully
registered with the rpc server.
--*/
{
InitializeIfNecessary();
*BindingVector = 0L;
return(GlobalRpcServer->InquireBindings(BindingVector));
}
RPC_STATUS RPC_ENTRY
RpcServerInqIf (
IN RPC_IF_HANDLE IfSpec,
IN UUID PAPI * MgrTypeUuid, OPTIONAL
OUT RPC_MGR_EPV PAPI * PAPI * MgrEpv
)
/*++
Routine Description:
A server application will call this routine to obtain the manager
entry point vector for a given interface and a given type uuid.
Arguments:
IfSpec - Supplies a description of the interface.
MgrTypeUuid - Optionally supplies the type uuid of the manager
entry point vector we want returned. If no manager type uuid
is specified, then the null uuid is assumed.
MgrEpv - Returns the manager entry point vector.
Return Value:
RPC_S_OK - The manager entry point vector has successfully been
returned.
RPC_S_UNKNOWN_MGR_TYPE - The specified type uuid is not registered
with the interface.
RPC_S_UNKNOWN_IF - The specified interface is not registered with
the rpc server.
--*/
{
InitializeIfNecessary();
return(GlobalRpcServer->InquireManagerEpv(
(RPC_SERVER_INTERFACE PAPI *) IfSpec,
(RPC_UUID PAPI *) MgrTypeUuid, MgrEpv));
}
RPC_STATUS RPC_ENTRY
RpcServerListen (
IN unsigned int MinimumCallThreads,
IN unsigned int MaxCalls,
IN unsigned int DontWait
)
/*++
Routine Description:
This routine gets called to start the rpc server listening for remote
procedure calls. We do not return until RpcMgmtStopServerListening
is called and all active remote procedure calls complete, or a fatal
error occurs in the runtime.
Arguments:
MinimumCallThreads - Supplies the minimum number of threads which
should be around to service remote procedure calls. A higher
value for this number will give more responsive service at the
cost of more threads.
MaxCalls - Supplies the maximum number of concurrent calls the rpc
server is willing to accept. This number must be greater than
or equal to the largest MaxCalls value specified to the
RpcServerUse* routines.
DontWait - Supplies a flag indicating whether or not to wait until
RpcMgmtStopServerListening has been called and all calls have
completed. A non-zero value indicates not to wait.
Return Value:
RPC_S_OK - Everything worked as expected. All active remote procedure
calls have completed. It is now safe to exit this process.
RPC_S_ALREADY_LISTENING - Another thread has already called
RpcServerListen and has not yet returned.
RPC_S_NO_PROTSEQS_REGISTERED - No protocol sequences have been
registered with the rpc server. As a consequence it is
impossible for the rpc server to receive any remote procedure
calls, hence, the error code.
RPC_S_MAX_CALLS_TOO_SMALL - The supplied value for MaxCalls is smaller
than the the supplied value for MinimumCallThreads, or the zero
was supplied for MaxCalls.
--*/
{
THREAD *Thread;
InitializeIfNecessary();
Thread = ThreadSelf();
if (Thread)
{
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
}
return(GlobalRpcServer->ServerListen(MinimumCallThreads, MaxCalls,
DontWait));
}
RPC_STATUS RPC_ENTRY
RpcServerRegisterIf (
IN RPC_IF_HANDLE IfSpec,
IN UUID PAPI * MgrTypeUuid OPTIONAL,
IN RPC_MGR_EPV PAPI * MgrEpv OPTIONAL
)
/*++
Routine Description:
This routine is used by server application to register a manager
entry point vector and optionally an interface. If the interface
has not been registered, then it will be registered. If it has
already been registered, the manager entry point vector will be
added to it under the specified type uuid.
Arguments:
IfSpec - Supplies a description of the interface. This is actually
a pointer to an opaque data structure which the runtime knows
how to interpret.
MgrTypeUuid - Optionally supplies the type uuid for the specified
manager entry point vector. If no type uuid is supplied, then
the null uuid will be used as the type uuid.
MgrEpv - Optionally supplies a manager entry point vector corresponding
to the type uuid. If a manager entry point vector is not supplied,
then the manager entry point vector in the interface will be
used.
Return Value:
RPC_S_OK - The specified rpc interface has been successfully
registered with the rpc server. It is now ready to accept
remote procedure calls.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to register
the rpc interface with the rpc server.
RPC_S_TYPE_ALREADY_REGISTERED - A manager entry point vector has
already been registered for the supplied rpc interface and
manager type UUID.
--*/
{
InitializeIfNecessary();
return(GlobalRpcServer->RegisterInterface(
(RPC_SERVER_INTERFACE PAPI *) IfSpec,
(RPC_UUID PAPI *) MgrTypeUuid, MgrEpv, 0,
MAX_IF_CALLS, gMaxRpcSize, 0));
}
RPC_STATUS RPC_ENTRY
RpcServerRegisterIfEx (
IN RPC_IF_HANDLE IfSpec,
IN UUID PAPI * MgrTypeUuid,
IN RPC_MGR_EPV PAPI * MgrEpv,
IN unsigned int Flags,
IN unsigned int MaxCalls,
IN RPC_IF_CALLBACK_FN PAPI *IfCallbackFn
)
/*++
Routine Description:
This routine is used by server application to register a manager
entry point vector and an interface. If the interface
has not been registered, then it will be registered. If it has
already been registered, the manager entry point vector will be
added to it under the specified type uuid. If the IF_AUTOLISTEN flag
has been specified, then the registered interface will be treated as an
auto-listen interface.
Arguments:
IfSpec - Supplies a description of the interface. This is actually
a pointer to an opaque data structure which the runtime knows
how to interpret.
MgrTypeUuid - Optionally supplies the type uuid for the specified
manager entry point vector. If no type uuid is supplied, then
the null uuid will be used as the type uuid.
MgrEpv - Optionally supplies a manager entry point vector corresponding
to the type uuid. If a manager entry point vector is not supplied,
then the manager entry point vector in the interface will be
used.
Flags -
RPC_IF_OLE - the interface is an OLE interface. Calls need to be dispatched
to procnum 0
RPC_IF_AUTOLISTEN - the interface is an auto-listen inteface, calls may be
dispatched on this inteface as soon as it is registered.
MaxCalls -
Maximum number of calls that can be simulaneously dispatched on this interface
Return Value:
RPC_S_OK - The specified rpc interface has been successfully
registered with the rpc server. It is now ready to accept
remote procedure calls.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to register
the rpc interface with the rpc server.
RPC_S_TYPE_ALREADY_REGISTERED - A manager entry point vector has
already been registered for the supplied rpc interface and
manager type UUID.
--*/
{
InitializeIfNecessary();
if (Flags & RPC_IF_OLE)
{
Flags |= RPC_IF_AUTOLISTEN ;
}
return(GlobalRpcServer->RegisterInterface(
(RPC_SERVER_INTERFACE PAPI *) IfSpec,
(RPC_UUID PAPI *) MgrTypeUuid, MgrEpv, Flags,
MaxCalls, gMaxRpcSize, IfCallbackFn));
}
RPC_STATUS RPC_ENTRY
RpcServerRegisterIf2 (
IN RPC_IF_HANDLE IfSpec,
IN UUID PAPI * MgrTypeUuid,
IN RPC_MGR_EPV PAPI * MgrEpv,
IN unsigned int Flags,
IN unsigned int MaxCalls,
IN unsigned int MaxRpcSize,
IN RPC_IF_CALLBACK_FN PAPI *IfCallbackFn
)
{
InitializeIfNecessary();
if (Flags & RPC_IF_OLE)
{
Flags |= RPC_IF_AUTOLISTEN ;
}
return(GlobalRpcServer->RegisterInterface(
(RPC_SERVER_INTERFACE PAPI *) IfSpec,
(RPC_UUID PAPI *) MgrTypeUuid, MgrEpv, Flags,
MaxCalls, MaxRpcSize, IfCallbackFn));
}
RPC_STATUS RPC_ENTRY
RpcServerUnregisterIf (
IN RPC_IF_HANDLE IfSpec,
IN UUID PAPI * MgrTypeUuid, OPTIONAL
IN unsigned int WaitForCallsToComplete
)
/*++
Routine Description:
A server application will use this routine to unregister an interface
with the rpc server. Depending on what is specified for the manager
type uuid one or all of the manager entry point vectors will be removed
from the interface.
Arguments:
IfSpec - Supplies a description of the interface. This is actually
a pointer to an opaque data structure which the runtime knows
how to interpret.
MgrTypeUuid - Optionally supplies the type uuid of the manager entry
point vector to be removed. If this argument is not supplied,
then all manager entry point vectors for this interface will
be removed.
WaitForCallsToComplete - Supplies a flag indicating whether or not
this routine should wait for all calls to complete using the
interface and manager being unregistered. A non-zero value
indicates to wait.
Return Value:
RPC_S_OK - The manager entry point vector(s) are(were) successfully
removed from the specified interface.
RPC_S_UNKNOWN_MGR_TYPE - The specified type uuid is not registered
with the interface.
RPC_S_UNKNOWN_IF - The specified interface is not registered with
the rpc server.
--*/
{
InitializeIfNecessary();
return(GlobalRpcServer->UnregisterIf(
(RPC_SERVER_INTERFACE PAPI *) IfSpec,
(RPC_UUID PAPI *) MgrTypeUuid, WaitForCallsToComplete));
}
RPC_STATUS RPC_ENTRY
RpcServerUnregisterIfEx (
IN RPC_IF_HANDLE IfSpec,
IN UUID PAPI * MgrTypeUuid, OPTIONAL
IN int RundownContextHandles
)
/*++
Routine Description:
Does the same as RpcServerUnregisterIf and in addition to that
will cleanup all context handles registered by this interface
provided that the interface is using strict_context_handles. If
the interface does not use strict context handles, this API will
return ERROR_INVALID_HANDLE, but the interface will be
unregistered. Unlike RpcServerUnregisterIf, this API requires the
IfSpec argument.
Arguments:
IfSpec - Supplies a description of the interface. This is actually
a pointer to an opaque data structure which the runtime knows
how to interpret.
MgrTypeUuid - Optionally supplies the type uuid of the manager entry
point vector to be removed. If this argument is not supplied,
then all manager entry point vectors for this interface will
be removed.
RundownContextHandles - if TRUE, the context handles belonging to
this interface will be rundown. If FALSE, only the runtime
portion of the context handle will be cleaned up, and the
server portion of the context handle will be left alone.
Return Value:
RPC_S_OK - The manager entry point vector(s) are(were) successfully
removed from the specified interface.
RPC_S_UNKNOWN_MGR_TYPE - The specified type uuid is not registered
with the interface.
RPC_S_UNKNOWN_IF - The specified interface is not registered with
the rpc server.
--*/
{
RPC_STATUS RpcStatus;
DestroyContextHandleCallbackContext CallbackContext;
InitializeIfNecessary();
if (!ARGUMENT_PRESENT(IfSpec))
return ERROR_INVALID_PARAMETER;
RpcStatus = RpcServerUnregisterIf(IfSpec,
MgrTypeUuid,
TRUE // WaitForCallsToComplete
);
if (RpcStatus != RPC_S_OK)
return RpcStatus;
CallbackContext.RpcInterfaceInformation = (RPC_SERVER_INTERFACE *) IfSpec;
CallbackContext.RundownContextHandles = RundownContextHandles;
RpcStatus = GlobalRpcServer->EnumerateAndCallEachAddress(
RPC_SERVER::actDestroyContextHandle,
&CallbackContext);
return RpcStatus;
}
RPC_STATUS RPC_ENTRY
RpcServerUseAllProtseqsEx (
IN unsigned int MaxCalls,
IN void PAPI * SecurityDescriptor,
IN PRPC_POLICY Policy
)
/*++
Routine Description:
A server application will use this routine to add all rpc protocol
sequences supported by the current operating environment to the
rpc server. An endpoint will be dynamically selected for each rpc
protocol sequence. We will inquire the supported rpc protocol
sequences, and then let the RPC_SERVER class take care of adding
each one for us.
Arguments:
MaxCalls - Supplies a lower bound for the number of concurrent
remote procedure calls the server must be able to handle.
SecurityDescriptor - Optionally supplies a security descriptor to
place on the rpc protocol sequence (address) we are adding to
the rpc server.
Return Value:
RPC_S_OK - All supported rpc protocol sequences have been added to
the rpc server.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to add all of
the supported rpc protocol sequences to the rpc server.
RPC_S_NO_PROTSEQS - The current system configuration does not
support any rpc protocol sequences.
RPC_S_INVALID_SECURITY_DESC - The supplied security descriptor is
invalid.
--*/
{
RPC_PROTSEQ_VECTOR * RpcProtseqVector;
RPC_STATUS Status;
unsigned int Index, ValidProtocolSequences = 0;
THREAD *Thread;
ULONG OriginalEndpointFlags;
InitializeIfNecessary();
if (Policy->Length < sizeof(RPC_POLICY))
{
return RPC_S_INVALID_BOUND ;
}
Thread = ThreadSelf();
if (!Thread)
return RPC_S_OUT_OF_MEMORY;
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
Status = RpcConfigInquireProtocolSequences(TRUE, &RpcProtseqVector);
if (Status != RPC_S_OK)
{
return(Status);
}
// save away the original value
OriginalEndpointFlags = Policy->EndpointFlags;
Policy->EndpointFlags |= RPC_C_DONT_FAIL;
for (Index = 0; Index < RpcProtseqVector->Count; Index++)
{
//
// Don't include nb protocols, ncadg_mq and ncacn_http
// in RpcServerUseAllProtseqs().
//
if ( (RpcpStringNCompare(RPC_CONST_STRING("ncacn_nb_"),
RpcProtseqVector->Protseq[Index],
9) == 0)
||(RpcpStringNCompare(RPC_CONST_STRING("ncadg_mq"),
RpcProtseqVector->Protseq[Index],
8) == 0)
#if !defined(APPLETALK_ON)
||(RpcpStringNCompare(RPC_CONST_STRING("ncacn_at_dsp"),
RpcProtseqVector->Protseq[Index],
12) == 0)
#endif
||(RpcpStringNCompare(RPC_CONST_STRING("ncacn_http"),
RpcProtseqVector->Protseq[Index],
10) == 0) )
{
continue;
}
Status = GlobalRpcServer->UseRpcProtocolSequence(NULL,
RpcProtseqVector->Protseq[Index], MaxCalls, 0,
SecurityDescriptor, Policy->EndpointFlags, Policy->NICFlags);
if ( Status == RPC_S_OK )
{
ValidProtocolSequences += 1;
}
else if ( ( Status == RPC_S_OUT_OF_MEMORY )
|| ( Status == RPC_S_INVALID_SECURITY_DESC )
|| ( Status == RPC_S_OUT_OF_RESOURCES ) )
{
RpcProtseqVectorFree(&RpcProtseqVector);
Policy->EndpointFlags = OriginalEndpointFlags;
return(Status);
}
}
Policy->EndpointFlags = OriginalEndpointFlags;
RpcProtseqVectorFree(&RpcProtseqVector);
if ( ValidProtocolSequences == 0 )
{
return(Status);
}
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
RpcServerUseAllProtseqs (
IN unsigned int MaxCalls,
IN void PAPI * SecurityDescriptor OPTIONAL
)
{
RPC_POLICY Policy ;
Policy.Length = sizeof(RPC_POLICY) ;
Policy.EndpointFlags = 0;
Policy.NICFlags = 0;
return RpcServerUseAllProtseqsEx (MaxCalls, SecurityDescriptor, &Policy) ;
}
RPC_STATUS RPC_ENTRY
RpcServerUseAllProtseqsIfEx (
IN unsigned int MaxCalls,
IN RPC_IF_HANDLE IfSpec,
IN void PAPI * SecurityDescriptor,
IN PRPC_POLICY Policy
)
/*++
Routine Description:
A server application will use this routine to add all protocol
sequences and endpoints specified in the header of an IDL file.
This information (from the IDL file) is specified by the interface
specification argument.
Arguments:
MaxCalls - Supplies a lower bound for the number of concurrent
remote procedure calls the server must be able to handle.
IfSpec - Supplies the interface specification from which we
should extract the rpc protocol sequence and end point
information to be used.
SecurityDescriptor - Optionally supplies a security descriptor to
place on the rpc protocol sequence (address) we are adding to
the rpc server.
Return Value:
RPC_S_OK - All of the support rpc protocol sequences (and their
associated endpoints) have been added to the rpc server.
RPC_S_NO_PROTSEQS - None of the specified rpc protocol sequences
are supported by the rpc server, or no rpc protocol sequences
were specified.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to add the
requested rpc protocol sequence to the rpc server.
RPC_S_INVALID_RPC_PROTSEQ - The specified rpc protocol sequence is
syntactically invalid.
RPC_S_DUPLICATE_ENDPOINT - One of the supplied endpoints has already
been added to this rpc server.
RPC_S_INVALID_SECURITY_DESC - The supplied security descriptor is
invalid.
--*/
{
RPC_SERVER_INTERFACE PAPI * RpcServerInfo;
unsigned int SupportedProtseqCount = 0;
unsigned int Index;
RPC_STATUS Status;
InitializeIfNecessary();
if (Policy->Length < sizeof(RPC_POLICY))
{
return RPC_S_INVALID_BOUND ;
}
RpcServerInfo = (RPC_SERVER_INTERFACE PAPI *) IfSpec;
if (RpcServerInfo->RpcProtseqEndpointCount == 0)
{
return(RPC_S_NO_PROTSEQS);
}
Policy->EndpointFlags |= RPC_C_DONT_FAIL;
for (Index = 0; Index < RpcServerInfo->RpcProtseqEndpointCount;
Index++)
{
Status = RpcServerUseProtseqEpExA(
RpcServerInfo->RpcProtseqEndpoint[Index].RpcProtocolSequence,
MaxCalls, RpcServerInfo->RpcProtseqEndpoint[Index].Endpoint,
SecurityDescriptor, Policy);
if ( Status == RPC_S_OK )
{
SupportedProtseqCount += 1;
}
else if ( ( Status == RPC_S_OUT_OF_MEMORY )
|| ( Status == RPC_S_INVALID_SECURITY_DESC )
|| ( Status == RPC_S_OUT_OF_RESOURCES ) )
{
return(Status);
}
}
if ( SupportedProtseqCount == 0 )
{
return(RPC_S_NO_PROTSEQS);
}
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
RpcServerUseAllProtseqsIf (
IN unsigned int MaxCalls,
IN RPC_IF_HANDLE IfSpec,
IN void PAPI * SecurityDescriptor OPTIONAL
)
{
RPC_POLICY Policy ;
Policy.Length = sizeof(RPC_POLICY) ;
Policy.EndpointFlags = 0;
Policy.NICFlags = 0;
return RpcServerUseAllProtseqsIfEx ( MaxCalls, IfSpec, SecurityDescriptor, &Policy) ;
}
RPC_STATUS RPC_ENTRY
I_RpcServerUseProtseq2 (
IN unsigned short PAPI *NetworkAddress,
IN unsigned short PAPI *Protseq,
IN unsigned int MaxCalls,
IN void PAPI *SecurityDescriptor,
IN void *pPolicy
)
{
PRPC_POLICY Policy = (PRPC_POLICY) pPolicy;
THREAD *Thread;
InitializeIfNecessary();
Thread = ThreadSelf();
if (!Thread)
return RPC_S_OUT_OF_MEMORY;
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
if (Policy->Length < sizeof(RPC_POLICY))
{
return RPC_S_INVALID_BOUND ;
}
return(GlobalRpcServer->UseRpcProtocolSequence(NetworkAddress, Protseq, MaxCalls, 0,
SecurityDescriptor, Policy->EndpointFlags, Policy->NICFlags));
}
RPC_STATUS RPC_ENTRY
RpcServerUseProtseqEx (
IN unsigned short PAPI * Protseq,
IN unsigned int MaxCalls,
IN void PAPI * SecurityDescriptor,
IN PRPC_POLICY Policy
)
/*++
Routine Description:
This routine is used by a server application to add an rpc protocol
sequence to the rpc server. An endpoint will be dynamically selected
for this rpc protocol sequence. What we do is to let the RPC_SERVER
class take care of most of the work.
Arguments:
Protseq - Supplies the rpc protocol sequence we wish to add. An
rpc protocol sequence contains two pieces of information we
are interested in: the rpc protocol (connection, datagram, or
shared memory) and the transport interface requested.
MaxCalls - Supplies a lower bound for the number of concurrent
remote procedure calls the server must be able to handle.
SecurityDescriptor - Optionally supplies a security descriptor to
place on the rpc protocol sequence (address) we are adding to
the rpc server.
Return Value:
RPC_S_OK - The requested rpc protocol sequence has been added to
the rpc server.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to add the
requested rpc protocol sequence to the rpc server.
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_S_INVALID_SECURITY_DESC - The supplied security descriptor is
invalid.
--*/
{
return I_RpcServerUseProtseq2(NULL, Protseq, MaxCalls, SecurityDescriptor, Policy);
}
RPC_STATUS RPC_ENTRY
RpcServerUseProtseq (
IN unsigned short PAPI * Protseq,
IN unsigned int MaxCalls,
IN void PAPI * SecurityDescriptor OPTIONAL
)
{
RPC_POLICY Policy ;
THREAD *Thread;
InitializeIfNecessary();
Policy.Length = sizeof(RPC_POLICY) ;
Policy.EndpointFlags = 0;
Policy.NICFlags = 0;
Thread = ThreadSelf();
if (!Thread)
return RPC_S_OUT_OF_MEMORY;
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
return RpcServerUseProtseqEx(Protseq, MaxCalls, SecurityDescriptor, &Policy) ;
}
RPC_STATUS RPC_ENTRY
I_RpcServerUseProtseqEp2 (
IN unsigned short PAPI * NetworkAddress,
IN unsigned short PAPI * Protseq,
IN unsigned int MaxCalls,
IN RPC_CHAR PAPI * Endpoint,
IN void PAPI * SecurityDescriptor,
IN void *pPolicy
)
{
PRPC_POLICY Policy = (PRPC_POLICY) pPolicy;
InitializeIfNecessary();
if (Policy->Length < sizeof(RPC_POLICY))
{
return RPC_S_INVALID_BOUND ;
}
return(GlobalRpcServer->UseRpcProtocolSequence(NetworkAddress, Protseq, MaxCalls,
Endpoint, SecurityDescriptor,
Policy->EndpointFlags, Policy->NICFlags));
}
RPC_STATUS RPC_ENTRY
RpcServerUseProtseqEpEx (
IN unsigned short PAPI * Protseq,
IN unsigned int MaxCalls,
IN unsigned short PAPI * Endpoint,
IN void PAPI * SecurityDescriptor,
IN PRPC_POLICY Policy
)
/*++
Routine Description:
This routine is used by a server application to add an rpc protocol
sequence and an endpoint to the rpc server. What we do is to let
the RPC_SERVER class take care of most of the work.
Arguments:
Protseq - Supplies the rpc protocol sequence we wish to add. An
rpc protocol sequence contains two pieces of information we
are interested in: the rpc protocol (connection, datagram, or
shared memory) and the transport interface requested.
MaxCalls - Supplies a lower bound for the number of concurrent
remote procedure calls the server must be able to handle.
Endpoint - Supplies the endpoint to use for this rpc protocol
sequence.
SecurityDescriptor - Optionally supplies a security descriptor to
place on the rpc protocol sequence (address) we are adding to
the rpc server.
Return Value:
RPC_S_OK - The requested rpc protocol sequence has been added to
the rpc server.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to add the
requested rpc protocol sequence to the rpc server.
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_S_INVALID_ENDPOINT_FORMAT -
RPC_S_DUPLICATE_ENDPOINT - The supplied endpoint has already been
added to this rpc server.
RPC_S_INVALID_SECURITY_DESC - The supplied security descriptor is
invalid.
--*/
{
return I_RpcServerUseProtseqEp2 (NULL, Protseq, MaxCalls, Endpoint,
SecurityDescriptor, (void *) Policy);
}
RPC_STATUS RPC_ENTRY
RpcServerUseProtseqEp (
IN RPC_CHAR PAPI * Protseq,
IN unsigned int MaxCalls,
IN RPC_CHAR PAPI * Endpoint,
IN void PAPI * SecurityDescriptor
)
{
RPC_POLICY Policy ;
Policy.Length = sizeof(RPC_POLICY) ;
Policy.EndpointFlags = 0;
Policy.NICFlags = 0;
return RpcServerUseProtseqEpEx(Protseq, MaxCalls, Endpoint,
SecurityDescriptor, &Policy) ;
}
RPC_STATUS RPC_ENTRY
RpcServerUseProtseqIfEx (
IN unsigned short PAPI * Protseq,
IN unsigned int MaxCalls,
IN RPC_IF_HANDLE IfSpec,
IN void PAPI * SecurityDescriptor,
IN PRPC_POLICY Policy
)
/*++
Routine Description:
A server application will use this routine to one of the protocol
sequences (and its associated endpoint) specified in the header of
an IDL file. This information (from the IDL file) is specified by
the interface specification argument.
Arguments:
Protseq - Supplies the rpc protocol sequence to be added to
the rpc server. The list of rpc protocol sequence -- endpoint
pairs in the interface specification will be searched to find
the corresponding endpoint.
MaxCalls - Supplies a lower bound for the number of concurrent
remote procedure calls the server must be able to handle.
IfSpec - Supplies the interface specification from which we
should extract the rpc protocol sequence and end point
information to be used.
SecurityDescriptor - Optionally supplies a security descriptor to
place on the rpc protocol sequence (address) we are adding to
the rpc server.
Return Value:
RPC_S_OK - The requested rpc protocol sequence (and its associated
endpoint) has been added to the rpc server.
RPC_S_PROTSEQ_NOT_SUPPORTED - The supplied rpc protocol sequence
is not supported by the rpc server.
RPC_S_PROTSEQ_NOT_SUPPORTED - The supplied rpc protocol sequence is not
in the list of rpc protocol sequences in the interface specification.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to add the
requested rpc protocol sequence to the rpc server.
RPC_S_INVALID_RPC_PROTSEQ - The specified rpc protocol sequence is
syntactically invalid.
RPC_S_INVALID_SECURITY_DESC - The supplied security descriptor is
invalid.
--*/
{
RPC_SERVER_INTERFACE PAPI * RpcServerInfo;
unsigned int Index, EndpointsRegistered = 0;
RPC_STATUS RpcStatus;
#ifdef UNICODE
UNICODE_STRING UnicodeString;
#endif // UNICODE
InitializeIfNecessary();
if (Policy->Length < sizeof(RPC_POLICY))
{
return RPC_S_INVALID_BOUND ;
}
RpcServerInfo = (RPC_SERVER_INTERFACE PAPI *) IfSpec;
for (Index = 0; Index < RpcServerInfo->RpcProtseqEndpointCount;
Index++)
{
#ifdef UNICODE
RpcStatus = AnsiToUnicodeString(
RpcServerInfo->RpcProtseqEndpoint[Index].RpcProtocolSequence,
&UnicodeString);
if (RpcStatus != RPC_S_OK)
return(RpcStatus);
if ( RpcpStringCompare(Protseq, UnicodeString.Buffer) == 0 )
#else // UNICODE
if ( RpcpStringCompare(Protseq,
RpcServerInfo->RpcProtseqEndpoint[Index].RpcProtocolSequence)
== 0 )
#endif // UNICODE
{
#ifdef UNICODE
RtlFreeUnicodeString(&UnicodeString);
#endif
RpcStatus = RpcServerUseProtseqEpExA(
RpcServerInfo->RpcProtseqEndpoint[ Index].RpcProtocolSequence,
MaxCalls, RpcServerInfo->RpcProtseqEndpoint[Index].Endpoint,
SecurityDescriptor, Policy);
if ( RpcStatus != RPC_S_OK )
{
return(RpcStatus);
}
EndpointsRegistered += 1;
}
#ifdef UNICODE
else
{
RtlFreeUnicodeString(&UnicodeString);
}
#endif // UNICODE
}
if ( EndpointsRegistered == 0 )
{
return(RPC_S_PROTSEQ_NOT_SUPPORTED);
}
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
RpcServerUseProtseqIf (
IN unsigned short PAPI * Protseq,
IN unsigned int MaxCalls,
IN RPC_IF_HANDLE IfSpec,
IN void PAPI * SecurityDescriptor
)
{
RPC_POLICY Policy ;
Policy.Length = sizeof(RPC_POLICY) ;
Policy.EndpointFlags = 0;
Policy.NICFlags = 0;
return RpcServerUseProtseqIfEx (Protseq, MaxCalls, IfSpec,
SecurityDescriptor, &Policy) ;
}
RPC_STATUS RPC_ENTRY
RpcMgmtStatsVectorFree (
IN OUT RPC_STATS_VECTOR ** StatsVector
)
/*++
Routine Description:
This routine is used to free the statistics vector obtained from
RpcMgmtInqStats.
Arguments:
StatsVector - Supplies the statistics vector to be freed; on return,
the pointer this pointer points to will be set to zero.
Return Value:
RPC_S_OK - The operation completed successfully.
RPC_S_INVALID_ARG - The specified statistics vectors does not contain
the address of a statistics vector.
--*/
{
InitializeIfNecessary();
if (StatsVector == 0)
return(RPC_S_INVALID_ARG);
RpcpFarFree(*StatsVector);
*StatsVector = 0;
return(RPC_S_OK);
}
// N.B. This must be the same as the range declared in the IDL file.
#define MAX_STATISTICS 50
RPC_STATUS RPC_ENTRY
RpcMgmtInqStats (
IN RPC_BINDING_HANDLE Binding,
OUT RPC_STATS_VECTOR ** Statistics
)
/*++
Routine Description:
This routine is used to inquire statistics about the server. In
particular, the statistics consist of the number of remote procedure
calls received by this server, the number of remote procedure calls
initiated by this server (callbacks), the number of network packets
received, and the number of network packets sent.
Arguments:
Binding - Optionally supplies a binding handle to the server. If this
argument is not supplied, the local application is queried.
Statistics - Returns the statistics vector for this server.
Return Value:
RPC_S_OK - Everything worked just fine, and you now know the
statistics for this server.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete
the operation.
RPC_S_INVALID_BINDING - The supplied binding is not zero.
--*/
{
unsigned long Status = 0;
unsigned long Count = MAX_STATISTICS;
unsigned long StatsVector[MAX_STATISTICS];
InitializeIfNecessary();
if (Binding == 0)
{
*Statistics = (RPC_STATS_VECTOR *) RpcpFarAllocate(sizeof(RPC_STATS_VECTOR)
+ 3 * sizeof(unsigned long));
if (*Statistics == 0)
return(RPC_S_OUT_OF_MEMORY);
(*Statistics)->Count = 4;
GlobalRpcServer->InquireStatistics(*Statistics);
return(RPC_S_OK);
}
_rpc_mgmt_inq_stats(Binding, &Count, StatsVector, &Status);
if ( Status == RPC_S_OK )
{
*Statistics = (RPC_STATS_VECTOR __RPC_FAR *) RpcpFarAllocate(
sizeof(RPC_STATS_VECTOR) + sizeof(unsigned long)
* (MAX_STATISTICS - 1));
if ( *Statistics == 0 )
{
return(RPC_S_OUT_OF_MEMORY);
}
for ((*Statistics)->Count = 0; (*Statistics)->Count < Count
&& (*Statistics)->Count < MAX_STATISTICS;
(*Statistics)->Count++)
{
(*Statistics)->Stats[(*Statistics)->Count] =
StatsVector[(*Statistics)->Count];
}
}
return(Status);
}
RPC_STATUS RPC_ENTRY
RpcMgmtIsServerListening (
IN RPC_BINDING_HANDLE Binding
)
/*++
Routine Description:
An application will use this routine to determine whether or not
the server is listening.
Arguments:
Binding - Optionally supplies a binding handle to the server. If this
argument is not supplied, the local application is queried.
Return Value:
RPC_S_OK - The server is listening.
RPC_S_INVALID_BINDING - The supplied binding is not zero.
RPC_S_NOT_LISTENING - The server is not listening.
--*/
{
unsigned long Result;
unsigned long Status = 0;
InitializeIfNecessary();
if (Binding == 0)
{
if (GlobalRpcServer->IsServerListening() == 0)
return(RPC_S_NOT_LISTENING);
return(RPC_S_OK);
}
Result = _rpc_mgmt_is_server_listening(Binding, &Status);
if (Status == RPC_S_OK)
{
return((Result == 1) ? RPC_S_OK : RPC_S_NOT_LISTENING);
}
if ( (Status == RPC_S_SERVER_UNAVAILABLE)
|| (Status == RPC_S_SERVER_TOO_BUSY) )
{
return (RPC_S_NOT_LISTENING);
}
return(Status);
}
RPC_STATUS RPC_ENTRY
RpcMgmtStopServerListening (
IN RPC_BINDING_HANDLE Binding
)
/*++
Routine Description:
This routine is used by an application to stop the rpc server from
accepting any more remote procedure calls. Currently active remote
procedure calls are allowed to complete.
Arguments:
Binding - Optionally supplies a binding handle to the server. If this
argument is not supplied, the local server is stopped.
Return Value:
RPC_S_OK - The server has been successfully notified that it should
stop listening for remote procedure calls. No new remote procedure
calls will be accepted after this routine returns. RpcServerListen
will return after all active calls have completed.
RPC_S_NOT_LISTENING - A thread has not called RpcServerListen (and
not returned) yet.
--*/
{
RPC_STATUS Status;
InitializeIfNecessary();
if (Binding == 0)
{
return(GlobalRpcServer->StopServerListening());
}
_rpc_mgmt_stop_server_listening(Binding, (unsigned long *)&Status);
return(Status);
}
RPC_STATUS RPC_ENTRY
RpcMgmtWaitServerListen (
void
)
/*++
Routine Description:
This routine performs the wait that RpcServerListen normally performs
when the DontWait flag is not set. An application must call this
routine only after RpcServerListen has been called with the DontWait
flag set. We do not return until RpcMgmtStopServerListening is called
and all active remote procedure calls complete, or a fatal error occurs
in the runtime.
Return Value:
RPC_S_OK - Everything worked as expected. All active remote procedure
calls have completed. It is now safe to exit this process.
RPC_S_ALREADY_LISTENING - Another thread has already called
RpcMgmtWaitServerListen and has not yet returned.
RPC_S_NOT_LISTENING - RpcServerListen has not yet been called.
--*/
{
InitializeIfNecessary();
return(GlobalRpcServer->WaitServerListen());
}
RPC_STATUS RPC_ENTRY
I_RpcBindingInqDynamicEndpointA (
IN RPC_BINDING_HANDLE Binding,
OUT unsigned char PAPI * PAPI * DynamicEndpoint
)
{
#ifdef UNICODE
return (RPC_S_CANNOT_SUPPORT);
#else
USES_CONVERSION;
CNlDelUnicodeAnsi thunkedDynamicEndpoint;
RPC_STATUS RpcStatus;
RpcStatus = I_RpcBindingInqDynamicEndpointW(Binding, thunkedDynamicEndpoint);
if (RpcStatus == RPC_S_OK)
{
ATTEMPT_CONVERT_W2A_OPTIONAL(thunkedDynamicEndpoint, DynamicEndpoint);
}
return RpcStatus;
#endif
}
RPC_STATUS RPC_ENTRY
I_RpcBindingInqDynamicEndpointW (
IN RPC_BINDING_HANDLE Binding,
OUT unsigned short PAPI * PAPI * DynamicEndpoint
)
/*++
Routine Description:
This routine is used to inquire the dynamic endpoint from a binding
handle. The only binding handles which will have dynamic endpoints
are those which are create from rpc addresses which have dynamic
endpoints. This routine will be used for one purpose and one purpose
only: RpcEpRegister and RpcEpRegisterNoReplace need to know which
binding handles have dynamic endpoints; only binding handles with
dynamic endpoints get placed into the endpoint mapper database.
Arguments:
Binding - Supplies the binding handle from which we wish to obtain
the dynamic endpoint.
DynamicEndpoint - Returns a pointer to a string containing the dynamic
endpoint for this binding handle if it has one; otherwise, it
will be zero. If a string is return, it must be freed using
RpcStringFree.
Return Value:
RPC_S_OK - The operation completed successfully. This does not
indicate whether or not the binding handle has a dynamic endpoint.
To determine that, you must check whether *DynamicEndpoint is
equal to zero.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to duplicate
the dynamic endpoint.
RPC_S_INVALID_BINDING - The binding argument does not specify a binding
handle.
--*/
{
BINDING_HANDLE * BindingHandle;
#ifndef UNICODE
USES_CONVERSION;
COutDelThunk thunkedDynamicEndpoint;
RPC_STATUS RpcStatus;
#endif
InitializeIfNecessary();
BindingHandle = (BINDING_HANDLE *) Binding;
if (BindingHandle->InvalidHandle(BINDING_HANDLE_TYPE))
return(RPC_S_INVALID_BINDING);
#ifdef UNICODE
return (BindingHandle->InquireDynamicEndpoint(DynamicEndpoint));
#else
RpcStatus = BindingHandle->InquireDynamicEndpoint(thunkedDynamicEndpoint);
if (RpcStatus == RPC_S_OK)
{
ATTEMPT_OUT_THUNK_OPTIONAL(thunkedDynamicEndpoint, DynamicEndpoint);
}
return RpcStatus;
#endif
}
RPC_STATUS RPC_ENTRY
RpcServerRegisterAuthInfo (
IN unsigned short PAPI * ServerPrincName,
IN unsigned long AuthnSvc,
IN RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn, OPTIONAL
IN void PAPI * Arg OPTIONAL
)
/*++
Routine Description:
A server application will use this routine to indicate to the runtime
what authentication service to use for authenticating remote procedure
calls. This routine should be called once for each pair of authentication
service and principal name which the server wishes to use for
authentication. In order for an client to be able to talk with an
authenticated server, the authentication service specified by the client
must be one of the ones registered by the server. Attempting to
register the same authentication service and principal name will not
result in an error.
Arguments:
ServerPrincName - Supplies the principal name for the server.
AuthnSvc - Supplies an authentication service to use when the server
receives a remote procedure call.
GetKeyFn - Optionally supplies a routine to be used when the runtime
needs an encryption key.
Arg - Optionally supplies an argument to be passed to the routine used
to get keys each time it is called.
Return Value:
RPC_S_OK - The authentication service and server principal name have
been registered with the runtime.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
operation.
RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
not supported.
--*/
{
THREAD *Thread;
InitializeIfNecessary();
Thread = ThreadSelf();
if (Thread)
{
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
}
return(GlobalRpcServer->RegisterAuthInformation(ServerPrincName,
AuthnSvc, GetKeyFn, Arg));
}
RPC_STATUS RPC_ENTRY
RpcBindingInqAuthClient (
IN RPC_BINDING_HANDLE ClientBinding, OPTIONAL
OUT RPC_AUTHZ_HANDLE PAPI * Privs,
OUT unsigned short PAPI * PAPI * PrincName, OPTIONAL
OUT unsigned long PAPI * AuthnLevel, OPTIONAL
OUT unsigned long PAPI * AuthnSvc, OPTIONAL
OUT unsigned long PAPI * AuthzSvc OPTIONAL
)
{
return RpcBindingInqAuthClientEx( ClientBinding,
Privs,
PrincName,
AuthnLevel,
AuthnSvc,
AuthzSvc,
0
);
}
RPC_STATUS RPC_ENTRY
RpcBindingInqAuthClientEx (
IN RPC_BINDING_HANDLE ClientBinding, OPTIONAL
OUT RPC_AUTHZ_HANDLE PAPI * Privs,
OUT unsigned short PAPI * PAPI * ServerPrincName, OPTIONAL
OUT unsigned long PAPI * AuthnLevel, OPTIONAL
OUT unsigned long PAPI * AuthnSvc, OPTIONAL
OUT unsigned long PAPI * AuthzSvc, OPTIONAL
IN unsigned long Flags
)
/*++
Routine Description:
A server application will use this routine to obtain the authorization
information about a client making an authenticated remote procedure
call.
Arguments:
ClientBinding - Optionally supplies a binding handle on the server
side which indicates for which remote procedure call we wish to
obtain authorization information. If no binding handle is supplied,
then it is taken to be the remote procedure call currently being
handled by this server thread.
Privs - Returns a handle to the privileges information for the client
thread which made the remote procedure call.
ServerPrincName - Optionally returns the server principal name specified
by the client application.
AuthnLevel - Optionally returns the authentication level requested
by the client application.
AuthnSvc - Optionally returns the authentication service requested by
the client application.
AuthzSvc - Optionally returns the authorization service requested by
the client application.
Return Value:
RPC_S_OK - We successfully obtained the requested authentication and
authorization information.
RPC_S_INVALID_BINDING - The supplied binding handle (as the binding
argument) is not a valid binding handle.
RPC_S_WRONG_KIND_OF_BINDING - The binding handle is not a binding handle
on the server side.
RPC_S_BINDING_HAS_NO_AUTH - The remote procedure call is not
authenticated.
RPC_S_NO_CALL_ACTIVE - No binding handle was supplied and there is no
call active for this server thread.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
operation.
--*/
{
SCALL * SCall;
InitializeIfNecessary();
if (ARGUMENT_PRESENT(ClientBinding))
{
SCall = (SCALL *) ClientBinding;
if (SCall->InvalidHandle(SCALL_TYPE))
{
return(RPC_S_INVALID_BINDING);
}
}
else
{
SCall = (SCALL *) RpcpGetThreadContext();
if ( SCall == 0 )
{
return(RPC_S_NO_CALL_ACTIVE);
}
}
return SCall->InquireAuthClient(Privs,
ServerPrincName,
AuthnLevel,
AuthnSvc,
AuthzSvc,
Flags
);
}
RPCRTAPI
RPC_STATUS
RPC_ENTRY
RpcServerInqCallAttributesW (
IN RPC_BINDING_HANDLE ClientBinding, OPTIONAL
IN OUT void *RpcCallAttributes
)
/*++
Routine Description:
A server application will use this routine to obtain the security context
attributes for the calling client.
Arguments:
ClientBinding - Optionally supplies a binding handle on the server
side which indicates for which remote procedure call we wish to
obtain authorization information. If no binding handle is supplied,
then it is taken to be the remote procedure call currently being
handled by this server thread.
RpcCallAttributes - a pointer to
RPC_CALL_ATTRIBUTES_V1_W structure. The Version
member must be initialized.
Return Value:
RPC_S_OK for success of RPC_S_* /Win32 error code for error. EEInfo is
supplied. If the function fails, the contents of
RpcCallAttributes is undefined.
--*/
{
SCALL * SCall;
RPC_CALL_ATTRIBUTES_V1 *CallAttributes;
CallAttributes =
(RPC_CALL_ATTRIBUTES_V1 *)RpcCallAttributes;
if (CallAttributes->Version != 1)
return ERROR_INVALID_PARAMETER;
if (CallAttributes->Flags & RPC_QUERY_SERVER_PRINCIPAL_NAME)
{
if ((CallAttributes->ServerPrincipalName == NULL) &&
(CallAttributes->ServerPrincipalNameBufferLength != 0))
{
return ERROR_INVALID_PARAMETER;
}
}
if (CallAttributes->Flags & RPC_QUERY_CLIENT_PRINCIPAL_NAME)
{
if ((CallAttributes->ClientPrincipalName == NULL) &&
(CallAttributes->ClientPrincipalNameBufferLength != 0))
{
return ERROR_INVALID_PARAMETER;
}
}
InitializeIfNecessary();
if (ARGUMENT_PRESENT(ClientBinding))
{
SCall = (SCALL *) ClientBinding;
if (SCall->InvalidHandle(SCALL_TYPE))
{
return(RPC_S_INVALID_BINDING);
}
}
else
{
SCall = (SCALL *) RpcpGetThreadContext();
if ( SCall == 0 )
{
return(RPC_S_NO_CALL_ACTIVE);
}
}
return SCall->InquireCallAttributes(CallAttributes);
}
RPC_STATUS RPC_ENTRY
RpcImpersonateClient (
IN RPC_BINDING_HANDLE ClientBinding OPTIONAL
)
/*++
Routine Description:
Arguments:
Return Values:
--*/
{
SCALL * SCall;
THREAD *Thread;
InitializeIfNecessary();
ASSERT(!RpcpCheckHeap());
Thread = ThreadSelf();
if (!Thread)
return RPC_S_OUT_OF_MEMORY;
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
if ( ClientBinding == 0 )
{
SCall = (SCALL *) RpcpGetThreadContext();
if (SCall == 0)
return(RPC_S_NO_CALL_ACTIVE);
}
else
{
SCall = (SCALL *) ClientBinding;
if (SCall->InvalidHandle(SCALL_TYPE))
return(RPC_S_INVALID_BINDING);
}
return(SCall->ImpersonateClient());
}
// the handle to the authz.dll. Protected by the global mutex. Once initialized,
// never uninitialized
HMODULE AuthzDllHandle = NULL;
// pointer to the AuthzInitializeContextFromToken function from authz.dll. Once
// initialized, never uninitialized
AuthzInitializeContextFromTokenFnType AuthzInitializeContextFromTokenFn = NULL;
// pointer to the AuthzInitializeContextFromSid function from authz.dll. Once
// initialized, never uninitialized
AuthzInitializeContextFromSidFnType AuthzInitializeContextFromSidFn = NULL;
// pointer to the AuthzInitializeContextFromContext function from authz.dll. Once
// initialized, never uninitialized
AuthzInitializeContextFromAuthzContextFnType AuthzInitializeContextFromAuthzContextFn = NULL;
// pointer to the AuthzInitializeContextFromToken function from authz.dll. Once
// initialized, never uninitialized
AuthzFreeContextFnType AuthzFreeContextFn = NULL;
// the dummy resource manager with NULL callbacks for everything. Protected
// by the global mutex. Once initialized, never uninitialized
AUTHZ_RESOURCE_MANAGER_HANDLE DummyResourceManager = NULL;
typedef struct tagProcLoadArgs
{
char *ProcName;
PVOID *ProcRoutine;
} ProcLoadArgs;
const ProcLoadArgs AuthzProcs[4] = {
{"AuthzInitializeContextFromToken", (PVOID *)&AuthzInitializeContextFromTokenFn},
{"AuthzInitializeContextFromAuthzContext", (PVOID *)&AuthzInitializeContextFromAuthzContextFn},
{"AuthzInitializeContextFromSid", (PVOID *)&AuthzInitializeContextFromSidFn},
{"AuthzFreeContext", (PVOID *) &AuthzFreeContextFn}
};
RPC_STATUS
InitializeAuthzSupportIfNecessary (
void
)
/*++
Routine Description:
Perform initialization required for Authz functions to work. Everybody
should call that before they use any Authz functionality.
Arguments:
Return Values:
RPC_S_OK for success and RPC_S_* for the rest
--*/
{
RPC_STATUS Status;
int i;
if (AuthzDllHandle)
return RPC_S_OK;
GlobalMutexRequest();
if (AuthzDllHandle)
{
GlobalMutexClear();
return RPC_S_OK;
}
AuthzDllHandle = LoadLibrary(L"Authz.dll");
if (AuthzDllHandle)
{
Status = RPC_S_OK;
for (i = 0; i < (sizeof(AuthzProcs) / sizeof(AuthzProcs[0])); i ++)
{
*(AuthzProcs[i].ProcRoutine) = GetProcAddress(AuthzDllHandle,
AuthzProcs[i].ProcName);
if (*(AuthzProcs[i].ProcRoutine) == NULL)
{
Status = GetLastError();
RpcpErrorAddRecord(EEInfoGCRuntime,
Status,
EEInfoDLInitializeAuthzSupportIfNecessary20,
AuthzProcs[i].ProcName);
FreeLibrary(AuthzDllHandle);
AuthzDllHandle = NULL;
break;
}
}
}
else
{
Status = GetLastError();
RpcpErrorAddRecord(EEInfoGCRuntime,
Status,
EEInfoDLInitializeAuthzSupportIfNecessary10,
L"Authz.dll");
}
GlobalMutexClear();
return Status;
}
typedef AUTHZAPI
BOOL
(WINAPI *AuthzInitializeResourceManagerFnType) (
IN DWORD AuthzFlags,
IN PFN_AUTHZ_DYNAMIC_ACCESS_CHECK pfnAccessCheck OPTIONAL,
IN PFN_AUTHZ_COMPUTE_DYNAMIC_GROUPS pfnComputeDynamicGroups OPTIONAL,
IN PFN_AUTHZ_FREE_DYNAMIC_GROUPS pfnFreeDynamicGroups OPTIONAL,
IN PCWSTR szResourceManagerName,
OUT PAUTHZ_RESOURCE_MANAGER_HANDLE pAuthzResourceManager
);
RPC_STATUS
CreateDummyResourceManagerIfNecessary (
void
)
/*++
Routine Description:
Perform initialization of the dummy resource manager. Any function that
uses the dummy resource manager must call this function beforehand.
This function must be called after InitializeAuthzSupportIfNecessary
Arguments:
Return Values:
RPC_S_OK for success and RPC_S_* for the rest
--*/
{
AuthzInitializeResourceManagerFnType AuthzInitializeResourceManagerFn;
RPC_STATUS Status;
BOOL Result;
ULONG Flags;
HANDLE EffectiveToken;
HANDLE SavedToken;
char Buffer[40];
ULONG ReturnLength;
ULONG LastError;
TOKEN_PRIVILEGES *ActualTokenPrivileges;
ULONG i;
// this function must be called after InitializeAuthzSupportIfNecessary
ASSERT(AuthzDllHandle);
if (DummyResourceManager)
return RPC_S_OK;
SavedToken = NULL;
Flags = AUTHZ_RM_FLAG_NO_AUDIT;
// check whether we have audit privilege. If we do, we won't specify
// AUTHZ_RM_FLAG_NO_AUDIT
Result = OpenThreadToken(
GetCurrentThread(),
TOKEN_IMPERSONATE | TOKEN_QUERY,
TRUE,
&EffectiveToken
);
if (Result)
{
SavedToken = EffectiveToken;
Result = RevertToSelf();
// we must always be able to revert to self unless the
// thread was created impersonating, in which case we
// already have a bug
ASSERT(Result);
}
else
{
LastError = GetLastError();
if ((LastError != ERROR_NO_TOKEN)
&& (LastError != ERROR_ACCESS_DENIED))
{
return RPC_S_OUT_OF_MEMORY;
}
}
// if either OpenThreadToken/Revert succeeded or we didn't fail with
// access denied, check the process token
if (Result || (LastError != ERROR_ACCESS_DENIED))
{
Result = OpenProcessToken (GetCurrentProcess(),
TOKEN_QUERY,
&EffectiveToken
);
if (Result == FALSE)
{
LastError = GetLastError();
if (LastError != ERROR_ACCESS_DENIED)
{
Status = RPC_S_OUT_OF_MEMORY;
goto CleanupAndExit;
}
ASSERT(Flags == AUTHZ_RM_FLAG_NO_AUDIT);
}
else
{
Result = GetTokenInformation (EffectiveToken,
TokenPrivileges,
Buffer,
sizeof(Buffer),
&ReturnLength
);
if (Result == FALSE)
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
ActualTokenPrivileges = (TOKEN_PRIVILEGES *) new char [ReturnLength];
if (ActualTokenPrivileges == NULL)
{
CloseHandle(EffectiveToken);
Status = RPC_S_OUT_OF_MEMORY;
goto CleanupAndExit;
}
Result = GetTokenInformation (EffectiveToken,
TokenPrivileges,
ActualTokenPrivileges,
ReturnLength,
&ReturnLength
);
if (Result == FALSE)
{
ASSERT(GetLastError() != ERROR_INSUFFICIENT_BUFFER);
delete [] ActualTokenPrivileges;
CloseHandle(EffectiveToken);
Status = RPC_S_OUT_OF_MEMORY;
goto CleanupAndExit;
}
}
else
{
CloseHandle(EffectiveToken);
Status = RPC_S_OUT_OF_MEMORY;
goto CleanupAndExit;
}
}
else
{
ActualTokenPrivileges = (TOKEN_PRIVILEGES *)Buffer;
}
// we no longer need the token - close it
CloseHandle(EffectiveToken);
// zoom through the list of privileges and look for the audit privilege
for (i = 0; i < ActualTokenPrivileges->PrivilegeCount; i ++)
{
if ((ActualTokenPrivileges->Privileges[i].Luid.LowPart == SE_AUDIT_PRIVILEGE)
&& (ActualTokenPrivileges->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED))
{
// we found the audit privilege enabled. Ask for auditing.
// (or rather don't ask for no auditing)
Flags = 0;
break;
}
}
// cleanup the allocation we made
if (ActualTokenPrivileges != (TOKEN_PRIVILEGES *)Buffer)
delete [] ActualTokenPrivileges;
}
}
else
{
// OpenThreadToken failed, and it failed with access denied.
// Make sure auditing is off, and make a best effort to
// initialize Authz.
ASSERT(Flags == AUTHZ_RM_FLAG_NO_AUDIT);
}
GlobalMutexRequest();
if (DummyResourceManager)
{
GlobalMutexClear();
Status = RPC_S_OK;
goto CleanupAndExit;
}
AuthzInitializeResourceManagerFn
= (AuthzInitializeResourceManagerFnType) GetProcAddress(AuthzDllHandle,
"AuthzInitializeResourceManager");
if (AuthzInitializeResourceManagerFn == NULL)
{
Status = GetLastError();
RpcpErrorAddRecord(EEInfoGCRuntime,
Status,
EEInfoDLCreateDummyResourceManagerIfNecessary10,
"AuthzInitializeResourceManager");
}
else
{
Result = AuthzInitializeResourceManagerFn(
Flags, // Flags
NULL, // pfnAccessCheck
NULL, // pfnComputeDynamicGroups
NULL, // pfnFreeDynamicGroups
L"", // Name
&DummyResourceManager);
if (Result == FALSE)
{
Status = GetLastError();
RpcpErrorAddRecord(EEInfoGCAuthz,
Status,
EEInfoDLCreateDummyResourceManagerIfNecessary20);
}
else
Status = RPC_S_OK;
}
GlobalMutexClear();
CleanupAndExit:
if (SavedToken)
{
Result = SetThreadToken (NULL, // NULL means current thread
SavedToken
);
// after the security folks reviewed some code, this should
// never fail unless there is a bug in the code above.
ASSERT(Result);
CloseHandle(SavedToken);
}
return Status;
}
RPC_STATUS RPC_ENTRY
RpcGetAuthorizationContextForClient (
IN RPC_BINDING_HANDLE ClientBinding OPTIONAL,
IN BOOL ImpersonateOnReturn,
IN PVOID Reserved1,
IN PLARGE_INTEGER pExpirationTime OPTIONAL,
IN LUID Reserved2,
IN DWORD Reserved3,
IN PVOID Reserved4,
OUT PVOID *pAuthzClientContext
)
/*++
Routine Description:
Gets an authorization context for the client that can be used
with Authz functions. The resulting context is owned by the caller
and must be freed by it.
Arguments:
ImpersonateOnReturn - if TRUE, when we return, we should be impersonating.
If the function fails, we're not impersonating
Reserved1 - the resource manager to use (passed to Authz). Must be
NULL for now
pExpirationTime - the expiration time to use (passed to Authz)
Reserved2 - the LUID (passed to Authz). Must be 0 for now.
Resevred3 - Flags (passed to Authz). Must be 0 for now.
Reserved4 - DynamicGroupArgs parameter required by Authz (passed to Authz)
pAuthzClientContext - the authorization context, returned on success.
Undefined on failure.
Return Values:
RPC_S_OK for success, ERROR_INVALID_PARAMETER for non-null values for
the Reserved parameters and RPC_S_* / Win32 errors for the rest
--*/
{
SCALL * SCall;
THREAD *Thread;
RPC_STATUS Status;
InitializeIfNecessary();
ASSERT(!RpcpCheckHeap());
Thread = ThreadSelf();
if (!Thread)
return RPC_S_OUT_OF_MEMORY;
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
if ((Reserved1 != NULL)
|| (Reserved2.HighPart != 0)
|| (Reserved2.LowPart != 0)
|| (Reserved3 != 0)
|| (Reserved4 != NULL))
{
return ERROR_INVALID_PARAMETER;
}
Status = InitializeAuthzSupportIfNecessary();
if (Status != RPC_S_OK)
return Status;
Status = CreateDummyResourceManagerIfNecessary();
if (Status != RPC_S_OK)
return Status;
if ( ClientBinding == 0 )
{
SCall = (SCALL *) RpcpGetThreadContext();
if (SCall == 0)
return(RPC_S_NO_CALL_ACTIVE);
}
else
{
SCall = (SCALL *) ClientBinding;
if (SCall->InvalidHandle(SCALL_TYPE))
return(RPC_S_INVALID_BINDING);
}
return(SCall->GetAuthorizationContext(ImpersonateOnReturn,
DummyResourceManager,
pExpirationTime,
Reserved2,
Reserved3,
Reserved4,
(PAUTHZ_CLIENT_CONTEXT_HANDLE)pAuthzClientContext));
}
RPC_STATUS RPC_ENTRY
RpcFreeAuthorizationContext (
IN OUT PVOID *pAuthzClientContext
)
/*++
Routine Description:
Frees an authorization context obtained through
RpcGetAuthorizationContextForClient
Arguments:
pAuthzClientContext - a pointer to the authorization context to
be freed. The function will zero-out the freed authorization context
to prevent accidental re-use in the success case. The authorization
context won't be touched in case of failure.
Return Values:
RPC_S_OK for success, Win32 errors for the rest
--*/
{
BOOL Result;
Result = AuthzFreeContextFn((AUTHZ_CLIENT_CONTEXT_HANDLE)(*pAuthzClientContext));
if (Result == FALSE)
{
return GetLastError();
}
else
{
*pAuthzClientContext = NULL;
return RPC_S_OK;
}
}
RPC_STATUS RPC_ENTRY
RpcRevertToSelfEx (
IN RPC_BINDING_HANDLE ClientBinding OPTIONAL
)
/*++
Routine Description:
Return Value:
--*/
{
SCALL * SCall ;
InitializeIfNecessary();
ASSERT(!RpcpCheckHeap());
if ( ClientBinding == 0 )
{
SCall = (SCALL *) RpcpGetThreadContext();
if ( SCall == 0 )
return(RPC_S_NO_CALL_ACTIVE);
}
else
{
SCall = (SCALL *) ClientBinding;
if (SCall->InvalidHandle(SCALL_TYPE))
return(RPC_S_INVALID_BINDING);
}
return(SCall->RevertToSelf());
}
RPC_STATUS RPC_ENTRY
RpcRevertToSelf (
)
/*++
Routine Description:
Return Value:
--*/
{
return(RpcRevertToSelfEx((RPC_BINDING_HANDLE) 0));
}
RPC_STATUS RPC_ENTRY
RpcMgmtSetServerStackSize (
IN unsigned long ThreadStackSize
)
/*++
Routine Description:
An application will use this routine to specify the stack size for
each of the threads created by the server to handle remote procedure
calls.
Arguments:
ThreadStackSize - Supplies the thread stack size in bytes.
Return Value:
RPC_S_OK - Everybody is happy with the stack size.
RPC_S_INVALID_ARG - The stack size is either too small, or too large.
--*/
{
InitializeIfNecessary();
return(SetThreadStackSize(ThreadStackSize));
}
RPC_STATUS RPC_ENTRY
I_RpcBindingIsClientLocal (
IN RPC_BINDING_HANDLE BindingHandle OPTIONAL,
OUT unsigned int PAPI * ClientLocalFlag
)
/*++
Routine Description:
This routine exists for one reason: so that the security system can
tell if a client is local or remote. The client must be using named
pipes to talk to the server.
Arguments:
BindingHandle - Optionally supplies a client binding handle specifing
which client we want to know if it is local or remote. If this
parameter is not supplied, then we will determine local/remote for
the client which made call currently being handled by this server
thread.
ClientLocalFlag - Returns an indication of whether or not the client is
local (ie. on the same machine as the server). This field will be
set to a non-zero value to indicate that the client is local;
otherwise, the client is remote.
Return Value:
RPC_S_OK - We successfully determined whether or not the client is
local.
RPC_S_NO_CALL_ACTIVE - There is no call active for this server thread.
RPC_S_CANNOT_SUPPORT - Only the connection oriented protocol over named
pipes can support this operation. If the client is using something
else, other than the connection oriented protocol, this will be
returned.
RPC_S_INVALID_BINDING - The binding argument does not supply a client
binding handle.
--*/
{
SCALL *SCall;
InitializeIfNecessary();
if ( BindingHandle == 0 )
{
SCall = (SCALL *) RpcpGetThreadContext();
if ( SCall == 0 )
{
return(RPC_S_NO_CALL_ACTIVE);
}
}
else
{
SCall = (SCALL *) BindingHandle;
if ( SCall->InvalidHandle(SCALL_TYPE) )
{
return(RPC_S_INVALID_BINDING);
}
}
return(SCall->IsClientLocal(ClientLocalFlag));
}
RPC_STATUS RPC_ENTRY
RpcMgmtInqIfIds (
IN RPC_BINDING_HANDLE Binding,
OUT RPC_IF_ID_VECTOR __RPC_FAR * __RPC_FAR * IfIdVector
)
/*++
Routine Description:
This routine is used to obtain a vector of the interface identifiers of
the interfaces supported by a server.
Arguments:
Binding - Optionally supplies a binding handle to the server. If this
argument is not supplied, the local application is queried.
IfIdVector - Returns a vector of the interfaces supported by the server.
Return Value:
RPC_S_OK - Everything worked just fine, and you now know the interfaces
supported by this server.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete
the operation.
RPC_S_INVALID_BINDING - The supplied binding is not zero.
--*/
{
RPC_STATUS Status;
unsigned int Count;
InitializeIfNecessary();
if ( Binding == 0 )
{
return(GlobalRpcServer->InquireInterfaceIds(IfIdVector));
}
// if callers pass in memory, they open the possibility for buffer
// overrun since this is out conformant structure. Prevent apps
// from shooting themselves in the foot.
*IfIdVector = NULL;
_rpc_mgmt_inq_if_ids(Binding, (rpc_if_id_vector_p_t *) IfIdVector,
(unsigned long *) &Status);
// do some basic consistency checks on the return vector.
if (Status == RPC_S_OK)
{
if (*IfIdVector == NULL)
{
return RPC_S_PROTOCOL_ERROR;
}
// check that we weren't supplied non-zero count, but 0 pointer.
if (((*IfIdVector)->Count > 0) && ((*IfIdVector)->IfId == NULL))
{
// RpcIfIdVectorFree is prepared to deal with this
RpcIfIdVectorFree(IfIdVector);
return RPC_S_PROTOCOL_ERROR;
}
// check that we are not returned sparse array. Technically this is valid
// but chances are callers won't handle it.
for (Count = 0; Count < (*IfIdVector)->Count; Count++)
{
if ( (*IfIdVector)->IfId[Count] == 0 )
{
// RpcIfIdVectorFree is prepared to deal with this
RpcIfIdVectorFree(IfIdVector);
return RPC_S_PROTOCOL_ERROR;
}
}
}
return(Status);
}
RPC_STATUS RPC_ENTRY
RpcIfIdVectorFree (
IN OUT RPC_IF_ID_VECTOR __RPC_FAR * __RPC_FAR * IfIdVector
)
/*++
Routine Description:
This routine is used to free an interface id vector.
Arguments:
IfIdVector - Supplies the interface id vector to be freed; on return
this will be set to zero.
Return Value:
RPC_S_OK - This will always be returned.
--*/
{
unsigned int Count;
InitializeIfNecessary();
if (!*IfIdVector)
{
return(RPC_S_OK);
}
for (Count = 0; Count < (*IfIdVector)->Count; Count++)
{
if ( (*IfIdVector)->IfId[Count] != 0 )
{
RpcpFarFree((*IfIdVector)->IfId[Count]);
}
}
RpcpFarFree(*IfIdVector);
*IfIdVector = 0;
return(RPC_S_OK);
}
// StringToUnicodeString lives in epmgmt.c
//
extern "C" RPC_CHAR *StringToWideCharString(unsigned char *, RPC_STATUS *);
#define SERVER_PRINC_NAME_SIZE 256
RPC_STATUS RPC_ENTRY
RpcMgmtInqServerPrincName (
IN RPC_BINDING_HANDLE Binding,
IN unsigned long AuthnSvc,
OUT unsigned short __RPC_FAR * __RPC_FAR * ServerPrincName
)
/*++
Routine Description:
Arguments:
Binding - Supplies
AuthnSvc - Supplies
ServerPrincName - Returns
Return Value:
RPC_S_OK - Everything worked just fine, and you now know the interfaces
supported by this server.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete
the operation.
RPC_S_INVALID_BINDING - The supplied binding is not zero.
--*/
{
RPC_STATUS Status;
unsigned char *AnsiPrincName;
THREAD *Thread;
InitializeIfNecessary();
Thread = ThreadSelf();
if (Thread)
{
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
}
if ( Binding == 0 )
{
return(GlobalRpcServer->InquirePrincipalName(AuthnSvc, ServerPrincName));
}
AnsiPrincName = new unsigned char[SERVER_PRINC_NAME_SIZE + 1];
if (AnsiPrincName == 0)
return(RPC_S_OUT_OF_MEMORY);
_rpc_mgmt_inq_princ_name(Binding, AuthnSvc, SERVER_PRINC_NAME_SIZE,
AnsiPrincName, (unsigned long *)&Status);
*ServerPrincName = 0;
if ( Status == RPC_S_OK )
{
Status = A2WAttachHelper((char *)AnsiPrincName, ServerPrincName);
if (Status != RPC_S_OK)
{
delete AnsiPrincName;
ASSERT(Status == RPC_S_OUT_OF_MEMORY);
return(RPC_S_OUT_OF_MEMORY);
}
}
delete AnsiPrincName;
return(Status);
}
RPC_STATUS RPC_ENTRY
RpcServerInqDefaultPrincName (
IN unsigned long AuthnSvc,
OUT unsigned short __RPC_FAR * __RPC_FAR * PrincName
)
/*++
Routine Description:
Arguments:
PrincName - Returns
Return Value:
RPC_S_OK - Everything worked just fine, and you now know the interfaces
supported by this server.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete
the operation.
--*/
{
RPC_STATUS Status = RPC_S_OK;
SECURITY_CREDENTIALS *pCredentials;
SEC_CHAR * DefaultPrincName = NULL;
RPC_CHAR *CopyPrincName;
InitializeIfNecessary();
Status = FindServerCredentials(
NULL,
NULL,
AuthnSvc,
0,
NULL,
&pCredentials
);
if (Status != RPC_S_OK) {
return (Status);
}
Status = pCredentials->InquireDefaultPrincName(&DefaultPrincName);
if (Status != RPC_S_OK) {
pCredentials->DereferenceCredentials();
return (Status);
}
ASSERT(DefaultPrincName);
CopyPrincName = DuplicateString((RPC_CHAR *)DefaultPrincName);
pCredentials->DereferenceCredentials();
if (CopyPrincName == 0)
return(RPC_S_OUT_OF_MEMORY);
*PrincName = CopyPrincName;
return (RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
THUNK_FN(RpcServerInqDefaultPrincName) (
IN unsigned long AuthnSvc,
OUT THUNK_CHAR **PrincName
)
{
RPC_STATUS RpcStatus;
USES_CONVERSION;
COutDelThunk thunkedPrincName;
RpcStatus = RpcServerInqDefaultPrincName(AuthnSvc,
thunkedPrincName);
if (RpcStatus != RPC_S_OK)
{
return(RpcStatus);
}
ATTEMPT_OUT_THUNK(thunkedPrincName, PrincName);
return (RpcStatus);
}
RPC_STATUS RPC_ENTRY
RpcBindingServerFromClient (
IN RPC_BINDING_HANDLE ClientBinding,
OUT RPC_BINDING_HANDLE __RPC_FAR * ServerBinding
)
/*++
Routine Description:
This routine is used by a server application to convert a client binding
handle (server side binding handle) into a partially bound server binding
handle (client side binding handle).
Arguments:
ClientBinding - Supplies a client binding.
ServerBinding - Returns a partially bound server binding handle which
can be used to get back to the client.
Return Values:
RPC_S_OK - The client binding handle has been successfully converted into
a server binding handle.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete this
operation.
RPC_S_CANNOT_SUPPORT - The requested operation can not be supported.
RPC_S_INVALID_BINDING - The supplied client binding is invalid.
RPC_S_WRONG_KIND_OF_BINDING - The supplied client binding is not a
client binding.
--*/
{
GENERIC_OBJECT * SCall;
THREAD *Thread;
InitializeIfNecessary();
Thread = ThreadSelf();
if (!Thread)
return RPC_S_OUT_OF_MEMORY;
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
if (ARGUMENT_PRESENT(ClientBinding))
{
SCall = (GENERIC_OBJECT *) ClientBinding;
if (SCall->InvalidHandle(CALL_TYPE | BINDING_HANDLE_TYPE))
{
*ServerBinding = 0;
return(RPC_S_INVALID_BINDING);
}
if (SCall->InvalidHandle(SCALL_TYPE))
{
*ServerBinding = 0;
return(RPC_S_WRONG_KIND_OF_BINDING);
}
}
else
{
SCall = (GENERIC_OBJECT *) RpcpGetThreadContext();
if ( SCall == 0 )
{
*ServerBinding = 0;
return(RPC_S_NO_CALL_ACTIVE);
}
}
return(((SCALL *) SCall)->ConvertToServerBinding(ServerBinding));
}
RPC_STATUS RPC_ENTRY
I_RpcServerRegisterForwardFunction(
IN RPC_FORWARD_FUNCTION __RPC_FAR * pForwardFunction
)
/*++
Routine Description:
Allows Epmapper to register a function with the runtime
to allow the runtime to determine the 'forwarding' endpoint
(that is the local endpoint the server must forward the
currently received packet to).
Return Value:
--*/
{
InitializeIfNecessary();
GlobalRpcServer->RegisterRpcForwardFunction(pForwardFunction);
return RPC_S_OK;
}
RPC_ADDRESS_CHANGE_FN * gAddressChangeFn = 0;
RPC_ADDRESS_CHANGE_FN * RPC_ENTRY
I_RpcServerInqAddressChangeFn()
{
return gAddressChangeFn;
}
RPC_STATUS RPC_ENTRY
I_RpcServerSetAddressChangeFn(
IN RPC_ADDRESS_CHANGE_FN * pAddressChangeFn
)
{
gAddressChangeFn = pAddressChangeFn;
return RPC_S_OK;
}
RPC_STATUS
RPC_ENTRY
I_RpcServerInqLocalConnAddress (
IN RPC_BINDING_HANDLE Binding,
IN OUT void *Buffer,
IN OUT unsigned long *BufferSize,
OUT unsigned long *AddressFormat
)
/*++
Routine Description:
This routine is used by a server application to inquire about the local
address on which a call is made.
Arguments:
Binding - Supplies a valid server binding (SCALL).
Buffer - The buffer that will receive the output address
BufferSize - the size of the supplied Buffer on input. On output the
number of bytes written to the buffer. If the buffer is too small
to receive all the output data, ERROR_MORE_DATA is returned,
nothing is written to the buffer, and BufferSize is set to
the size of the buffer needed to return all the data.
AddressFormat - a constant indicating the format of the returned address.
Currently supported are RPC_P_ADDR_FORMAT_TCP_IPV4 and
RPC_P_ADDR_FORMAT_TCP_IPV6. Undefined on failure.
Return Values:
RPC_S_OK - success.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete this
operation.
RPC_S_INVALID_BINDING - The supplied client binding is invalid.
RPC_S_CANNOT_SUPPORT - The local address was inquired for a protocol
sequence that doesn't support this type of functionality. Currently
only ncacn_ip_tcp supports it.
RPC_S_* or Win32 error for other errors
--*/
{
SCALL *SCall;
THREAD *Thread;
RPC_STATUS Status;
InitializeIfNecessary();
ASSERT(!RpcpCheckHeap());
Thread = ThreadSelf();
if (!Thread)
return RPC_S_OUT_OF_MEMORY;
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
if ( Binding == 0 )
{
SCall = (SCALL *) RpcpGetThreadContext();
if (SCall == 0)
return(RPC_S_NO_CALL_ACTIVE);
}
else
{
SCall = (SCALL *) Binding;
if (SCall->InvalidHandle(SCALL_TYPE))
return(RPC_S_INVALID_BINDING);
}
return InqLocalConnAddress(
SCall,
Buffer,
BufferSize,
AddressFormat);
}
RPC_STATUS RPC_ENTRY
I_RpcServerUnregisterEndpoint (
IN RPC_CHAR * Protseq,
IN RPC_CHAR * Endpoint
)
{
InitializeIfNecessary();
return GlobalRpcServer->UnregisterEndpoint(Protseq, Endpoint);
}
RPC_STATUS
RPC_ENTRY
I_RpcServerTurnOnOffKeepalives (
IN RPC_BINDING_HANDLE Binding OPTIONAL,
IN BOOL TurnOn,
IN ULONG Time,
IN ULONG Interval
)
/*++
Routine Description:
A server application will use this routine to set the comminucation timeout
for the connection for the current call. This works for ncacn_ip_tcp only.
The transport layer will issue keepalive packets to monitor the connection,
so care must be taken when setting this.
Arguments:
Binding - Optionally supplies a binding handle on the server
side which indicates for which remote procedure call we wish to
set the timeout. If no binding handle is supplied, then the
remote procedure call currently being handled by this server thread is used.
TurnOn - If non-zero the keepalives will be turned on. Must be non-zero.
Time - The length in milliseconds between the last keep alive
response and the next probe.
Interval - The keepalive interval in milliseconds between
two consequitive keep alive probes if the first one
did not receive a response.
Return Value:
RPC_S_OK for success of RPC_S_* /Win32 error code for error.
--*/
{
SCALL * SCall;
InitializeIfNecessary();
if (!TurnOn)
{
return(RPC_S_CANNOT_SUPPORT);
}
if (ARGUMENT_PRESENT(Binding))
{
SCall = (SCALL *) Binding;
if (SCall->InvalidHandle(SCALL_TYPE))
{
return(RPC_S_INVALID_BINDING);
}
}
else
{
SCall = (SCALL *) RpcpGetThreadContext();
if ( SCall == 0 )
{
return(RPC_S_NO_CALL_ACTIVE);
}
}
return SCall->TurnOnOffKeepAlives (TurnOn, Time, Interval);
}
// declare it as pure C so that it gets exported properly
extern "C"
{
RPC_STATUS
RPC_ENTRY
I_RpcServerIsClientDisconnected (
IN RPC_BINDING_HANDLE Binding OPTIONAL,
OUT BOOL *ClientIsDisconnected
);
};
RPC_STATUS
RPC_ENTRY
I_RpcServerIsClientDisconnected (
IN RPC_BINDING_HANDLE Binding OPTIONAL,
OUT BOOL *ClientIsDisconnected
)
/*++
Routine Description:
Checks whether the client for the given call has disconnected. This is
supported only for ncalrpc and ncacn* protocol sequences. It is not
supported for ncadg* protocol sequences.
Arguments:
Binding - Optionally supplies a binding handle on the server
side which indicates for which remote procedure call we wish to
set the timeout. If no binding handle is supplied, then the
remote procedure call currently being handled by this server thread is used.
ClientIsDisconnected - on output it will contain non-zero if the client is
disconnected. If the client is still connected, it will contain 0.
Undefined on failure.
Return Value:
RPC_S_OK for success of RPC_S_CANNOT_SUPPORT. This API cannot fail if called
with valid arguments and within the context of an RPC call.
Note:
If called on async RPC calls, it is the obligation of the caller to make sure that
the call is not completed while this API is in progress.
--*/
{
SCALL * SCall;
InitializeIfNecessary();
if (ARGUMENT_PRESENT(Binding))
{
SCall = (SCALL *) Binding;
}
else
{
SCall = (SCALL *) RpcpGetThreadContext();
if ( SCall == 0 )
{
return(RPC_S_NO_CALL_ACTIVE);
}
}
if (SCall->InvalidHandle(OSF_SCALL_TYPE | LRPC_SCALL_TYPE))
{
return(RPC_S_INVALID_BINDING);
}
SCall->IsClientDisconnected (ClientIsDisconnected);
return RPC_S_OK;
}
int
InitializeRpcServer (
)
/*++
Routine Description:
This routine will be called once at DLL initialization time. We
have got to create and initialize the server. This will get it
all ready to hang protocol sequences (addresses) and interfaces
from.
Return Value:
Zero will be returned if everything is initialized correctly;
otherwise, non-zero will be returned.
--*/
{
RPC_STATUS RpcStatus = RPC_S_OK;
if (GlobalRpcServer == NULL)
{
GlobalRpcServer = new RPC_SERVER(&RpcStatus);
if ( GlobalRpcServer == NULL )
{
return(RPC_S_OUT_OF_MEMORY);
}
else if (RpcStatus != RPC_S_OK)
{
delete GlobalRpcServer;
GlobalRpcServer = NULL;
return(RPC_S_OUT_OF_MEMORY);
}
}
if (SIDCache == NULL)
{
SIDCache = new SID_CACHE(&RpcStatus);
if (SIDCache == NULL)
{
return RPC_S_OUT_OF_MEMORY;
delete GlobalRpcServer;
GlobalRpcServer = NULL;
}
else if (RpcStatus != RPC_S_OK)
{
delete GlobalRpcServer;
GlobalRpcServer = NULL;
delete SIDCache;
SIDCache = NULL;
return(RPC_S_OUT_OF_MEMORY);
}
}
GroupIdCounter = GetTickCount();
// If we can't create the global management interface
// don't worry about it; it probably won't be used anyway.
// When it is used, it should be checked for NULL.
if (GlobalManagementInterface == NULL)
{
// We should not expect to have more then RPC_C_PROTSEQ_MAX_REQS_DEFAULT
// simultaneous calls on this interface. The calls do not receive more then 10K.
GlobalManagementInterface = new RPC_INTERFACE(
(RPC_SERVER_INTERFACE *)mgmt_ServerIfHandle,
GlobalRpcServer, 0, MAX_IF_CALLS, mgmt_MaxRpcSize, 0, &RpcStatus);
if ( GlobalManagementInterface == NULL )
{
return(RPC_S_OUT_OF_MEMORY);
}
else if (RpcStatus != RPC_S_OK)
{
delete GlobalManagementInterface;
GlobalManagementInterface = NULL;
return(RPC_S_OUT_OF_MEMORY);
}
GlobalManagementInterface->RegisterTypeManager(0,
((RPC_SERVER_INTERFACE *)mgmt_ServerIfHandle)->DefaultManagerEpv);
}
return(RpcStatus);
}