diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/csr | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/csr')
26 files changed, 7161 insertions, 0 deletions
diff --git a/private/csr/dirs b/private/csr/dirs new file mode 100644 index 000000000..ed20d8c56 --- /dev/null +++ b/private/csr/dirs @@ -0,0 +1,25 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dirs. + +Abstract: + + This file specifies the subdirectories of the current directory that + contain component makefiles. + + +Author: + + Steve Wood (stevewo) 17-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl + +!ENDIF + +DIRS=server + +OPTIONAL_DIRS= diff --git a/private/csr/inc/csr.h b/private/csr/inc/csr.h new file mode 100644 index 000000000..fe844e02a --- /dev/null +++ b/private/csr/inc/csr.h @@ -0,0 +1,66 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + csr.h + +Abstract: + + Include file that defines all the common data types and constants for + the Client-Server Runtime (CSR) SubSystem + +Author: + + Steve Wood (stevewo) 8-Oct-1990 + +Revision History: + +--*/ + + +// +// Include NT Definitions. +// + +#include "nt.h" +#include "ntrtl.h" +#include "nturtl.h" +#include "string.h" + +#define GetModuleHandle GetModuleHandleA + +// +// Define debugging flag as false if not defined already. +// + +#ifndef DBG +#define DBG 0 +#endif + + +// +// Define IF_DEBUG macro that can be used to enable debugging code that is +// optimized out if the debugging flag is false. +// + +#if DBG +#define IF_DEBUG if (TRUE) +#else +#define IF_DEBUG if (FALSE) +#endif + +// +// Common types and constant definitions +// + +typedef enum _CSRP_API_NUMBER { + CsrpNullApiCall = 0, // CSRSRV_FIRST_API_NUMBER defined in ntcsrmsg.h + CsrpClientConnect, + CsrpThreadConnect, + CsrpProfileControl, + CsrpIdentifyAlertable, + CsrpSetPriorityClass, + CsrpMaxApiNumber +} CSRP_API_NUMBER, *PCSRP_API_NUMBER; diff --git a/private/csr/server/alpha/evpair.s b/private/csr/server/alpha/evpair.s new file mode 100644 index 000000000..a8e7fcd63 --- /dev/null +++ b/private/csr/server/alpha/evpair.s @@ -0,0 +1,63 @@ +// TITLE("Fast Event Pair Support") +//++ +// +// Copyright (c) 1992 Microsoft Corporation +// Copyright (c) 1993 Digital Equipement Corporation +// +// Module Name: +// +// evpair.s +// +// Abstract: +// +// This module contains the system call interface for the fast event pair +// system service that is used from the server side. +// +// Author: +// +// David N. Cutler (davec) 29-Oct-1992 +// Joe Notarangelo 20-Feb-1993 +// +// Environment: +// +// Kernel mode. +// +// Revision History: +// +//-- + +#include "ksalpha.h" + + SBTTL("Set High Wait Low Thread") +//++ +// +// NTSTATUS +// XySetHighWaitLowThread ( +// ) +// +// Routine Description: +// +// This function calls the fast evnet pair system service. +// +// N.B. The return from this routine is directly to the caller. +// +// Arguments: +// +// None. +// +// Return Value: +// +// STATUS_NO_EVENT_PAIR is returned if no event pair is associated with +// the current thread. Otherwise, the status of the wait operation is +// returned as the function value. +// +// +//-- + + LEAF_ENTRY(XySetHighWaitLowThread) + + ldil v0, SET_HIGH_WAIT_LOW // set system service number + SYSCALL // call system service + + .end XySetHighWaitLowThread + diff --git a/private/csr/server/alpha/sources b/private/csr/server/alpha/sources new file mode 100644 index 000000000..a04f9d731 --- /dev/null +++ b/private/csr/server/alpha/sources @@ -0,0 +1,3 @@ +ALPHA_LNKFLAGS=-stack:98304,8192 + +ALPHA_SOURCES=alpha\evpair.s diff --git a/private/csr/server/apiinit.c b/private/csr/server/apiinit.c new file mode 100644 index 000000000..6e539dbd5 --- /dev/null +++ b/private/csr/server/apiinit.c @@ -0,0 +1,174 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + apiinit.c + +Abstract: + + This module contains the code to initialize the ApiPort of the + Server side of the Client-Server Runtime Subsystem to the Session + Manager SubSystem. + +Author: + + Steve Wood (stevewo) 8-Oct-1990 + +Environment: + + User Mode Only + +Revision History: + +--*/ + +#include "csrsrv.h" + +static SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY; + +NTSTATUS +CsrApiPortInitialize( VOID ) +{ + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + ULONG i; + HANDLE Thread; + CLIENT_ID ClientId; + PLIST_ENTRY ListHead, ListNext; + PCSR_THREAD ServerThread; + HANDLE EventHandle; + ULONG Length; + PSID SeWorldSid; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PACL Dacl; + + Length = CsrDirectoryName.Length + + sizeof( CSR_API_PORT_NAME ) + + sizeof( OBJ_NAME_PATH_SEPARATOR ); + CsrApiPortName.Buffer = RtlAllocateHeap( CsrHeap, MAKE_TAG( INIT_TAG ), Length ); + if (CsrApiPortName.Buffer == NULL) { + return( STATUS_NO_MEMORY ); + } + CsrApiPortName.Length = 0; + CsrApiPortName.MaximumLength = (USHORT)Length; + RtlAppendUnicodeStringToString( &CsrApiPortName, &CsrDirectoryName ); + RtlAppendUnicodeToString( &CsrApiPortName, L"\\" ); + RtlAppendUnicodeToString( &CsrApiPortName, CSR_API_PORT_NAME ); + + IF_CSR_DEBUG( INIT ) { + DbgPrint( "CSRSS: Creating %wZ port and associated threads\n", + &CsrApiPortName ); + DbgPrint( "CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n", + sizeof( CSR_API_CONNECTINFO ), + sizeof( CSR_API_MSG ) + ); + } + + // + // create a security descriptor that allows all access + // + + SeWorldSid = RtlAllocateHeap( CsrHeap, MAKE_TAG( TMP_TAG ), RtlLengthRequiredSid( 1 ) ); + RtlInitializeSid( SeWorldSid, &WorldSidAuthority, 1 ); + *(RtlSubAuthoritySid( SeWorldSid, 0 )) = SECURITY_WORLD_RID; + + Length = SECURITY_DESCRIPTOR_MIN_LENGTH + + (ULONG)sizeof(ACL) + + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid( SeWorldSid ) + + 8; // The 8 is just for good measure + SecurityDescriptor = RtlAllocateHeap( CsrHeap, MAKE_TAG( TMP_TAG ), Length); + ASSERT( SecurityDescriptor != NULL ); + + Dacl = (PACL)((PCHAR)SecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); + + RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); + RtlCreateAcl( Dacl, Length - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION2); + + RtlAddAccessAllowedAce ( + Dacl, + ACL_REVISION2, + PORT_ALL_ACCESS, + SeWorldSid + ); + RtlSetDaclSecurityDescriptor ( + SecurityDescriptor, + TRUE, + Dacl, + FALSE + ); + + InitializeObjectAttributes( &ObjectAttributes, &CsrApiPortName, 0, + NULL, SecurityDescriptor ); + Status = NtCreatePort( &CsrApiPort, + &ObjectAttributes, + sizeof( CSR_API_CONNECTINFO ), + sizeof( CSR_API_MSG ), + 4096 * 16 + ); + ASSERT( NT_SUCCESS( Status ) ); + + // + // clean up security stuff + // + + RtlFreeHeap( CsrHeap, 0, SeWorldSid ); + RtlFreeHeap( CsrHeap, 0, SecurityDescriptor ); + + // + // use same port for exception handling. + // + + CsrExceptionPort = CsrApiPort; + + Status = NtCreateEvent(&EventHandle, + EVENT_ALL_ACCESS, + NULL, + SynchronizationEvent, + FALSE + ); + ASSERT( NT_SUCCESS( Status ) ); + + // + // Create the inital request thread + // + + Status = RtlCreateUserThread( NtCurrentProcess(), + NULL, + TRUE, + 0, + 0, + 0, + CsrApiRequestThread, + (PVOID)EventHandle, + &Thread, + &ClientId + ); + ASSERT( NT_SUCCESS( Status ) ); + CsrAddStaticServerThread(Thread,&ClientId,CSR_STATIC_API_THREAD); + + ListHead = &CsrRootProcess->ThreadList; + ListNext = ListHead->Flink; + while (ListNext != ListHead) { + ServerThread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link ); + Status = NtResumeThread( ServerThread->ThreadHandle, NULL ); + if (ServerThread->Flags & CSR_STATIC_API_THREAD) { + Status = NtWaitForSingleObject(EventHandle,FALSE,NULL); + ASSERT( NT_SUCCESS( Status ) ); + } + ListNext = ListNext->Flink; + } + NtClose(EventHandle); + + + return( Status ); +} + +HANDLE +CsrQueryApiPort(VOID) +{ + return CsrApiPort; +} + diff --git a/private/csr/server/apilistn.c b/private/csr/server/apilistn.c new file mode 100644 index 000000000..4e817b5b6 --- /dev/null +++ b/private/csr/server/apilistn.c @@ -0,0 +1,65 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + apilistn.c + +Abstract: + + This module contains the Listen thread procedure for the Server side + of the Client-Server Runtime Subsystem. + +Author: + + Steve Wood (stevewo) 8-Oct-1990 + +Revision History: + +--*/ + +#include "csrsrv.h" + +NTSTATUS +CsrApiListenThread( + IN PVOID Parameter + ) +{ + NTSTATUS Status; + CONNECTION_REQUEST ConnectionRequest; + CSR_API_CONNECTINFO ConnectionInformation; + ULONG ConnectionInformationLength; + + while (TRUE) { + IF_CSR_DEBUG( LPC ) { + DbgPrint( "CSRSS: Listening for connections to ApiPort\n" ); + } + + ConnectionInformationLength = sizeof( ConnectionInformation ); + ConnectionRequest.Length = sizeof( ConnectionRequest ); + Status = NtListenPort( CsrApiPort, + &ConnectionRequest, + (PVOID)&ConnectionInformation, + &ConnectionInformationLength + ); + if (!NT_SUCCESS( Status )) { + IF_DEBUG { + DbgPrint( "CSRSS: Listen failed - Status == %X\n", + Status + ); + } + break; + } + + } + + // + // Explicitly terminate this thread if we fail in the listen loop. + // + + NtTerminateThread( NtCurrentThread(), Status ); + + return( Status ); // Remove no return value warning. + Parameter; // Remove unreferenced parameter warning. +} diff --git a/private/csr/server/apireqst.c b/private/csr/server/apireqst.c new file mode 100644 index 000000000..fdfcb51b3 --- /dev/null +++ b/private/csr/server/apireqst.c @@ -0,0 +1,1077 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + apireqst.c + +Abstract: + + This module contains the Request thread procedure for the Server side + of the Client-Server Runtime Subsystem. + +Author: + + Steve Wood (stevewo) 8-Oct-1990 + +Revision History: + +--*/ + +#include "csrsrv.h" + +NTSTATUS +CsrApiHandleConnectionRequest( + IN PCSR_API_MSG Message + ); + +EXCEPTION_DISPOSITION +CsrUnhandledExceptionFilter( + struct _EXCEPTION_POINTERS *ExceptionInfo + ); + +ULONG CsrpDynamicThreadTotal; +ULONG CsrpStaticThreadCount; + +PCSR_THREAD CsrConnectToUser( VOID ) +{ + static BOOLEAN (*ClientThreadSetupRoutine)(VOID) = NULL; + NTSTATUS Status; + ANSI_STRING DllName; + UNICODE_STRING DllName_U; + STRING ProcedureName; + HANDLE UserClientModuleHandle; + PTEB Teb; + PCSR_THREAD Thread; + BOOLEAN fConnected; + + if (ClientThreadSetupRoutine == NULL) { + RtlInitAnsiString(&DllName, "user32"); + Status = RtlAnsiStringToUnicodeString(&DllName_U, &DllName, TRUE); + ASSERT(NT_SUCCESS(Status)); + Status = LdrGetDllHandle( + UNICODE_NULL, + NULL, + &DllName_U, + (PVOID *)&UserClientModuleHandle + ); + + RtlFreeUnicodeString(&DllName_U); + + if ( NT_SUCCESS(Status) ) { + RtlInitString(&ProcedureName,"ClientThreadSetup"); + Status = LdrGetProcedureAddress( + UserClientModuleHandle, + &ProcedureName, + 0L, + (PVOID *)&ClientThreadSetupRoutine + ); + ASSERT(NT_SUCCESS(Status)); + } + } + + try { + fConnected = ClientThreadSetupRoutine(); + } except (EXCEPTION_EXECUTE_HANDLER) { + fConnected = FALSE; + } + if (!fConnected) { + IF_DEBUG { + DbgPrint("CSRSS: CsrConnectToUser failed\n"); + } + return NULL; + } + + /* + * Set up CSR_THREAD pointer in the TEB + */ + Teb = NtCurrentTeb(); + Thread = CsrLocateThreadInProcess(NULL, &Teb->ClientId); + if (Thread) + Teb->CsrClientThread = Thread; + + return Thread; +} + +NTSTATUS +CsrpCheckRequestThreads(VOID) +{ + // + // See if we need to create a new thread for api requests. + // + // Don't create a thread if we're in the middle of debugger + // initialization, which would cause the thread to be + // lost to the debugger. + // + // If we are not a dynamic api request thread, then decrement + // the static thread count. If it underflows, then create a temporary + // request thread + // + + if ( !--CsrpStaticThreadCount && !CsrpServerDebugInitialize ) { + + if ( CsrpDynamicThreadTotal < CsrMaxApiRequestThreads ) { + + HANDLE QuickThread; + CLIENT_ID ClientId; + NTSTATUS CreateStatus; + + // + // If we are ready to create quick threads, then create one + // + + CreateStatus = RtlCreateUserThread( + NtCurrentProcess(), + NULL, + TRUE, + 0, + 0, + 0, + CsrApiRequestThread, + NULL, + &QuickThread, + &ClientId + ); + + if ( NT_SUCCESS(CreateStatus) ) { + CsrpStaticThreadCount++; + CsrpDynamicThreadTotal++; + if ( CsrAddStaticServerThread(QuickThread,&ClientId,CSR_STATIC_API_THREAD) ) { + NtResumeThread(QuickThread,NULL); + } + else { + CsrpStaticThreadCount--; + CsrpDynamicThreadTotal--; + NtTerminateThread(QuickThread,0); + NtClose(QuickThread); + return STATUS_UNSUCCESSFUL; + } + } + } + } + + return STATUS_SUCCESS; +} +NTSTATUS +CsrApiRequestThread( + IN PVOID Parameter + ) +{ + NTSTATUS Status; + PCSR_PROCESS Process; + PCSR_THREAD Thread; + PCSR_THREAD MyThread; + CSR_API_MSG ReceiveMsg; + PCSR_API_MSG ReplyMsg; + HANDLE ReplyPortHandle; + PCSR_SERVER_DLL LoadedServerDll; + PTEB Teb; + ULONG ServerDllIndex; + ULONG ApiTableIndex; + CSR_REPLY_STATUS ReplyStatus; + ULONG i; + PVOID PortContext; + USHORT MessageType; + ULONG ApiNumber; + PLPC_CLIENT_DIED_MSG CdMsg; + + Teb = NtCurrentTeb(); + ReplyMsg = NULL; + ReplyPortHandle = CsrApiPort; + +// Initialize GDI accelerators. It's really pretty hokey that these are +// done here, but there's no DLL init called for these threads! +// (Also see SRVQUICK.C.) + + Teb->GdiClientPID = PID_SERVERLPC; + Teb->GdiClientTID = (ULONG) Teb->ClientId.UniqueThread; + + // + // Try to connect to USER. + // + + while (!CsrConnectToUser()) { + LARGE_INTEGER TimeOut; + + // + // The connect failed. The best thing to do is sleep for + // 30 seconds and retry the connect. Clear the + // initialized bit in the TEB so the retry can + // succeed. + // + + Teb->Win32ClientInfo[0] = 0; + TimeOut.QuadPart = Int32x32To64(30000, -10000); + NtDelayExecution(FALSE, &TimeOut); + } + MyThread = Teb->CsrClientThread; + + if ( Parameter ) { + Status = NtSetEvent((HANDLE)Parameter,NULL); + ASSERT( NT_SUCCESS( Status ) ); + CsrpStaticThreadCount++; + CsrpDynamicThreadTotal++; + } + + while (TRUE) { + NtCurrentTeb()->RealClientId = NtCurrentTeb()->ClientId; +#if DBG + if ( NtCurrentTeb()->CountOfOwnedCriticalSections != 0 ) { + DbgPrint("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n", + NtCurrentTeb()->CountOfOwnedCriticalSections + ); + DbgPrint("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",&ReceiveMsg,ReplyMsg); + DbgBreakPoint(); + } + +#endif // DBG + + Status = NtReplyWaitReceivePort( ReplyPortHandle, + &PortContext, + (PPORT_MESSAGE)ReplyMsg, + (PPORT_MESSAGE)&ReceiveMsg + ); + if (Status != 0) { + if (NT_SUCCESS( Status )) { + continue; // Try again if alerted or a failure + } + + IF_DEBUG { + if (Status == STATUS_INVALID_CID || + Status == STATUS_UNSUCCESSFUL || + (Status == STATUS_INVALID_HANDLE && + ReplyPortHandle != CsrApiPort + ) + ) { + } + else { + DbgPrint( "CSRSS: ReceivePort failed - Status == %X\n", Status ); + DbgPrint( "CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPortHandle, CsrApiPort ); + } + } + + // + // Ignore if client went away. + // + + ReplyMsg = NULL; + ReplyPortHandle = CsrApiPort; + continue; + } + + NtCurrentTeb()->RealClientId = ReceiveMsg.h.ClientId; + MessageType = ReceiveMsg.h.u2.s2.Type; + + // + // Check to see if this is a connection request and handle + // + + if (MessageType == LPC_CONNECTION_REQUEST) { + CsrApiHandleConnectionRequest( &ReceiveMsg ); + ReplyPortHandle = CsrApiPort; + ReplyMsg = NULL; + continue; + } + + // + // Check to see if this is a debug message and handle + // + + if ( MessageType == LPC_DEBUG_EVENT ) { + DbgSsHandleKmApiMsg((PDBGKM_APIMSG)&ReceiveMsg,NULL); + ReplyPortHandle = CsrApiPort; + ReplyMsg = NULL; + continue; + } + + + // + // We must acquire the process structure lock before we look up + // the API thread. + // + + AcquireProcessStructureLock(); + + // + // Lookup the client thread structure using the client id + // + + Thread = CsrLocateThreadByClientId( &Process, + &ReceiveMsg.h.ClientId + ); + + if (!Thread) { + ReleaseProcessStructureLock(); + if ( MessageType == LPC_EXCEPTION ) { + ReplyMsg = &ReceiveMsg; + ReplyPortHandle = CsrApiPort; + ReplyMsg->ReturnValue = DBG_CONTINUE; + } + else + if ( MessageType == LPC_CLIENT_DIED || + MessageType == LPC_PORT_CLOSED + ) { + ReplyPortHandle = CsrApiPort; + ReplyMsg = NULL; + } + else { + + // + // This must be a non-csr thread calling us. Tell it + // to get lost. (unless this is a hard error) + // + + if (MessageType == LPC_ERROR_EVENT) { + PHARDERROR_MSG m; + + m = (PHARDERROR_MSG)&ReceiveMsg; + m->Response = (ULONG)ResponseNotHandled; + + // + // Only call the handler if there are other + // request threads available to handle + // message processing. + // + + if (NT_SUCCESS(CsrpCheckRequestThreads())) { + for (i=0; i<CSR_MAX_SERVER_DLL; i++) { + LoadedServerDll = CsrLoadedServerDll[ i ]; + if (LoadedServerDll && LoadedServerDll->HardErrorRoutine) { + + (*LoadedServerDll->HardErrorRoutine)( Thread, + m ); + if (m->Response != (ULONG)ResponseNotHandled) + break; + } + } + ++CsrpStaticThreadCount; + } + + if (m->Response == (ULONG)-1) { + + // + // Hard error handler will directly reply to the client + // + + ReplyPortHandle = CsrApiPort; + ReplyMsg = NULL; + } + else { + ReplyPortHandle = CsrApiPort; + ReplyMsg = &ReceiveMsg; + } + + } + else { + ReplyPortHandle = CsrApiPort; + if ( MessageType == LPC_REQUEST ) { + ReplyMsg = &ReceiveMsg; + ReplyMsg->ReturnValue = (ULONG)STATUS_ILLEGAL_FUNCTION; + } + else if (MessageType == LPC_DATAGRAM) { + // + // If this is a datagram, make the api call + // + + ApiNumber = ReceiveMsg.ApiNumber; + ServerDllIndex = + CSR_APINUMBER_TO_SERVERDLLINDEX( ApiNumber ); + if (ServerDllIndex >= CSR_MAX_SERVER_DLL || + (LoadedServerDll = CsrLoadedServerDll[ ServerDllIndex ]) == NULL + ) { + IF_DEBUG { + DbgPrint( "CSRSS: %lx is invalid ServerDllIndex (%08x)\n", + ServerDllIndex, LoadedServerDll + ); + DbgBreakPoint(); + } + + ReplyPortHandle = CsrApiPort; + ReplyMsg = NULL; + continue; + } + else { + ApiTableIndex = + CSR_APINUMBER_TO_APITABLEINDEX( ApiNumber ) - + LoadedServerDll->ApiNumberBase; + if (ApiTableIndex >= LoadedServerDll->MaxApiNumber ) { + IF_DEBUG { + DbgPrint( "CSRSS: %lx is invalid ApiTableIndex for %Z\n", + LoadedServerDll->ApiNumberBase + ApiTableIndex, + &LoadedServerDll->ModuleName + ); + } + + ReplyPortHandle = CsrApiPort; + ReplyMsg = NULL; + continue; + } + } + +#if DBG + IF_CSR_DEBUG( LPC ) { + DbgPrint( "[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n", + NtCurrentTeb()->ClientId.UniqueThread, + ReceiveMsg.h.ClientId.UniqueProcess, + ReceiveMsg.h.ClientId.UniqueThread, + LoadedServerDll->ApiNameTable[ ApiTableIndex ], + Thread + ); + } +#endif // DBG + + ReceiveMsg.ReturnValue = (ULONG)STATUS_SUCCESS; + + try { + + CsrpCheckRequestThreads(); + + ReplyPortHandle = CsrApiPort; + ReplyMsg = NULL; + + (*(LoadedServerDll->ApiDispatchTable[ ApiTableIndex ]))( + &ReceiveMsg, + &ReplyStatus + ); + ++CsrpStaticThreadCount; + } + except ( CsrUnhandledExceptionFilter( GetExceptionInformation() ) ){ + ReplyPortHandle = CsrApiPort; + ReplyMsg = NULL; + } + } + else { + ReplyMsg = NULL; + } + } + } + continue; + } + + // + // See if this is a client died message. If so, + // callout and then teardown thread/process structures. + // this is how ExitThread is seen by CSR. + // + // LPC_CLIENT_DIED is caused by ExitProcess. ExitProcess + // calls TerminateProcess, which terminates all of the process's + // threads except the caller. this termination generates + // LPC_CLIENT_DIED. + // + + ReplyPortHandle = CsrApiPort; + + if (MessageType != LPC_REQUEST) { + + if (MessageType == LPC_CLIENT_DIED) { + + CdMsg = (PLPC_CLIENT_DIED_MSG)&ReceiveMsg; + if (CdMsg->CreateTime.QuadPart == Thread->CreateTime.QuadPart) { + ReplyPortHandle = Thread->Process->ClientPort; + + CsrLockedReferenceThread(Thread); + Status = CsrDestroyThread( &ReceiveMsg.h.ClientId ); + + // + // if this thread is it, then we also need to dereference + // the process since it will not be going through the + // normal destroy process path. + // + + if ( Process->ThreadCount == 1 ) { + CsrDestroyProcess(&Thread->ClientId,0); + } + CsrLockedDereferenceThread(Thread); + } + ReleaseProcessStructureLock(); + ReplyPortHandle = CsrApiPort; + ReplyMsg = NULL; + continue; + } + + CsrLockedReferenceThread(Thread); + ReleaseProcessStructureLock(); + + // + // if this is an exception message, terminate the process + // + + if (MessageType == LPC_EXCEPTION) { + PDBGKM_APIMSG m; + + NtTerminateProcess(Process->ProcessHandle,STATUS_ABANDONED); + Status = CsrDestroyProcess( &ReceiveMsg.h.ClientId,STATUS_ABANDONED ); + m = (PDBGKM_APIMSG)&ReceiveMsg; + m->ReturnedStatus = DBG_CONTINUE; + ReplyPortHandle = CsrApiPort; + ReplyMsg = &ReceiveMsg; + CsrDereferenceThread(Thread); + continue; + } + + // + // If this is a hard error message, return return to caller + // + + if (MessageType == LPC_ERROR_EVENT) { + PHARDERROR_MSG m; + + m = (PHARDERROR_MSG)&ReceiveMsg; + m->Response = (ULONG)ResponseNotHandled; + + // + // Only call the handler if there are other + // request threads available to handle + // message processing. + // + + if (NT_SUCCESS(CsrpCheckRequestThreads())) { + for (i=0; i<CSR_MAX_SERVER_DLL; i++) { + LoadedServerDll = CsrLoadedServerDll[ i ]; + if (LoadedServerDll && LoadedServerDll->HardErrorRoutine) { + + (*LoadedServerDll->HardErrorRoutine)( Thread, + m ); + if (m->Response != (ULONG)ResponseNotHandled) { + break; + } + } + } + ++CsrpStaticThreadCount; + } + + if (m->Response == (ULONG)-1) { + + // + // Hard error handler will directly reply to the client + // + + ReplyPortHandle = CsrApiPort; + ReplyMsg = NULL; + } + else { + CsrDereferenceThread(Thread); + ReplyPortHandle = CsrApiPort; + ReplyMsg = &ReceiveMsg; + } + continue; + } + + CsrDereferenceThread(Thread); + ReplyPortHandle = CsrApiPort; + ReplyMsg = NULL; + continue; + } + + CsrLockedReferenceThread(Thread); + ReleaseProcessStructureLock(); + + ApiNumber = ReceiveMsg.ApiNumber; + ServerDllIndex = + CSR_APINUMBER_TO_SERVERDLLINDEX( ApiNumber ); + if (ServerDllIndex >= CSR_MAX_SERVER_DLL || + (LoadedServerDll = CsrLoadedServerDll[ ServerDllIndex ]) == NULL + ) { + IF_DEBUG { + DbgPrint( "CSRSS: %lx is invalid ServerDllIndex (%08x)\n", + ServerDllIndex, LoadedServerDll + ); + DbgBreakPoint(); + } + + ReplyMsg = &ReceiveMsg; + ReplyPortHandle = CsrApiPort; + ReplyMsg->ReturnValue = (ULONG)STATUS_ILLEGAL_FUNCTION; + CsrDereferenceThread(Thread); + continue; + } + else { + ApiTableIndex = + CSR_APINUMBER_TO_APITABLEINDEX( ApiNumber ) - + LoadedServerDll->ApiNumberBase; + if (ApiTableIndex >= LoadedServerDll->MaxApiNumber ) { + IF_DEBUG { + DbgPrint( "CSRSS: %lx is invalid ApiTableIndex for %Z\n", + LoadedServerDll->ApiNumberBase + ApiTableIndex, + &LoadedServerDll->ModuleName + ); + DbgBreakPoint(); + } + + ReplyMsg = &ReceiveMsg; + ReplyPortHandle = CsrApiPort; + ReplyMsg->ReturnValue = (ULONG)STATUS_ILLEGAL_FUNCTION; + CsrDereferenceThread(Thread); + continue; + } + } + +#if 0//DBG + IF_CSR_DEBUG( LPC ) { + DbgPrint( "[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n", + NtCurrentTeb()->ClientId.UniqueThread, + ReceiveMsg.h.ClientId.UniqueProcess, + ReceiveMsg.h.ClientId.UniqueThread, + LoadedServerDll->ApiNameTable[ ApiTableIndex ], + Thread + ); + } +#endif // DBG + + ReceiveMsg.ReturnValue = (ULONG)STATUS_SUCCESS; + if (ReceiveMsg.CaptureBuffer != NULL) { + if (!CsrCaptureArguments( Thread, &ReceiveMsg )) { + ReplyPortHandle = Thread->Process->ClientPort; + CsrDereferenceThread(Thread); + goto failit; + } + } + + try { + + CsrpCheckRequestThreads(); + + Teb->CsrClientThread = (PVOID)Thread; + + ReplyMsg = &ReceiveMsg; + ReplyPortHandle = Thread->Process->ClientPort; + + ReplyStatus = CsrReplyImmediate; + ReplyMsg->ReturnValue = + (*(LoadedServerDll->ApiDispatchTable[ ApiTableIndex ]))( + &ReceiveMsg, + &ReplyStatus + ); + ++CsrpStaticThreadCount; + + Teb->CsrClientThread = (PVOID)MyThread; + + if (ReplyStatus == CsrReplyImmediate) { + // + // free captured arguments if a capture buffer was allocated + // AND we're replying to the message now (no wait block has + // been created). + // + + if (ReplyMsg && ReceiveMsg.CaptureBuffer != NULL) { + CsrReleaseCapturedArguments( &ReceiveMsg ); + } + CsrDereferenceThread(Thread); + } + else if (ReplyStatus == CsrClientDied) { + NtReplyPort( ReplyPortHandle, + (PPORT_MESSAGE)ReplyMsg + ); + ReplyPortHandle = CsrApiPort; + ReplyMsg = NULL; + CsrDereferenceThread(Thread); + } + else if (ReplyStatus == CsrReplyPending) { + ReplyPortHandle = CsrApiPort; + ReplyMsg = NULL; + } + else { + if (ReplyMsg && ReceiveMsg.CaptureBuffer != NULL) { + CsrReleaseCapturedArguments( &ReceiveMsg ); + } + CsrDereferenceThread(Thread); + } + + } + except ( CsrUnhandledExceptionFilter( GetExceptionInformation() ) ){ + ReplyPortHandle = CsrApiPort; + ReplyMsg = NULL; + } +failit: + ; + } + + NtTerminateThread( NtCurrentThread(), Status ); + return( Status ); +} + +NTSTATUS +CsrCallServerFromServer( + PCSR_API_MSG ReceiveMsg, + PCSR_API_MSG ReplyMsg + ) + +/*++ + +Routine Description: + + This function dispatches an API call the same way CsrApiRequestThread + does, but it does it as a direct call, not an LPC connect. It is used + by the csr dll when the server is calling a dll function. We don't + worry about process serialization here because none of the process APIs + can be called from the server. + +Arguments: + + ReceiveMessage - Pointer to the API request message received. + + ReplyMessage - Pointer to the API request message to return. + +Return Value: + + Status Code + +--*/ + +{ + + ULONG ServerDllIndex; + ULONG ApiTableIndex; + PCSR_SERVER_DLL LoadedServerDll; + PTEB Teb; + CSR_REPLY_STATUS ReplyStatus; + + Teb = NtCurrentTeb(); + ServerDllIndex = + CSR_APINUMBER_TO_SERVERDLLINDEX( ReceiveMsg->ApiNumber ); + if (ServerDllIndex >= CSR_MAX_SERVER_DLL || + (LoadedServerDll = CsrLoadedServerDll[ ServerDllIndex ]) == NULL + ) { + IF_DEBUG { + DbgPrint( "CSRSS: %lx is invalid ServerDllIndex (%08x)\n", + ServerDllIndex, LoadedServerDll + ); + // DbgBreakPoint(); + } + + ReplyMsg->ReturnValue = (ULONG)STATUS_ILLEGAL_FUNCTION; + return STATUS_ILLEGAL_FUNCTION; + } + else { + ApiTableIndex = + CSR_APINUMBER_TO_APITABLEINDEX( ReceiveMsg->ApiNumber ) - + LoadedServerDll->ApiNumberBase; + if (ApiTableIndex >= LoadedServerDll->MaxApiNumber || + (LoadedServerDll->ApiServerValidTable && + !LoadedServerDll->ApiServerValidTable[ ApiTableIndex ])) { + IF_DEBUG { + DbgPrint( "CSRSS: %lx (%s) is invalid ApiTableIndex for %Z or is an invalid API to call from the server.\n", + LoadedServerDll->ApiNumberBase + ApiTableIndex, + (LoadedServerDll->ApiNameTable && + LoadedServerDll->ApiNameTable[ ApiTableIndex ] + ) ? LoadedServerDll->ApiNameTable[ ApiTableIndex ] + : "*** UNKNOWN ***", + &LoadedServerDll->ModuleName + ); + DbgBreakPoint(); + } + + ReplyMsg->ReturnValue = (ULONG)STATUS_ILLEGAL_FUNCTION; + return STATUS_ILLEGAL_FUNCTION; + } + } + +#if 0//DBG + IF_CSR_DEBUG( LPC ) { + DbgPrint( "CSRSS: %s Api Request received from server process\n", + LoadedServerDll->ApiNameTable[ ApiTableIndex ] + ); + } +#endif // DBG + try { + ReplyMsg->ReturnValue = + (*(LoadedServerDll->ApiDispatchTable[ ApiTableIndex ]))( + ReceiveMsg, + &ReplyStatus + ); + } except( EXCEPTION_EXECUTE_HANDLER ) { + ReplyMsg->ReturnValue = (ULONG)STATUS_ACCESS_VIOLATION; + } + + return STATUS_SUCCESS; +} + +BOOLEAN +CsrCaptureArguments( + IN PCSR_THREAD t, + IN PCSR_API_MSG m + ) +{ + PCSR_CAPTURE_HEADER ClientCaptureBuffer; + PCSR_CAPTURE_HEADER ServerCaptureBuffer; + PULONG PointerOffsets; + ULONG PointerDelta, Length, CountPointers, Pointer; + + try { + ClientCaptureBuffer = m->CaptureBuffer; + Length = ClientCaptureBuffer->Length; + if ((PCH)ClientCaptureBuffer < t->Process->ClientViewBase || + ((PCH)ClientCaptureBuffer + Length) >= t->Process->ClientViewBounds + ) { + IF_DEBUG { + DbgPrint( "*** CSRSS: CaptureBuffer outside of ClientView\n" ); + DbgBreakPoint(); + } + + m->ReturnValue = (ULONG)STATUS_INVALID_PARAMETER; + return( FALSE ); + } + } + except ( EXCEPTION_EXECUTE_HANDLER ) { + m->ReturnValue = (ULONG)STATUS_INVALID_PARAMETER; + return( FALSE ); + } + + ServerCaptureBuffer = RtlAllocateHeap( CsrHeap, MAKE_TAG( CAPTURE_TAG ), Length ); + if (ServerCaptureBuffer == NULL) { + m->ReturnValue = (ULONG)STATUS_NO_MEMORY; + return( FALSE ); + } + + RtlMoveMemory( ServerCaptureBuffer, ClientCaptureBuffer, Length ); + PointerDelta = (ULONG)ServerCaptureBuffer - (ULONG)ClientCaptureBuffer; + + ServerCaptureBuffer->MessagePointerOffsets = (PULONG) + ((PCHAR)ServerCaptureBuffer->MessagePointerOffsets + PointerDelta); + PointerOffsets = ServerCaptureBuffer->MessagePointerOffsets; + CountPointers = ServerCaptureBuffer->CountMessagePointers; + while (CountPointers--) { + Pointer = *PointerOffsets++; + if (Pointer != 0) { + Pointer += (ULONG)m; + if ((PCH)*(PULONG)Pointer >= t->Process->ClientViewBase && + (PCH)*(PULONG)Pointer < t->Process->ClientViewBounds + ) { + *(PULONG)Pointer += PointerDelta; + } + else { + IF_DEBUG { + DbgPrint( "*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n" ); + DbgBreakPoint(); + } + + m->ReturnValue = (ULONG)STATUS_INVALID_PARAMETER; + } + } + } + ServerCaptureBuffer->CapturePointerOffsets = (PULONG) + ((PCHAR)ServerCaptureBuffer->CapturePointerOffsets + PointerDelta); + PointerOffsets = ServerCaptureBuffer->CapturePointerOffsets; + CountPointers = ServerCaptureBuffer->CountCapturePointers; + while (CountPointers--) { + Pointer = *PointerOffsets++; + if (Pointer != 0) { + Pointer += (ULONG)ServerCaptureBuffer; + if ((PCH)*(PULONG)Pointer >= t->Process->ClientViewBase && + (PCH)*(PULONG)Pointer < t->Process->ClientViewBounds + ) { + *(PULONG)Pointer += PointerDelta; + } + else { + IF_DEBUG { + DbgPrint( "*** CSRSS: CaptureBuffer CapturePointer outside of ClientView\n" ); + DbgBreakPoint(); + } + + m->ReturnValue = (ULONG)STATUS_INVALID_PARAMETER; + } + } + } + + if (m->ReturnValue != STATUS_SUCCESS) { + RtlFreeHeap( CsrHeap, 0, ServerCaptureBuffer ); + return( FALSE ); + } + else { + ServerCaptureBuffer->RelatedCaptureBuffer = ClientCaptureBuffer; + m->CaptureBuffer = ServerCaptureBuffer; + return( TRUE ); + } +} + +VOID +CsrReleaseCapturedArguments( + IN PCSR_API_MSG m + ) +{ + PCSR_CAPTURE_HEADER ClientCaptureBuffer; + PCSR_CAPTURE_HEADER ServerCaptureBuffer; + PULONG PointerOffsets; + ULONG PointerDelta, CountPointers, Pointer; + + ServerCaptureBuffer = m->CaptureBuffer; + ClientCaptureBuffer = ServerCaptureBuffer->RelatedCaptureBuffer; + if (ServerCaptureBuffer == NULL) { + return; + } + ServerCaptureBuffer->RelatedCaptureBuffer = NULL; + + PointerDelta = (ULONG)ClientCaptureBuffer - (ULONG)ServerCaptureBuffer; + + ServerCaptureBuffer->MessagePointerOffsets = (PULONG) + ((PCHAR)ServerCaptureBuffer->MessagePointerOffsets + PointerDelta); + PointerOffsets = ServerCaptureBuffer->MessagePointerOffsets; + CountPointers = ServerCaptureBuffer->CountMessagePointers; + while (CountPointers--) { + Pointer = *PointerOffsets++; + if (Pointer != 0) { + Pointer += (ULONG)m; + *(PULONG)Pointer += PointerDelta; + } + } + + ServerCaptureBuffer->CapturePointerOffsets = (PULONG) + ((PCHAR)ServerCaptureBuffer->CapturePointerOffsets + PointerDelta); + PointerOffsets = ServerCaptureBuffer->CapturePointerOffsets; + CountPointers = ServerCaptureBuffer->CountCapturePointers; + while (CountPointers--) { + Pointer = *PointerOffsets++; + if (Pointer != 0) { + Pointer += (ULONG)ServerCaptureBuffer; + *(PULONG)Pointer += PointerDelta; + } + } + + RtlMoveMemory( ClientCaptureBuffer, + ServerCaptureBuffer, + ServerCaptureBuffer->Length + ); + + RtlFreeHeap( CsrHeap, 0, ServerCaptureBuffer ); + + return; +} + + + +ULONG +CsrSrvNullApiCall( + IN OUT PCSR_API_MSG m, + IN OUT PCSR_REPLY_STATUS ReplyStatus + ) +{ + PCSR_NULLAPICALL_MSG a = (PCSR_NULLAPICALL_MSG)&m->u.ApiMessageData; + ULONG i, j; + LONG CountArguments; + PCHAR *Arguments; + + CountArguments = a->CountArguments; + if (CountArguments > 0) { + Arguments = a->Arguments; + j = 0; + for (i=0; i<(ULONG)CountArguments; i++) { + if (Arguments[ i ] != NULL && *Arguments[ i ] != '\0') { + j++; + } + } + } + else { + j = 0; + CountArguments = -CountArguments; + Arguments = (PCHAR *)(&a->FastArguments[ 0 ]); + for (i=0; i<(ULONG)CountArguments; i++) { + if (Arguments[ i ]) { + j++; + } + } + } + + return( 0 ); + ReplyStatus; // get rid of unreferenced parameter warning message +} + + +NTSTATUS +CsrApiHandleConnectionRequest( + IN PCSR_API_MSG Message + ) +{ + NTSTATUS Status; + REMOTE_PORT_VIEW ClientView; + BOOLEAN AcceptConnection; + HANDLE PortHandle; + PCSR_PROCESS Process; + PCSR_THREAD Thread; + PCSR_API_CONNECTINFO ConnectionInformation; + + ConnectionInformation = &Message->ConnectionRequest; + AcceptConnection = FALSE; + + AcquireProcessStructureLock(); + Thread = CsrLocateThreadByClientId( NULL, &Message->h.ClientId ); + if (Thread != NULL && (Process = Thread->Process) != NULL) { + Status = NtDuplicateObject( NtCurrentProcess(), + CsrObjectDirectory, + Process->ProcessHandle, + &ConnectionInformation->ObjectDirectory, + 0, + 0, + DUPLICATE_SAME_ACCESS | + DUPLICATE_SAME_ATTRIBUTES + ); + if (NT_SUCCESS( Status )) { + Status = CsrSrvAttachSharedSection( Process, + ConnectionInformation + ); + if (NT_SUCCESS( Status )) { + +#if DBG + ConnectionInformation->DebugFlags = CsrDebug; +#endif + AcceptConnection = TRUE; + } + } + } + + ReleaseProcessStructureLock(); + + ClientView.Length = sizeof( ClientView ); + ClientView.ViewSize = 0; + ClientView.ViewBase = 0; + Status = NtAcceptConnectPort( &PortHandle, + AcceptConnection ? (PVOID)Process->SequenceNumber : 0, + &Message->h, + AcceptConnection, + NULL, + &ClientView + ); + if (NT_SUCCESS( Status ) && AcceptConnection) { + IF_CSR_DEBUG( LPC ) { + DbgPrint( "CSRSS: ClientId: %lx.%lx has ClientView: Base=%lx, Size=%lx\n", + Message->h.ClientId.UniqueProcess, + Message->h.ClientId.UniqueThread, + ClientView.ViewBase, + ClientView.ViewSize + ); + } + + Process->ClientPort = PortHandle; + Process->ClientViewBase = (PCH)ClientView.ViewBase; + Process->ClientViewBounds = (PCH)ClientView.ViewBase + + ClientView.ViewSize; + Status = NtCompleteConnectPort( PortHandle ); + if (!NT_SUCCESS( Status )) { + IF_DEBUG { + DbgPrint( "CSRSS: NtCompleteConnectPort - failed. Status == %X\n", + Status + ); + } + // FIX, FIX - need to destroy Session + } + } + else { + if (!NT_SUCCESS( Status )) { + IF_DEBUG { + DbgPrint( "CSRSS: NtAcceptConnectPort - failed. Status == %X\n", + Status + ); + } + } + else { + IF_DEBUG { + DbgPrint( "CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n", + Message->h.ClientId.UniqueProcess, + Message->h.ClientId.UniqueThread + ); + } + } + } + + return Status; +} diff --git a/private/csr/server/csrdebug.c b/private/csr/server/csrdebug.c new file mode 100644 index 000000000..a5ea1c93f --- /dev/null +++ b/private/csr/server/csrdebug.c @@ -0,0 +1,1028 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + csrdebug.c + +Abstract: + + This module implements CSR Debug Services. + +Author: + + Mark Lucovsky (markl) 02-Apr-1991 + +Revision History: + +--*/ + +#include "csrsrv.h" +#include "ntrtl.h" +#define WIN32_CONSOLE_APP +#include <windows.h> +#include <ntsdexts.h> + +PCSR_PROCESS CsrDebugProcessPtr; +BOOLEAN fWin32ServerDebugger = FALSE; +CLIENT_ID ClientIdWin32ServerDebugger; + +PIMAGE_DEBUG_DIRECTORY +CsrpLocateDebugSection( + IN HANDLE ProcessHandle, + IN PVOID Base + ); + +NTSTATUS +CsrDebugProcess( + IN ULONG TargetProcessId, + IN PCLIENT_ID DebugUserInterface, + IN PCSR_ATTACH_COMPLETE_ROUTINE AttachCompleteRoutine + ) +{ + + PLIST_ENTRY ListHead, ListNext; + PCSR_PROCESS Process; + NTSTATUS Status; + BOOLEAN ProcessFound = FALSE; + HANDLE ProcessHandle; + + // + // only allow CSR debugging if it has not been disabled in the + // ntglobalflag + // + + if ( TargetProcessId == -1 ) { + if (!(RtlGetNtGlobalFlags() & FLG_ENABLE_CSRDEBUG)) { + KdPrint(( "CSRSRV: CSR Debugging not enabled - NtGlobalFlag == %x\n", RtlGetNtGlobalFlags())); + return STATUS_ACCESS_DENIED; + } + } + + // + // Locate the target process + // + + AcquireProcessStructureLock(); + + ListHead = &CsrRootProcess->ListLink; + ListNext = ListHead->Flink; + while (ListNext != ListHead) { + Process = CONTAINING_RECORD( ListNext, CSR_PROCESS, ListLink ); + if (Process->ClientId.UniqueProcess == (HANDLE)TargetProcessId + || (TargetProcessId == -1 && CsrDebugProcessPtr == NULL) + ) { + ProcessFound = TRUE; + if ( TargetProcessId == -1 ) { + + CsrpServerDebugInitialize = TRUE; + + Process = CsrInitializeCsrDebugProcess(NULL); + + // + // Mark the process as being debugged + // + + Process->DebugFlags = CSR_DEBUG_THIS_PROCESS; + Process->DebugUserInterface = *DebugUserInterface; + + fWin32ServerDebugger = TRUE; + ClientIdWin32ServerDebugger = *DebugUserInterface; + } + else { + + // + // Mark the process as being debugged + // + + Process->DebugFlags = CSR_DEBUG_THIS_PROCESS; + Process->DebugUserInterface = *DebugUserInterface; + + Process = CsrInitializeCsrDebugProcess(Process); + } + if ( !Process ) { + ReleaseProcessStructureLock(); + return STATUS_NO_MEMORY; + } + + CsrSuspendProcess(Process); + + if ( TargetProcessId != -1 ) { + + // + // Process is being debugged, so set up debug port + // + + Status = NtSetInformationProcess( + Process->ProcessHandle, + ProcessDebugPort, + (PVOID)&CsrApiPort, + sizeof(HANDLE) + ); + if ( !NT_SUCCESS(Status) ){ + CsrResumeProcess(Process); + CsrTeardownCsrDebugProcess(Process); + ReleaseProcessStructureLock(); + return Status; + } + } + else { + ProcessHandle = Process->ProcessHandle; + } + + break; + } + ListNext = ListNext->Flink; + } + ReleaseProcessStructureLock(); + + if ( !ProcessFound ) { + return( STATUS_UNSUCCESSFUL ); + } + + + Status = CsrSendProcessAndThreadEvents(Process,AttachCompleteRoutine); + CsrResumeProcess(Process); + CsrTeardownCsrDebugProcess(Process); + + CsrpServerDebugInitialize = FALSE; + + if ( NT_SUCCESS(Status) ) { + if ( TargetProcessId == -1 ) { + NtSetInformationProcess( + ProcessHandle, + ProcessDebugPort, + (PVOID)&CsrSmApiPort, + sizeof(HANDLE) + ); + NtClose(ProcessHandle); + DbgBreakPoint(); + } + } + return Status; +} + + +NTSTATUS +CsrSendProcessAndThreadEvents( + IN PCSR_PROCESS Process, + IN PCSR_ATTACH_COMPLETE_ROUTINE AttachCompleteRoutine + ) + +/*++ + +Routine Description: + + This procedure sends the create process and create thread + debug events to the debug subsystem. + +Arguments: + + Process - Supplies the address of the process being debugged. + + AttachCompleteRoutine - Supplies the address of the function in the + clients address space that is remote called to cause entry into + the debugger. + +Return Value: + + None. + +--*/ + +{ + PPEB Peb; + NTSTATUS Status; + PROCESS_BASIC_INFORMATION BasicInfo; + PLDR_DATA_TABLE_ENTRY LdrEntry; + LDR_DATA_TABLE_ENTRY LdrEntryData; + PLIST_ENTRY LdrHead,LdrNext; + PPEB_LDR_DATA Ldr; + PLIST_ENTRY ThreadListHead, ThreadListNext; + PCSR_THREAD Thread, FirstThread; + DBGKM_APIMSG m; + PDBGKM_CREATE_THREAD CreateThreadArgs; + PDBGKM_CREATE_PROCESS CreateProcessArgs; + PDBGKM_LOAD_DLL LoadDllArgs; + PVOID ImageBaseAddress; + HANDLE ReplyEvent; + + Status = NtCreateEvent( + &ReplyEvent, + EVENT_ALL_ACCESS, + NULL, + SynchronizationEvent, + FALSE + ); + if ( !NT_SUCCESS(Status) ) { + return Status; + } + + Status = NtQueryInformationProcess( + Process->ProcessHandle, + ProcessBasicInformation, + &BasicInfo, + sizeof(BasicInfo), + NULL + ); + if ( !NT_SUCCESS(Status) ) { + goto bail; + } + + Peb = BasicInfo.PebBaseAddress; + + // + // Ldr = Peb->Ldr + // + + Status = NtReadVirtualMemory( + Process->ProcessHandle, + &Peb->Ldr, + &Ldr, + sizeof(Ldr), + NULL + ); + if ( !NT_SUCCESS(Status) ) { + goto bail; + } + + LdrHead = &Ldr->InLoadOrderModuleList; + + // + // LdrNext = Head->Flink; + // + + Status = NtReadVirtualMemory( + Process->ProcessHandle, + &LdrHead->Flink, + &LdrNext, + sizeof(LdrNext), + NULL + ); + if ( !NT_SUCCESS(Status) ) { + goto bail; + } + + if ( LdrNext != LdrHead ) { + + // + // This is the entry data for the image. + // + + LdrEntry = CONTAINING_RECORD(LdrNext,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks); + Status = NtReadVirtualMemory( + Process->ProcessHandle, + LdrEntry, + &LdrEntryData, + sizeof(LdrEntryData), + NULL + ); + if ( !NT_SUCCESS(Status) ) { + goto bail; + } + Status = NtReadVirtualMemory( + Process->ProcessHandle, + &Peb->ImageBaseAddress, + &ImageBaseAddress, + sizeof(ImageBaseAddress), + NULL + ); + if ( !NT_SUCCESS(Status) ) { + goto bail; + } + + LdrNext = LdrEntryData.InLoadOrderLinks.Flink; + + } + else { + LdrEntry = NULL; + } + + FirstThread = NULL; + + ThreadListHead = &Process->ThreadList; + ThreadListNext = ThreadListHead->Flink; + while (ThreadListNext != ThreadListHead) { + Thread = CONTAINING_RECORD( ThreadListNext, CSR_THREAD, Link ); + + if ( !FirstThread ) { + FirstThread = Thread; + + // + // Send the CreateProcess Message + // + + CreateThreadArgs = &m.u.CreateProcessInfo.InitialThread; + CreateThreadArgs->SubSystemKey = 0; + + CreateProcessArgs = &m.u.CreateProcessInfo; + CreateProcessArgs->SubSystemKey = 0; + + CsrComputeImageInformation( + Process, + &LdrEntryData, + &CreateProcessArgs->BaseOfImage, + &CreateProcessArgs->DebugInfoFileOffset, + &CreateProcessArgs->DebugInfoSize + ); + + CsrOpenLdrEntry( + FirstThread, + Process, + &LdrEntryData, + &CreateProcessArgs->FileHandle + ); + + CreateThreadArgs->StartAddress = NULL; + + DBGKM_FORMAT_API_MSG(m,DbgKmCreateProcessApi,sizeof(*CreateProcessArgs)); + + m.h.ClientId = Thread->ClientId; + DbgSsHandleKmApiMsg(&m,ReplyEvent); + Status = NtWaitForSingleObject(ReplyEvent,FALSE,NULL); + if ( !NT_SUCCESS(Status) ) { + goto bail; + } + } + else { + + // + // Send the CreateThread Message + // + + CreateThreadArgs = &m.u.CreateThread; + CreateThreadArgs->SubSystemKey = 0; + CreateThreadArgs->StartAddress = NULL; + + DBGKM_FORMAT_API_MSG(m,DbgKmCreateThreadApi,sizeof(*CreateThreadArgs)); + + m.h.ClientId = Thread->ClientId; + + DbgSsHandleKmApiMsg(&m,ReplyEvent); + Status = NtWaitForSingleObject(ReplyEvent,FALSE,NULL); + if ( !NT_SUCCESS(Status) ) { + goto bail; + } + } + ThreadListNext = ThreadListNext->Flink; + } + + // + // Send all of the load module messages + // + + while ( LdrNext != LdrHead ) { + LdrEntry = CONTAINING_RECORD(LdrNext,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks); + Status = NtReadVirtualMemory( + Process->ProcessHandle, + LdrEntry, + &LdrEntryData, + sizeof(LdrEntryData), + NULL + ); + if ( !NT_SUCCESS(Status) ) { + goto bail; + } + + LoadDllArgs = &m.u.LoadDll; + + CsrComputeImageInformation( + Process, + &LdrEntryData, + &LoadDllArgs->BaseOfDll, + &LoadDllArgs->DebugInfoFileOffset, + &LoadDllArgs->DebugInfoSize + ); + + CsrOpenLdrEntry( + FirstThread, + Process, + &LdrEntryData, + &LoadDllArgs->FileHandle + ); + if ( LoadDllArgs->FileHandle ) { + DBGKM_FORMAT_API_MSG(m,DbgKmLoadDllApi,sizeof(*LoadDllArgs)); + m.h.ClientId = FirstThread->ClientId; + DbgSsHandleKmApiMsg(&m,ReplyEvent); + Status = NtWaitForSingleObject(ReplyEvent,FALSE,NULL); + if ( !NT_SUCCESS(Status) ) { + goto bail; + } + } + + LdrNext = LdrEntryData.InLoadOrderLinks.Flink; + } +bail: + NtClose(ReplyEvent); + return Status; +} + +VOID +CsrComputeImageInformation( + IN PCSR_PROCESS Process, + IN PLDR_DATA_TABLE_ENTRY LdrEntry, + OUT PVOID *BaseOfImage, + OUT PULONG DebugInfoFileOffset, + OUT PULONG DebugInfoSize + ) + +/*++ + +Routine Description: + + This function is called to compute the image base and + debug information from a ldr entry. + +Arguments: + + Process - Supplies the address of the process whose context this + information is to be calculated from. + + LdrEntry - Supplies the address of the loader data table entry + whose info is being computed relative to. This pointer is + valid in the callers (current) context. + + BaseOfImage - Returns the image's base. + + DebugInfoFileOffset - Returns the offset of the debug info. + + DebugInfoSize - Returns the size of the debug info. + +Return Value: + + None. + +--*/ + +{ + PIMAGE_DEBUG_DIRECTORY pDebugDir; + IMAGE_DEBUG_DIRECTORY DebugDir; + IMAGE_COFF_SYMBOLS_HEADER DebugInfo; + NTSTATUS Status; + + *BaseOfImage = LdrEntry->DllBase; + + pDebugDir = CsrpLocateDebugSection( + Process->ProcessHandle, + LdrEntry->DllBase + ); + + *DebugInfoFileOffset = 0; + *DebugInfoSize = 0; + if ( pDebugDir ) { + + Status = NtReadVirtualMemory( + Process->ProcessHandle, + pDebugDir, + &DebugDir, + sizeof(IMAGE_DEBUG_DIRECTORY), + NULL + ); + + if ( !NT_SUCCESS(Status) ) { + return; + } + + Status = NtReadVirtualMemory( + Process->ProcessHandle, + (PVOID)((ULONG)LdrEntry->DllBase + DebugDir.AddressOfRawData), + &DebugInfo, + sizeof(IMAGE_COFF_SYMBOLS_HEADER), + NULL + ); + + if ( !NT_SUCCESS(Status) ) { + return; + } + + *DebugInfoFileOffset = DebugDir.PointerToRawData + DebugInfo.LvaToFirstSymbol; + *DebugInfoSize = DebugInfo.NumberOfSymbols; + } + else { + *DebugInfoFileOffset = 0; + *DebugInfoSize = 0; + } +} + +PIMAGE_DEBUG_DIRECTORY +CsrpLocateDebugSection( + IN HANDLE ProcessHandle, + IN PVOID Base + ) + +{ + PVOID ImageHeaderRawData; + PIMAGE_DOS_HEADER DosHeaderRawData; + PIMAGE_NT_HEADERS NtHeaders; + ULONG AllocSize, Addr; + NTSTATUS Status; + + // + // Allocate a buffer, and read the image header from the + // target process + // + + DosHeaderRawData = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), + sizeof(IMAGE_DOS_HEADER)); + + if ( !DosHeaderRawData ) { + return NULL; + } + + Status = NtReadVirtualMemory( + ProcessHandle, + Base, + DosHeaderRawData, + sizeof(IMAGE_DOS_HEADER), + NULL + ); + + AllocSize = DosHeaderRawData->e_lfanew + sizeof(IMAGE_NT_HEADERS); + RtlFreeHeap(RtlProcessHeap(), 0, DosHeaderRawData); + + if ( !NT_SUCCESS(Status) ) { + return NULL; + } + + ImageHeaderRawData = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), AllocSize); + if ( !ImageHeaderRawData ) { + return NULL; + } + Status = NtReadVirtualMemory( + ProcessHandle, + Base, + ImageHeaderRawData, + AllocSize, + NULL + ); + if ( !NT_SUCCESS(Status) ){ + RtlFreeHeap(RtlProcessHeap(),0,ImageHeaderRawData); + return NULL; + } + + NtHeaders = RtlImageNtHeader(ImageHeaderRawData); + if ( NtHeaders ) { + Addr = (ULONG)NtHeaders->OptionalHeader.DataDirectory + [IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + + if ( Addr ) { + Addr += (ULONG)Base; + } + } + else { + Addr = 0; + } + + RtlFreeHeap(RtlProcessHeap(),0,ImageHeaderRawData); + return((PIMAGE_DEBUG_DIRECTORY)Addr); +} + +VOID +CsrOpenLdrEntry( + IN PCSR_THREAD Thread, + IN PCSR_PROCESS Process, + IN PLDR_DATA_TABLE_ENTRY LdrEntry, + OUT PHANDLE FileHandle + ) + +/*++ + +Routine Description: + + This function opens a handle to the image/dll file described + by the ldr entry in the context of the specified process. + +Arguments: + + Thread - Supplies the address of the first thread in the process + + Process - Supplies the address of the process whose context this + file is to be opened in. + + LdrEntry - Supplies the address of the loader data table entry + whose file is to be opened. + + FileHandle - Returns a handle to the associated file + valid in the context of the process being attached to. + +Return Value: + + None. + +--*/ + +{ + + UNICODE_STRING DosName; + UNICODE_STRING FileName; + NTSTATUS Status; + OBJECT_ATTRIBUTES Obja; + HANDLE LocalHandle; + IO_STATUS_BLOCK IoStatusBlock; + BOOLEAN TranslationStatus; + NTSTATUS ImpersonationStatus; + HANDLE NewToken; + + *FileHandle = NULL; + DosName.Length = LdrEntry->FullDllName.Length; + DosName.MaximumLength = LdrEntry->FullDllName.MaximumLength; + DosName.Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), DosName.MaximumLength); + if ( !DosName.Buffer ) { + return; + } + + Status = NtReadVirtualMemory( + Process->ProcessHandle, + LdrEntry->FullDllName.Buffer, + DosName.Buffer, + DosName.MaximumLength, + NULL + ); + if ( !NT_SUCCESS(Status) ) { + RtlFreeHeap(RtlProcessHeap(),0,DosName.Buffer); + return; + } + + // + // special case CSR + // + if ( RtlDetermineDosPathNameType_U(DosName.Buffer) == RtlPathTypeRooted ) { + InitializeObjectAttributes( + &Obja, + &DosName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + Status = NtOpenFile( + &LocalHandle, + (ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE), + &Obja, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT + ); + + RtlFreeHeap(RtlProcessHeap(),0,DosName.Buffer); + if ( !NT_SUCCESS(Status) ) { + return; + } + + // + // The file is open in our context. Dup this to target processes context + // so that dbgss can dup it to the user interface + // + + Status = NtDuplicateObject( + NtCurrentProcess(), + LocalHandle, + Process->ProcessHandle, + FileHandle, + 0L, + 0L, + DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES | + DUPLICATE_CLOSE_SOURCE + ); + if ( !NT_SUCCESS(Status) ) { + *FileHandle = NULL; + } + return; + } + + TranslationStatus = RtlDosPathNameToNtPathName_U( + DosName.Buffer, + &FileName, + NULL, + NULL + ); + + if ( !TranslationStatus ) { + RtlFreeHeap(RtlProcessHeap(),0,DosName.Buffer); + return; + } + + InitializeObjectAttributes( + &Obja, + &FileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + Status = NtOpenFile( + &LocalHandle, + (ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE), + &Obja, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT + ); + if ( !NT_SUCCESS(Status) && Thread ) { + ImpersonationStatus = NtImpersonateThread( + NtCurrentThread(), + Thread->ThreadHandle, + &CsrSecurityQos + ); + if ( NT_SUCCESS(ImpersonationStatus) ) { + Status = NtOpenFile( + &LocalHandle, + (ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE), + &Obja, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT + ); + + NewToken = NULL; + ImpersonationStatus = NtSetInformationThread( + NtCurrentThread(), + ThreadImpersonationToken, + (PVOID)&NewToken, + (ULONG)sizeof(HANDLE) + ); + ASSERT( NT_SUCCESS(ImpersonationStatus) ); + } + } + RtlFreeHeap(RtlProcessHeap(),0,DosName.Buffer); + RtlFreeHeap(RtlProcessHeap(),0,FileName.Buffer); + if ( !NT_SUCCESS(Status) ) { + return; + } + + // + // The file is open in our context. Dup this to target processes context + // so that dbgss can dup it to the user interface + // + + Status = NtDuplicateObject( + NtCurrentProcess(), + LocalHandle, + Process->ProcessHandle, + FileHandle, + 0L, + 0L, + DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES | + DUPLICATE_CLOSE_SOURCE + ); + if ( !NT_SUCCESS(Status) ) { + *FileHandle = NULL; + return; + } +} + + +VOID +CsrSuspendProcess( + IN PCSR_PROCESS Process + ) + +/*++ + +Routine Description: + + This procedure is called when doing a debug attach to suspend all + threads within the effected process. + +Arguments: + + Process - Supplies the address of the process to suspend. + +Return Value: + + None. + +--*/ + +{ + + PLIST_ENTRY ListHead, ListNext; + PCSR_THREAD Thread; + NTSTATUS Status; + + if ( Process == CsrDebugProcessPtr ) { + return; + } + + // + // Now walk through the processes thread list and + // suspend all of its threads. + // + + ListHead = &Process->ThreadList; + ListNext = ListHead->Flink; + while (ListNext != ListHead) { + Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link ); + NtSuspendThread(Thread->ThreadHandle,NULL); + ListNext = ListNext->Flink; + } +} + + +VOID +CsrResumeProcess( + IN PCSR_PROCESS Process + ) + +/*++ + +Routine Description: + + This procedure is called when doing a debug attach to resume all + threads within the effected process. + +Arguments: + + Process - Supplies the address of the process to resume. + +Return Value: + + None. + +--*/ + +{ + + PLIST_ENTRY ListHead, ListNext; + PCSR_THREAD Thread; + NTSTATUS Status; + + if ( Process == CsrDebugProcessPtr ) { + return; + } + + // + // Now walk through the processes thread list and + // suspend all of its threads. + // + + ListHead = &Process->ThreadList; + ListNext = ListHead->Flink; + while (ListNext != ListHead) { + Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link ); + NtResumeThread(Thread->ThreadHandle,NULL); + ListNext = ListNext->Flink; + } +} + +PCSR_PROCESS +CsrInitializeCsrDebugProcess( + PCSR_PROCESS TargetProcess + ) + +/*++ + +Routine Description: + + This function is called to build a side process tree to use when + doing debug attaches. + + After the attach completes, this structure is torn down. + +Arguments: + + Process - Supplies the address of the process to attach to. A value of + NULL indicates CSR. + +Return Value: + + Returns the address of the dummy CSR process. + +--*/ + +{ + PCSR_PROCESS Process; + OBJECT_ATTRIBUTES Obja; + PCSR_THREAD Thread; + PLIST_ENTRY ProcessListHead, ProcessListNext; + PLIST_ENTRY ThreadListHead, ThreadListNext; + PCSR_THREAD ThreadPtr; + PCSR_PROCESS ProcessPtr; + THREAD_BASIC_INFORMATION BasicInfo; + NTSTATUS Status; + PCSR_THREAD ServerThread; + + Process = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( PROCESS_TAG ),sizeof(*Process)); + if (!Process) { + return NULL; + } + + if ( TargetProcess == NULL ) { + CsrDebugProcessPtr = Process; + InitializeListHead(&Process->ThreadList); + Process->ClientId = NtCurrentTeb()->ClientId; + + InitializeObjectAttributes( + &Obja, + NULL, + 0, + NULL, + NULL + ); + Status = NtOpenProcess( + &Process->ProcessHandle, + PROCESS_ALL_ACCESS, + &Obja, + &Process->ClientId + ); + if ( !NT_SUCCESS(Status) ) { + RtlFreeHeap(RtlProcessHeap(),0,Process); + return NULL; + } + + // + // Compute the threads. This is cumbersome. First we have to + // locate the static threads, then walk through the entire structure + // looking for threads with associated server threads. + // + + ThreadListHead = &CsrRootProcess->ThreadList; + ThreadListNext = ThreadListHead->Flink; + while (ThreadListNext != ThreadListHead) { + ServerThread = CONTAINING_RECORD( ThreadListNext, CSR_THREAD, Link ); + Thread = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( PROCESS_TAG ),sizeof(*Thread)); + if ( Thread ) { + Thread->ClientId = ServerThread->ClientId; + Thread->ThreadHandle = ServerThread->ThreadHandle; + InsertTailList( &Process->ThreadList, &Thread->Link ); + } + ThreadListNext = ThreadListNext->Flink; + } + + } + else { + + // + // Regular non-csr process attach... Just copy the thread and + // process to a new set of structures + // + + InitializeListHead(&Process->ThreadList); + Process->ClientId = TargetProcess->ClientId; + Process->ProcessHandle = TargetProcess->ProcessHandle; + + ThreadListHead = &TargetProcess->ThreadList; + ThreadListNext = ThreadListHead->Flink; + while (ThreadListNext != ThreadListHead) { + ThreadPtr = CONTAINING_RECORD( ThreadListNext, CSR_THREAD, Link ); + Thread = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( PROCESS_TAG ),sizeof(*Thread)); + if ( Thread ) { + Thread->ThreadHandle = ThreadPtr->ThreadHandle; + Thread->ClientId = ThreadPtr->ClientId; + InsertTailList( &Process->ThreadList, &Thread->Link ); + } + ThreadListNext = ThreadListNext->Flink; + } + } + return Process; +} + +VOID +CsrTeardownCsrDebugProcess( + PCSR_PROCESS TargetProcess + ) + +/*++ + +Routine Description: + + This function is called after a debug attach to + a process is complete + + It's purpose is to tear down the structure created in the + initialization phase. + +Arguments: + + TargetProcess - Supplies the address of the process to teardown. + +Return Value: + + None. + +--*/ + +{ + PCSR_PROCESS Process; + PLIST_ENTRY ThreadListHead, ThreadListNext; + PCSR_THREAD ThreadPtr; + NTSTATUS Status; + + if ( TargetProcess == CsrDebugProcessPtr ) { + CsrDebugProcessPtr = (PCSR_PROCESS)-1; + } + Process = TargetProcess; + + + ThreadListHead = &Process->ThreadList; + ThreadListNext = ThreadListHead->Flink; + while (ThreadListNext != ThreadListHead) { + ThreadPtr = CONTAINING_RECORD( ThreadListNext, CSR_THREAD, Link ); + ThreadListNext = ThreadListNext->Flink; + RemoveEntryList(&ThreadPtr->Link); + RtlFreeHeap(RtlProcessHeap(),0,ThreadPtr); + } + + RtlFreeHeap(RtlProcessHeap(),0,Process); +} diff --git a/private/csr/server/csrsrv.h b/private/csr/server/csrsrv.h new file mode 100644 index 000000000..b3adefafd --- /dev/null +++ b/private/csr/server/csrsrv.h @@ -0,0 +1,603 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + csrsrv.h + +Abstract: + + Main include file for Server side of the Client Server Runtime (CSR) + +Author: + + Steve Wood (stevewo) 8-Oct-1990 + +Revision History: + +--*/ + +// +// Include definitions common between the Client and Server portions. +// + +#include "csr.h" + +// +// Include definitions specific to the Server portion. +// + +#include "ntcsrsrv.h" +#include "ntdbg.h" + +// +// Define debugging flags and macro for testing them. All debug code +// should be contained within a IF_CSR_DEBUG macro call so that when +// the system is compiled with debug code disabled, none of the code +// is generated. +// + +#if DBG +#define CSR_DEBUG_INIT 0x00000001 +#define CSR_DEBUG_LPC 0x00000002 +#define CSR_DEBUG_FLAG3 0x00000004 +#define CSR_DEBUG_FLAG4 0x00000008 +#define CSR_DEBUG_FLAG5 0x00000010 +#define CSR_DEBUG_FLAG6 0x00000020 +#define CSR_DEBUG_FLAG7 0x00000040 +#define CSR_DEBUG_FLAG8 0x00000080 +#define CSR_DEBUG_FLAG9 0x00000100 +#define CSR_DEBUG_FLAG10 0x00000200 +#define CSR_DEBUG_FLAG11 0x00000400 +#define CSR_DEBUG_FLAG12 0x00000800 +#define CSR_DEBUG_FLAG13 0x00001000 +#define CSR_DEBUG_FLAG14 0x00002000 +#define CSR_DEBUG_FLAG15 0x00004000 +#define CSR_DEBUG_FLAG16 0x00008000 +#define CSR_DEBUG_FLAG17 0x00010000 +#define CSR_DEBUG_FLAG18 0x00020000 +#define CSR_DEBUG_FLAG19 0x00040000 +#define CSR_DEBUG_FLAG20 0x00080000 +#define CSR_DEBUG_FLAG21 0x00100000 +#define CSR_DEBUG_FLAG22 0x00200000 +#define CSR_DEBUG_FLAG23 0x00400000 +#define CSR_DEBUG_FLAG24 0x00800000 +#define CSR_DEBUG_FLAG25 0x01000000 +#define CSR_DEBUG_FLAG26 0x02000000 +#define CSR_DEBUG_FLAG27 0x04000000 +#define CSR_DEBUG_FLAG28 0x08000000 +#define CSR_DEBUG_FLAG29 0x10000000 +#define CSR_DEBUG_FLAG30 0x20000000 +#define CSR_DEBUG_FLAG31 0x40000000 +#define CSR_DEBUG_FLAG32 0x80000000 + +ULONG CsrDebug; + +#define IF_CSR_DEBUG( ComponentFlag ) \ + if (CsrDebug & (CSR_DEBUG_ ## ComponentFlag)) + + +#else +#define IF_CSR_DEBUG( ComponentFlag ) if (FALSE) + +#endif + +#if DBG + +#define CSRSS_PROTECT_HANDLES 1 + +BOOLEAN +ProtectHandle( + HANDLE hObject + ); + +BOOLEAN +UnProtectHandle( + HANDLE hObject + ); + +#else + +#define CSRSS_PROTECT_HANDLES 0 + +#define ProtectHandle( hObject ) +#define UnProtectHandle( hObject ) + +#endif + + +BOOLEAN CsrProfileControl; + +// +// Event indicating the csr server has completed initialization. +// + +HANDLE CsrInitializationEvent; + +// +// Include NT Session Manager and Debug SubSystem Interfaces + +#include <ntsm.h> +#include <ntdbg.h> +typedef BOOLEAN (*PSB_API_ROUTINE)( IN PSBAPIMSG SbApiMsg ); + +// +// Global data accessed by Client-Server Runtime Server +// + +ULONG CsrSubSystemType; + +#if DBG +ULONG CsrDebugFlag; +#endif // DBG + +PVOID CsrHeap; + +HANDLE CsrObjectDirectory; + +#define CSR_SBAPI_PORT_NAME L"SbApiPort" + +UNICODE_STRING CsrDirectoryName; +UNICODE_STRING CsrApiPortName; +UNICODE_STRING CsrSbApiPortName; + +HANDLE CsrApiPort; +HANDLE CsrSbApiPort; +HANDLE CsrSmApiPort; +HANDLE CsrExceptionPort; + +ULONG CsrMaxApiRequestThreads; +BOOLEAN CsrpServerDebugInitialize; + +#define CSR_MAX_THREADS 16 + +#define CSR_STATIC_API_THREAD 0x00000010 + +PCSR_THREAD CsrSbApiRequestThreadPtr; + +LIST_ENTRY CsrZombieThreadList; + +// +// GDI PID codes. (See WINGDIP.H) +// + +#define PID_PUBLIC 0 +#define PID_CURRENT 1 +#define PID_NOOWNER 2 +#define PID_TERMINATION 3 +#define PID_SERVERLPC 4 + +#define FIRST_SEQUENCE_COUNT 5 + +// +// Routines defined in srvinit.c +// + +// +// The CsrNtSysInfo global variable contains NT specific constants of +// interest, such as page size, allocation granularity, etc. It is filled +// in once during process initialization. +// + +SYSTEM_BASIC_INFORMATION CsrNtSysInfo; + +#define ROUND_UP_TO_PAGES(SIZE) (((ULONG)(SIZE) + CsrNtSysInfo.PageSize - 1) & ~(CsrNtSysInfo.PageSize - 1)) +#define ROUND_DOWN_TO_PAGES(SIZE) (((ULONG)(SIZE)) & ~(CsrNtSysInfo.PageSize - 1)) + +#define QUAD_ALIGN(VALUE) ( ((ULONG)(VALUE) + 7) & ~7 ) + +NTSTATUS +CsrParseServerCommandLine( + IN ULONG argc, + IN PCH argv[] + ); + +NTSTATUS +CsrServerDllInitialization( + IN PCSR_SERVER_DLL LoadedServerDll + ); + +NTSTATUS +CsrSrvProfileControl( + IN OUT PCSR_API_MSG m, + IN OUT PCSR_REPLY_STATUS ReplyStatus + ); + +NTSTATUS +CsrEnablePrivileges( + VOID + ); + + +// +// Routines define in srvdebug.c +// + +#if DBG + +#else + +#endif // DBG + + + +// +// Routines defined in sbinit.c +// + +NTSTATUS +CsrSbApiPortInitialize( VOID ); + + +VOID +CsrSbApiPortTerminate( + NTSTATUS Status + ); + +// +// Routines defined in sbreqst.c +// + +NTSTATUS +CsrSbApiRequestThread( + IN PVOID Parameter + ); + +// +// Routines defined in sbapi.c +// + +BOOLEAN +CsrSbCreateSession( + IN PSBAPIMSG Msg + ); + +BOOLEAN +CsrSbTerminateSession( + IN PSBAPIMSG Msg + ); + +BOOLEAN +CsrSbForeignSessionComplete( + IN PSBAPIMSG Msg + ); + +// +// Routines defined in session.c +// + +RTL_CRITICAL_SECTION CsrNtSessionLock; +LIST_ENTRY CsrNtSessionList; + +#define LockNtSessionList() RtlEnterCriticalSection( &CsrNtSessionLock ) +#define UnlockNtSessionList() RtlLeaveCriticalSection( &CsrNtSessionLock ) + +NTSTATUS +CsrInitializeNtSessionList( VOID ); + +PCSR_NT_SESSION +CsrAllocateNtSession( + ULONG SessionId + ); + +VOID +CsrReferenceNtSession( + PCSR_NT_SESSION Session + ); + +VOID +CsrDereferenceNtSession( + PCSR_NT_SESSION Session, + NTSTATUS ExitStatus + ); + + +// +// Routines defined in apiinit.c +// + +NTSTATUS +CsrApiPortInitialize( VOID ); + + +// +// Routines defined in apireqst.c +// + +NTSTATUS +CsrApiRequestThread( + IN PVOID Parameter + ); + +BOOLEAN +CsrCaptureArguments( + IN PCSR_THREAD t, + IN PCSR_API_MSG m + ); + +VOID +CsrReleaseCapturedArguments( + IN PCSR_API_MSG m + ); + +ULONG +CsrSrvNullApiCall( + IN OUT PCSR_API_MSG m, + IN OUT PCSR_REPLY_STATUS ReplyStatus + ); + + +// +// Routines and data defined in srvloadr.c +// + +#define CSR_MAX_SERVER_DLL 16 + +PCSR_SERVER_DLL CsrLoadedServerDll[ CSR_MAX_SERVER_DLL ]; + +ULONG CsrTotalPerProcessDataLength; +ULONG CsrTotalPerThreadDataLength; +HANDLE CsrSrvSharedSection; +ULONG CsrSrvSharedSectionSize; +PVOID CsrSrvSharedSectionBase; +PVOID CsrSrvSharedSectionHeap; +PVOID *CsrSrvSharedStaticServerData; + +NTSTATUS +CsrLoadServerDll( + IN PCH ModuleName, + IN PCH InitRoutineString, + IN ULONG ServerDllIndex + ); + +ULONG +CsrSrvClientConnect( + IN OUT PCSR_API_MSG m, + IN OUT PCSR_REPLY_STATUS ReplyStatus + ); + + +NTSTATUS +CsrSrvCreateSharedSection( + IN PCH SizeParameter + ); + + +NTSTATUS +CsrSrvAttachSharedSection( + IN PCSR_PROCESS Process OPTIONAL, + OUT PCSR_API_CONNECTINFO p + ); + +// +// Routines and data defined in process.c +// + +// +// The CsrProcessStructureLock critical section protects all of the link +// fields of the Windows Process objects. You must own this lock to examine +// or modify any of the following fields of the CSR_PROCESS structure: +// +// ListLink +// +// It also protects the following variables: +// +// CsrRootProcess +// + +RTL_CRITICAL_SECTION CsrProcessStructureLock; +#define AcquireProcessStructureLock() RtlEnterCriticalSection( &CsrProcessStructureLock ) +#define ReleaseProcessStructureLock() RtlLeaveCriticalSection( &CsrProcessStructureLock ) + +// +// The following is a dummy process that acts as the root of the Windows Process +// Structure. It has a ClientId of -1.-1 so it does not conflict with actual +// Windows Processes. All processes created via the session manager are children +// of this process, as are all orphaned processes. The ListLink field of this +// process is the head of a list of all Windows Processes. +// + +PCSR_PROCESS CsrRootProcess; + +// +// reference/dereference thread are public in ntcsrsrv.h +// + +VOID +CsrReferenceProcess( + PCSR_PROCESS p + ); + +VOID +CsrLockedReferenceProcess( + PCSR_PROCESS p + ); + +VOID +CsrLockedReferenceThread( + PCSR_THREAD t + ); + +VOID +CsrLockedDereferenceProcess( + PCSR_PROCESS p + ); + +VOID +CsrLockedDereferenceThread( + PCSR_THREAD t + ); + +NTSTATUS +CsrInitializeProcessStructure( VOID ); + +PCSR_PROCESS +CsrAllocateProcess( VOID ); + +VOID +CsrDeallocateProcess( + IN PCSR_PROCESS Process + ); + +VOID +CsrInsertProcess( + IN PCSR_PROCESS ParentProcess, + IN PCSR_PROCESS CallingProcess, + IN PCSR_PROCESS Process + ); + +VOID +CsrRemoveProcess( + IN PCSR_PROCESS Process + ); + +NTSTATUS +CsrSetProcessContext( + IN PCSR_PROCESS Process, + IN PCSR_THREAD Thread, + IN BOOLEAN StartedBySm + ); + +PCSR_THREAD +CsrAllocateThread( + IN PCSR_PROCESS Process + ); + +VOID +CsrDeallocateThread( + IN PCSR_THREAD Thread + ); + +VOID +CsrInitializeThreadData( + IN PCSR_THREAD Thread, + IN PCSR_THREAD CallingThread OPTIONAL + ); + +VOID +CsrInsertThread( + IN PCSR_PROCESS Process, + IN PCSR_THREAD Thread + ); + +VOID +CsrRemoveThread( + IN PCSR_THREAD Thread + ); + +PCSR_THREAD +CsrLocateThreadByClientId( + OUT PCSR_PROCESS *Process, + IN PCLIENT_ID ClientId + ); + +NTSTATUS +CsrUiLookup( + IN PCLIENT_ID AppClientId, + OUT PCLIENT_ID DebugUiClientId + ); + +NTSTATUS +CsrSrvIdentifyAlertableThread( + IN OUT PCSR_API_MSG m, + IN OUT PCSR_REPLY_STATUS ReplyStatus + ); + +NTSTATUS +CsrSrvSetPriorityClass( + IN OUT PCSR_API_MSG m, + IN OUT PCSR_REPLY_STATUS ReplyStatus + ); + + +// +// Routines and data defined in csrdebug.c +// + +VOID +CsrSuspendProcess( + IN PCSR_PROCESS Process + ); + +VOID +CsrResumeProcess( + IN PCSR_PROCESS Process + ); + +NTSTATUS +CsrSendProcessAndThreadEvents( + IN PCSR_PROCESS Process, + IN PCSR_ATTACH_COMPLETE_ROUTINE AttachCompleteRoutine + ); + +VOID +CsrComputeImageInformation( + IN PCSR_PROCESS Process, + IN PLDR_DATA_TABLE_ENTRY LdrEntry, + OUT PVOID *BaseOfImage, + OUT PULONG DebugInfoFileOffset, + OUT PULONG DebugInfoSize + ); + +VOID +CsrOpenLdrEntry( + IN PCSR_THREAD Thread, + IN PCSR_PROCESS Process, + IN PLDR_DATA_TABLE_ENTRY LdrEntry, + OUT PHANDLE FileHandle + ); + +PCSR_PROCESS +CsrInitializeCsrDebugProcess( + PCSR_PROCESS TargetProcess + ); + +VOID +CsrTeardownCsrDebugProcess( + PCSR_PROCESS TargetProcess + ); + + + +// +// Routines and data defined in wait.c +// + +#define AcquireWaitListsLock() RtlEnterCriticalSection( &CsrWaitListsLock ) +#define ReleaseWaitListsLock() RtlLeaveCriticalSection( &CsrWaitListsLock ) + +RTL_CRITICAL_SECTION CsrWaitListsLock; +extern SECURITY_QUALITY_OF_SERVICE CsrSecurityQos; + +BOOLEAN +CsrInitializeWait( + IN CSR_WAIT_ROUTINE WaitRoutine, + IN PCSR_THREAD WaitingThread, + IN OUT PCSR_API_MSG WaitReplyMessage, + IN PVOID WaitParameter, + OUT PCSR_WAIT_BLOCK *WaitBlockPtr + ); + +BOOLEAN +CsrNotifyWaitBlock( + IN PCSR_WAIT_BLOCK WaitBlock, + IN PLIST_ENTRY WaitQueue, + IN PVOID SatisfyParameter1, + IN PVOID SatisfyParameter2, + IN ULONG WaitFlags, + IN BOOLEAN DereferenceThread + ); + +ULONG CsrBaseTag; +ULONG CsrSharedBaseTag; + +#define MAKE_TAG( t ) (RTL_HEAP_MAKE_TAG( CsrBaseTag, t )) + +#define TMP_TAG 0 +#define INIT_TAG 1 +#define CAPTURE_TAG 2 +#define PROCESS_TAG 3 + +#define MAKE_SHARED_TAG( t ) (RTL_HEAP_MAKE_TAG( CsrSharedBaseTag, t )) +#define SHR_INIT_TAG 0 diff --git a/private/csr/server/csrsrv.src b/private/csr/server/csrsrv.src new file mode 100644 index 000000000..a3135ca84 --- /dev/null +++ b/private/csr/server/csrsrv.src @@ -0,0 +1,38 @@ +LIBRARY CSRSRV + +DESCRIPTION 'Client-Server Runtime Subsystem - Server Stubs' + +EXPORTS + CsrServerInitialization + CsrCreateProcess + CsrCreateThread + CsrCreateRemoteThread + CsrDestroyProcess + CsrDestroyThread + CsrCallServerFromServer + CsrGetApiPorts + CsrCreateWait + CsrNotifyWait + CsrDestroyWait + CsrDebugProcess + CsrAddStaticServerThread + CsrReferenceThread + CsrDereferenceThread + CsrLockProcessByClientId + CsrUnlockProcess + CsrLockThreadByClientId + CsrUnlockThread + CsrLocateThreadInProcess + CsrDereferenceWait + CsrComputePriorityClass + CsrShutdownProcesses + CsrGetProcessLuid + CsrDereferenceProcess + CsrImpersonateClient + CsrRevertToSelf + CsrSetForegroundPriority + CsrSetBackgroundPriority + CsrSetCallingSpooler + CsrQueryApiPort + CsrConnectToUser + CsrUnhandledExceptionFilter diff --git a/private/csr/server/csrss.c b/private/csr/server/csrss.c new file mode 100644 index 000000000..cb5f592ec --- /dev/null +++ b/private/csr/server/csrss.c @@ -0,0 +1,107 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + csrss.c + +Abstract: + + This is the main startup module for the Server side of the Client + Server Runtime Subsystem (CSRSS) + +Author: + + Steve Wood (stevewo) 8-Oct-1990 + +Environment: + + User Mode Only + +Revision History: + +--*/ + +#include "csrsrv.h" + +VOID +DisableErrorPopups( + VOID + ) +{ + + ULONG NewMode; + + NewMode = 0; + NtSetInformationProcess( + NtCurrentProcess(), + ProcessDefaultHardErrorMode, + (PVOID) &NewMode, + sizeof(NewMode) + ); +} + +int +_cdecl +main( + IN ULONG argc, + IN PCH argv[], + IN PCH envp[], + IN ULONG DebugFlag OPTIONAL + ) +{ + NTSTATUS status; + ULONG ErrorResponse; + KPRIORITY SetBasePriority; + + SetBasePriority = FOREGROUND_BASE_PRIORITY + 4; + NtSetInformationProcess( + NtCurrentProcess(), + ProcessBasePriority, + (PVOID) &SetBasePriority, + sizeof(SetBasePriority) + ); + + // + // Give IOPL to the server so GDI and the display drivers can access the + // video registers. + // + + status = NtSetInformationProcess( NtCurrentProcess(), + ProcessUserModeIOPL, + NULL, + 0 ); + + if (!NT_SUCCESS( status )) { + + IF_DEBUG { + + DbgPrint( "CSRSS: Unable to give IOPL to the server. status == %X\n", + status); + } + + status = NtRaiseHardError( (NTSTATUS)STATUS_IO_PRIVILEGE_FAILED, + 0, + 0, + NULL, + OptionOk, + &ErrorResponse + ); + } + + status = CsrServerInitialization( argc, argv ); + + if (!NT_SUCCESS( status )) { + IF_DEBUG { + DbgPrint( "CSRSS: Unable to initialize server. status == %X\n", + status + ); + } + + NtTerminateProcess( NtCurrentProcess(), status ); + } + DisableErrorPopups(); + NtTerminateThread( NtCurrentThread(), status ); + return( 0 ); +} diff --git a/private/csr/server/csrss.rc b/private/csr/server/csrss.rc new file mode 100644 index 000000000..e838c0237 --- /dev/null +++ b/private/csr/server/csrss.rc @@ -0,0 +1,10 @@ +#include <windows.h> +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Client Server Runtime Process" +#define VER_INTERNALNAME_STR "CSRSrv.DLL and CSRSS.Exe" +#define VER_ORIGINALFILENAME_STR "CSRSrv.DLL and CSRSS.Exe" + +#include "common.ver" diff --git a/private/csr/server/i386/sources b/private/csr/server/i386/sources new file mode 100644 index 000000000..e55485376 --- /dev/null +++ b/private/csr/server/i386/sources @@ -0,0 +1 @@ +386_LNKFLAGS=-stack:65536,8192 diff --git a/private/csr/server/makefile b/private/csr/server/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/csr/server/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/csr/server/mips/sources b/private/csr/server/mips/sources new file mode 100644 index 000000000..1fdb5b447 --- /dev/null +++ b/private/csr/server/mips/sources @@ -0,0 +1 @@ +MIPS_LNKFLAGS=-stack:65536,8192 diff --git a/private/csr/server/ppc/sources b/private/csr/server/ppc/sources new file mode 100644 index 000000000..2bf092a8d --- /dev/null +++ b/private/csr/server/ppc/sources @@ -0,0 +1,2 @@ +PPC_LNKFLAGS=-stack:65536,8192 + diff --git a/private/csr/server/process.c b/private/csr/server/process.c new file mode 100644 index 000000000..2de0c513a --- /dev/null +++ b/private/csr/server/process.c @@ -0,0 +1,2002 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + process.c + +Abstract: + + This module contains the worker routines called to create and + maintain the application process structure for the Client-Server + Runtime Subsystem to the Session Manager SubSystem. + +Author: + + Steve Wood (stevewo) 10-Oct-1990 + +Revision History: + +--*/ + + +#include "csrsrv.h" + +// ProcessSequenceCount will never be a value less than FIRST_SEQUENCE_COUNT +// currently GDI needs 0 - 4 to be reserved. + +ULONG ProcessSequenceCount = FIRST_SEQUENCE_COUNT; + + +#define THREAD_HASH_SIZE 256 +#define THREAD_ID_TO_HASH(id) ((ULONG)(id)&(THREAD_HASH_SIZE-1)) +LIST_ENTRY CsrThreadHashTable[THREAD_HASH_SIZE]; + +LIST_ENTRY CsrZombieThreadList; + + +SECURITY_QUALITY_OF_SERVICE CsrSecurityQos = { + sizeof(SECURITY_QUALITY_OF_SERVICE), SecurityImpersonation, + SECURITY_DYNAMIC_TRACKING, FALSE +}; + +PCSR_PROCESS +FindProcessForShutdown( + PLUID CallerLuid + ); + +VOID +CsrpSetToNormalPriority( + VOID + ) +{ + + KPRIORITY SetBasePriority; + + SetBasePriority = FOREGROUND_BASE_PRIORITY + 4; + NtSetInformationProcess( + NtCurrentProcess(), + ProcessBasePriority, + (PVOID) &SetBasePriority, + sizeof(SetBasePriority) + ); +} + +VOID +CsrpSetToShutdownPriority( + VOID + ) +{ + + KPRIORITY SetBasePriority; + + SetBasePriority = FOREGROUND_BASE_PRIORITY + 6; + NtSetInformationProcess( + NtCurrentProcess(), + ProcessBasePriority, + (PVOID) &SetBasePriority, + sizeof(SetBasePriority) + ); +} + +VOID +CsrpComputePriority( + IN ULONG PriorityClass, + OUT PUCHAR ProcessPriorityClass + ) +{ + if ( PriorityClass & CSR_NORMAL_PRIORITY_CLASS ) { + *ProcessPriorityClass = PROCESS_PRIORITY_CLASS_NORMAL; + } + else if ( PriorityClass & CSR_IDLE_PRIORITY_CLASS ) { + *ProcessPriorityClass = PROCESS_PRIORITY_CLASS_IDLE; + } + else if ( PriorityClass & CSR_HIGH_PRIORITY_CLASS ) { + *ProcessPriorityClass = PROCESS_PRIORITY_CLASS_HIGH; + } + else if ( PriorityClass & CSR_REALTIME_PRIORITY_CLASS ) { + *ProcessPriorityClass = PROCESS_PRIORITY_CLASS_REALTIME; + } + else { + *ProcessPriorityClass = PROCESS_PRIORITY_CLASS_NORMAL; + } +} + +ULONG +CsrComputePriorityClass( + IN PCSR_PROCESS Process + ) +{ + ULONG ReturnValue; + + if ( Process->PriorityClass == PROCESS_PRIORITY_CLASS_NORMAL ) { + ReturnValue = CSR_NORMAL_PRIORITY_CLASS; + } + else if ( Process->PriorityClass == PROCESS_PRIORITY_CLASS_IDLE ) { + ReturnValue = CSR_IDLE_PRIORITY_CLASS; + } + else if ( Process->PriorityClass == PROCESS_PRIORITY_CLASS_HIGH ) { + ReturnValue = CSR_HIGH_PRIORITY_CLASS; + } + else if ( Process->PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME ) { + ReturnValue = CSR_REALTIME_PRIORITY_CLASS; + } + else { + ReturnValue = 0; + } + return ReturnValue; +} +VOID +CsrSetForegroundPriority( + IN PCSR_PROCESS Process + ) +{ + PROCESS_PRIORITY_CLASS PriorityClass; + + // + // priority seperation is set 0, 1, 2 as the process + // + + if ( (ULONG)Process <= 2 ) { + ULONG PrioritySeperation; + + PrioritySeperation = (ULONG)Process; + NtSetSystemInformation( + SystemPrioritySeperation, + &PrioritySeperation, + sizeof(ULONG) + ); + return; + } + + PriorityClass.Foreground = TRUE; + PriorityClass.PriorityClass = Process->PriorityClass; + + NtSetInformationProcess( + Process->ProcessHandle, + ProcessPriorityClass, + (PVOID)&PriorityClass, + sizeof(PriorityClass) + ); +} + +VOID +CsrSetBackgroundPriority( + IN PCSR_PROCESS Process + ) +{ + PROCESS_PRIORITY_CLASS PriorityClass; + + PriorityClass.Foreground = FALSE; + PriorityClass.PriorityClass = Process->PriorityClass; + + NtSetInformationProcess( + Process->ProcessHandle, + ProcessPriorityClass, + (PVOID)&PriorityClass, + sizeof(PriorityClass) + ); +} + + +NTSTATUS +CsrInitializeProcessStructure( VOID ) +{ + NTSTATUS Status; + ULONG i; + + Status = RtlInitializeCriticalSection( &CsrProcessStructureLock ); + ASSERT( NT_SUCCESS( Status ) ); + + CsrRootProcess = NULL; + CsrRootProcess = CsrAllocateProcess(); + ASSERT( CsrRootProcess != NULL ); + InitializeListHead( &CsrRootProcess->ListLink ); + CsrRootProcess->ProcessHandle = (HANDLE)0xFFFFFFFF; + CsrRootProcess->ClientId = NtCurrentTeb()->ClientId; + for ( i=0; i<THREAD_HASH_SIZE; i++ ) { + InitializeListHead(&CsrThreadHashTable[i]); + } + InitializeListHead(&CsrZombieThreadList); + Status = RtlInitializeCriticalSection( &CsrWaitListsLock ); + ASSERT( NT_SUCCESS( Status ) ); + + return( Status ); +} + + +PCSR_PROCESS +CsrAllocateProcess( VOID ) +{ + PCSR_PROCESS Process; + ULONG ProcessSize; + + // + // Allocate an Windows Process Object. At the end of the process + // structure is an array of pointers to each server DLL's per process + // data. The per process data is contained in the memory after the + // array. + // + + ProcessSize = QUAD_ALIGN(sizeof( CSR_PROCESS ) + + (CSR_MAX_SERVER_DLL * sizeof(PVOID))) + CsrTotalPerProcessDataLength; + Process = (PCSR_PROCESS)RtlAllocateHeap( CsrHeap, MAKE_TAG( PROCESS_TAG ), + ProcessSize + ); + ASSERT( Process != NULL ); + if (Process == NULL) { + return( NULL ); + } + + // + // Initialize the fields of the process object + // + + RtlZeroMemory( Process, ProcessSize); + + // + // grab the ProcessSequenceNumber and increment it, making sure that it + // is never less than FIRST_SEQUENCE_COUNT. + // + + Process->SequenceNumber = ProcessSequenceCount++; + + if (ProcessSequenceCount < FIRST_SEQUENCE_COUNT) + ProcessSequenceCount = FIRST_SEQUENCE_COUNT; + + Process->PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL; + + CsrLockedReferenceProcess(Process); + + InitializeListHead( &Process->ThreadList ); + return( Process ); +} + + +VOID +CsrDeallocateProcess( + IN PCSR_PROCESS Process + ) +{ + RtlFreeHeap( CsrHeap, 0, Process ); +} + +VOID +CsrInsertProcess( + IN PCSR_PROCESS ParentProcess, + IN PCSR_PROCESS CallingProcess, + IN PCSR_PROCESS Process + ) +// NOTE: the process structure lock must be held when calling this routine +{ + PCSR_SERVER_DLL LoadedServerDll; + ULONG i; + + Process->Parent = ParentProcess; + InsertTailList( &CsrRootProcess->ListLink, &Process->ListLink ); + + for (i=0; i<CSR_MAX_SERVER_DLL; i++) { + LoadedServerDll = CsrLoadedServerDll[ i ]; + if (LoadedServerDll && LoadedServerDll->AddProcessRoutine) { + (*LoadedServerDll->AddProcessRoutine)( CallingProcess, Process ); + } + } +} + + +VOID +CsrRemoveProcess( + IN PCSR_PROCESS Process + ) +// NOTE: the process structure lock must be held when calling this routine +{ + PCSR_SERVER_DLL LoadedServerDll; + ULONG i; + + RemoveEntryList( &Process->ListLink ); + ReleaseProcessStructureLock(); + + for (i=0; i<CSR_MAX_SERVER_DLL; i++) { + LoadedServerDll = CsrLoadedServerDll[ i ]; + if (LoadedServerDll && LoadedServerDll->DisconnectRoutine) { + (LoadedServerDll->DisconnectRoutine)( Process ); + } + } + +} + +NTSTATUS +CsrSetProcessContext( + IN PCSR_PROCESS Process, + IN PCSR_THREAD Thread, + IN BOOLEAN StartedBySm + ) +{ +#if 0 + Process->InitialPebCsrData.Length = sizeof( Process->InitialPebCsrData ); + Process->InitialPebCsrData.StartedBySm = StartedBySm; +#endif + + return( STATUS_SUCCESS ); +} + +NTSTATUS +CsrCreateProcess( + IN HANDLE ProcessHandle, + IN HANDLE ThreadHandle, + IN PCLIENT_ID ClientId, + IN PCSR_NT_SESSION Session, + IN ULONG DebugFlags, + IN PCLIENT_ID DebugUserInterface OPTIONAL + ) +{ + PCSR_PROCESS Process; + PCSR_THREAD Thread; + NTSTATUS Status; + ULONG i; + PVOID ProcessDataPtr; + CLIENT_ID CallingClientId; + PCSR_THREAD CallingThread; + PCSR_PROCESS CallingProcess; + KERNEL_USER_TIMES TimeInfo; + + CallingThread = CSR_SERVER_QUERYCLIENTTHREAD(); + + // + // remember the client id of the calling process. + // + + CallingClientId = CallingThread->ClientId; + + AcquireProcessStructureLock(); + + // + // look for calling thread. + // + + CallingThread = CsrLocateThreadByClientId( &CallingProcess, + &CallingClientId + ); + if (CallingThread == NULL) { + ReleaseProcessStructureLock(); + return STATUS_THREAD_IS_TERMINATING; + } + + Process = CsrAllocateProcess(); + if (Process == NULL) { + Status = STATUS_NO_MEMORY; + ReleaseProcessStructureLock(); + return( Status ); + } + + // + // copy per-process data from parent to child + // + + CallingProcess = (CSR_SERVER_QUERYCLIENTTHREAD())->Process; + ProcessDataPtr = (PVOID)QUAD_ALIGN(&Process->ServerDllPerProcessData[CSR_MAX_SERVER_DLL]); + for (i=0; i<CSR_MAX_SERVER_DLL; i++) { + if (CsrLoadedServerDll[i] != NULL && CsrLoadedServerDll[i]->PerProcessDataLength) { + Process->ServerDllPerProcessData[i] = ProcessDataPtr; + RtlMoveMemory(ProcessDataPtr, + CallingProcess->ServerDllPerProcessData[i], + CsrLoadedServerDll[i]->PerProcessDataLength + ); + ProcessDataPtr = (PVOID)QUAD_ALIGN((ULONG)ProcessDataPtr + CsrLoadedServerDll[i]->PerProcessDataLength); + } + else { + Process->ServerDllPerProcessData[i] = NULL; + } + } + + Status = NtSetInformationProcess( + ProcessHandle, + ProcessExceptionPort, + (PVOID)&CsrApiPort, + sizeof(HANDLE) + ); + if ( !NT_SUCCESS(Status) ) { + CsrDeallocateProcess( Process ); + ReleaseProcessStructureLock(); + return( STATUS_NO_MEMORY ); + } + ASSERT(NT_SUCCESS(Status)); + + CsrpComputePriority( + DebugFlags, + &Process->PriorityClass + ); + + // + // If we are creating a process group, the group leader has the same + // process id and sequence number of itself. If the leader dies and + // his pid is recycled, the sequence number mismatch will prevent it + // from being viewed as a group leader. + // + + if ( DebugFlags & CSR_CREATE_PROCESS_GROUP ) { + Process->ProcessGroupId = (ULONG)ClientId->UniqueProcess; + Process->ProcessGroupSequence = Process->SequenceNumber; + } + else { + Process->ProcessGroupId = CallingProcess->ProcessGroupId; + Process->ProcessGroupSequence = CallingProcess->ProcessGroupSequence; + } + + if ( DebugFlags & CSR_PROCESS_CONSOLEAPP ) { + Process->Flags |= CSR_PROCESS_CONSOLEAPP; + } + + DebugFlags &= ~(CSR_PROCESS_CONSOLEAPP | CSR_NORMAL_PRIORITY_CLASS|CSR_IDLE_PRIORITY_CLASS|CSR_HIGH_PRIORITY_CLASS|CSR_REALTIME_PRIORITY_CLASS|CSR_CREATE_PROCESS_GROUP); + + if ( !DebugFlags && CallingProcess->DebugFlags & CSR_DEBUG_PROCESS_TREE ) { + Process->DebugFlags = CSR_DEBUG_PROCESS_TREE; + Process->DebugUserInterface = CallingProcess->DebugUserInterface; + } + if ( DebugFlags & (CSR_DEBUG_THIS_PROCESS | CSR_DEBUG_PROCESS_TREE) && + ARGUMENT_PRESENT(DebugUserInterface) ) { + Process->DebugFlags = DebugFlags; + Process->DebugUserInterface = *DebugUserInterface; + } + + + if ( Process->DebugFlags ) { + + // + // Process is being debugged, so set up debug port + // + + Status = NtSetInformationProcess( + ProcessHandle, + ProcessDebugPort, + (PVOID)&CsrApiPort, + sizeof(HANDLE) + ); + ASSERT(NT_SUCCESS(Status)); + if ( !NT_SUCCESS(Status) ) { + CsrDeallocateProcess( Process ); + ReleaseProcessStructureLock(); + return( STATUS_NO_MEMORY ); + } + } + // + // capture the thread's createtime so that we can use + // this as a sequence number + // + + Status = NtQueryInformationThread( + ThreadHandle, + ThreadTimes, + (PVOID)&TimeInfo, + sizeof(TimeInfo), + NULL + ); + if ( !NT_SUCCESS(Status) ) { + CsrDeallocateProcess( Process ); + ReleaseProcessStructureLock(); + return( Status ); + } + + Thread = CsrAllocateThread( Process ); + if (Thread == NULL) { + CsrDeallocateProcess( Process ); + ReleaseProcessStructureLock(); + return( STATUS_NO_MEMORY ); + } + + CsrInitializeThreadData(Thread, CSR_SERVER_QUERYCLIENTTHREAD()); + + Thread->CreateTime = TimeInfo.CreateTime; + + Thread->ClientId = *ClientId; + Thread->ThreadHandle = ThreadHandle; + +ProtectHandle(ThreadHandle); + + Thread->Flags = 0; + CsrInsertThread( Process, Thread ); + + CsrReferenceNtSession(Session); + Process->NtSession = Session; + + Process->ClientId = *ClientId; + Process->ProcessHandle = ProcessHandle; + + CsrSetBackgroundPriority(Process); + + Process->ShutdownLevel = 0x00000280; + + CsrInsertProcess( NULL, (CSR_SERVER_QUERYCLIENTTHREAD())->Process, Process ); + ReleaseProcessStructureLock(); + return STATUS_SUCCESS; +} + + +NTSTATUS +CsrDestroyProcess( + IN PCLIENT_ID ClientId, + IN NTSTATUS ExitStatus + ) +{ + PLIST_ENTRY ListHead, ListNext; + PCSR_THREAD DyingThread; + PCSR_PROCESS DyingProcess; + + CLIENT_ID DyingClientId; + + DyingClientId = *ClientId; + + AcquireProcessStructureLock(); + + + DyingThread = CsrLocateThreadByClientId( &DyingProcess, + &DyingClientId + ); + if (DyingThread == NULL) { + ReleaseProcessStructureLock(); + return STATUS_THREAD_IS_TERMINATING; + } + + // + // prevent multiple destroys from causing problems. Scottlu and Markl + // beleive all known race conditions are now fixed. This is simply a + // precaution since we know that if this happens we process reference + // count underflow + // + + if ( DyingProcess->Flags & CSR_PROCESS_DESTROYED ) { + ReleaseProcessStructureLock(); + return STATUS_THREAD_IS_TERMINATING; + } + + DyingProcess->Flags |= CSR_PROCESS_DESTROYED; + + ListHead = &DyingProcess->ThreadList; + ListNext = ListHead->Flink; + while (ListNext != ListHead) { + DyingThread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link ); + ListNext = ListNext->Flink; + if ( DyingThread->Flags & CSR_THREAD_DESTROYED ) { + continue; + } + else { + DyingThread->Flags |= CSR_THREAD_DESTROYED; + } + AcquireWaitListsLock(); + if (DyingThread->WaitBlock != NULL) { + CsrNotifyWaitBlock(DyingThread->WaitBlock, + NULL, + NULL, + NULL, + CSR_PROCESS_TERMINATING, + TRUE + ); + } + ReleaseWaitListsLock(); + CsrLockedDereferenceThread(DyingThread); + } + + ReleaseProcessStructureLock(); + return STATUS_SUCCESS; +} + + +NTSTATUS +CsrCreateThread( + IN PCSR_PROCESS Process, + IN HANDLE ThreadHandle, + IN PCLIENT_ID ClientId + ) +{ + PCSR_THREAD Thread; + CLIENT_ID CallingClientId; + PCSR_THREAD CallingThread; + PCSR_PROCESS CallingProcess; + KERNEL_USER_TIMES TimeInfo; + NTSTATUS Status; + + CallingThread = CSR_SERVER_QUERYCLIENTTHREAD(); + + // + // remember the client id of the calling process. + // + + CallingClientId = CallingThread->ClientId; + + AcquireProcessStructureLock(); + + // + // look for calling thread. + // + + CallingThread = CsrLocateThreadByClientId( &CallingProcess, + &CallingClientId + ); + if (CallingThread == NULL) { + ReleaseProcessStructureLock(); + return STATUS_THREAD_IS_TERMINATING; + } + + Status = NtQueryInformationThread( + ThreadHandle, + ThreadTimes, + (PVOID)&TimeInfo, + sizeof(TimeInfo), + NULL + ); + if ( !NT_SUCCESS(Status) ) { + ReleaseProcessStructureLock(); + return( Status ); + } + + Thread = CsrAllocateThread( Process ); + if (Thread == NULL) { + ReleaseProcessStructureLock(); + return( STATUS_NO_MEMORY ); + } + + CsrInitializeThreadData(Thread, CallingThread); + + Thread->CreateTime = TimeInfo.CreateTime; + + Thread->ClientId = *ClientId; + Thread->ThreadHandle = ThreadHandle; + +ProtectHandle(ThreadHandle); + + Thread->Flags = 0; + CsrInsertThread( Process, Thread ); + ReleaseProcessStructureLock(); + return STATUS_SUCCESS; +} + +NTSTATUS +CsrCreateRemoteThread( + IN HANDLE ThreadHandle, + IN PCLIENT_ID ClientId + ) +{ + PCSR_THREAD Thread; + PCSR_PROCESS Process; + NTSTATUS Status; + HANDLE hThread; + KERNEL_USER_TIMES TimeInfo; + + Status = NtQueryInformationThread( + ThreadHandle, + ThreadTimes, + (PVOID)&TimeInfo, + sizeof(TimeInfo), + NULL + ); + if ( !NT_SUCCESS(Status) ) { + return( Status ); + } + + Status = CsrLockProcessByClientId( ClientId->UniqueProcess, + &Process + ); + if (!NT_SUCCESS( Status )) { + return( Status ); + } + + // + // Don't create the thread structure if the thread + // has already terminated. + // + + if ( TimeInfo.ExitTime.QuadPart != 0 ) { + CsrUnlockProcess( Process ); + return( STATUS_THREAD_IS_TERMINATING ); + } + + Thread = CsrAllocateThread( Process ); + if (Thread == NULL) { + CsrUnlockProcess( Process ); + return( STATUS_NO_MEMORY ); + } + Status = NtDuplicateObject( + NtCurrentProcess(), + ThreadHandle, + NtCurrentProcess(), + &hThread, + 0L, + 0L, + DUPLICATE_SAME_ACCESS + ); + if (!NT_SUCCESS(Status)) { + hThread = ThreadHandle; + } + + CsrInitializeThreadData(Thread, NULL); + + Thread->CreateTime = TimeInfo.CreateTime; + + Thread->ClientId = *ClientId; + Thread->ThreadHandle = hThread; + +ProtectHandle(hThread); + + Thread->Flags = 0; + CsrInsertThread( Process, Thread ); + CsrUnlockProcess( Process ); + return STATUS_SUCCESS; +} + + +NTSTATUS +CsrDestroyThread( + IN PCLIENT_ID ClientId + ) +{ + CLIENT_ID DyingClientId; + PCSR_THREAD DyingThread; + PCSR_PROCESS DyingProcess; + + DyingClientId = *ClientId; + + AcquireProcessStructureLock(); + + DyingThread = CsrLocateThreadByClientId( &DyingProcess, + &DyingClientId + ); + if (DyingThread == NULL) { + ReleaseProcessStructureLock(); + return STATUS_THREAD_IS_TERMINATING; + } + + if ( DyingThread->Flags & CSR_THREAD_DESTROYED ) { + ReleaseProcessStructureLock(); + return STATUS_THREAD_IS_TERMINATING; + } + else { + DyingThread->Flags |= CSR_THREAD_DESTROYED; + } + + AcquireWaitListsLock(); + if (DyingThread->WaitBlock != NULL) { + CsrNotifyWaitBlock(DyingThread->WaitBlock, + NULL, + NULL, + NULL, + CSR_PROCESS_TERMINATING, + TRUE + ); + } + ReleaseWaitListsLock(); + CsrLockedDereferenceThread(DyingThread); + + ReleaseProcessStructureLock(); + return STATUS_SUCCESS; +} + + +PCSR_THREAD +CsrAllocateThread( + IN PCSR_PROCESS Process + ) +{ + PCSR_THREAD Thread; + ULONG ThreadSize; + + // + // Allocate an Windows Thread Object. At the end of the thread + // structure is an array of pointers to each server DLL's per thread + // data. The per thread data is contained in the memory after the + // array. + // + // + + ThreadSize = QUAD_ALIGN(sizeof( CSR_THREAD ) + + (CSR_MAX_SERVER_DLL * sizeof(PVOID))) + CsrTotalPerThreadDataLength; + Thread = (PCSR_THREAD)RtlAllocateHeap( CsrHeap, MAKE_TAG( PROCESS_TAG ), + ThreadSize + ); + if (Thread == NULL) { + return( NULL ); + } + + // + // Initialize the fields of the thread object + // + + RtlZeroMemory( Thread, ThreadSize ); + + CsrLockedReferenceThread(Thread); + CsrLockedReferenceProcess(Process); + Thread->Process = Process; + + return( Thread ); +} + + +VOID +CsrDeallocateThread( + IN PCSR_THREAD Thread + ) +{ + ASSERT (Thread->WaitBlock == NULL); + RtlFreeHeap( CsrHeap, 0, Thread ); +} + + +VOID +CsrInitializeThreadData( + IN PCSR_THREAD Thread, + IN PCSR_THREAD CallingThread + ) +{ + PVOID ThreadDataPtr; + ULONG i; + + // + // if there is a parent, copy per-thread data from parent to child + // + + ThreadDataPtr = (PVOID)QUAD_ALIGN(&Thread->ServerDllPerThreadData[CSR_MAX_SERVER_DLL]); + for (i=0; i<CSR_MAX_SERVER_DLL; i++) { + if (CsrLoadedServerDll[i] != NULL && CsrLoadedServerDll[i]->PerThreadDataLength) { + Thread->ServerDllPerThreadData[i] = ThreadDataPtr; + if (CallingThread) { + RtlMoveMemory(ThreadDataPtr, + CallingThread->ServerDllPerThreadData[i], + CsrLoadedServerDll[i]->PerThreadDataLength + ); + } + ThreadDataPtr = (PVOID)QUAD_ALIGN((ULONG)ThreadDataPtr + CsrLoadedServerDll[i]->PerThreadDataLength); + } + else { + Thread->ServerDllPerThreadData[i] = NULL; + } + } +} + +VOID +CsrInsertThread( + IN PCSR_PROCESS Process, + IN PCSR_THREAD Thread + ) + +// NOTE: the process structure lock must be held exclusively while calling this routine + +{ + PCSR_SERVER_DLL LoadedServerDll; + ULONG i; + + InsertTailList( &Process->ThreadList, &Thread->Link ); + Process->ThreadCount++; + i = THREAD_ID_TO_HASH(Thread->ClientId.UniqueThread); + InsertHeadList( &CsrThreadHashTable[i], &Thread->HashLinks); + for (i=0; i<CSR_MAX_SERVER_DLL; i++) { + LoadedServerDll = CsrLoadedServerDll[ i ]; + if (LoadedServerDll && LoadedServerDll->AddThreadRoutine) { + (*LoadedServerDll->AddThreadRoutine)( Thread ); + } + } +} + +VOID +CsrRemoveThread( + IN PCSR_THREAD Thread + ) + + +{ + PCSR_SERVER_DLL LoadedServerDll; + ULONG i; + + RemoveEntryList( &Thread->Link ); + Thread->Process->ThreadCount--; + if (Thread->HashLinks.Flink) + RemoveEntryList( &Thread->HashLinks ); + + // + // if this is the last thread, then make sure we undo the reference + // that this thread had on the process. + // + + if ( Thread->Process->ThreadCount == 0 ) { + if ( !(Thread->Process->Flags & CSR_PROCESS_LASTTHREADOK) ) { + Thread->Process->Flags |= CSR_PROCESS_LASTTHREADOK; + CsrLockedDereferenceProcess(Thread->Process); + } + } + + // + // Set the termination thread *before* calling the delete thread routines + // in each server .dll. Need to set this ahead of time because USER looks + // at this flag from the context of a thread that gets woken up by this + // thread while calling DeleteThreadRoutine. + // + + Thread->Flags |= CSR_THREAD_TERMINATING; + + // + // Set the reference count before the structure lock is released. + // This will prevent gui threads from deleting the thread + // structure during cleanup. + // + + Thread->ReferenceCount = 1; + + ReleaseProcessStructureLock(); + + for (i=0; i<CSR_MAX_SERVER_DLL; i++) { + LoadedServerDll = CsrLoadedServerDll[ i ]; + if (LoadedServerDll && LoadedServerDll->DeleteThreadRoutine) { + + (*LoadedServerDll->DeleteThreadRoutine)( Thread ); + } + } + + // + // Reset the refcount so gui threads can free the thread structure. + // + + AcquireProcessStructureLock(); + Thread->ReferenceCount = 0; +} + + +NTSTATUS +CsrLockProcessByClientId( + IN HANDLE UniqueProcessId, + OUT PCSR_PROCESS *Process + ) +{ + NTSTATUS Status; + PLIST_ENTRY ListHead, ListNext; + PCSR_PROCESS ProcessPtr; + + + AcquireProcessStructureLock(); + + if (ARGUMENT_PRESENT(Process)) { + *Process = NULL; + } + + Status = STATUS_UNSUCCESSFUL; + ListHead = &CsrRootProcess->ListLink; + ListNext = ListHead; + do { + ProcessPtr = CONTAINING_RECORD( ListNext, CSR_PROCESS, ListLink ); + if (ProcessPtr->ClientId.UniqueProcess == UniqueProcessId) { + Status = STATUS_SUCCESS; + break; + } + ListNext = ListNext->Flink; + } while (ListNext != ListHead); + + if (NT_SUCCESS( Status )) { + CsrLockedReferenceProcess(ProcessPtr); + *Process = ProcessPtr; + } + else { + ReleaseProcessStructureLock(); + } + + return( Status ); +} + +NTSTATUS +CsrUnlockProcess( + IN PCSR_PROCESS Process + ) +{ + CsrLockedDereferenceProcess( Process ); + ReleaseProcessStructureLock(); + return( STATUS_SUCCESS ); +} + +NTSTATUS +CsrLockThreadByClientId( + IN HANDLE UniqueThreadId, + OUT PCSR_THREAD *Thread + ) +{ + NTSTATUS Status; + ULONG Index; + PLIST_ENTRY ListHead, ListNext; + PCSR_THREAD ThreadPtr; + CLIENT_ID ClientId; + + AcquireProcessStructureLock(); + + if (ARGUMENT_PRESENT(Thread)) { + *Thread = NULL; + } + + Index = THREAD_ID_TO_HASH(UniqueThreadId); + + ListHead = &CsrThreadHashTable[Index]; + ListNext = ListHead->Flink; + while (ListNext != ListHead) { + ThreadPtr = CONTAINING_RECORD( ListNext, CSR_THREAD, HashLinks ); + if ( ThreadPtr->ClientId.UniqueThread == UniqueThreadId && + !(ThreadPtr->Flags & CSR_THREAD_DESTROYED) ) { + break; + } + ListNext = ListNext->Flink; + } + if (ListNext == ListHead) + ThreadPtr = NULL; + + if (ThreadPtr != NULL) { + Status = STATUS_SUCCESS; + CsrLockedReferenceThread(ThreadPtr); + *Thread = ThreadPtr; + } + else { + Status = STATUS_UNSUCCESSFUL; + ReleaseProcessStructureLock(); + } + + return( Status ); +} + +NTSTATUS +CsrUnlockThread( + IN PCSR_THREAD Thread + ) +{ + CsrLockedDereferenceThread( Thread ); + ReleaseProcessStructureLock(); + return( STATUS_SUCCESS ); +} + +PCSR_THREAD +CsrLocateThreadByClientId( + OUT PCSR_PROCESS *Process OPTIONAL, + IN PCLIENT_ID ClientId + ) + +// NOTE: process structure lock must be held while calling this routine + +{ + ULONG Index; + PLIST_ENTRY ListHead, ListNext; + PCSR_THREAD Thread; + + Index = THREAD_ID_TO_HASH(ClientId->UniqueThread); + + if (ARGUMENT_PRESENT(Process)) { + *Process = NULL; + } + ListHead = &CsrThreadHashTable[Index]; + ListNext = ListHead->Flink; + while (ListNext != ListHead) { + Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, HashLinks ); + if ( Thread->ClientId.UniqueThread == ClientId->UniqueThread && + Thread->ClientId.UniqueProcess == ClientId->UniqueProcess ) { + if (ARGUMENT_PRESENT(Process)) { + *Process = Thread->Process; + } + return Thread; + } + ListNext = ListNext->Flink; + } + return NULL; +} + +PCSR_THREAD +CsrLocateThreadInProcess( + IN PCSR_PROCESS Process OPTIONAL, + IN PCLIENT_ID ClientId + ) + +// NOTE: process structure lock must be held while calling this routine + +{ + PLIST_ENTRY ListHead, ListNext; + PCSR_THREAD Thread; + + if (Process == NULL) + Process = CsrRootProcess; + + ListHead = &Process->ThreadList; + ListNext = ListHead->Flink; + while (ListNext != ListHead) { + Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link ); + if (Thread->ClientId.UniqueThread == ClientId->UniqueThread) { + return( Thread ); + } + + ListNext = ListNext->Flink; + } + + return( NULL ); +} + +BOOLEAN +CsrImpersonateClient( + IN PCSR_THREAD Thread + ) +{ + NTSTATUS Status; + PCSR_THREAD CallingThread; + + CallingThread = CSR_SERVER_QUERYCLIENTTHREAD(); + + if (Thread == NULL) { + Thread = CallingThread; + } + + if (Thread == NULL) { + return FALSE; + } + + if (!NT_SUCCESS(Status = NtImpersonateThread(NtCurrentThread(), + Thread->ThreadHandle, &CsrSecurityQos))) { + IF_DEBUG { + DbgPrint( "CSRSS: Can't impersonate client thread - Status = %lx\n", + Status + ); + if (Status != STATUS_BAD_IMPERSONATION_LEVEL) + DbgBreakPoint(); + } + return FALSE; + } + + // + // Keep track of recursion by printer drivers + // + + if (CallingThread != NULL) + ++CallingThread->ImpersonateCount; + + return TRUE; +} + +BOOLEAN +CsrRevertToSelf( VOID ) +{ + HANDLE NewToken; + NTSTATUS Status; + PCSR_THREAD CallingThread; + + CallingThread = CSR_SERVER_QUERYCLIENTTHREAD(); + + // + // Keep track of recursion by printer drivers + // + + if (CallingThread != NULL) { + if (CallingThread->ImpersonateCount == 0) { + IF_DEBUG { + DbgPrint( "CSRSS: CsrRevertToSelf called while not impersonating\n" ); + DbgBreakPoint(); + } + return FALSE; + } + if (--CallingThread->ImpersonateCount > 0) + return TRUE; + } + + NewToken = NULL; + Status = NtSetInformationThread( + NtCurrentThread(), + ThreadImpersonationToken, + (PVOID)&NewToken, + (ULONG)sizeof(HANDLE) + ); + ASSERT( NT_SUCCESS(Status) ); + + return NT_SUCCESS(Status); +} + +NTSTATUS +CsrUiLookup( + IN PCLIENT_ID AppClientId, + OUT PCLIENT_ID DebugUiClientId + ) +{ + PCSR_THREAD Thread; + NTSTATUS Status; + + Status = STATUS_UNSUCCESSFUL; + AcquireProcessStructureLock(); + Thread = CsrLocateThreadByClientId( NULL, AppClientId ); + if ( Thread ) { + if ( Thread->Process->DebugFlags ) { + *DebugUiClientId = Thread->Process->DebugUserInterface; + Status = STATUS_SUCCESS; + } + } +#if DEVL + else { + extern PCSR_PROCESS CsrDebugProcessPtr; + + if (AppClientId->UniqueProcess == + NtCurrentTeb()->ClientId.UniqueProcess && + CsrDebugProcessPtr && CsrDebugProcessPtr != (PCSR_PROCESS)-1) { + *DebugUiClientId = CsrDebugProcessPtr->DebugUserInterface; + Status = STATUS_SUCCESS; + } + } +#endif // DEVL + ReleaseProcessStructureLock(); + return Status; +} + +PVOID +CsrAddStaticServerThread( + IN HANDLE ThreadHandle, + IN PCLIENT_ID ClientId, + IN ULONG Flags + ) + +/*++ + +Routine Description: + + This function must be called by client DLL's whenever they create a + thread that runs in the context of CSR. This function is not called + for server threads that are attached to a client in the "server + handle" field. This function replaces the old static thread tables. + +Arguments: + + ThreadHandle - Supplies a handle to the thread. + + ClientId - Supplies the address of the thread's client id. + + Flags - Not Used. + +Return Value: + + Returns the address of the static server thread created by this + function. + +--*/ + +{ + PCSR_THREAD Thread; + + ASSERT(CsrRootProcess != NULL); + AcquireProcessStructureLock(); + Thread = CsrAllocateThread(CsrRootProcess); + if ( Thread ) { + + CsrInitializeThreadData(Thread, NULL); + + Thread->ThreadHandle = ThreadHandle; + +ProtectHandle(ThreadHandle); + + Thread->ClientId = *ClientId; + Thread->Flags = Flags; + InsertTailList(&CsrRootProcess->ThreadList, &Thread->Link); + CsrRootProcess->ThreadCount++; + } + ReleaseProcessStructureLock(); + return (PVOID)Thread; +} + +NTSTATUS +CsrSrvIdentifyAlertableThread( + IN OUT PCSR_API_MSG m, + IN OUT PCSR_REPLY_STATUS ReplyStatus + ) +{ + PCSR_THREAD t; + + t = CSR_SERVER_QUERYCLIENTTHREAD(); + t->Flags |= CSR_ALERTABLE_THREAD; + return STATUS_SUCCESS; + m;ReplyStatus; // get rid of unreferenced parameter warning message +} + + +NTSTATUS +CsrSrvSetPriorityClass( + IN OUT PCSR_API_MSG m, + IN OUT PCSR_REPLY_STATUS ReplyStatus + ) +{ + NTSTATUS Status; + PCSR_SETPRIORITY_CLASS_MSG a = (PCSR_SETPRIORITY_CLASS_MSG)&m->u.ApiMessageData; + HANDLE TargetProcess; + PCSR_THREAD t; + PROCESS_BASIC_INFORMATION BasicInfo; + PLIST_ENTRY ListHead, ListNext; + PCSR_PROCESS ProcessPtr; + KPRIORITY ForegroundPriority,BackgroundPriority; + PROCESS_PRIORITY_CLASS PriorityClass; + + t = CSR_SERVER_QUERYCLIENTTHREAD(); + + // + // Get a handle to the process whose priority we are planning to + // change. + // + + Status = NtDuplicateObject( + t->Process->ProcessHandle, + a->ProcessHandle, + NtCurrentProcess(), + &TargetProcess, + 0, + 0, + DUPLICATE_SAME_ACCESS + ); + if ( !NT_SUCCESS(Status) ) { + m->ReturnValue = Status; + return Status; + } + + // + // Now that we have a handle to the process, get its process + // id so we can look it up + // + + Status = NtQueryInformationProcess( + TargetProcess, + ProcessBasicInformation, + (PVOID)&BasicInfo, + sizeof(BasicInfo), + NULL + ); + if ( !NT_SUCCESS(Status) ) { + NtClose(TargetProcess); + m->ReturnValue = Status; + return Status; + } + + // + // The process id is now in hand. Now we have to locate the CSR + // process with this ID. To do this, we need to drop our current + // locks and scan the process table while holding the process + // structure lock + // + + AcquireProcessStructureLock(); + + ListHead = &CsrRootProcess->ListLink; + ListNext = ListHead->Flink; + Status = STATUS_ACCESS_DENIED; + while (ListNext != ListHead) { + ProcessPtr = CONTAINING_RECORD( ListNext, CSR_PROCESS, ListLink ); + if (ProcessPtr->ClientId.UniqueProcess == (HANDLE)BasicInfo.UniqueProcessId) { + + // + // The process was found. Now set or get its priority + // + // I guess we need to know if it is currently in the + // foreground or backgroud ! For now (until I add a CsrSetFg) + // I will just assign it to the background + // + + if ( a->PriorityClass ) { + + // + // Compute the base priorities for the + // process and call NT to set its base. + // + + CsrpComputePriority( + a->PriorityClass, + &PriorityClass.PriorityClass + ); + + PriorityClass.Foreground = FALSE; + + Status = NtSetInformationProcess( + ProcessPtr->ProcessHandle, + ProcessPriorityClass, + (PVOID)&PriorityClass, + sizeof(PriorityClass) + ); + + if ( NT_SUCCESS(Status) ) { + ProcessPtr->PriorityClass = PriorityClass.PriorityClass; + } + } + else { + + // + // We are trying to get the processes priority + // + + a->PriorityClass = CsrComputePriorityClass(ProcessPtr); + if ( a->PriorityClass ) { + Status = STATUS_SUCCESS; + } + } + break; + } + ListNext = ListNext->Flink; + } + + ReleaseProcessStructureLock(); + + NtClose(TargetProcess); + + m->ReturnValue = Status; + return Status; +} + + +VOID +CsrReferenceProcess( + PCSR_PROCESS p + ) +{ + AcquireProcessStructureLock(); + p->ReferenceCount++; + + ReleaseProcessStructureLock(); +} + +VOID +CsrReferenceThread( + PCSR_THREAD t + ) +{ + AcquireProcessStructureLock(); + t->ReferenceCount++; + ReleaseProcessStructureLock(); +} + +VOID +CsrProcessRefcountZero( + PCSR_PROCESS p + ) +{ + CsrRemoveProcess(p); + if (p->NtSession) { + CsrDereferenceNtSession(p->NtSession,0); + } + + // + // process might not have made it through dll init routine. + // + + if ( p->ClientPort ) { + NtClose(p->ClientPort); + } + NtClose(p->ProcessHandle ); + CsrDeallocateProcess(p); +} + +VOID +CsrDereferenceProcess( + PCSR_PROCESS p + ) +{ + LONG LockCount; + AcquireProcessStructureLock(); + + LockCount = --(p->ReferenceCount); + +ASSERT(LockCount >= 0); + if ( !LockCount ) { + CsrProcessRefcountZero(p); + } + else { + ReleaseProcessStructureLock(); + } +} + +VOID +CsrThreadRefcountZero( + PCSR_THREAD t + ) +{ + PCSR_PROCESS p; + NTSTATUS Status; + + p = t->Process; + + CsrRemoveThread(t); + + ReleaseProcessStructureLock(); + +UnProtectHandle(t->ThreadHandle); + Status = NtClose(t->ThreadHandle); + ASSERT(NT_SUCCESS(Status)); + CsrDeallocateThread(t); + + CsrDereferenceProcess(p); +} + +VOID +CsrDereferenceThread( + PCSR_THREAD t + ) +{ + LONG LockCount; + AcquireProcessStructureLock(); + + LockCount = --(t->ReferenceCount); + + ASSERT(LockCount >= 0); + if ( !LockCount ) { + CsrThreadRefcountZero(t); + } + else { + ReleaseProcessStructureLock(); + } +} + +VOID +CsrLockedReferenceProcess( + PCSR_PROCESS p + ) +{ + p->ReferenceCount++; + +} + +VOID +CsrLockedReferenceThread( + PCSR_THREAD t + ) +{ + t->ReferenceCount++; +} + +VOID +CsrLockedDereferenceProcess( + PCSR_PROCESS p + ) +{ + LONG LockCount; + + LockCount = --(p->ReferenceCount); + + ASSERT(LockCount >= 0); + if ( !LockCount ) { + AcquireProcessStructureLock(); + CsrProcessRefcountZero(p); + } +} + +VOID +CsrLockedDereferenceThread( + PCSR_THREAD t + ) +{ + LONG LockCount; + + LockCount = --(t->ReferenceCount); + + ASSERT(LockCount >= 0); + if ( !LockCount ) { + AcquireProcessStructureLock(); + CsrThreadRefcountZero(t); + } +} + +// +// This routine will shutdown processes so either a logoff or a shutdown can +// occur. This simply calls the shutdown process handlers for each .dll until +// one .dll recognizes this process and will shut it down. Only the processes +// with the passed sid are shutdown. +// + +NTSTATUS +CsrShutdownProcesses( + PLUID CallerLuid, + ULONG Flags + ) +{ + PLIST_ENTRY ListHead, ListNext; + PCSR_PROCESS Process; + ULONG i; + PCSR_SERVER_DLL LoadedServerDll; + ULONG Command; + BOOLEAN fFirstPass; + NTSTATUS Status = STATUS_UNSUCCESSFUL; +#ifdef DEVL + BOOLEAN fFindDebugger; + extern BOOLEAN fWin32ServerDebugger; + extern CLIENT_ID ClientIdWin32ServerDebugger; + + // + // Remember if we need to look for a debugger debugging the win32 server. + // We can't close this down because it'll hang the system. + // + fFindDebugger = fWin32ServerDebugger; +#endif // DEVL + + // + // Question: how do we avoid processes starting when we're in shutdown + // mode? Can't just set a global because this'll mean no processes can + // start. Probably need to do it based on the security context of the + // user shutting down. + // + + AcquireProcessStructureLock(); + + // + // Mark the root process as system context. + // + + CsrRootProcess->ShutdownFlags |= SHUTDOWN_SYSTEMCONTEXT; + + // + // Clear all the bits indicating that shutdown has visited this process. + // + + ListHead = &CsrRootProcess->ListLink; + ListNext = ListHead->Flink; + while (ListNext != ListHead) { + Process = CONTAINING_RECORD(ListNext, CSR_PROCESS, ListLink); + Process->Flags &= ~CSR_PROCESS_SHUTDOWNSKIP; + Process->ShutdownFlags = 0; + ListNext = ListNext->Flink; + } + try { + CsrpSetToShutdownPriority(); + while (TRUE) { + + // + // Find the next process to shutdown. + // + + Process = FindProcessForShutdown(CallerLuid); + + if (Process == NULL) { + ReleaseProcessStructureLock(); + Status = STATUS_SUCCESS; + goto ExitLoop; + } + + // + // If this process is debugging the server, don't shut it down or + // else the system will hang. + // +#ifdef DEVL + if (fFindDebugger) { + if (Process->ClientId.UniqueProcess == + ClientIdWin32ServerDebugger.UniqueProcess) { + Process->Flags |= CSR_PROCESS_SHUTDOWNSKIP; + Process->ShutdownFlags |= SHUTDOWN_SYSTEMCONTEXT; + fFindDebugger = FALSE; + continue; + } + } +#endif // DEVL + + CsrLockedReferenceProcess(Process); + + fFirstPass = TRUE; +TryAgain: + for (i=0; i<CSR_MAX_SERVER_DLL; i++) { + LoadedServerDll = CsrLoadedServerDll[ i ]; + if (LoadedServerDll && LoadedServerDll->ShutdownProcessRoutine) { + + // + // Release process structure lock before calling off. + // CSR_PROCESS structure is still reference counted. + // + ReleaseProcessStructureLock(); + Command = (*LoadedServerDll->ShutdownProcessRoutine)( + Process, Flags, fFirstPass); + AcquireProcessStructureLock(); + + if (Command == SHUTDOWN_KNOWN_PROCESS) { + // + // Process structure is unlocked. + // + break; + } + if (Command == SHUTDOWN_UNKNOWN_PROCESS) { + // + // Process structure is locked. + // + continue; + } + if (Command == SHUTDOWN_CANCEL) { +#if DBG + if (Flags & 4) { + DbgPrint("Process %x cancelled forced shutdown (Dll = %d)\n", + Process->ClientId.UniqueProcess, i); + DbgBreakPoint(); + } +#endif + // + // Unlock process structure. + // + ReleaseProcessStructureLock(); + Status = STATUS_CANCELLED; + goto ExitLoop; + } + } + } + + // + // No subsystem has an exact match. Now go through them again and + // let them know there was no exact match. Some .dll should terminate + // it for us (most likely, console). + // + + if (fFirstPass && Command == SHUTDOWN_UNKNOWN_PROCESS) { + fFirstPass = FALSE; + goto TryAgain; + } + + // + // Dereference this process structure if nothing knows about it + // we hit the end of our loop. + // + if (i == CSR_MAX_SERVER_DLL) + CsrLockedDereferenceProcess(Process); + + } +ExitLoop:; + } + finally { + CsrpSetToNormalPriority(); + return Status; + } +} + +PCSR_PROCESS +FindProcessForShutdown( + PLUID CallerLuid + ) +{ + LUID ProcessLuid; + LUID SystemLuid = SYSTEM_LUID; + PLIST_ENTRY ListHead, ListNext; + PCSR_PROCESS Process; + PCSR_PROCESS ProcessT; + PCSR_THREAD Thread; + ULONG dwLevel; + BOOLEAN fEqual; + NTSTATUS Status; + + ProcessT = NULL; + dwLevel = 0; + + ListHead = &CsrRootProcess->ListLink; + ListNext = ListHead->Flink; + while (ListNext != ListHead) { + Process = CONTAINING_RECORD(ListNext, CSR_PROCESS, ListLink); + ListNext = ListNext->Flink; + + // + // If we've visited this process already, then skip it. + // + + if (Process->Flags & CSR_PROCESS_SHUTDOWNSKIP) + continue; + + // + // See if this process is running under the passed sid. If not, mark + // it as visited and continue. + // + + Status = CsrGetProcessLuid(Process->ProcessHandle, &ProcessLuid); + if (Status == STATUS_ACCESS_DENIED && Process->ThreadCount > 0) { + + // + // Impersonate one of the threads and try again. + // + Thread = CONTAINING_RECORD( Process->ThreadList.Flink, + CSR_THREAD, Link ); + if (NT_SUCCESS(CsrImpersonateClient(Thread))) { + Status = CsrGetProcessLuid(NULL, &ProcessLuid); + CsrRevertToSelf(); + } + } + if (!NT_SUCCESS(Status)) { + + // + // We don't have access to this process' luid, so skip it + // + + Process->Flags |= CSR_PROCESS_SHUTDOWNSKIP; + continue; + } + + // + // is it equal to the system context luid? If so, we want to + // remember this because we don't terminate this process: + // we only notify them. + // + + fEqual = RtlEqualLuid(&ProcessLuid,&SystemLuid); + if (fEqual) { + Process->ShutdownFlags |= SHUTDOWN_SYSTEMCONTEXT; + } + + // + // See if this process's luid is the same as the luid we're supposed + // to shut down (CallerSid). + // + + if (!fEqual) { + fEqual = RtlEqualLuid(&ProcessLuid, CallerLuid); + } + + // + // If not equal to either, mark it as such and return + // + + if (!fEqual) { + Process->ShutdownFlags |= SHUTDOWN_OTHERCONTEXT; + } + + if (Process->ShutdownLevel > dwLevel) { + dwLevel = Process->ShutdownLevel; + ProcessT = Process; + } + } + + if (ProcessT != NULL) { + ProcessT->Flags |= CSR_PROCESS_SHUTDOWNSKIP; + return ProcessT; + } + + return NULL; +} + +NTSTATUS +CsrGetProcessLuid( + HANDLE ProcessHandle, + PLUID LuidProcess + ) +{ + HANDLE UserToken = NULL; + PTOKEN_STATISTICS pStats; + ULONG BytesRequired; + NTSTATUS Status, CloseStatus; + + if (ProcessHandle == NULL) { + + // + // Check for a thread token first + // + + Status = NtOpenThreadToken(NtCurrentThread(), TOKEN_QUERY, FALSE, + &UserToken); + + if (!NT_SUCCESS(Status)) { + if (Status != STATUS_NO_TOKEN) + return Status; + + // + // No thread token, go to the process + // + + ProcessHandle = NtCurrentProcess(); + UserToken = NULL; + } + } + + if (UserToken == NULL) { + Status = NtOpenProcessToken(ProcessHandle, TOKEN_QUERY, &UserToken); + if (!NT_SUCCESS(Status)) + return Status; + } + + Status = NtQueryInformationToken( + UserToken, // Handle + TokenStatistics, // TokenInformationClass + NULL, // TokenInformation + 0, // TokenInformationLength + &BytesRequired // ReturnLength + ); + + if (Status != STATUS_BUFFER_TOO_SMALL) { + NtClose(UserToken); + return Status; + } + + // + // Allocate space for the user info + // + + pStats = (PTOKEN_STATISTICS)RtlAllocateHeap(CsrHeap, MAKE_TAG( TMP_TAG ), BytesRequired); + if (pStats == NULL) { + NtClose(UserToken); + return Status; + } + + // + // Read in the user info + // + + Status = NtQueryInformationToken( + UserToken, // Handle + TokenStatistics, // TokenInformationClass + pStats, // TokenInformation + BytesRequired, // TokenInformationLength + &BytesRequired // ReturnLength + ); + + // + // We're finished with the token handle + // + + CloseStatus = NtClose(UserToken); + ASSERT(NT_SUCCESS(CloseStatus)); + + // + // Return the authentication LUID + // + + *LuidProcess = pStats->AuthenticationId; + + RtlFreeHeap(CsrHeap, 0, pStats); + return Status; +} + +VOID +CsrSetCallingSpooler( + BOOLEAN fSet) +{ + + // + // Obsolete function that may be called by third part drivers. + // + return; + + fSet; +} + +#if CSRSS_PROTECT_HANDLES +BOOLEAN +ProtectHandle( + HANDLE hObject + ) +{ + NTSTATUS Status; + OBJECT_HANDLE_FLAG_INFORMATION HandleInfo; + + Status = NtQueryObject( hObject, + ObjectHandleFlagInformation, + &HandleInfo, + sizeof( HandleInfo ), + NULL + ); + if (NT_SUCCESS( Status )) { + HandleInfo.ProtectFromClose = TRUE; + + Status = NtSetInformationObject( hObject, + ObjectHandleFlagInformation, + &HandleInfo, + sizeof( HandleInfo ) + ); + if (NT_SUCCESS( Status )) { + return TRUE; + } + } + + return FALSE; +} + + +BOOLEAN +UnProtectHandle( + HANDLE hObject + ) +{ + NTSTATUS Status; + OBJECT_HANDLE_FLAG_INFORMATION HandleInfo; + + Status = NtQueryObject( hObject, + ObjectHandleFlagInformation, + &HandleInfo, + sizeof( HandleInfo ), + NULL + ); + if (NT_SUCCESS( Status )) { + HandleInfo.ProtectFromClose = FALSE; + + Status = NtSetInformationObject( hObject, + ObjectHandleFlagInformation, + &HandleInfo, + sizeof( HandleInfo ) + ); + if (NT_SUCCESS( Status )) { + return TRUE; + } + } + + return FALSE; +} +#endif diff --git a/private/csr/server/sbapi.c b/private/csr/server/sbapi.c new file mode 100644 index 000000000..d2936e51c --- /dev/null +++ b/private/csr/server/sbapi.c @@ -0,0 +1,171 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sbapi.c + +Abstract: + + This module contains the implementations of the Sb API calls exported + by the Server side of the Client-Server Runtime Subsystem to the + Session Manager SubSystem. + +Author: + + Steve Wood (stevewo) 8-Oct-1990 + +Revision History: + +--*/ + +#include "csrsrv.h" + +VOID +CsrpComputePriority( + IN ULONG PriorityClass, + OUT PUCHAR ProcessPriorityClass + + ); + +BOOLEAN +CsrSbCreateSession( + IN PSBAPIMSG Msg + ) +{ + PSBCREATESESSION a = &Msg->u.CreateSession; + PCSR_PROCESS Process; + PCSR_THREAD Thread; + PVOID ProcessDataPtr; + ULONG i; + NTSTATUS Status; + HANDLE ProcessHandle; + HANDLE ThreadHandle; + KERNEL_USER_TIMES TimeInfo; + + + ProcessHandle = a->ProcessInformation.Process; + ThreadHandle = a->ProcessInformation.Thread; + + AcquireProcessStructureLock(); + Process = CsrAllocateProcess(); + if (Process == NULL) { + Msg->ReturnedStatus = STATUS_NO_MEMORY; + ReleaseProcessStructureLock(); + return( TRUE ); + } + + Status = NtSetInformationProcess( + ProcessHandle, + ProcessExceptionPort, + &CsrApiPort, + sizeof(HANDLE) + ); + if ( !NT_SUCCESS(Status) ) { + CsrDeallocateProcess( Process ); + ReleaseProcessStructureLock(); + return( (BOOLEAN)STATUS_NO_MEMORY ); + } + + CsrpComputePriority( + CSR_NORMAL_PRIORITY_CLASS, + &Process->PriorityClass + ); + + CsrSetBackgroundPriority(Process); + + // + // capture the thread's createtime so that we can use + // this as a sequence number + // + + Status = NtQueryInformationThread( + ThreadHandle, + ThreadTimes, + (PVOID)&TimeInfo, + sizeof(TimeInfo), + NULL + ); + if ( !NT_SUCCESS(Status) ) { + CsrDeallocateProcess( Process ); + ReleaseProcessStructureLock(); + return( (BOOLEAN)Status ); + } + + Thread = CsrAllocateThread( Process ); + if (Thread == NULL) { + CsrDeallocateProcess( Process ); + Msg->ReturnedStatus = STATUS_NO_MEMORY; + ReleaseProcessStructureLock(); + return( TRUE ); + } + + CsrInitializeThreadData(Thread, NULL); + + Thread->CreateTime = TimeInfo.CreateTime; + Thread->ClientId = a->ProcessInformation.ClientId; + Thread->ThreadHandle = a->ProcessInformation.Thread; + +ProtectHandle(Thread->ThreadHandle); + + Thread->Flags = 0; + CsrInsertThread( Process, Thread ); + + // + // this needs a little more thought + // + Process->NtSession = CsrAllocateNtSession( a->SessionId ); + + Process->ClientId = a->ProcessInformation.ClientId; + Process->ProcessHandle = a->ProcessInformation.Process; + + // + // initialize each DLL's per process data area. + // + + ProcessDataPtr = (PVOID)QUAD_ALIGN(&Process->ServerDllPerProcessData[CSR_MAX_SERVER_DLL]); + for (i=0;i<CSR_MAX_SERVER_DLL;i++) { + if (CsrLoadedServerDll[i] != NULL && CsrLoadedServerDll[i]->PerProcessDataLength) { + Process->ServerDllPerProcessData[i] = ProcessDataPtr; + ProcessDataPtr = (PVOID)QUAD_ALIGN((ULONG)ProcessDataPtr + CsrLoadedServerDll[i]->PerProcessDataLength); + } + else { + Process->ServerDllPerProcessData[i] = NULL; + } + } + + CsrSetProcessContext( Process, + Thread, + TRUE + ); + + CsrInsertProcess( NULL, NULL, Process ); + Msg->ReturnedStatus = NtResumeThread( a->ProcessInformation.Thread, + NULL + ); + ReleaseProcessStructureLock(); + return( TRUE ); +} + +BOOLEAN +CsrSbTerminateSession( + IN PSBAPIMSG Msg + ) +{ + PSBTERMINATESESSION a = &Msg->u.TerminateSession; + + Msg->ReturnedStatus = STATUS_NOT_IMPLEMENTED; + return( TRUE ); +} + +BOOLEAN +CsrSbForeignSessionComplete( + IN PSBAPIMSG Msg + ) +{ + PSBFOREIGNSESSIONCOMPLETE a = &Msg->u.ForeignSessionComplete; + + Msg->ReturnedStatus = STATUS_NOT_IMPLEMENTED; + return( TRUE ); +} diff --git a/private/csr/server/sbinit.c b/private/csr/server/sbinit.c new file mode 100644 index 000000000..f45e618e3 --- /dev/null +++ b/private/csr/server/sbinit.c @@ -0,0 +1,100 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sbinit.c + +Abstract: + + This module contains the code to initialize the SbApiPort of the + Server side of the Client-Server Runtime Subsystem. + +Author: + + Steve Wood (stevewo) 8-Oct-1990 + +Environment: + + User Mode Only + +Revision History: + +--*/ + +#include "csrsrv.h" + +NTSTATUS +CsrSbApiPortInitialize( VOID ) +{ + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE Thread; + CLIENT_ID ClientId; + ULONG n; + + n = CsrDirectoryName.Length + + sizeof( CSR_SBAPI_PORT_NAME ) + + sizeof( OBJ_NAME_PATH_SEPARATOR ); + CsrSbApiPortName.Buffer = RtlAllocateHeap( CsrHeap, MAKE_TAG( INIT_TAG ), n ); + if (CsrSbApiPortName.Buffer == NULL) { + return( STATUS_NO_MEMORY ); + } + CsrSbApiPortName.Length = 0; + CsrSbApiPortName.MaximumLength = (USHORT)n; + RtlAppendUnicodeStringToString( &CsrSbApiPortName, &CsrDirectoryName ); + RtlAppendUnicodeToString( &CsrSbApiPortName, L"\\" ); + RtlAppendUnicodeToString( &CsrSbApiPortName, CSR_SBAPI_PORT_NAME ); + + IF_CSR_DEBUG( LPC ) { + DbgPrint( "CSRSS: Creating %wZ port and associated thread\n", + &CsrSbApiPortName ); + } + + InitializeObjectAttributes( &ObjectAttributes, &CsrSbApiPortName, 0, + NULL, NULL ); + Status = NtCreatePort( &CsrSbApiPort, + &ObjectAttributes, + sizeof( SBCONNECTINFO ), + sizeof( SBAPIMSG ), + sizeof( SBAPIMSG ) * 32 + ); + ASSERT( NT_SUCCESS( Status ) ); + + Status = RtlCreateUserThread( NtCurrentProcess(), + NULL, + TRUE, + 0, + 0, + 0, + CsrSbApiRequestThread, + NULL, + &Thread, + &ClientId + ); + ASSERT( NT_SUCCESS( Status ) ); + CsrSbApiRequestThreadPtr = CsrAddStaticServerThread(Thread,&ClientId,0); + + Status = NtResumeThread( Thread, NULL ); + ASSERT( NT_SUCCESS( Status ) ); + + return( Status ); +} + + +VOID +CsrSbApiPortTerminate( + NTSTATUS Status + ) +{ + IF_CSR_DEBUG( LPC ) { + DbgPrint( "CSRSS: Closing Sb port and associated thread\n" ); + } + NtTerminateThread( CsrSbApiRequestThreadPtr->ThreadHandle, + Status + ); + + NtClose( CsrSbApiPort ); + NtClose( CsrSmApiPort ); +} diff --git a/private/csr/server/sbreqst.c b/private/csr/server/sbreqst.c new file mode 100644 index 000000000..b6e44c10a --- /dev/null +++ b/private/csr/server/sbreqst.c @@ -0,0 +1,175 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sbreqst.c + +Abstract: + + This module contains the Server Request thread procedure for the Sb + API calls exported by the Server side of the Client-Server Runtime + Subsystem to the Session Manager SubSystem. + +Author: + + Steve Wood (stevewo) 8-Oct-1990 + +Revision History: + +--*/ + +#include "csrsrv.h" + +PSB_API_ROUTINE CsrServerSbApiDispatch[ SbMaxApiNumber+1 ] = { + CsrSbCreateSession, + CsrSbTerminateSession, + CsrSbForeignSessionComplete, + NULL +}; + +#if DBG +PSZ CsrServerSbApiName[ SbMaxApiNumber+1 ] = { + "SbCreateSession", + "SbTerminateSession", + "SbForeignSessionComplete", + "Unknown Csr Sb Api Number" +}; +#endif // DBG + + +NTSTATUS +CsrSbApiHandleConnectionRequest( + IN PSBAPIMSG Message + ); + +NTSTATUS +CsrSbApiRequestThread( + IN PVOID Parameter + ) +{ + NTSTATUS Status; + SBAPIMSG ReceiveMsg; + PSBAPIMSG ReplyMsg; + + ReplyMsg = NULL; + while (TRUE) { + IF_CSR_DEBUG( LPC ) { + DbgPrint( "CSRSS: Sb Api Request Thread waiting...\n" ); + } + Status = NtReplyWaitReceivePort( CsrSbApiPort, + NULL, + (PPORT_MESSAGE)ReplyMsg, + (PPORT_MESSAGE)&ReceiveMsg + ); + + if (Status != 0) { + if (NT_SUCCESS( Status )) { + continue; // Try again if alerted or a failure + } + else { + IF_DEBUG { + DbgPrint( "CSRSS: ReceivePort failed - Status == %X\n", Status ); + } + break; + } + } + + // + // Check to see if this is a connection request and handle + // + + if (ReceiveMsg.h.u2.s2.Type == LPC_CONNECTION_REQUEST) { + CsrSbApiHandleConnectionRequest( &ReceiveMsg ); + ReplyMsg = NULL; + continue; + } + + if ((ULONG)ReceiveMsg.ApiNumber >= SbMaxApiNumber) { + IF_DEBUG { + DbgPrint( "CSRSS: %lx is invalid Sb ApiNumber\n", + ReceiveMsg.ApiNumber + ); + } + + ReceiveMsg.ApiNumber = SbMaxApiNumber; + } + +#if DBG + IF_CSR_DEBUG( LPC ) { + DbgPrint( "CSRSS: %s Sb Api Request received from %lx.%lx\n", + CsrServerSbApiName[ ReceiveMsg.ApiNumber ], + ReceiveMsg.h.ClientId.UniqueProcess, + ReceiveMsg.h.ClientId.UniqueThread + ); + } +#endif // DBG + + ReplyMsg = &ReceiveMsg; + if (ReceiveMsg.ApiNumber < SbMaxApiNumber) { + if (!(*CsrServerSbApiDispatch[ ReceiveMsg.ApiNumber ])( &ReceiveMsg )) { + ReplyMsg = NULL; + } + } + else { + ReplyMsg->ReturnedStatus = STATUS_NOT_IMPLEMENTED; + } + +#if DBG + IF_CSR_DEBUG( LPC ) { + if (ReplyMsg != NULL) { + DbgPrint( "CSRSS: %s Sb Api sending %lx status reply to %lx.%lx\n", + CsrServerSbApiName[ ReceiveMsg.ApiNumber ], + ReplyMsg->ReturnedStatus, + ReplyMsg->h.ClientId.UniqueProcess, + ReplyMsg->h.ClientId.UniqueThread + ); + } + } +#endif // DBG + } + + NtTerminateThread( NtCurrentThread(), Status ); + + return( Status ); // Remove no return value warning. + Parameter; // Remove unreferenced parameter warning. +} + +NTSTATUS +CsrSbApiHandleConnectionRequest( + IN PSBAPIMSG Message + ) +{ + NTSTATUS st; + REMOTE_PORT_VIEW ClientView; + HANDLE CommunicationPort; + + // + // The protocol for a subsystem is to connect to the session manager, + // then to listen and accept a connection from the session manager + // + + ClientView.Length = sizeof(ClientView); + st = NtAcceptConnectPort( + &CommunicationPort, + NULL, + (PPORT_MESSAGE)Message, + TRUE, + NULL, + &ClientView + ); + + if ( !NT_SUCCESS(st) ) { + KdPrint(("CSRSS: Sb Accept Connection failed %lx\n",st)); + return st; + } + + st = NtCompleteConnectPort(CommunicationPort); + + if ( !NT_SUCCESS(st) ) { + KdPrint(("CSRSS: Sb Complete Connection failed %lx\n",st)); + } + + return st; +} diff --git a/private/csr/server/semphore b/private/csr/server/semphore new file mode 100644 index 000000000..df3ef3edd --- /dev/null +++ b/private/csr/server/semphore @@ -0,0 +1,30 @@ +To prevent deadlock, semaphores must be taken in the following +order: + + ProcessStructureLock + ProcessLock + ThreadLock + CurrentConsoleLock + ConsoleHandleTableLock + ConsoleLock + ReadCountLock (console) + WaitListsLock + + +ProcessStructureLock - + must be held to change process or thread structure. + held while traversing process/thread tree. always must be held + when calling CsrLocateThreadByClientId. + +ProcessLock - + must be held exclusively to destroy a process + can be held shared or exclusive. + held shared for during of an api call so that process isn't destroyed + by another process during call. + held exclusively means that no one else can access contents + +ThreadLock - + must be held exclusively to destroy a thread + can be held shared or exclusive. + held shared for during of an api call so that thread isn't destroyed + by another thread during call. diff --git a/private/csr/server/session.c b/private/csr/server/session.c new file mode 100644 index 000000000..729d9a8ba --- /dev/null +++ b/private/csr/server/session.c @@ -0,0 +1,95 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + session.c + +Abstract: + + This module contains the worker routines called by the Sb API + Request routines in sbapi.c to create and delete sessions. Also + called whenever an application process creates a new child process + within the same session. + +Author: + + Steve Wood (stevewo) 08-Oct-1990 + +Revision History: + +--*/ + + +#include "csrsrv.h" + +NTSTATUS +CsrInitializeNtSessionList( VOID ) +{ + NTSTATUS Status; + + InitializeListHead( &CsrNtSessionList ); + + Status = RtlInitializeCriticalSection( &CsrNtSessionLock ); + return( Status ); +} + + +PCSR_NT_SESSION +CsrAllocateNtSession( + ULONG SessionId + ) +{ + PCSR_NT_SESSION Session; + + Session = RtlAllocateHeap( CsrHeap, MAKE_TAG( PROCESS_TAG ), sizeof( CSR_NT_SESSION ) ); + ASSERT( Session != NULL ); + + if (Session != NULL) { + Session->SessionId = SessionId; + Session->ReferenceCount = 1; + LockNtSessionList(); + InsertHeadList( &CsrNtSessionList, &Session->SessionLink ); + UnlockNtSessionList(); + } + + return( Session ); +} + +VOID +CsrReferenceNtSession( + PCSR_NT_SESSION Session + ) +{ + LockNtSessionList(); + + ASSERT( !IsListEmpty( &Session->SessionLink ) ); + ASSERT( Session->SessionId != 0 ); + ASSERT( Session->ReferenceCount != 0 ); + Session->ReferenceCount++; + UnlockNtSessionList(); +} + +VOID +CsrDereferenceNtSession( + PCSR_NT_SESSION Session, + NTSTATUS ExitStatus + ) +{ + LockNtSessionList(); + + ASSERT( !IsListEmpty( &Session->SessionLink ) ); + ASSERT( Session->SessionId != 0 ); + ASSERT( Session->ReferenceCount != 0 ); + + if (--Session->ReferenceCount == 0) { + RemoveEntryList( &Session->SessionLink ); + UnlockNtSessionList(); + SmSessionComplete(CsrSmApiPort,Session->SessionId,ExitStatus); + RtlFreeHeap( CsrHeap, 0, Session ); + } + else { + UnlockNtSessionList(); + } +} diff --git a/private/csr/server/sources b/private/csr/server/sources new file mode 100644 index 000000000..6b4e11410 --- /dev/null +++ b/private/csr/server/sources @@ -0,0 +1,62 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 8-Oct-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=csr +MINORCOMP=server + +TARGETNAME=csrsrv +TARGETPATH=obj +TARGETPATHLIB=$(BASEDIR)\public\sdk\lib +TARGETTYPE=DYNLINK +TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\smdll.lib + +INCLUDES=..\inc + +USE_NTDLL=1 + +MSC_WARNING_LEVEL=/W3 /WX + +C_DEFINES=$(C_DEFINES) -D_CSRSRV_ + +BACKGROUND_USE=1 + +SOURCES=srvinit.c \ + srvloadr.c \ + sbinit.c \ + sbreqst.c \ + sbapi.c \ + apiinit.c \ + apireqst.c \ + session.c \ + process.c \ + csrdebug.c \ + csrss.rc \ + wait.c + +DLLDEF=obj\*\csrsrv.def + +UMTYPE=ntss +UMAPPL=csrss +UMLIBS=$(BASEDIR)\public\sdk\lib\*\csrsrv.lib obj\*\csrss.res +COFFBASE=csrss diff --git a/private/csr/server/srvinit.c b/private/csr/server/srvinit.c new file mode 100644 index 000000000..5cd909496 --- /dev/null +++ b/private/csr/server/srvinit.c @@ -0,0 +1,580 @@ +/*++ + +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" + +PCSR_API_ROUTINE CsrServerApiDispatchTable[ CsrpMaxApiNumber ] = { + (PCSR_API_ROUTINE)CsrSrvNullApiCall, + (PCSR_API_ROUTINE)CsrSrvClientConnect, + (PCSR_API_ROUTINE)NULL, + (PCSR_API_ROUTINE)CsrSrvProfileControl, + (PCSR_API_ROUTINE)CsrSrvIdentifyAlertableThread, + (PCSR_API_ROUTINE)CsrSrvSetPriorityClass +}; + +BOOLEAN CsrServerApiServerValidTable[ CsrpMaxApiNumber ] = { + TRUE, // CsrSrvNullApiCall, + TRUE, // CsrSrvClientConnect, + FALSE, // CsrSrvThreadConnect, + TRUE, // CsrSrvProfileControl, + TRUE, // CsrSrvIdentifyAlertableThread + TRUE // CsrSrvSetPriorityClass +}; + +#if DBG +PSZ CsrServerApiNameTable[ CsrpMaxApiNumber ] = { + "NullApiCall", + "ClientConnect", + "ThreadConnect", + "ProfileControl", + "IdentifyAlertableThread", + "SetPriorityClass" +}; +#endif // DBG + +NTSTATUS +CsrSetProcessSecurity( + VOID + ); + +NTSTATUS +CsrServerInitialization( + IN ULONG argc, + IN PCH argv[] + ) +{ + NTSTATUS Status; + ULONG i; + PVOID ProcessDataPtr; + PTEB Teb; + PCSR_SERVER_DLL LoadedServerDll; + +// Initialize GDI accelerators. This thread ends up in GDI doing graphics, +// courtesy of USER! (Also see SRVQUICK.C, APIREQST.C) + + Teb = NtCurrentTeb(); + Teb->GdiClientPID = PID_SERVERLPC; + Teb->GdiClientTID = (ULONG) Teb->ClientId.UniqueThread; + + Status = NtCreateEvent(&CsrInitializationEvent, + EVENT_ALL_ACCESS, + NULL, + SynchronizationEvent, + FALSE + ); + ASSERT( NT_SUCCESS( Status ) ); + + // + // Save away system information in a global variable + // + + Status = NtQuerySystemInformation( SystemBasicInformation, + &CsrNtSysInfo, + sizeof( CsrNtSysInfo ), + NULL + ); + ASSERT( NT_SUCCESS( 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" + ); + + + // + // Set up CSRSS process security + // + + Status = CsrSetProcessSecurity(); + ASSERT( NT_SUCCESS( Status ) ); + + // + // Initialize the Session List + // + + Status = CsrInitializeNtSessionList(); + ASSERT( NT_SUCCESS( Status ) ); + + // + // Initialize the Process List + // + + Status = CsrInitializeProcessStructure(); + ASSERT( NT_SUCCESS( Status ) ); + + // + // Process the command line arguments + // + + Status = CsrParseServerCommandLine( argc, argv ); + ASSERT( NT_SUCCESS( Status ) ); + + + // + // Fix up per-process data for root process + // + + ProcessDataPtr = (PCSR_PROCESS)RtlAllocateHeap( CsrHeap, + MAKE_TAG( PROCESS_TAG ) | HEAP_ZERO_MEMORY, + CsrTotalPerProcessDataLength + ); + for (i=0; i<CSR_MAX_SERVER_DLL; i++) { + LoadedServerDll = CsrLoadedServerDll[ i ]; + if (LoadedServerDll && LoadedServerDll->PerProcessDataLength) { + CsrRootProcess->ServerDllPerProcessData[i] = ProcessDataPtr; + ProcessDataPtr = (PVOID)QUAD_ALIGN((ULONG)ProcessDataPtr + LoadedServerDll->PerProcessDataLength); + } + else { + CsrRootProcess->ServerDllPerProcessData[i] = NULL; + } + } + + // + // Let server dlls know about the root process. + // + + for (i=0; i<CSR_MAX_SERVER_DLL; i++) { + LoadedServerDll = CsrLoadedServerDll[ i ]; + if (LoadedServerDll && LoadedServerDll->AddProcessRoutine) { + (*LoadedServerDll->AddProcessRoutine)( NULL, CsrRootProcess ); + } + } + + // + // Initialize the Windows Server API Port, and one or more + // request threads. + // + + CsrpServerDebugInitialize = FALSE; + + Status = CsrApiPortInitialize(); + ASSERT( NT_SUCCESS( Status ) ); + + Status = DbgSsInitialize( CsrApiPort, CsrUiLookup , NULL, NULL ); + ASSERT( NT_SUCCESS( Status ) ); + + // + // Initialize the Server Session Manager API Port and one + // request thread. + // + + Status = CsrSbApiPortInitialize(); + ASSERT( NT_SUCCESS( Status ) ); + + // + // Connect to the session manager so we can start foreign sessions + // + + Status = SmConnectToSm( &CsrSbApiPortName, + CsrSbApiPort, + CsrSubSystemType, + &CsrSmApiPort + ); + ASSERT( NT_SUCCESS( Status ) ); + + Status = NtSetEvent(CsrInitializationEvent,NULL); + ASSERT( NT_SUCCESS( Status ) ); + NtClose(CsrInitializationEvent); + + Status = NtSetDefaultHardErrorPort(CsrApiPort); + return( Status ); +} + +// BUGBUG this routine should go away when we get exportable DLL data +NTSTATUS +CsrGetApiPorts( + OUT PHANDLE SbApiPort OPTIONAL, + OUT PHANDLE SmApiPort OPTIONAL + ) +{ + if (ARGUMENT_PRESENT(SbApiPort)) { + *SbApiPort = CsrSbApiPort; + } + if (ARGUMENT_PRESENT(SmApiPort)) { + *SmApiPort = CsrSmApiPort; + } + return STATUS_SUCCESS; +} + +NTSTATUS +CsrParseServerCommandLine( + IN ULONG argc, + IN PCH argv[] + ) +{ + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + ULONG i, ServerDllIndex; + PCH KeyName, KeyValue, s; + PCH InitRoutine; + + CsrTotalPerProcessDataLength = 0; + CsrTotalPerThreadDataLength = 0; + CsrSubSystemType = IMAGE_SUBSYSTEM_WINDOWS_GUI; + CsrObjectDirectory = NULL; + CsrMaxApiRequestThreads = CSR_MAX_THREADS; + + for (i=1; i<argc ; i++) { + KeyName = argv[ i ]; + KeyValue = NULL; + while (*KeyName) { + if (*KeyName == '=') { + *KeyName++ = '\0'; + KeyValue = KeyName; + break; + } + + KeyName++; + } + KeyName = argv[ i ]; + + if (!_stricmp( KeyName, "ObjectDirectory" )) { + ANSI_STRING AnsiString; + + // + // Create an object directory in the object name space with the + // name specified. It will be the root for all object names + // created by the Server side of the Client Server Runtime + // SubSystem. + // + + RtlInitString( &AnsiString, KeyValue ); + Status = RtlAnsiStringToUnicodeString( &CsrDirectoryName, &AnsiString, TRUE ); + ASSERT(NT_SUCCESS(Status)); + InitializeObjectAttributes( &ObjectAttributes, + &CsrDirectoryName, + OBJ_PERMANENT | OBJ_OPENIF | OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + Status = NtCreateDirectoryObject( &CsrObjectDirectory, + DIRECTORY_ALL_ACCESS, + &ObjectAttributes + ); + if (!NT_SUCCESS( Status )) { + break; + } + } + else + if (!_stricmp( KeyName, "SubSystemType" )) { + } + else + if (!_stricmp( KeyName, "MaxRequestThreads" )) { + Status = RtlCharToInteger( KeyValue, + (ULONG)NULL, + &CsrMaxApiRequestThreads + ); + } + else + if (!_stricmp( KeyName, "RequestThreads" )) { +#if 0 + Status = RtlCharToInteger( KeyValue, + (ULONG)NULL, + &CsrNumberApiRequestThreads + ); +#else + // + // wait until hive change ! + // + + Status = STATUS_SUCCESS; + +#endif + } + else + if (!_stricmp( KeyName, "ProfileControl" )) { + if(!_stricmp( KeyValue, "On" )) { + CsrProfileControl = TRUE; + } + else { + CsrProfileControl = FALSE; + } + } + else + if (!_stricmp( KeyName, "SharedSection" )) { + Status = CsrSrvCreateSharedSection( KeyValue ); + if (!NT_SUCCESS( Status )) { + IF_DEBUG { + DbgPrint( "CSRSS: *** Invalid syntax for %s=%s (Status == %X)\n", + KeyName, + KeyValue, + Status + ); + } + } + Status = CsrLoadServerDll( "CSRSS", NULL, CSRSRV_SERVERDLL_INDEX ); + } + else + if (!_stricmp( KeyName, "ServerDLL" )) { + s = KeyValue; + InitRoutine = NULL; + + Status = STATUS_INVALID_PARAMETER; + while (*s) { + if ((*s == ':') && (InitRoutine == NULL)) { + *s++ = '\0'; + InitRoutine = s; + } + + if (*s++ == ',') { + Status = RtlCharToInteger ( s, 10, &ServerDllIndex ); + if (NT_SUCCESS( Status )) { + s[ -1 ] = '\0'; + } + + break; + } + } + + if (!NT_SUCCESS( Status )) { + IF_DEBUG { + DbgPrint( "CSRSS: *** Invalid syntax for ServerDll=%s (Status == %X)\n", + KeyValue, + Status + ); + } + } + else { + IF_CSR_DEBUG( INIT) { + DbgPrint( "CSRSS: Loading ServerDll=%s:%s\n", KeyValue, InitRoutine ); + } + + Status = CsrLoadServerDll( KeyValue, InitRoutine, ServerDllIndex); + + IF_DEBUG { + if (!NT_SUCCESS( Status )) { + DbgPrint( "CSRSS: *** Failed loading ServerDll=%s (Status == %X)\n", + KeyValue, + Status + ); + } + } + } + } + else + // + // This is a temporary hack until Windows & Console are friends. + // + if (!_stricmp( KeyName, "Windows" )) { + } + else { + Status = STATUS_INVALID_PARAMETER; + } + } + + return( Status ); +} + + +NTSTATUS +CsrServerDllInitialization( + IN PCSR_SERVER_DLL LoadedServerDll + ) +{ + PVOID SharedHeap; + PCSR_FAST_ANSI_OEM_TABLES XlateTables; + PVOID p; + NTSTATUS Status; + + LoadedServerDll->ApiNumberBase = CSRSRV_FIRST_API_NUMBER; + LoadedServerDll->MaxApiNumber = CsrpMaxApiNumber; + LoadedServerDll->ApiDispatchTable = CsrServerApiDispatchTable; + LoadedServerDll->ApiServerValidTable = CsrServerApiServerValidTable; +#if DBG + LoadedServerDll->ApiNameTable = CsrServerApiNameTable; +#else + LoadedServerDll->ApiNameTable = NULL; +#endif + LoadedServerDll->PerProcessDataLength = 0; + LoadedServerDll->PerThreadDataLength = 0; + LoadedServerDll->ConnectRoutine = NULL; + LoadedServerDll->DisconnectRoutine = NULL; + + + SharedHeap = LoadedServerDll->SharedStaticServerData; + + XlateTables = RtlAllocateHeap(SharedHeap, MAKE_SHARED_TAG( SHR_INIT_TAG ), sizeof(CSR_FAST_ANSI_OEM_TABLES)); + if ( !XlateTables ) { + return STATUS_NO_MEMORY; + } + + LoadedServerDll->SharedStaticServerData = (PVOID)XlateTables; + + return( STATUS_SUCCESS ); +} + +NTSTATUS +CsrSrvProfileControl( + IN OUT PCSR_API_MSG m, + IN OUT PCSR_REPLY_STATUS ReplyStatus + ) +{ + return STATUS_INVALID_PARAMETER; +} + + + + +NTSTATUS +CsrSetProcessSecurity( + VOID + ) +{ + HANDLE Token; + NTSTATUS Status; + PTOKEN_USER User; + ULONG LengthSid, Length; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PACL Dacl; + + // + // Open the token and get the system sid + // + + Status = NtOpenProcessToken( NtCurrentProcess(), + TOKEN_QUERY, + &Token + ); + if (!NT_SUCCESS(Status)) { + return Status; + } + + NtQueryInformationToken( Token, + TokenUser, + NULL, + 0, + &Length + ); + User = (PTOKEN_USER)RtlAllocateHeap( CsrHeap, + MAKE_TAG( PROCESS_TAG ) | HEAP_ZERO_MEMORY, + Length + ); + ASSERT( User != NULL ); + Status = NtQueryInformationToken( Token, + TokenUser, + User, + Length, + &Length + ); + + NtClose( Token ); + if (!NT_SUCCESS(Status)) { + RtlFreeHeap( CsrHeap, 0, User ); + return Status; + } + LengthSid = RtlLengthSid( User->User.Sid ); + + // + // Allocate a buffer to hold the SD + // + + SecurityDescriptor = RtlAllocateHeap( CsrHeap, + MAKE_TAG( PROCESS_TAG ) | HEAP_ZERO_MEMORY, + SECURITY_DESCRIPTOR_MIN_LENGTH + + sizeof(ACL) + LengthSid + + sizeof(ACCESS_ALLOWED_ACE) + ); + ASSERT( SecurityDescriptor != NULL ); + 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; + } + RtlCreateAcl( Dacl, + sizeof(ACL) + LengthSid + sizeof(ACCESS_ALLOWED_ACE), + ACL_REVISION2 + ); + 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: + RtlFreeHeap( CsrHeap, 0, SecurityDescriptor ); + RtlFreeHeap( CsrHeap, 0, User ); + + return Status; +} diff --git a/private/csr/server/srvloadr.c b/private/csr/server/srvloadr.c new file mode 100644 index 000000000..67b3bd65c --- /dev/null +++ b/private/csr/server/srvloadr.c @@ -0,0 +1,423 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + srvloadr.c + +Abstract: + + This is the server DLL loader 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" + +EXCEPTION_DISPOSITION +CsrUnhandledExceptionFilter( + struct _EXCEPTION_POINTERS *ExceptionInfo + ) +{ + + UNICODE_STRING UnicodeParameter; + ULONG Parameters[ 4 ]; + ULONG Response; + BOOLEAN WasEnabled; + NTSTATUS Status; + + // + // Terminating will cause sm's wait to sense that we crashed. This will + // result in a clean shutdown due to sm's hard error logic + // + + // + // We are hosed, so raise a fata system error to shutdown the system. + // (Basically a user mode KeBugCheck). + // + + Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE, + (BOOLEAN)TRUE, + TRUE, + &WasEnabled + ); + + if (Status == STATUS_NO_TOKEN) { + + // + // No thread token, use the process token + // + + Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE, + (BOOLEAN)TRUE, + FALSE, + &WasEnabled + ); + } + + RtlInitUnicodeString( &UnicodeParameter, L"Windows SubSystem" ); + Parameters[ 0 ] = (ULONG)&UnicodeParameter; + Parameters[ 1 ] = (ULONG)ExceptionInfo->ExceptionRecord->ExceptionCode; + Parameters[ 2 ] = (ULONG)ExceptionInfo->ExceptionRecord->ExceptionAddress; + Parameters[ 3 ] = (ULONG)ExceptionInfo->ContextRecord; + Status = NtRaiseHardError( STATUS_SYSTEM_PROCESS_TERMINATED, + 4, + 1, + Parameters, + OptionShutdownSystem, + &Response + ); + + // + // If this returns, giveup + // + + NtTerminateProcess(NtCurrentProcess(),ExceptionInfo->ExceptionRecord->ExceptionCode); + + return EXCEPTION_EXECUTE_HANDLER; +} + +NTSTATUS +CsrLoadServerDll( + IN PCH ModuleName, + IN PCH InitRoutineString, + IN ULONG ServerDllIndex + ) +{ + NTSTATUS Status; + ANSI_STRING ModuleNameString; + UNICODE_STRING ModuleNameString_U; + HANDLE ModuleHandle; + PCSR_SERVER_DLL LoadedServerDll; + STRING ProcedureNameString; + PCSR_SERVER_DLL_INIT_ROUTINE ServerDllInitialization; + ULONG n; + + if (ServerDllIndex > CSR_MAX_SERVER_DLL) { + return( STATUS_TOO_MANY_NAMES ); + } + + if (CsrLoadedServerDll[ ServerDllIndex ] != NULL) { + return( STATUS_INVALID_PARAMETER ); + } + + RtlInitAnsiString( &ModuleNameString, ModuleName ); + Status = RtlAnsiStringToUnicodeString(&ModuleNameString_U, &ModuleNameString, TRUE); + ASSERT(NT_SUCCESS(Status)); + if (ServerDllIndex != CSRSRV_SERVERDLL_INDEX) { + Status = LdrLoadDll( UNICODE_NULL, NULL, &ModuleNameString_U, &ModuleHandle ); + if ( !NT_SUCCESS(Status) ) { + + PUNICODE_STRING ErrorStrings[2]; + UNICODE_STRING ErrorDllPath; + ULONG ErrorResponse; + NTSTATUS ErrorStatus; + + ErrorStrings[0] = &ModuleNameString_U; + ErrorStrings[1] = &ErrorDllPath; + RtlInitUnicodeString(&ErrorDllPath,L"Default Load Path"); + + // + // need to get image name + // + + ErrorStatus = NtRaiseHardError( + (NTSTATUS)STATUS_DLL_NOT_FOUND, + 2, + 0x00000003, + (PULONG)ErrorStrings, + OptionOk, + &ErrorResponse + ); + + } + RtlFreeUnicodeString(&ModuleNameString_U); + if (!NT_SUCCESS( Status )) { + return( Status ); + } + } + else { + ModuleHandle = NULL; + } + + n = sizeof( *LoadedServerDll ) + ModuleNameString.MaximumLength; + + LoadedServerDll = RtlAllocateHeap( CsrHeap, MAKE_TAG( INIT_TAG ), n ); + if (LoadedServerDll == NULL) { + if (ModuleHandle != NULL) { + LdrUnloadDll( ModuleHandle ); + } + + return( STATUS_NO_MEMORY ); + } + + RtlZeroMemory( LoadedServerDll, n ); + LoadedServerDll->SharedStaticServerData = CsrSrvSharedSectionHeap; + LoadedServerDll->Length = n; + LoadedServerDll->CsrInitializationEvent = CsrInitializationEvent; + LoadedServerDll->ModuleName.Length = ModuleNameString.Length; + LoadedServerDll->ModuleName.MaximumLength = ModuleNameString.MaximumLength; + LoadedServerDll->ModuleName.Buffer = (PCH)(LoadedServerDll+1); + if (ModuleNameString.Length != 0) { + strncpy( LoadedServerDll->ModuleName.Buffer, + ModuleNameString.Buffer, + ModuleNameString.Length + ); + } + + LoadedServerDll->ServerDllIndex = ServerDllIndex; + LoadedServerDll->ModuleHandle = ModuleHandle; + + if (ModuleHandle != NULL) { + + RtlInitString( + &ProcedureNameString, + (InitRoutineString == NULL) ? "ServerDllInitialization" : InitRoutineString); + + Status = LdrGetProcedureAddress( ModuleHandle, + &ProcedureNameString, + (ULONG) NULL, + (PVOID *) &ServerDllInitialization + ); + } + else { + ServerDllInitialization = CsrServerDllInitialization; + Status = STATUS_SUCCESS; + } + + if (NT_SUCCESS( Status )) { + try { + Status = (*ServerDllInitialization)( LoadedServerDll ); + } + except ( CsrUnhandledExceptionFilter( GetExceptionInformation() ) ){ + Status = GetExceptionCode(); + } + if (NT_SUCCESS( Status )) { + CsrTotalPerProcessDataLength += QUAD_ALIGN(LoadedServerDll->PerProcessDataLength); + CsrTotalPerThreadDataLength += QUAD_ALIGN(LoadedServerDll->PerThreadDataLength); + + CsrLoadedServerDll[ LoadedServerDll->ServerDllIndex ] = + LoadedServerDll; + if ( LoadedServerDll->SharedStaticServerData != CsrSrvSharedSectionHeap ) { + CsrSrvSharedStaticServerData[LoadedServerDll->ServerDllIndex] = LoadedServerDll->SharedStaticServerData; + } + } + else { + if (ModuleHandle != NULL) { + LdrUnloadDll( ModuleHandle ); + } + + RtlFreeHeap( CsrHeap, 0, LoadedServerDll ); + } + } + else { + if (ModuleHandle != NULL) { + LdrUnloadDll( ModuleHandle ); + } + + RtlFreeHeap( CsrHeap, 0, LoadedServerDll ); + } + + return( Status ); +} + + +ULONG +CsrSrvClientConnect( + IN OUT PCSR_API_MSG m, + IN OUT PCSR_REPLY_STATUS ReplyStatus + ) +{ + NTSTATUS Status; + PCSR_CLIENTCONNECT_MSG a = (PCSR_CLIENTCONNECT_MSG)&m->u.ApiMessageData; + PCSR_SERVER_DLL LoadedServerDll; + + *ReplyStatus = CsrReplyImmediate; + + if (a->ServerDllIndex > CSR_MAX_SERVER_DLL) { + return( (ULONG)STATUS_TOO_MANY_NAMES ); + } + else + if (CsrLoadedServerDll[ a->ServerDllIndex ] == NULL) { + return( (ULONG)STATUS_INVALID_PARAMETER ); + } + else { + LoadedServerDll = CsrLoadedServerDll[ a->ServerDllIndex ]; + + if (LoadedServerDll->ConnectRoutine) { + + Status = (LoadedServerDll->ConnectRoutine)( + (CSR_SERVER_QUERYCLIENTTHREAD())->Process, + a->ConnectionInformation, + &a->ConnectionInformationLength + ); + } + else { + Status = STATUS_SUCCESS; + } + } + + return( (ULONG)Status ); +} + + +NTSTATUS +CsrSrvCreateSharedSection( + IN PCH SizeParameter + ) +{ + NTSTATUS Status; + LARGE_INTEGER SectionSize; + ULONG ViewSize; + ULONG HandleTableSize; + ULONG HeapSize; + PCH s; + + s = SizeParameter; + while (*s) { + if (*s == ',') { + *s++ = '\0'; + break; + } + else { + s++; + } + } + + + if (!*s) { + return( STATUS_INVALID_PARAMETER ); + } + + Status = RtlCharToInteger( SizeParameter, + (ULONG)NULL, + &HandleTableSize + ); + if (NT_SUCCESS( Status )) { + Status = RtlCharToInteger( SizeParameter, + (ULONG)NULL, + &HeapSize + ); + } + if (!NT_SUCCESS( Status )) { + return( Status ); + } + + + HandleTableSize = ROUND_UP_TO_PAGES( HandleTableSize * 1024 ); + HeapSize = ROUND_UP_TO_PAGES( HeapSize * 1024 ); + CsrSrvSharedSectionSize = HandleTableSize + HeapSize; + + SectionSize.LowPart = CsrSrvSharedSectionSize; + SectionSize.HighPart = 0; + Status = NtCreateSection( &CsrSrvSharedSection, + SECTION_ALL_ACCESS, + (POBJECT_ATTRIBUTES) NULL, + &SectionSize, + PAGE_EXECUTE_READWRITE, + SEC_BASED | SEC_RESERVE, + (HANDLE) NULL + ); + if (!NT_SUCCESS( Status )) { + return( Status ); + } + + ViewSize = 0; + CsrSrvSharedSectionBase = NULL; + Status = NtMapViewOfSection( CsrSrvSharedSection, + NtCurrentProcess(), + &CsrSrvSharedSectionBase, + 0, // Zerobits? + 0, + NULL, + &ViewSize, + ViewUnmap, + MEM_TOP_DOWN, + PAGE_EXECUTE_READWRITE + ); + if (!NT_SUCCESS( Status )) { + NtClose( CsrSrvSharedSection ); + return( Status ); + } + CsrSrvSharedSectionHeap = (PVOID) + ((ULONG)CsrSrvSharedSectionBase + HandleTableSize ); + + if (RtlCreateHeap( HEAP_ZERO_MEMORY | HEAP_CLASS_7, + CsrSrvSharedSectionHeap, + HeapSize, + 4*1024, + 0, + 0 + ) == NULL + ) { + NtUnmapViewOfSection( NtCurrentProcess(), + CsrSrvSharedSectionBase + ); + NtClose( CsrSrvSharedSection ); + return( STATUS_NO_MEMORY ); + } + + CsrSharedBaseTag = RtlCreateTagHeap( CsrSrvSharedSectionHeap, + 0, + L"CSRSHR!", + L"!CSRSHR\0" + L"INIT\0" + ); + CsrSrvSharedStaticServerData = (PVOID *)RtlAllocateHeap( + CsrSrvSharedSectionHeap, + MAKE_SHARED_TAG( SHR_INIT_TAG ), + CSR_MAX_SERVER_DLL * sizeof(PVOID) + ); + + NtCurrentPeb()->ReadOnlySharedMemoryBase = CsrSrvSharedSectionBase; + NtCurrentPeb()->ReadOnlySharedMemoryHeap = CsrSrvSharedSectionHeap; + NtCurrentPeb()->ReadOnlyStaticServerData = (PVOID *)CsrSrvSharedStaticServerData; + + return( STATUS_SUCCESS ); +} + + +NTSTATUS +CsrSrvAttachSharedSection( + IN PCSR_PROCESS Process OPTIONAL, + OUT PCSR_API_CONNECTINFO p + ) +{ + NTSTATUS Status; + ULONG ViewSize; + + if (ARGUMENT_PRESENT( Process )) { + ViewSize = 0; + Status = NtMapViewOfSection( CsrSrvSharedSection, + Process->ProcessHandle, + &CsrSrvSharedSectionBase, + 0, + 0, + NULL, + &ViewSize, + ViewUnmap, + SEC_NO_CHANGE, + PAGE_EXECUTE_READ + ); + if (!NT_SUCCESS( Status )) { + return( Status ); + } + } + + p->SharedSectionBase = CsrSrvSharedSectionBase; + p->SharedSectionHeap = CsrSrvSharedSectionHeap; + p->SharedStaticServerData = CsrSrvSharedStaticServerData; + + return( STATUS_SUCCESS ); +} diff --git a/private/csr/server/wait.c b/private/csr/server/wait.c new file mode 100644 index 000000000..c2da3f237 --- /dev/null +++ b/private/csr/server/wait.c @@ -0,0 +1,254 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + wait.c + +Abstract: + + This module contains the primitives to implement the Wait functions + on the Server side of the Client-Server Runtime Subsystem to the + Session Manager SubSystem. + +Author: + + Steve Wood (stevewo) 8-Oct-1990 + +Revision History: + +--*/ + +#include "csrsrv.h" + +BOOLEAN +CsrInitializeWait( + IN CSR_WAIT_ROUTINE WaitRoutine, + IN PCSR_THREAD WaitingThread, + IN OUT PCSR_API_MSG WaitReplyMessage, + IN PVOID WaitParameter, + OUT PCSR_WAIT_BLOCK *WaitBlockPtr + ) + +{ + ULONG Length; + PCSR_WAIT_BLOCK WaitBlock; + + Length = sizeof( *WaitBlock ) - sizeof( WaitBlock->WaitReplyMessage ) + + WaitReplyMessage->h.u1.s1.TotalLength; + + WaitBlock = RtlAllocateHeap( CsrHeap, MAKE_TAG( PROCESS_TAG ), Length ); + if (WaitBlock == NULL) { + WaitReplyMessage->ReturnValue = (ULONG)STATUS_NO_MEMORY; + return( FALSE ); + } + + WaitBlock->Length = Length; + WaitBlock->WaitingThread = WaitingThread; + WaitBlock->WaitParameter = WaitParameter; + WaitingThread->WaitBlock = WaitBlock; + WaitBlock->WaitRoutine = WaitRoutine; + WaitBlock->UserLink.Flink = WaitBlock->UserLink.Blink = NULL; + WaitBlock->Link.Flink = WaitBlock->Link.Blink = NULL; + RtlMoveMemory( &WaitBlock->WaitReplyMessage, + WaitReplyMessage, + WaitReplyMessage->h.u1.s1.TotalLength + ); + *WaitBlockPtr = WaitBlock; + return TRUE; +} + +BOOLEAN +CsrCreateWait( + IN PLIST_ENTRY WaitQueue, + IN CSR_WAIT_ROUTINE WaitRoutine, + IN PCSR_THREAD WaitingThread, + IN OUT PCSR_API_MSG WaitReplyMessage, + IN PVOID WaitParameter, + IN PLIST_ENTRY UserLinkListHead OPTIONAL + ) +{ + PCSR_WAIT_BLOCK WaitBlock; + + if (!CsrInitializeWait( WaitRoutine, + WaitingThread, + WaitReplyMessage, + WaitParameter, + &WaitBlock + ) + ) { + return FALSE; + } + + AcquireWaitListsLock(); + + if ( WaitingThread && (WaitingThread->Flags & CSR_THREAD_DESTROYED) ) { + WaitingThread->WaitBlock = NULL; + RtlFreeHeap( CsrHeap, 0, WaitBlock ); + ReleaseWaitListsLock(); + return FALSE; + } + + InsertTailList( WaitQueue, &WaitBlock->Link ); + + if ( ARGUMENT_PRESENT(UserLinkListHead) ) { + InsertTailList( UserLinkListHead, &WaitBlock->UserLink ); + } + + ReleaseWaitListsLock(); + return( TRUE ); +} + + +BOOLEAN +CsrNotifyWaitBlock( + IN PCSR_WAIT_BLOCK WaitBlock, + IN PLIST_ENTRY WaitQueue, + IN PVOID SatisfyParameter1, + IN PVOID SatisfyParameter2, + IN ULONG WaitFlags, + IN BOOLEAN DereferenceThread + ) +{ + if ((*WaitBlock->WaitRoutine)( WaitQueue, + WaitBlock->WaitingThread, + &WaitBlock->WaitReplyMessage, + WaitBlock->WaitParameter, + SatisfyParameter1, + SatisfyParameter2, + WaitFlags + ) + ) { + + // + // we don't take any locks other than the waitlist lock + // because the only thing we have to worry about is the thread + // going away beneath us and that's prevented by having + // DestroyThread and DestroyProcess take the waitlist lock. + // + + WaitBlock->WaitingThread->WaitBlock = NULL; + if (WaitBlock->WaitReplyMessage.CaptureBuffer != NULL) { + CsrReleaseCapturedArguments(&WaitBlock->WaitReplyMessage); + } + NtReplyPort( WaitBlock->WaitingThread->Process->ClientPort, + (PPORT_MESSAGE)&WaitBlock->WaitReplyMessage + ); + + if (DereferenceThread) { + if ( WaitBlock->Link.Flink ) { + RemoveEntryList( &WaitBlock->Link ); + } + if ( WaitBlock->UserLink.Flink ) { + RemoveEntryList( &WaitBlock->UserLink ); + } + CsrDereferenceThread(WaitBlock->WaitingThread); + RtlFreeHeap( CsrHeap, 0, WaitBlock ); + } + else { + + // + // indicate that this wait has been satisfied. when the + // console unwinds to the point where it can release the + // console lock, it will dereference the thread. + // + + WaitBlock->WaitRoutine = NULL; + } + return( TRUE ); + } + else { + return( FALSE ); + } +} + +BOOLEAN +CsrNotifyWait( + IN PLIST_ENTRY WaitQueue, + IN BOOLEAN SatisfyAll, + IN PVOID SatisfyParameter1, + IN PVOID SatisfyParameter2 + ) +{ + PLIST_ENTRY ListHead, ListNext; + PCSR_WAIT_BLOCK WaitBlock; + BOOLEAN Result; + + Result = FALSE; + + AcquireWaitListsLock(); + + ListHead = WaitQueue; + ListNext = ListHead->Flink; + while (ListNext != ListHead) { + WaitBlock = CONTAINING_RECORD( ListNext, CSR_WAIT_BLOCK, Link ); + ListNext = ListNext->Flink; + if (WaitBlock->WaitRoutine) { + Result |= CsrNotifyWaitBlock( WaitBlock, + WaitQueue, + SatisfyParameter1, + SatisfyParameter2, + 0, + FALSE + ); + if (!SatisfyAll) { + break; + } + } + } + + ReleaseWaitListsLock(); + return( Result ); +} + +VOID +CsrDereferenceWait( + IN PLIST_ENTRY WaitQueue + ) +{ + PLIST_ENTRY ListHead, ListNext; + PCSR_WAIT_BLOCK WaitBlock; + + AcquireProcessStructureLock(); + AcquireWaitListsLock(); + + ListHead = WaitQueue; + ListNext = ListHead->Flink; + while (ListNext != ListHead) { + WaitBlock = CONTAINING_RECORD( ListNext, CSR_WAIT_BLOCK, Link ); + ListNext = ListNext->Flink; + if (!WaitBlock->WaitRoutine) { + if ( WaitBlock->Link.Flink ) { + RemoveEntryList( &WaitBlock->Link ); + } + if ( WaitBlock->UserLink.Flink ) { + RemoveEntryList( &WaitBlock->UserLink ); + } + CsrDereferenceThread(WaitBlock->WaitingThread); + RtlFreeHeap( CsrHeap, 0, WaitBlock ); + } + } + + ReleaseWaitListsLock(); + ReleaseProcessStructureLock(); +} + +VOID +CsrDestroyWait( + IN PCSR_WAIT_BLOCK WaitBlock + ) +{ + AcquireWaitListsLock(); + + WaitBlock->WaitingThread->WaitBlock = NULL; + RemoveEntryList( &WaitBlock->Link ); + + if ( WaitBlock->UserLink.Flink ) { + RemoveEntryList( &WaitBlock->UserLink ); + } + + ReleaseWaitListsLock(); + + RtlFreeHeap( CsrHeap, 0, WaitBlock ); +} |