/*++ 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 #include #include #include #include #include #include #include #include long GroupIdCounter; RPC_INTERFACE * GlobalManagementInterface; 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; 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); } 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); return(Status); } } 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 ) { if ( Status == RPC_S_PROTSEQ_NOT_SUPPORTED ) { return(RPC_S_NO_PROTSEQS); } return(Status); } 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); } #define MAX_STATISTICS 4 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; // this function must be called after InitializeAuthzSupportIfNecessary ASSERT(AuthzDllHandle); if (DummyResourceManager) return RPC_S_OK; GlobalMutexRequest(); if (DummyResourceManager) { GlobalMutexClear(); return RPC_S_OK; } AuthzInitializeResourceManagerFn = (AuthzInitializeResourceManagerFnType) GetProcAddress(AuthzDllHandle, "AuthzInitializeResourceManager"); if (AuthzInitializeResourceManagerFn == NULL) { Status = GetLastError(); RpcpErrorAddRecord(EEInfoGCRuntime, Status, EEInfoDLCreateDummyResourceManagerIfNecessary10, "AuthzInitializeResourceManager"); } else { Result = AuthzInitializeResourceManagerFn( 0, // 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(); 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; InitializeIfNecessary(); if ( Binding == 0 ) { return(GlobalRpcServer->InquireInterfaceIds(IfIdVector)); } *IfIdVector = 0; _rpc_mgmt_inq_if_ids(Binding, (rpc_if_id_vector_p_t *) IfIdVector, (unsigned long *) &Status); 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) { return (Status); } ASSERT(DefaultPrincName); CopyPrincName = DuplicateString((RPC_CHAR *)DefaultPrincName); 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); } 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; GlobalRpcServer = new RPC_SERVER(&RpcStatus); if ( ( GlobalRpcServer == 0 ) || ( RpcStatus != RPC_S_OK ) ) { return(1); } 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. GlobalManagementInterface = new RPC_INTERFACE( (RPC_SERVER_INTERFACE *)mgmt_ServerIfHandle, GlobalRpcServer, 0, MAX_IF_CALLS, gMaxRpcSize, 0, &RpcStatus); if (GlobalManagementInterface) { GlobalManagementInterface->RegisterTypeManager(0, ((RPC_SERVER_INTERFACE *)mgmt_ServerIfHandle)->DefaultManagerEpv); } return(RpcStatus); }