/*++ Copyright (c) 1989 Microsoft Corporation Module Name: srvinit.c Abstract: This is the main initialization module for the Server side of the Client Server Runtime Subsystem (CSRSS) Author: Steve Wood (stevewo) 08-Oct-1990 Environment: User Mode Only Revision History: --*/ #include "csrsrv.h" #include #include #include CONST PCSR_API_ROUTINE CsrServerApiDispatchTable[CsrpMaxApiNumber] = { (PCSR_API_ROUTINE)CsrSrvClientConnect, (PCSR_API_ROUTINE)CsrSrvUnusedFunction, (PCSR_API_ROUTINE)CsrSrvUnusedFunction, (PCSR_API_ROUTINE)CsrSrvUnusedFunction, (PCSR_API_ROUTINE)CsrSrvUnusedFunction }; BOOLEAN CsrServerApiServerValidTable[CsrpMaxApiNumber] = { TRUE, // CsrSrvClientConnect, FALSE, // CsrSrvUnusedFunction, FALSE, // CsrSrvUnusedFunction, FALSE, // CsrSrvUnusedFunction, FALSE // CsrSrvUnusedFunction, }; #if DBG CONST PSZ CsrServerApiNameTable[CsrpMaxApiNumber] = { "ClientConnect", "CsrSrvUnusedFunction", "CsrSrvUnusedFunction", "CsrSrvUnusedFunction", "CsrSrvUnusedFunction", }; #endif NTSTATUS CsrSetProcessSecurity( VOID ); NTSTATUS CsrSetDirectorySecurity( IN HANDLE DirectoryHandle ); NTSTATUS GetDosDevicesProtection ( PSECURITY_DESCRIPTOR SecurityDescriptor ); VOID FreeDosDevicesProtection ( PSECURITY_DESCRIPTOR SecurityDescriptor ); NTSTATUS CsrPopulateDosDevicesDirectory( HANDLE NewDirectoryHandle, PPROCESS_DEVICEMAP_INFORMATION pGlobalProcessDeviceMapInfo ); // Though this function does not seem to cleanup on failure, failure // will cause CSRSS to exit, so any allocated memory will be freed and // any open handle will be closed. NTSTATUS CsrServerInitialization( IN ULONG argc, IN PCH argv[] ) { NTSTATUS Status; ULONG i; PVOID ProcessDataPtr; PCSR_SERVER_DLL LoadedServerDll; #if DBG BOOLEAN bIsRemoteSession = NtCurrentPeb()->SessionId != 0; #endif // // Initialize Wow64 stuffs // #ifdef _WIN64 InitializeWow64OnBoot(1); #endif // // Save away system information in a global variable // Status = NtQuerySystemInformation( SystemBasicInformation, &CsrNtSysInfo, sizeof( CsrNtSysInfo ), NULL ); ASSERT( NT_SUCCESS( Status ) || bIsRemoteSession ); if (!NT_SUCCESS( Status )) { return Status; } // // Use the process heap for memory allocation. // CsrHeap = RtlProcessHeap(); CsrBaseTag = RtlCreateTagHeap( CsrHeap, 0, L"CSRSS!", L"TMP\0" L"INIT\0" L"CAPTURE\0" L"PROCESS\0" L"THREAD\0" L"SECURITY\0" L"SESSION\0" L"WAIT\0" ); // // Set up CSRSS process security // Status = CsrSetProcessSecurity(); ASSERT(NT_SUCCESS(Status) || bIsRemoteSession); if (!NT_SUCCESS(Status)) { return Status; } // // Initialize the Session List // Status = CsrInitializeNtSessionList(); ASSERT(NT_SUCCESS(Status) || bIsRemoteSession); if (!NT_SUCCESS(Status)) { return Status; } // // Initialize the Process List // Status = CsrInitializeProcessStructure(); ASSERT(NT_SUCCESS(Status) || bIsRemoteSession); if (!NT_SUCCESS(Status)) { return Status; } // // Process the command line arguments // Status = CsrParseServerCommandLine(argc, argv); ASSERT(NT_SUCCESS(Status) || bIsRemoteSession); if (!NT_SUCCESS(Status)) { return Status; } #if DBG Status = RtlInitializeCriticalSection(&CsrTrackLpcLock); if (!NT_SUCCESS(Status)) { return Status; } LpcTrackIndex = 0; #endif // // Fix up per-process data for root process // ProcessDataPtr = (PCSR_PROCESS)RtlAllocateHeap( CsrHeap, MAKE_TAG( PROCESS_TAG ) | HEAP_ZERO_MEMORY, CsrTotalPerProcessDataLength ); if (ProcessDataPtr == NULL) { return STATUS_NO_MEMORY; } for (i=0; iPerProcessDataLength) { CsrRootProcess->ServerDllPerProcessData[i] = ProcessDataPtr; ProcessDataPtr = (PVOID)QUAD_ALIGN((PCHAR)ProcessDataPtr + LoadedServerDll->PerProcessDataLength); } else { CsrRootProcess->ServerDllPerProcessData[i] = NULL; } } // // Let server dlls know about the root process. // for (i=0; iAddProcessRoutine) { (*LoadedServerDll->AddProcessRoutine)( NULL, CsrRootProcess ); } } // // Initialize the Windows Server API Port, and one or more // request threads. // Status = CsrApiPortInitialize(); ASSERT( NT_SUCCESS( Status ) || bIsRemoteSession ); if (!NT_SUCCESS( Status )) { return Status; } // // Initialize the Server Session Manager API Port and one // request thread. // Status = CsrSbApiPortInitialize(); ASSERT( NT_SUCCESS( Status ) || bIsRemoteSession); if (!NT_SUCCESS( Status )) { return Status; } // // Connect to the session manager so we can start foreign sessions // Status = SmConnectToSm( &CsrSbApiPortName, CsrSbApiPort, IMAGE_SUBSYSTEM_WINDOWS_GUI, &CsrSmApiPort ); ASSERT( NT_SUCCESS( Status ) || bIsRemoteSession ); if (!NT_SUCCESS( Status )) { return Status; } // // Only on Console (HYDRA) // if (NtCurrentPeb()->SessionId == 0) { Status = NtSetDefaultHardErrorPort(CsrApiPort); } return( Status ); } NTSTATUS CsrParseServerCommandLine( IN ULONG argc, IN PCH argv[] ) { NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; ULONG i, ServerDllIndex; PCH KeyName, KeyValue, s; PCH InitRoutine; CsrTotalPerProcessDataLength = 0; CsrObjectDirectory = NULL; CsrMaxApiRequestThreads = CSR_MAX_THREADS; SessionId = NtCurrentPeb()->SessionId; // // Create session specific object directories // Status = CsrCreateSessionObjectDirectory ( SessionId ); if (!NT_SUCCESS(Status)) { if (SessionId == 0) { ASSERT( NT_SUCCESS( Status ) ); DbgPrint("CSRSS: CsrCreateSessionObjectDirectory failed status = %lx\n", Status); } else { DbgPrint("CSRSS: CsrCreateSessionObjectDirectory failed status = %lx\n", Status); return Status; } } for (i=1; iApiNumberBase = CSRSRV_FIRST_API_NUMBER; LoadedServerDll->MaxApiNumber = CsrpMaxApiNumber; LoadedServerDll->ApiDispatchTable = CsrServerApiDispatchTable; LoadedServerDll->ApiServerValidTable = CsrServerApiServerValidTable; #if DBG LoadedServerDll->ApiNameTable = CsrServerApiNameTable; #endif LoadedServerDll->PerProcessDataLength = 0; LoadedServerDll->ConnectRoutine = NULL; LoadedServerDll->DisconnectRoutine = NULL; return( STATUS_SUCCESS ); } NTSTATUS CsrSrvUnusedFunction( IN OUT PCSR_API_MSG m, IN OUT PCSR_REPLY_STATUS ReplyStatus ) { IF_DEBUG { DbgPrint("CSRSS: Calling obsolete function %x\n", m->ApiNumber); } return STATUS_INVALID_PARAMETER; } NTSTATUS CsrSetProcessSecurity( VOID ) { HANDLE Token; NTSTATUS Status; PTOKEN_USER User = NULL; ULONG LengthSid, Length; PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; PACL Dacl; // // Open the token and get the system sid // Status = NtOpenProcessToken( NtCurrentProcess(), TOKEN_QUERY, &Token); if (!NT_SUCCESS(Status)) { return Status; } Status = NtQueryInformationToken (Token, TokenUser, NULL, 0, &Length); User = (PTOKEN_USER)RtlAllocateHeap (CsrHeap, MAKE_TAG( SECURITY_TAG ) | HEAP_ZERO_MEMORY, Length); if (User == NULL) { NtClose( Token ); Status = STATUS_NO_MEMORY; goto error_cleanup; } Status = NtQueryInformationToken( Token, TokenUser, User, Length, &Length ); NtClose( Token ); if (!NT_SUCCESS(Status)) { goto error_cleanup; } LengthSid = RtlLengthSid( User->User.Sid ); // // Allocate a buffer to hold the SD // SecurityDescriptor = RtlAllocateHeap (CsrHeap, MAKE_TAG( SECURITY_TAG ) | HEAP_ZERO_MEMORY, SECURITY_DESCRIPTOR_MIN_LENGTH + sizeof(ACL) + LengthSid + sizeof(ACCESS_ALLOWED_ACE)); if (SecurityDescriptor == NULL) { Status = STATUS_NO_MEMORY; goto error_cleanup; } Dacl = (PACL)((PCHAR)SecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); // // Create the SD // Status = RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); if (!NT_SUCCESS(Status)) { IF_DEBUG { DbgPrint("CSRSS: SD creation failed - status = %lx\n", Status); } goto error_cleanup; } Status = RtlCreateAcl( Dacl, sizeof(ACL) + LengthSid + sizeof(ACCESS_ALLOWED_ACE), ACL_REVISION2); if (!NT_SUCCESS(Status)) { IF_DEBUG { DbgPrint("CSRSS: DACL creation failed - status = %lx\n", Status); } goto error_cleanup; } Status = RtlAddAccessAllowedAce( Dacl, ACL_REVISION, ( PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_DUP_HANDLE | PROCESS_TERMINATE | PROCESS_SET_PORT | READ_CONTROL | PROCESS_QUERY_INFORMATION ), User->User.Sid); if (!NT_SUCCESS(Status)) { IF_DEBUG { DbgPrint("CSRSS: ACE creation failed - status = %lx\n", Status); } goto error_cleanup; } // // Set DACL to NULL to deny all access // Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE, Dacl, FALSE); if (!NT_SUCCESS(Status)) { IF_DEBUG { DbgPrint("CSRSS: set DACL failed - status = %lx\n", Status); } goto error_cleanup; } // // Put the DACL onto the process // Status = NtSetSecurityObject(NtCurrentProcess(), DACL_SECURITY_INFORMATION, SecurityDescriptor); if (!NT_SUCCESS(Status)) { IF_DEBUG { DbgPrint("CSRSS: set process DACL failed - status = %lx\n", Status); } } // // Cleanup // error_cleanup: if (SecurityDescriptor != NULL) { RtlFreeHeap( CsrHeap, 0, SecurityDescriptor ); } if (User != NULL) { RtlFreeHeap( CsrHeap, 0, User ); } return Status; } NTSTATUS CsrSetDirectorySecurity( IN HANDLE DirectoryHandle ) { PSID WorldSid = NULL; PSID SystemSid = NULL; SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; NTSTATUS Status; ULONG AclLength; PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; PACL Dacl; // // Get the SIDs for world and system // Status = RtlAllocateAndInitializeSid( &WorldAuthority, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &WorldSid ); if (!NT_SUCCESS(Status)) { WorldSid = NULL; goto error_cleanup; } Status = RtlAllocateAndInitializeSid( &NtAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &SystemSid ); if (!NT_SUCCESS(Status)) { SystemSid = NULL; goto error_cleanup; } // // Allocate a buffer to hold the SD // AclLength = sizeof(ACL) + RtlLengthSid( WorldSid ) + RtlLengthSid( SystemSid ) + 2 * sizeof(ACCESS_ALLOWED_ACE); SecurityDescriptor = RtlAllocateHeap( CsrHeap, MAKE_TAG( SECURITY_TAG ) | HEAP_ZERO_MEMORY, SECURITY_DESCRIPTOR_MIN_LENGTH + AclLength ); if (SecurityDescriptor == NULL) { Status = STATUS_NO_MEMORY; goto error_cleanup; } // // Create the SD // Status = RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); if (!NT_SUCCESS(Status)) { IF_DEBUG { DbgPrint("CSRSS: SD creation failed - status = %lx\n", Status); } goto error_cleanup; } // // Create the DACL // Dacl = (PACL)((PCHAR)SecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); RtlCreateAcl( Dacl, AclLength, ACL_REVISION ); Status = RtlAddAccessAllowedAce( Dacl, ACL_REVISION, STANDARD_RIGHTS_READ | DIRECTORY_QUERY | DIRECTORY_TRAVERSE, WorldSid ); if (!NT_SUCCESS(Status)) { IF_DEBUG { DbgPrint("CSRSS: ACE creation failed - status = %lx\n", Status); } goto error_cleanup; } Status = RtlAddAccessAllowedAce( Dacl, ACL_REVISION, DIRECTORY_ALL_ACCESS, SystemSid ); if (!NT_SUCCESS(Status)) { IF_DEBUG { DbgPrint("CSRSS: ACE creation failed - status = %lx\n", Status); } goto error_cleanup; } // // Set DACL into the SD // Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE, Dacl, FALSE); if (!NT_SUCCESS(Status)) { IF_DEBUG { DbgPrint("CSRSS: set DACL failed - status = %lx\n", Status); } goto error_cleanup; } // // Put the DACL onto the direcory // Status = NtSetSecurityObject(DirectoryHandle, DACL_SECURITY_INFORMATION, SecurityDescriptor); if (!NT_SUCCESS(Status)) { IF_DEBUG { DbgPrint("CSRSS: set directory DACL failed - status = %lx\n", Status); } } // // Cleanup // error_cleanup: if (SecurityDescriptor != NULL) { RtlFreeHeap( CsrHeap, 0, SecurityDescriptor ); } if (WorldSid != NULL) { RtlFreeSid( WorldSid ); } if (SystemSid != NULL) { RtlFreeSid( SystemSid ); } return Status; } /******************************************************************************* * * CsrPopulateDosDevices * * Populate the new session specific DosDevices Directory. This is an * export called by ntuser\server when a connection is completed. * * The security descriptor on the sessions \DosDevices should already * have been set. * * ENTRY: * HANDLE NewDosDevicesDirectory - Session specific DosDevices Directory * PPROCESS_DEVICEMAP_INFORMATION pGlobalProcessDeviceMapInfo * * EXIT: * STATUS_SUCCESS * ******************************************************************************/ NTSTATUS CsrPopulateDosDevices( VOID ) { NTSTATUS Status = STATUS_SUCCESS; PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo; PROCESS_DEVICEMAP_INFORMATION GlobalProcessDeviceMapInfo; // // Get the global ProcessDeviceMap. We will use this to only add // non-network drive letters to the session specific dos devices // directory // Status = NtQueryInformationProcess( NtCurrentProcess(), ProcessDeviceMap, &GlobalProcessDeviceMapInfo.Query, sizeof( GlobalProcessDeviceMapInfo.Query ), NULL ); if (!NT_SUCCESS( Status )) { DbgPrint("CSRSS: NtQueryInformationProcess failed in CsrPopulateDosDevices - status = %lx\n", Status); return Status; } // // Set the CSRSS's ProcessDeviceMap to the newly created DosDevices Directory // ProcessDeviceMapInfo.Set.DirectoryHandle = DosDevicesDirectory; Status = NtSetInformationProcess( NtCurrentProcess(), ProcessDeviceMap, &ProcessDeviceMapInfo.Set, sizeof( ProcessDeviceMapInfo.Set ) ); if (!NT_SUCCESS( Status )) { DbgPrint("CSRSS: NtSetInformationProcess failed in CsrPopulateDosDevices - status = %lx\n", Status); return Status; } // // Populate the session specfic DosDevices Directory // Status = CsrPopulateDosDevicesDirectory( DosDevicesDirectory, &GlobalProcessDeviceMapInfo ); return Status; } /******************************************************************************* * * CsrPopulateDosDevicesDirectory * * Populate the new session specific DosDevices Direcotory * * ENTRY: * HANDLE NewDosDevicesDirectory - Session specific DosDevices Directory * PPROCESS_DEVICEMAP_INFORMATION pGlobalProcessDeviceMapInfo * * EXIT: * STATUS_SUCCESS * ******************************************************************************/ NTSTATUS CsrPopulateDosDevicesDirectory( HANDLE NewDirectoryHandle, PPROCESS_DEVICEMAP_INFORMATION pGlobalProcessDeviceMapInfo ) { NTSTATUS Status; UNICODE_STRING UnicodeString; UNICODE_STRING Target; OBJECT_ATTRIBUTES Attributes; HANDLE DirectoryHandle = NULL; HANDLE LinkHandle; POBJECT_DIRECTORY_INFORMATION DirInfo; ULONG DirInfoBufferLength = 16384; //16K PVOID DirInfoBuffer = NULL; WCHAR lpTargetPath[ 4096 ]; ULONG Context; ULONG ReturnedLength = 0; ULONG DosDeviceDriveIndex = 0; WCHAR DosDeviceDriveLetter; // // Open the global DosDevices Directory. This used to populate the // the session specific DosDevices Directory // RtlInitUnicodeString( &UnicodeString, L"\\GLOBAL??" ); InitializeObjectAttributes( &Attributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtOpenDirectoryObject( &DirectoryHandle, DIRECTORY_QUERY, &Attributes ); if (!NT_SUCCESS( Status )) { DbgPrint("CSRSS: NtOpenDirectoryObject failed in CsrPopulateDosDevicesDirectory - status = %lx\n", Status); return Status; } Restart: Context = 0; DirInfoBuffer = RtlAllocateHeap( CsrHeap, MAKE_TAG( PROCESS_TAG ) | HEAP_ZERO_MEMORY, DirInfoBufferLength ); if (DirInfoBuffer == NULL) { Status = STATUS_NO_MEMORY; goto cleanup; } while (TRUE) { DirInfo = (POBJECT_DIRECTORY_INFORMATION)DirInfoBuffer; Status = NtQueryDirectoryObject( DirectoryHandle, (PVOID)DirInfo, DirInfoBufferLength, FALSE, FALSE, &Context, &ReturnedLength ); // // Check the status of the operation. // if (!NT_SUCCESS( Status )) { if (Status == STATUS_BUFFER_TOO_SMALL) { DirInfoBufferLength = ReturnedLength; RtlFreeHeap( CsrHeap, 0, DirInfoBuffer ); goto Restart; } if (Status == STATUS_NO_MORE_ENTRIES) { Status = STATUS_SUCCESS; } break; } while (DirInfo->Name.Length != 0) { if (!wcscmp( DirInfo->TypeName.Buffer, L"SymbolicLink" )) { InitializeObjectAttributes( &Attributes, &DirInfo->Name, OBJ_CASE_INSENSITIVE, DirectoryHandle, NULL ); Status = NtOpenSymbolicLinkObject( &LinkHandle, SYMBOLIC_LINK_QUERY, &Attributes ); if (NT_SUCCESS( Status )) { Target.Buffer = lpTargetPath; Target.Length = 0; Target.MaximumLength = 4096; ReturnedLength = 0; Status = NtQuerySymbolicLinkObject( LinkHandle, &Target, &ReturnedLength ); NtClose( LinkHandle ); if (NT_SUCCESS( Status )) { // // We only want to add Non-DOSDEVICE_DRIVE_REMOTE symbolic // links to the session specific directory // if ((DirInfo->Name.Length == 2 * sizeof( WCHAR )) && (DirInfo->Name.Buffer[ 1 ] == L':')) { DosDeviceDriveLetter = RtlUpcaseUnicodeChar( DirInfo->Name.Buffer[ 0 ] ); if ((DosDeviceDriveLetter >= L'A') && (DosDeviceDriveLetter <= L'Z')) { DosDeviceDriveIndex = DosDeviceDriveLetter - L'A'; if ( ( (pGlobalProcessDeviceMapInfo->Query.DriveType[DosDeviceDriveIndex] == DOSDEVICE_DRIVE_REMOTE) && !( //Need to populate the Netware gateway drive ((Target.Length >= 13) && ((_wcsnicmp(Target.Buffer,L"\\Device\\NwRdr",13)==0))) && ((Target.Length >= 16) && (Target.Buffer[15] != L':')) ) ) || ( (pGlobalProcessDeviceMapInfo->Query.DriveType[DosDeviceDriveIndex] == DOSDEVICE_DRIVE_CALCULATE) && ( ((Target.Length > 4) && (!_wcsnicmp(Target.Buffer,L"\\??\\",4))) || ((Target.Length >= 14) && (!_wcsnicmp(Target.Buffer,L"\\Device\\WinDfs",14))) ) ) ) { //Skip remote drives and virtual drives (subst) DirInfo = (POBJECT_DIRECTORY_INFORMATION)(((PUCHAR) DirInfo) + sizeof(OBJECT_DIRECTORY_INFORMATION)); continue; } } } // // Create the new Symbolic Link // // The security on the new link is inherited // from the parent directory, which is setup // at create time. // InitializeObjectAttributes( &Attributes, &DirInfo->Name, 0, NewDirectoryHandle, NULL // Default security ); Target.MaximumLength = Target.Length + sizeof( WCHAR ); Attributes.Attributes |= OBJ_PERMANENT; Status = NtCreateSymbolicLinkObject( &LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &Attributes, &Target ); Target.MaximumLength = 4096; // Don't close the handles. Cleaned up when CSRSS goes away if (!NT_SUCCESS( Status )) { #if DBG DbgPrint("CSRSS: Symbolic link creation failed in CsrPopulateDosDevicesDirectory for Name %ws and Target %ws- status = %lx for Session %ld\n", DirInfo->Name.Buffer, Target.Buffer, Status,NtCurrentPeb()->SessionId); #endif ASSERT(FALSE); } else { NtClose( LinkHandle ); } } } } DirInfo = (POBJECT_DIRECTORY_INFORMATION)(((PUCHAR) DirInfo) + sizeof(OBJECT_DIRECTORY_INFORMATION)); } } cleanup: if (DirectoryHandle) { NtClose(DirectoryHandle); } if (DirInfoBuffer) { RtlFreeHeap( CsrHeap, 0, DirInfoBuffer ); } return Status; } /******************************************************************************* * * CsrCreateSessionObjectDirectory * * Creates \Sessions\ and \Sessions\\DosDevices * Object Directories * * ENTRY: * ULONG SessionId * * EXIT: * STATUS_SUCCESS * ******************************************************************************/ NTSTATUS CsrCreateSessionObjectDirectory( ULONG SessionId ) { NTSTATUS Status = STATUS_SUCCESS; WCHAR szString[MAX_SESSION_PATH]; WCHAR szTargetString[MAX_SESSION_PATH]; UNICODE_STRING UnicodeString, LinkTarget; OBJECT_ATTRIBUTES Obja; HANDLE SymbolicLinkHandle; SECURITY_DESCRIPTOR DosDevicesSD; /* * \Sessions\BNOLINKS\0 -> \BaseNamedObjects * \Sessions\BNOLINKS\6 -> \Sessions\6\BaseNamedObjects * \Sessions\BNOLINKS\7 -> \Sessions\7\BaseNamedObjects */ // //Create/Open the \\Sessions\BNOLINKS directory // swprintf(szString,L"%ws\\BNOLINKS",SESSION_ROOT); RtlInitUnicodeString( &UnicodeString, szString ); InitializeObjectAttributes( &Obja, &UnicodeString, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, NULL, NULL ); Status = NtCreateDirectoryObject( &BNOLinksDirectory, DIRECTORY_ALL_ACCESS, &Obja ); if (!NT_SUCCESS( Status )) { DbgPrint("CSRSS: NtCreateDirectoryObject failed in CsrCreateSessionObjectDirectory - status = %lx\n", Status); return Status; } // // Create a symbolic link \\Sessions\BNOLINKS\ pointing // to the session specific BaseNamedObjects directory // This symbolic link will be used by proccesses that want to e.g. access a // event in another session. This will be done by using the following // naming convention : Session\\\\ObjectName // swprintf(szString,L"%ld",SessionId); RtlInitUnicodeString( &UnicodeString, szString ); if (SessionId == 0) { RtlInitUnicodeString( &LinkTarget, L"\\BaseNamedObjects" ); } else { swprintf(szTargetString,L"%ws\\%ld\\BaseNamedObjects",SESSION_ROOT,SessionId); RtlInitUnicodeString(&LinkTarget, szTargetString); } InitializeObjectAttributes( &Obja, &UnicodeString, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, (HANDLE)BNOLinksDirectory, NULL); Status = NtCreateSymbolicLinkObject( &SymbolicLinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &Obja, &LinkTarget ); if (!NT_SUCCESS( Status )) { DbgPrint("CSRSS: NtCreateSymbolicLinkObject failed in CsrCreateSessionObjectDirectory - status = %lx\n", Status); return Status; } // // Create the security descriptor to use for the object directories // Status = GetDosDevicesProtection( &DosDevicesSD ); if (!NT_SUCCESS( Status )) { return Status; } // // Create the Sessions\\Type == REG_DWORD && *(PULONG)KeyValueInformation->Data) { ProtectionMode = *(PULONG)KeyValueInformation->Data; } } NtClose( KeyHandle ); } if (ProtectionMode & 0x00000003) { // // If ProtectionMode is set to 1 or 2 Terminal Server // locks down sessions tight. // // Dacl: // Grant: System: All Access (With Inherit) // Grant: Admins: All Access (With Inherit) // Grant: Owner: All Access (Inherit Only) // Grant: World: No Access // aclLength = sizeof( ACL ) + 3 * sizeof( ACCESS_ALLOWED_ACE ) + RtlLengthSid( LocalSystemSid ) + RtlLengthSid( AliasAdminsSid ) + RtlLengthSid( CreatorOwnerSid ); dacl = (PACL)RtlAllocateHeap( CsrHeap, MAKE_TAG( SECURITY_TAG ) | HEAP_ZERO_MEMORY, aclLength ); if (dacl == NULL) { Status = STATUS_NO_MEMORY; ASSERT( NT_SUCCESS( Status ) ); goto cleanup; } Status = RtlCreateAcl( dacl, aclLength, ACL_REVISION2); if (!NT_SUCCESS( Status )) { ASSERT( NT_SUCCESS( Status ) ); goto cleanup; } aceIndex = 0; accessMask = (GENERIC_ALL); Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, LocalSystemSid ); if (!NT_SUCCESS( Status )) { ASSERT( NT_SUCCESS( Status ) ); goto cleanup; } Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace ); if (!NT_SUCCESS( Status )) { ASSERT( NT_SUCCESS( Status ) ); goto cleanup; } ace->AceFlags |= inheritFlags; aceIndex++; accessMask = (GENERIC_ALL); Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, AliasAdminsSid ); if (!NT_SUCCESS( Status )) { ASSERT( NT_SUCCESS( Status ) ); goto cleanup; } Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace ); if (!NT_SUCCESS( Status )) { ASSERT( NT_SUCCESS( Status ) ); goto cleanup; } ace->AceFlags |= inheritFlags; // // Inherit only ACE at the end of the ACL // Owner // aceIndex++; accessMask = (GENERIC_ALL); Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, CreatorOwnerSid ); if (!NT_SUCCESS( Status )) { ASSERT( NT_SUCCESS( Status ) ); goto cleanup; } Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace ); if (!NT_SUCCESS( Status )) { ASSERT( NT_SUCCESS( Status ) ); goto cleanup; } ace->AceFlags |= inheritOnlyFlags; Status = RtlSetDaclSecurityDescriptor( SecurityDescriptor, TRUE, //DaclPresent, dacl, //Dacl FALSE ); //!DaclDefaulted if (!NT_SUCCESS( Status )) { ASSERT( NT_SUCCESS( Status ) ); goto cleanup; } } else { // // DACL: // Grant: World: Execute | Read | Write (No Inherit) // Grant: System: All Access (No Inherit) // Grant: World: All Access (Inherit Only) // aclLength = sizeof( ACL ) + 3 * sizeof( ACCESS_ALLOWED_ACE ) + (2*RtlLengthSid( WorldSid )) + RtlLengthSid( LocalSystemSid ); dacl = (PACL)RtlAllocateHeap( CsrHeap, MAKE_TAG( SECURITY_TAG ) | HEAP_ZERO_MEMORY, aclLength ); if (dacl == NULL) { ASSERT( NT_SUCCESS( Status ) ); Status = STATUS_NO_MEMORY; goto cleanup; } Status = RtlCreateAcl( dacl, aclLength, ACL_REVISION2); if (!NT_SUCCESS( Status )) { ASSERT( NT_SUCCESS( Status ) ); goto cleanup; } // // Non-inheritable ACEs first // World // System // aceIndex = 0; accessMask = (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE); Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, WorldSid ); if (!NT_SUCCESS( Status )) { ASSERT( NT_SUCCESS( Status ) ); goto cleanup; } aceIndex++; accessMask = (GENERIC_ALL); Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, LocalSystemSid ); if (!NT_SUCCESS( Status )) { ASSERT( NT_SUCCESS( Status ) ); goto cleanup; } // // Inheritable ACEs at the end of the ACL // World // aceIndex++; accessMask = (GENERIC_ALL); Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, WorldSid ); if (!NT_SUCCESS( Status )) { ASSERT( NT_SUCCESS( Status ) ); goto cleanup; } Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace ); if (!NT_SUCCESS( Status )) { ASSERT( NT_SUCCESS( Status ) ); goto cleanup; } ace->AceFlags |= inheritOnlyFlags; Status = RtlSetDaclSecurityDescriptor( SecurityDescriptor, TRUE, //DaclPresent, dacl, //Dacl FALSE ); //!DaclDefaulted if (!NT_SUCCESS( Status )) { ASSERT( NT_SUCCESS( Status ) ); goto cleanup; } } cleanup: if (!NT_SUCCESS( Status ) && (dacl != NULL)) { RtlFreeHeap( CsrHeap, 0, dacl); } RtlFreeSid( LocalSystemSid ); RtlFreeSid( WorldSid ); RtlFreeSid( AliasAdminsSid ); RtlFreeSid( CreatorOwnerSid ); if (!NT_SUCCESS( Status )) { DbgPrint("CSRSS: GetDosDevicesProtection failed - status = %lx\n", Status); ASSERT( NT_SUCCESS( Status ) ); } return Status; } VOID FreeDosDevicesProtection ( PSECURITY_DESCRIPTOR SecurityDescriptor ) /*++ Routine Description: This routine frees memory allocated via GetDosDevicesProtection(). Arguments: SecurityDescriptor - The address of a security descriptor initialized by GetDosDevicesProtection(). Return Value: None. --*/ { NTSTATUS Status; PACL Dacl = NULL; BOOLEAN DaclPresent, Defaulted; Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor, &DaclPresent, &Dacl, &Defaulted); ASSERT(NT_SUCCESS(Status)); ASSERT(DaclPresent); ASSERT(Dacl != NULL); if (NT_SUCCESS(Status) && Dacl != NULL) { RtlFreeHeap(CsrHeap, 0, Dacl); } }