/*++ Copyright (c) 1990-1993 Microsoft Corporation Module Name: RpcServ.c Abstract: This file contains routines for starting and stoping RPC servers. NetpInitRpcServer NetpStartRpcServer NetpStopRpcServer Author: Dan Lafferty danl 09-May-1991 Environment: User Mode - Win32 Revision History: 26-May-1993 Danl Added call to RpcMgmtWaitServerListen when shutting down the last RPC server in the process. This fixes the problem where if we shut down all the RPC services in lmsvcs.exe (but the process stays up due to other services), and then start them up again, all calls to those RPC interfaces would return RPC_SERVER_BUSY. 18-May-1993 Danl Changed RpcServerUnregisterIf so that it waits for outstanding RPC calls to complete. 29-Jan-1993 Danl Free memory allocated for Endpoint and Security Descriptor. Also, fix it so StartListen() is only called if RpcServerRegisterIf() succeeeds. 23-Oct-1991 Danl Added Critical Section Locks and made sure the instance count gets incremented. Added NetpInitRpcServer(). 09-May-1991 Danl Created --*/ // // INCLUDES // // These must be included first: #include // DbgPrint #include // DbgPrint #include // win32 typedefs #include // NET_API_STATUS #include // rpc prototypes #include #include #include // needed for winbase.h #include // LocalAlloc // These may be included in any order: #include // DbgPrint #include // NetError codes #include // MIDL_user_allocate(), MIDL_user_free(). #include // for strcpy strcat strlen memcmp #include // for STRCPY STRCAT STRLEN memcmp #include // IF_DEBUG #include // FORMAT_NTSTATUS, NetpKdPrint(()). // // GLOBALS // static CRITICAL_SECTION RpcpCriticalSection; static DWORD RpcpNumInstances; NET_API_STATUS NetpInitRpcServer( VOID ) /*++ Routine Description: This function initializes the critical section used to protect the global server handle and instance count. Arguments: none Return Value: none --*/ { InitializeCriticalSection(&RpcpCriticalSection); RpcpNumInstances = 0; return(0); } NET_API_STATUS NetpStartRpcServer( IN LPTSTR InterfaceName, IN RPC_IF_HANDLE InterfaceSpecification ) /*++ Routine Description: Starts an RPC Server, adds the address (or port/pipe), and adds the interface (dispatch table). Arguments: InterfaceName - This is a pointer to a character string that identifies the interface. InterfaceSpecification - Supplies a description of the interface to be added. Return Value: NERR_Success, or any RPC error codes, or any windows error codes that can be returned by LocalAlloc. --*/ { RPC_STATUS RpcStatus; LPTSTR Endpoint=NULL; DWORD status; PSECURITY_DESCRIPTOR SecurityDescriptor=NULL; BOOLEAN Bool; Endpoint = (LPTSTR)LocalAlloc(0, STRSIZE(InterfaceName) + STRSIZE(NT_PIPE_PREFIX)); if (Endpoint == 0) { status = GetLastError(); IF_DEBUG(RPC) { NetpKdPrint(("NetpStartRpcServer:LocalAlloc Failure %ld\n",status)); } return(status); } STRCPY(Endpoint, NT_PIPE_PREFIX); STRCAT(Endpoint, InterfaceName); IF_DEBUG(RPC) { NetpKdPrint(("Creating Interface: %s\n", Endpoint)); } // // All code from this point on must goto a CleanExit prior to returning. // EnterCriticalSection(&RpcpCriticalSection); IF_DEBUG(RPC) { NetpKdPrint(("[NetpStartRpcServer]Adding Address & Interface...\n")); } // // Croft up a security descriptor that will grant everyone // all access to the object (basically, no security) // // We do this by putting in a NULL Dacl. // // BUGBUG: rpc doesn't know how to copy a security descriptor, // so just allocate this and leave it around for the time being. // We need to fix this before we ship. // SecurityDescriptor = (PSECURITY_DESCRIPTOR)LocalAlloc( LMEM_FIXED, sizeof( SECURITY_DESCRIPTOR )); if (SecurityDescriptor == NULL) { RpcStatus = RPC_S_OUT_OF_MEMORY; goto CleanExit; } InitializeSecurityDescriptor( SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION ); Bool = SetSecurityDescriptorDacl ( SecurityDescriptor, TRUE, // Dacl present NULL, // NULL Dacl FALSE // Not defaulted ); ASSERT( Bool ); RpcStatus = RpcServerUseProtseqEp( TEXT("ncacn_np"), 10, Endpoint, SecurityDescriptor); if ((RpcStatus != RPC_S_OK) && (RpcStatus != RPC_S_DUPLICATE_ENDPOINT)) { IF_DEBUG(RPC) { NetpKdPrint(("RpcServerUseProtseqA failed! rpcstatus = %u\n",RpcStatus)); } goto CleanExit; } RpcStatus = RpcServerRegisterIf(InterfaceSpecification, 0, 0); if (RpcStatus != RPC_S_OK) { IF_DEBUG(RPC) { NetpKdPrint(("RpcServerRegisterIf failed! rpcstatus = %u\n",RpcStatus)); } goto CleanExit; } RpcpNumInstances++; if (RpcpNumInstances == 1) { RpcStatus = RpcServerListen(1, 12345, 1); if ( RpcStatus == RPC_S_ALREADY_LISTENING ) { RpcStatus = RPC_S_OK; } } CleanExit: LeaveCriticalSection(&RpcpCriticalSection); if (Endpoint != NULL) { LocalFree(Endpoint); } if (SecurityDescriptor != NULL) { LocalFree(SecurityDescriptor); } return NetpRpcStatusToApiStatus(RpcStatus); } NET_API_STATUS NetpStopRpcServer( IN RPC_IF_HANDLE InterfaceSpecification ) /*++ Routine Description: Deletes the interface. Arguments: InterfaceSpecification - Supplies a description of the interface to be deleted. Return Value: NERR_Success, or any RPC error codes that can be returned from RpcServerUnregisterIf. --*/ { RPC_STATUS RpcStatus; RpcStatus = RpcServerUnregisterIf(InterfaceSpecification, 0, 1); EnterCriticalSection(&RpcpCriticalSection); RpcpNumInstances--; if (RpcpNumInstances == 0) { RpcMgmtStopServerListening(0); RpcMgmtWaitServerListen(); } LeaveCriticalSection(&RpcpCriticalSection); return NetpRpcStatusToApiStatus(RpcStatus); }