/*++ Copyright (c) 1990-1993 Microsoft Corporation Module Name: splrpc.c Abstract: This file contains routines for starting and stopping RPC servers. SpoolerStartRpcServer SpoolerStopRpcServer Author: Krishna Ganugapati krishnaG Environment: User Mode - Win32 Revision History: 14-Oct-1993 KrishnaG Created 25-May-1999 khaleds Added: CreateNamedPipeSecurityDescriptor BuildNamedPipeProtection --*/ // // INCLUDES // #define NOMINMAX #include #include #include #include #include #include #include #include "splsvr.h" #include "splr.h" #include "server.h" #ifndef _SRVRMEM_H_ #include "srvrmem.h" #endif WCHAR szSerializeRpc []= L"SerializeRpc"; WCHAR szCallExitProcessOnShutdown []= L"CallExitProcessOnShutdown"; WCHAR szMaxRpcSize []= L"MaxRpcSize"; WCHAR szPrintKey[] = L"System\\CurrentControlSet\\Control\\Print"; #define DEFAULT_MAX_RPC_SIZE 1024*1024 // default maximum rpc data block size in bytes DWORD dwCallExitProcessOnShutdown = TRUE; RPC_STATUS SpoolerStartRpcServer( VOID) /*++ Routine Description: Arguments: Return Value: NERR_Success, or any RPC error codes that can be returned from RpcServerUnregisterIf. --*/ { unsigned char * InterfaceAddress; RPC_STATUS status; PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; BOOL Bool; HKEY hKey; DWORD cbData; DWORD dwSerializeRpc = 0; DWORD dwType; DWORD dwMaxRpcSize; InterfaceAddress = "\\pipe\\spoolss"; // 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. // // NOTE: rpc should copy the security descriptor, // Since it currently doesn't, simply allocate it for now and // leave it around forever. // SecurityDescriptor = CreateNamedPipeSecurityDescriptor(); if (SecurityDescriptor == 0) { DBGMSG(DBG_ERROR, ("Spoolss: out of memory\n")); return FALSE; } // // For now, ignore the second argument. // status = RpcServerUseProtseqEpA("ncacn_np", 10, InterfaceAddress, SecurityDescriptor); if (status) { DBGMSG(DBG_WARN, ("RpcServerUseProtseqEpA 1 = %u\n",status)); return FALSE; } // // For now, ignore the second argument. // status = RpcServerUseProtseqEpA("ncalrpc", 10, "spoolss", SecurityDescriptor); if (status) { DBGMSG(DBG_WARN, ("RpcServerUseProtseqEpA 2 = %u\n",status)); return FALSE; } if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, szPrintKey, 0, KEY_READ, &hKey)) { // // Ignore failure case since we can use the default // cbData = sizeof(dwSerializeRpc); RegQueryValueEx(hKey, szSerializeRpc, NULL, &dwType, (LPBYTE)&dwSerializeRpc, &cbData); // // This value can be used to control if spooler controls ExitProcess // on shutdown // cbData = sizeof(dwCallExitProcessOnShutdown); RegQueryValueEx(hKey, szCallExitProcessOnShutdown, NULL, &dwType, (LPBYTE)&dwCallExitProcessOnShutdown, &cbData); // // dwMaxRpcSize specifies the maximum size in bytes of incoming RPC data blocks. // cbData = sizeof(dwMaxRpcSize); if (RegQueryValueEx(hKey, szMaxRpcSize, NULL, &dwType, (LPBYTE)&dwMaxRpcSize, &cbData) != ERROR_SUCCESS) { dwMaxRpcSize = DEFAULT_MAX_RPC_SIZE; } RegCloseKey(hKey); } // // Now we need to add the interface. We can just use the winspool_ServerIfHandle // specified by the MIDL compiler in the stubs (winspl_s.c). // status = RpcServerRegisterIf2( winspool_ServerIfHandle, 0, 0, 0, RPC_C_PROTSEQ_MAX_REQS_DEFAULT, dwMaxRpcSize, NULL ); if (status) { DBGMSG(DBG_WARN, ("RpcServerRegisterIf = %u\n",status)); return FALSE; } if (dwSerializeRpc) { // By default, rpc will serialize access to context handles. Since // the spooler needs to be able to have two threads access a context // handle at once, and it knows what it is doing, we will tell rpc // not to serialize access to context handles. I_RpcSsDontSerializeContext(); } status = RpcMgmtSetServerStackSize(INITIAL_STACK_COMMIT); if (status != RPC_S_OK) { DBGMSG(DBG_ERROR, ("Spoolss : RpcMgmtSetServerStackSize = %d\n", status)); } // The first argument specifies the minimum number of threads to // create to handle calls; the second argument specifies the maximum // concurrent calls to handle. The third argument indicates that // the routine should not wait. status = RpcServerListen(1,SPL_MAX_RPC_CALLS,1); if ( status != RPC_S_OK ) { DBGMSG(DBG_ERROR, ("Spoolss : RpcServerListen = %d\n", status)); } return (status); } #define MAX_ACE 7 #define DBGCHK( Condition, ErrorInfo ) \ if( Condition ) DBGMSG( DBG_WARNING, ErrorInfo ) /*++ Routine Description: This routine adds prepares the required masks and flags required for the DACL on the named pipes used by RPC Arguments: None Return Value: An allocated Security Descriptor --*/ PSECURITY_DESCRIPTOR CreateNamedPipeSecurityDescriptor( VOID ) { UCHAR AceType[MAX_ACE]; PSID AceSid[MAX_ACE]; BYTE InheritFlags[MAX_ACE]; DWORD AceCount; PSECURITY_DESCRIPTOR ServerSD = NULL; // // For Code optimization we replace 5 individaul // SID_IDENTIFIER_AUTHORITY with an array of // SID_IDENTIFIER_AUTHORITYs // where // SidAuthority[0] = UserSidAuthority // SidAuthority[1] = PowerSidAuthority // SidAuthority[2] = EveryOneSidAuthority // SidAuthority[3] = CreatorSidAuthority // SidAuthority[4] = SystemSidAuthority // SidAuthority[5] = AdminSidAuthority // SID_IDENTIFIER_AUTHORITY SidAuthority[MAX_ACE] = { SECURITY_NT_AUTHORITY, SECURITY_NT_AUTHORITY, SECURITY_WORLD_SID_AUTHORITY, SECURITY_NT_AUTHORITY, SECURITY_CREATOR_SID_AUTHORITY, SECURITY_NT_AUTHORITY, SECURITY_NT_AUTHORITY }; // // For code optimization we replace 6 individual Sids with // an array of Sids; On Whistler, Anonymous user will no longer // be granted access to resources whose ACLs grant access to Everyone. // // We need to give access to Anonymous user to access the RPC pipe // for the reverse RPC connection when RPC calls could come as // Anonymous from either NT4 machines, Whistler Personal or Whitler // across domains. // // Sid[0] = UserSid // Sid[1] = PowerSid // Sid[2] = EveryOne // Sid[3] = Anonymous // Sid[4] = CreatorSid // Sid[5] = SystemSid // Sid[6] = AdminSid // PSID Sids[MAX_ACE] = {NULL,NULL,NULL,NULL,NULL}; ACCESS_MASK AceMask[MAX_ACE] = { FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE , FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE , (FILE_GENERIC_READ | FILE_WRITE_DATA | FILE_ALL_ACCESS) & ~WRITE_DAC &~WRITE_OWNER & ~DELETE & ~FILE_CREATE_PIPE_INSTANCE, (FILE_GENERIC_READ | FILE_WRITE_DATA | FILE_ALL_ACCESS) & ~WRITE_DAC &~WRITE_OWNER & ~DELETE & ~FILE_CREATE_PIPE_INSTANCE, STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_ALL_ACCESS, STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_ALL_ACCESS, STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | FILE_GENERIC_READ | FILE_ALL_ACCESS }; DWORD SubAuthorities[3*MAX_ACE] = { 2 , SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_USERS , 2 , SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_POWER_USERS , 1 , SECURITY_WORLD_RID , 0 , 1 , SECURITY_ANONYMOUS_LOGON_RID , 0 , 1 , SECURITY_CREATOR_OWNER_RID , 0 , 1 , SECURITY_LOCAL_SYSTEM_RID , 0 , 2 , SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_ADMINS }; // // Name Pipe SD // for(AceCount = 0; ( (AceCount < MAX_ACE) && AllocateAndInitializeSid(&SidAuthority[AceCount], (BYTE)SubAuthorities[AceCount*3], SubAuthorities[AceCount*3+1], SubAuthorities[AceCount*3+2], 0, 0, 0, 0, 0, 0, &Sids[AceCount])); AceCount++) { AceType[AceCount] = ACCESS_ALLOWED_ACE_TYPE; AceSid[AceCount] = Sids[AceCount]; InheritFlags[AceCount] = 0; } if(AceCount == MAX_ACE) { if(!BuildNamedPipeProtection( AceType, AceCount, AceSid, AceMask, InheritFlags, NULL, NULL, NULL, &ServerSD ) ) { DBGMSG( DBG_WARNING,( "Couldn't buidl Named Pipe protection" ) ); } } else { DBGMSG( DBG_WARNING,( "Couldn't Allocate and initialize SIDs" ) ); } for(AceCount=0;AceCountHeader.AceFlags = InheritFlags[i]; } } OK = SetSecurityDescriptorDacl (&Absolute, TRUE, TmpAcl, FALSE ); DBGCHK( !OK, ( "Failed to set security descriptor DACL. Error %d", GetLastError() ) ); // // Convert the Security Descriptor to Self-Relative // // Get the length needed // Allocate that much memory // Copy it // Free the generated absolute ACLs // SDLength = GetSecurityDescriptorLength( &Absolute ); Relative = LocalAlloc( 0, SDLength ); if (!Relative) { DBGCHK( !Relative, ( "Out of heap space: Can't allocate security descriptor" ) ); goto Fail; } OK = MakeSelfRelativeSD(&Absolute, Relative, &SDLength ); if (!OK) { DBGCHK( !OK, ( "Failed to create self-relative security descriptor DACL. Error %d", GetLastError() ) ); goto Fail; } SrvrFreeSplMem( TmpAcl ); *ppSecurityDescriptor = Relative; return( OK ); Fail: if (TmpAcl){ FreeSplMem(TmpAcl); } if (Relative) { LocalFree(Relative); } *ppSecurityDescriptor = NULL; return(FALSE); }