diff --git a/reactos/include/ndk/extypes.h b/reactos/include/ndk/extypes.h index 4d1a052a4f4..26b853c621d 100644 --- a/reactos/include/ndk/extypes.h +++ b/reactos/include/ndk/extypes.h @@ -13,7 +13,7 @@ /* DEPENDENCIES **************************************************************/ #include /* FIXME: this needs be implemented in the w32api ddk */ -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(NTOS_MODE_USER) #include #endif #include "cmtypes.h" diff --git a/reactos/include/ndk/ldrfuncs.h b/reactos/include/ndk/ldrfuncs.h index cb96ed7c698..6776c00d7c1 100644 --- a/reactos/include/ndk/ldrfuncs.h +++ b/reactos/include/ndk/ldrfuncs.h @@ -12,7 +12,7 @@ /* DEPENDENCIES **************************************************************/ #include "ldrtypes.h" /* FIXME: this needs be implemented in the w32api ddk */ -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(NTOS_MODE_USER) #include #endif diff --git a/reactos/include/ndk/rtltypes.h b/reactos/include/ndk/rtltypes.h index 4620416f115..f48581f1e84 100644 --- a/reactos/include/ndk/rtltypes.h +++ b/reactos/include/ndk/rtltypes.h @@ -393,6 +393,14 @@ typedef LPOSVERSIONINFOW PRTL_OSVERSIONINFOW; typedef OSVERSIONINFOEXW RTL_OSVERSIONINFOEXW; typedef LPOSVERSIONINFOEXW PRTL_OSVERSIONINFOEXW; +typedef EXCEPTION_DISPOSITION +(*PEXCEPTION_HANDLER)( + struct _EXCEPTION_RECORD*, + PVOID, + struct _CONTEXT*, + PVOID +); + typedef struct _RTL_HEAP_PARAMETERS { ULONG Length; diff --git a/reactos/include/subsys/csr/protocol.h b/reactos/include/subsys/csr/protocol.h deleted file mode 100644 index 32d2101b93a..00000000000 --- a/reactos/include/subsys/csr/protocol.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __INCLUDE_CSR_PROTOCOL_H -#define __INCLUDE_CSR_PROTOCOL_H - -typedef ULONG CSR_API_NUMBER; - -#define MAKE_CSR_OPCODE(s,m) ((s) << 16) + (m) - -// -// Shared CSR Message Header for all CSR Servers -// Gary Nebbett - Alex Ionescu -// -typedef struct _CSR_PORT_MESSAGE_HEADER -{ - // - // LPC Header - // - PORT_MESSAGE PortHeader; - - // - // Buffer allocated with CsrAllocateCaptureBuffer. - // Sent as 2nd parameter to CsrClientCallServer. - // - PVOID CsrCaptureData; - - // - // CSR API Message ID and Return Value - // - CSR_API_NUMBER Opcode; - ULONG Status; - ULONG Reserved; - - // - // Server-defined union of supported structures - // -} CSR_PORT_MESSAGE_HEADER, * PCSR_PORT_MESSAGE_HEADER; - -#endif /* ndef __INCLUDE_CSR_PROTOCOL_H */ diff --git a/reactos/include/subsys/csr/server.h b/reactos/include/subsys/csr/server.h index 4b230068236..542c93f71ee 100644 --- a/reactos/include/subsys/csr/server.h +++ b/reactos/include/subsys/csr/server.h @@ -1,106 +1,306 @@ -#if !defined(__INCLUDE_CSR_SERVER_H) -#define __INCLUDE_CSR_SERVER_H +#ifndef _CSRSERVER_H +#define _CSRSERVER_H #define CSR_SRV_SERVER 0 -typedef struct _CSR_SESSION +typedef enum _CSR_PROCESS_FLAGS { - ULONG SessionId; - HANDLE Heap; - PVOID ServerData; + CsrProcessTerminating = 0x1, + CsrProcessSkipShutdown = 0x2, + CsrProcessCreateNewGroup = 0x100, + CsrProcessTerminated = 0x200, + CsrProcessLastThreadTerminated = 0x400, + CsrProcessIsConsoleApp = 0x800 +} CSR_PROCESS_FLAGS, *PCSR_PROCESS_FLAGS; -} CSR_SESSION, * PCSR_SESSION; +typedef enum _CSR_THREAD_FLAGS +{ + CsrThreadAltertable = 0x1, + CsrThreadInTermination = 0x2, + CsrThreadTerminated = 0x4, + CsrThreadIsServerThread = 0x10 +} CSR_THREAD_FLAGS, *PCSR_THREAD_FLAGS; +typedef enum _SHUTDOWN_RESULT +{ + CsrShutdownCsrProcess = 1, + CsrShutdownNonCsrProcess, + CsrShutdownCancelled +} SHUTDOWN_RESULT, *PSHUTDOWN_RESULT; + +typedef enum _CSR_SHUTDOWN_FLAGS +{ + CsrShutdownSystem = 4, + CsrShutdownOther = 8 +} CSR_SHUTDOWN_FLAGS, *PCSR_SHUTDOWN_FLAGS; + +typedef enum _CSR_DEBUG_FLAGS +{ + CsrDebugOnlyThisProcess = 1, + CsrDebugProcessChildren = 2 +} CSR_PROCESS_DEBUG_FLAGS, *PCSR_PROCESS_DEBUG_FLAGS; + +typedef struct _CSR_NT_SESSION +{ + ULONG ReferenceCount; + LIST_ENTRY SessionList; + ULONG SessionId; +} CSR_NT_SESSION, *PCSR_NT_SESSION; typedef struct _CSR_PROCESS { - CLIENT_ID ClientId; - LIST_ENTRY ListLink; - LIST_ENTRY ThreadList; - PCSR_SESSION NtSession; - ULONG ExpectedVersion; - HANDLE ClientPort; - ULONG_PTR ClientViewBase; - ULONG_PTR ClientViewBounds; - HANDLE ProcessHandle; - ULONG SequenceNumber; - ULONG Flags; - ULONG DebugFlags; - ULONG ReferenceCount; - ULONG ProcessGroupId; - ULONG ProcessGroupSequence; - ULONG fVDM; - ULONG ThreadCount; - ULONG PriorityClass; - ULONG Reserved; - ULONG ShutdownLevel; - ULONG ShutdownFlags; - PVOID ServerData; - -} CSR_PROCESS, * PCSR_PROCESS; - -struct _CSR_WAIT; + CLIENT_ID ClientId; + LIST_ENTRY ListLink; + LIST_ENTRY ThreadList; + struct _CSR_PROCESS *Parent; + PCSR_NT_SESSION NtSession; + ULONG ExpectedVersion; + HANDLE ClientPort; + ULONG_PTR ClientViewBase; + ULONG_PTR ClientViewBounds; + HANDLE ProcessHandle; + ULONG SequenceNumber; + ULONG Flags; + ULONG DebugFlags; + CLIENT_ID DebugCid; + ULONG ReferenceCount; + ULONG ProcessGroupId; + ULONG ProcessGroupSequence; + ULONG fVDM; + ULONG ThreadCount; + ULONG PriorityClass; + ULONG Reserved; + ULONG ShutdownLevel; + ULONG ShutdownFlags; + PVOID ServerData[]; +} CSR_PROCESS, *PCSR_PROCESS; typedef struct _CSR_THREAD { - LARGE_INTEGER CreateTime; - LIST_ENTRY Link; - LIST_ENTRY HashLinks; - CLIENT_ID ClientId; - PCSR_PROCESS Process; - struct _CSR_WAIT *WaitBlock; - HANDLE ThreadHandle; - ULONG Flags; - ULONG ReferenceCount; - ULONG ImpersonationCount; - -} CSR_THREAD, * PCSR_THREAD; + LARGE_INTEGER CreateTime; + LIST_ENTRY Link; + LIST_ENTRY HashLinks; + CLIENT_ID ClientId; + PCSR_PROCESS Process; + struct _CSR_WAIT_BLOCK *WaitBlock; + HANDLE ThreadHandle; + ULONG Flags; + ULONG ReferenceCount; + ULONG ImpersonationCount; +} CSR_THREAD, *PCSR_THREAD; -typedef struct _CSR_WAIT +typedef +NTSTATUS +(*PCSR_CONNECT_CALLBACK)( + IN PCSR_PROCESS CsrProcess, + IN OUT PVOID ConnectionInfo, + IN OUT PULONG ConnectionInfoLength +); + +typedef +VOID +(*PCSR_DISCONNECT_CALLBACK)(IN PCSR_PROCESS CsrProcess); + +typedef +NTSTATUS +(*PCSR_NEWPROCESS_CALLBACK)( + IN PCSR_PROCESS Parent, + IN PCSR_PROCESS CsrProcess +); + +typedef +VOID +(*PCSR_HARDERROR_CALLBACK)( + IN PCSR_THREAD CsrThread, + IN PHARDERROR_MSG HardErrorMessage +); + +typedef +ULONG +(*PCSR_SHUTDOWNPROCESS_CALLBACK)( + IN PCSR_PROCESS CsrProcess, + IN ULONG Flags, + IN BOOLEAN FirstPhase +); + +/* FIXME: Put into public NDK Header */ +typedef ULONG CSR_API_NUMBER; + +#define CSR_MAKE_OPCODE(s,m) ((s) << 16) | (m) +#define CSR_API_ID_FROM_OPCODE(n) ((ULONG)((USHORT)(n))) +#define CSR_SERVER_ID_FROM_OPCODE(n) (ULONG)((n) >> 16) + +typedef struct _CSR_CONNECTION_INFO { - PCSR_THREAD CsrThread; + ULONG Unknown[2]; + HANDLE ObjectDirectory; + PVOID SharedSectionBase; + PVOID SharedSectionHeap; + PVOID SharedSectionData; + ULONG DebugFlags; + ULONG Unknown2[3]; + HANDLE ProcessId; +} CSR_CONNECTION_INFO, *PCSR_CONNECTION_INFO; -} CSR_WAIT, * PCSR_WAIT; +typedef struct _CSR_CLIENT_CONNECT +{ + ULONG ServerId; + PVOID ConnectionInfo; + ULONG ConnectionInfoSize; +} CSR_CLIENT_CONNECT, *PCSR_CLIENT_CONNECT; +typedef struct _CSR_API_MESSAGE +{ + PORT_MESSAGE Header; + union + { + CSR_CONNECTION_INFO ConnectionInfo; + struct + { + PVOID CsrCaptureData; + CSR_API_NUMBER Opcode; + ULONG Status; + ULONG Reserved; + union + { + CSR_CLIENT_CONNECT CsrClientConnect; + }; + }; + }; +} CSR_API_MESSAGE, *PCSR_API_MESSAGE; -typedef VOID (CALLBACK * CSR_SERVER_THREAD)(PVOID); +typedef struct _CSR_CAPTURE_BUFFER +{ + ULONG Size; + struct _CSR_CAPTURE_BUFFER *PreviousCaptureBuffer; + ULONG PointerCount; + ULONG_PTR BufferEnd; +} CSR_CAPTURE_BUFFER, *PCSR_CAPTURE_BUFFER; -/* symbols exported by native DLL csrsrv.dll */ +/* Private data resumes here */ +typedef +NTSTATUS +(NTAPI *PCSR_API_ROUTINE)( + IN OUT PCSR_API_MESSAGE ApiMessage, + IN OUT PULONG Reply +); -NTSTATUS STDCALL CsrAddStaticServerThread(CSR_SERVER_THREAD); -NTSTATUS STDCALL CsrCallServerFromServer(); -NTSTATUS STDCALL CsrCreateProcess(PCSR_SESSION,PCSR_PROCESS*); -NTSTATUS STDCALL CsrCreateRemoteThread(); -NTSTATUS STDCALL CsrCreateSession(PCSR_SESSION*); -NTSTATUS STDCALL CsrCreateThread(PCSR_PROCESS,PCSR_THREAD*); -NTSTATUS STDCALL CsrCreateWait(PCSR_THREAD,PCSR_WAIT*); -NTSTATUS STDCALL CsrDebugProcess(PCSR_PROCESS); -NTSTATUS STDCALL CsrDebugProcessStop(PCSR_PROCESS); -NTSTATUS STDCALL CsrDereferenceProcess(PCSR_PROCESS); -NTSTATUS STDCALL CsrDereferenceThread(PCSR_THREAD); -NTSTATUS STDCALL CsrDereferenceWait(PCSR_WAIT); -NTSTATUS STDCALL CsrDestroyProcess(PCSR_PROCESS); -NTSTATUS STDCALL CsrDestroySession (PCSR_SESSION); -NTSTATUS STDCALL CsrDestroyThread(PCSR_THREAD); -NTSTATUS STDCALL CsrExecServerThread(); -NTSTATUS STDCALL CsrGetProcessLuid(PCSR_PROCESS,PLUID); -NTSTATUS STDCALL CsrImpersonateClient(); -NTSTATUS STDCALL CsrLockProcessByClientId(); -NTSTATUS STDCALL CsrLockThreadByClientId(); -NTSTATUS STDCALL CsrMoveSatisfiedWait(PCSR_WAIT); -NTSTATUS STDCALL CsrNotifyWait(PCSR_WAIT); -HANDLE STDCALL CsrQueryApiPort(VOID); -NTSTATUS STDCALL CsrReferenceThread(PCSR_THREAD); -NTSTATUS STDCALL CsrRevertToSelf(); -NTSTATUS STDCALL CsrServerInitialization(ULONG,LPWSTR*); -NTSTATUS STDCALL CsrSetBackgroundPriority(); -NTSTATUS STDCALL CsrSetCallingSpooler(); -NTSTATUS STDCALL CsrSetForegroundPriority(); -NTSTATUS STDCALL CsrShutdownProcesses(PCSR_SESSION); -NTSTATUS STDCALL CsrUnhandledExceptionFilter(); -NTSTATUS STDCALL CsrUnlockProcess(PCSR_PROCESS); -NTSTATUS STDCALL CsrUnlockThread(PCSR_THREAD); -NTSTATUS STDCALL CsrValidateMessageBuffer(); -NTSTATUS STDCALL CsrValidateMessageString(); +typedef struct _CSR_SERVER_DLL +{ + ULONG Length; + HANDLE Event; + ANSI_STRING Name; + HANDLE ServerHandle; + ULONG ServerId; + ULONG Unknown; + ULONG ApiBase; + ULONG HighestApiSupported; + PCSR_API_ROUTINE *DispatchTable; + PBOOLEAN ValidTable; + PCHAR *NameTable; + ULONG SizeOfProcessData; + PCSR_CONNECT_CALLBACK ConnectCallback; + PCSR_DISCONNECT_CALLBACK DisconnectCallback; + PCSR_HARDERROR_CALLBACK HardErrorCallback; + PVOID SharedSection; + PCSR_NEWPROCESS_CALLBACK NewProcessCallback; + PCSR_SHUTDOWNPROCESS_CALLBACK ShutdownProcessCallback; + ULONG Unknown2[3]; +} CSR_SERVER_DLL, *PCSR_SERVER_DLL; -#endif /* ndef __INCLUDE_CSR_SERVER_H */ +typedef +NTSTATUS +(NTAPI *PCSR_SERVER_DLL_INIT_CALLBACK)(IN PCSR_SERVER_DLL ServerDll); + +typedef +BOOLEAN +(*CSR_WAIT_FUNCTION)( + IN PLIST_ENTRY WaitList, + IN PCSR_THREAD WaitThread, + IN PCSR_API_MESSAGE WaitApiMessage, + IN PVOID WaitContext, + IN PVOID WaitArgument1, + IN PVOID WaitArgument2, + IN ULONG WaitFlags +); + +typedef struct _CSR_WAIT_BLOCK +{ + ULONG Size; + LIST_ENTRY WaitList; + LIST_ENTRY UserWaitList; + PVOID WaitContext; + PCSR_THREAD WaitThread; + CSR_WAIT_FUNCTION WaitFunction; + CSR_API_MESSAGE WaitApiMessage; +} CSR_WAIT_BLOCK, *PCSR_WAIT_BLOCK; + +/* FIXME: Put into new SM headers */ +typedef struct _SB_CREATE_SESSION +{ + ULONG SessionId; + RTL_USER_PROCESS_INFORMATION ProcessInfo; +} SB_CREATE_SESSION, *PSB_CREATE_SESSION; + +typedef struct _SB_TERMINATE_SESSION +{ + ULONG SessionId; +} SB_TERMINATE_SESSION, *PSB_TERMINATE_SESSION; + +typedef struct _SB_FOREIGN_SESSION_COMPLETE +{ + ULONG SessionId; +} SB_FOREIGN_SESSION_COMPLETE, *PSB_FOREIGN_SESSION_COMPLETE; + +typedef struct _SB_CREATE_PROCESS +{ + ULONG SessionId; +} SB_CREATE_PROCESS, *PSB_CREATE_PROCESS; + +typedef struct _SB_CONNECTION_INFO +{ + ULONG SubsystemId; +} SB_CONNECTION_INFO, *PSB_CONNECTION_INFO; + +typedef struct _SB_API_MESSAGE +{ + PORT_MESSAGE Header; + union + { + SB_CONNECTION_INFO ConnectionInfo; + struct + { + ULONG Opcode; + NTSTATUS Status; + union + { + SB_CREATE_SESSION SbCreateSession; + SB_TERMINATE_SESSION SbTerminateSession; + SB_FOREIGN_SESSION_COMPLETE SbForeignSessionComplete; + SB_CREATE_PROCESS SbCreateProcess; + }; + }; + }; +} SB_API_MESSAGE, *PSB_API_MESSAGE; + +typedef +BOOLEAN +(NTAPI *PSB_API_ROUTINE)(IN PSB_API_MESSAGE ApiMessage); + +NTSTATUS +NTAPI +SmSessionComplete( + IN HANDLE hApiPort, + IN ULONG SessionId, + IN NTSTATUS Status +); + +NTSTATUS +NTAPI +SmConnectToSm( + IN PUNICODE_STRING SbApiPortName OPTIONAL, + IN HANDLE hSbApiPort OPTIONAL, + IN ULONG SubsystemType OPTIONAL, + OUT PHANDLE hSmApiPort +); +#endif diff --git a/reactos/subsys/csr/args.c b/reactos/subsys/csr/args.c deleted file mode 100644 index 15b2f6d1ad0..00000000000 --- a/reactos/subsys/csr/args.c +++ /dev/null @@ -1,126 +0,0 @@ -/* $Id$ - * - * args.c - Client/Server Runtime - command line parsing - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ -#include "csr.h" - -#define NDEBUG -#include - -/********************************************************************** - * NAME PRIVATE - * CsrParseCommandLine/2 - */ -NTSTATUS FASTCALL CsrParseCommandLine (PPEB Peb, - PCOMMAND_LINE_ARGUMENT Argument) -{ - HANDLE ProcessHeap = Peb->ProcessHeap; - PRTL_USER_PROCESS_PARAMETERS RtlProcessParameters = RtlNormalizeProcessParams (Peb->ProcessParameters); - INT i = 0; - INT afterlastspace = 0; - - - DPRINT("CSR: %s called\n", __FUNCTION__); - - RtlZeroMemory (Argument, sizeof (COMMAND_LINE_ARGUMENT)); - - Argument->Vector = (PWSTR *) RtlAllocateHeap (ProcessHeap, - 0, - (CSRP_MAX_ARGUMENT_COUNT * sizeof Argument->Vector[0])); - if(NULL == Argument->Vector) - { - DPRINT("CSR: %s: no memory for Argument->Vector\n", __FUNCTION__); - return STATUS_NO_MEMORY; - } - - Argument->Buffer.Length = - Argument->Buffer.MaximumLength = - RtlProcessParameters->CommandLine.Length - + sizeof Argument->Buffer.Buffer [0]; /* zero terminated */ - Argument->Buffer.Buffer = - (PWSTR) RtlAllocateHeap (ProcessHeap, - 0, - Argument->Buffer.MaximumLength); - if(NULL == Argument->Buffer.Buffer) - { - DPRINT("CSR: %s: no memory for Argument->Buffer.Buffer\n", __FUNCTION__); - return STATUS_NO_MEMORY; - } - - RtlCopyMemory (Argument->Buffer.Buffer, - RtlProcessParameters->CommandLine.Buffer, - RtlProcessParameters->CommandLine.Length); - - while (Argument->Buffer.Buffer [i]) - { - if (Argument->Buffer.Buffer[i] == L' ') - { - Argument->Count ++; - Argument->Buffer.Buffer [i] = L'\0'; - Argument->Vector [Argument->Count - 1] = & (Argument->Buffer.Buffer [afterlastspace]); - i++; - while (Argument->Buffer.Buffer [i] == L' ') - { - i++; - } - afterlastspace = i; - } - else - { - i++; - } - } - - if (Argument->Buffer.Buffer [afterlastspace] != L'\0') - { - Argument->Count ++; - Argument->Buffer.Buffer [i] = L'\0'; - Argument->Vector [Argument->Count - 1] = & (Argument->Buffer.Buffer [afterlastspace]); - } -#if !defined(NDEBUG) - for (i=0; iCount; i++) - { - DPRINT("CSR: Argument[%d] = '%S'\n", i, Argument->Vector [i]); - } -#endif - return STATUS_SUCCESS; -} -/********************************************************************** - * NAME PRIVATE - * CsrFreeCommandLine/2 - */ - -VOID FASTCALL CsrFreeCommandLine (PPEB Peb, - PCOMMAND_LINE_ARGUMENT Argument) -{ - DPRINT("CSR: %s called\n", __FUNCTION__); - - RtlFreeHeap (Peb->ProcessHeap, - 0, - Argument->Vector); - RtlFreeHeap (Peb->ProcessHeap, - 0, - Argument->Buffer.Buffer); -} -/* EOF */ diff --git a/reactos/subsys/csr/csr.h b/reactos/subsys/csr/csr.h deleted file mode 100644 index 5b6a33aecce..00000000000 --- a/reactos/subsys/csr/csr.h +++ /dev/null @@ -1,34 +0,0 @@ -#if !defined(_INCLUDE_CSR_H) -#define _INCLUDE_CSR_H - -/* PSDK/NDK Headers */ -#include -#include - -#define NTOS_MODE_USER -#include - -#include - - -#define CSRSS_ARGUMENT_SIZE 16 - -/* args.c */ -#define CSRP_MAX_ARGUMENT_COUNT 512 - -typedef struct _COMMAND_LINE_ARGUMENT -{ - ULONG Count; - UNICODE_STRING Buffer; - PWSTR * Vector; - -} COMMAND_LINE_ARGUMENT, *PCOMMAND_LINE_ARGUMENT; - -NTSTATUS FASTCALL CsrParseCommandLine (PPEB,PCOMMAND_LINE_ARGUMENT); -VOID FASTCALL CsrFreeCommandLine (PPEB,PCOMMAND_LINE_ARGUMENT); - -/* csrsrv.dll */ -NTSTATUS STDCALL CsrServerInitialization (ULONG,LPWSTR*); - -#endif /* !def _INCLUDE_CSR_H */ - diff --git a/reactos/subsys/csr/csrsrv/api.c b/reactos/subsys/csr/csrsrv/api.c new file mode 100644 index 00000000000..221e033a1ad --- /dev/null +++ b/reactos/subsys/csr/csrsrv/api.c @@ -0,0 +1,1412 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS CSR Sub System + * FILE: subsys/csr/csrsrv/api.c + * PURPOSE: CSR Server DLL API LPC Implementation + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + */ + +/* INCLUDES ******************************************************************/ + +#include "srv.h" + +#define NDEBUG +#include + +/* DATA **********************************************************************/ +BOOLEAN (*CsrClientThreadSetup)(VOID) = NULL; +ULONG CsrMaxApiRequestThreads; +UNICODE_STRING CsrSbApiPortName; +UNICODE_STRING CsrApiPortName; +HANDLE CsrSbApiPort; +HANDLE CsrApiPort; +PCSR_THREAD CsrSbApiRequestThreadPtr; +ULONG CsrpStaticThreadCount; +ULONG CsrpDynamicThreadTotal; + +/* PRIVATE FUNCTIONS *********************************************************/ + +/*++ + * @name CsrCheckRequestThreads + * + * The CsrCheckRequestThreads routine checks if there are no more threads + * to handle CSR API Requests, and creates a new thread if possible, to + * avoid starvation. + * + * @param None. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * if a new thread couldn't be created. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrCheckRequestThreads(VOID) +{ + HANDLE hThread; + CLIENT_ID ClientId; + NTSTATUS Status; + + /* Decrease the count, and see if we're out */ + if (!(InterlockedDecrement(&CsrpStaticThreadCount))) + { + /* Check if we've still got space for a Dynamic Thread */ + if (CsrpDynamicThreadTotal < CsrMaxApiRequestThreads) + { + /* Create a new dynamic thread */ + Status = RtlCreateUserThread(NtCurrentProcess(), + NULL, + TRUE, + 0, + 0, + 0, + CsrApiRequestThread, + NULL, + &hThread, + &ClientId); + /* Check success */ + if(NT_SUCCESS(Status)) + { + /* Increase the thread counts */ + CsrpStaticThreadCount++; + CsrpDynamicThreadTotal++; + + /* Add a new server thread */ + if (CsrAddStaticServerThread(hThread, + &ClientId, + CsrThreadIsServerThread)) + { + /* Activate it */ + NtResumeThread(hThread,NULL); + } + else + { + /* Failed to create a new static thread */ + CsrpStaticThreadCount--; + CsrpDynamicThreadTotal--; + + /* Terminate it */ + NtTerminateThread(hThread,0); + NtClose(hThread); + + /* Return */ + return STATUS_UNSUCCESSFUL; + } + } + } + } + + /* Success */ + return STATUS_SUCCESS; +} + +/*++ + * @name CsrSbApiPortInitialize + * + * The CsrSbApiPortInitialize routine initializes the LPC Port used for + * communications with the Session Manager (SM) and initializes the static + * thread that will handle connection requests and APIs. + * + * @param None + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrSbApiPortInitialize(VOID) +{ + ULONG Size; + PSECURITY_DESCRIPTOR PortSd; + OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS Status; + HANDLE hRequestThread; + CLIENT_ID ClientId; + + /* Calculate how much space we'll need for the Port Name */ + Size = CsrDirectoryName.Length + sizeof(SB_PORT_NAME) + sizeof(WCHAR); + + /* Allocate space for it, and create it */ + CsrSbApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size); + CsrSbApiPortName.Length = 0; + CsrSbApiPortName.MaximumLength = (USHORT)Size; + RtlAppendUnicodeStringToString(&CsrSbApiPortName, &CsrDirectoryName); + RtlAppendUnicodeToString(&CsrSbApiPortName, UNICODE_PATH_SEP); + RtlAppendUnicodeToString(&CsrSbApiPortName, SB_PORT_NAME); + + /* Create Security Descriptor for this Port */ + CsrCreateLocalSystemSD(&PortSd); + + /* Initialize the Attributes */ + InitializeObjectAttributes(&ObjectAttributes, + &CsrSbApiPortName, + 0, + PortSd, + NULL); + + /* Create the Port Object */ + Status = NtCreatePort(&CsrSbApiPort, + &ObjectAttributes, + sizeof(SB_CONNECTION_INFO), + sizeof(SB_API_MESSAGE), + 32 * sizeof(SB_API_MESSAGE)); + if(!NT_SUCCESS(Status)) + { + + } + + /* Create the Thread to handle the API Requests */ + Status = RtlCreateUserThread(NtCurrentProcess(), + NULL, + TRUE, + 0, + 0, + 0, + (PVOID)CsrSbApiRequestThread, + NULL, + &hRequestThread, + &ClientId); + if(!NT_SUCCESS(Status)) + { + + } + + /* Add it as a Static Server Thread */ + CsrSbApiRequestThreadPtr = CsrAddStaticServerThread(hRequestThread, + &ClientId, + 0); + + /* Activate it */ + return NtResumeThread(hRequestThread, NULL); +} + +/*++ + * @name CsrApiPortInitialize + * + * The CsrApiPortInitialize routine initializes the LPC Port used for + * communications with the Client/Server Runtime (CSR) and initializes the + * static thread that will handle connection requests and APIs. + * + * @param None + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrApiPortInitialize(VOID) +{ + ULONG Size; + OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS Status; + HANDLE hRequestEvent, hThread; + CLIENT_ID ClientId; + PLIST_ENTRY ListHead, NextEntry; + PCSR_THREAD ServerThread; + + /* Calculate how much space we'll need for the Port Name */ + Size = CsrDirectoryName.Length + sizeof(CSR_PORT_NAME) + sizeof(WCHAR); + + /* Allocate space for it, and create it */ + CsrApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size); + CsrApiPortName.Length = 0; + CsrApiPortName.MaximumLength = (USHORT)Size; + RtlAppendUnicodeStringToString(&CsrApiPortName, &CsrDirectoryName); + RtlAppendUnicodeToString(&CsrApiPortName, UNICODE_PATH_SEP); + RtlAppendUnicodeToString(&CsrApiPortName, CSR_PORT_NAME); + + /* FIXME: Create a Security Descriptor */ + + /* Initialize the Attributes */ + InitializeObjectAttributes(&ObjectAttributes, + &CsrApiPortName, + 0, + NULL, + NULL /* FIXME*/); + + /* Create the Port Object */ + Status = NtCreatePort(&CsrApiPort, + &ObjectAttributes, + sizeof(CSR_CONNECTION_INFO), + sizeof(CSR_API_MESSAGE), + 16 * PAGE_SIZE); + if(!NT_SUCCESS(Status)) + { + + } + + /* Create the event the Port Thread will use */ + Status = NtCreateEvent(&hRequestEvent, + EVENT_ALL_ACCESS, + NULL, + SynchronizationEvent, + FALSE); + if(!NT_SUCCESS(Status)) + { + + } + + /* Create the Request Thread */ + Status = RtlCreateUserThread(NtCurrentProcess(), + NULL, + TRUE, + 0, + 0, + 0, + (PVOID)CsrApiRequestThread, + (PVOID)hRequestEvent, + &hThread, + &ClientId); + if(!NT_SUCCESS(Status)) + { + + } + + /* Add this as a static thread to CSRSRV */ + CsrAddStaticServerThread(hThread, &ClientId, CsrThreadIsServerThread); + + /* Get the Thread List Pointers */ + ListHead = &CsrRootProcess->ThreadList; + NextEntry = ListHead->Flink; + + /* Start looping the list */ + while (NextEntry != ListHead) + { + /* Get the Thread */ + ServerThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link); + + /* Start it up */ + Status = NtResumeThread(ServerThread->ThreadHandle, NULL); + + /* Is this a Server Thread? */ + if (ServerThread->Flags & CsrThreadIsServerThread) + { + /* If so, then wait for it to initialize */ + NtWaitForSingleObject(hRequestEvent, FALSE, NULL); + } + + /* Next thread */ + NextEntry = NextEntry->Flink; + } + + /* We don't need this anymore */ + NtClose(hRequestEvent); + + /* Return */ + return Status; +} + +/*++ + * @name CsrApiRequestThread + * + * The CsrApiRequestThread routine handles incoming messages or connection + * requests on the CSR API LPC Port. + * + * @param Parameter + * System-default user-defined parameter. Unused. + * + * @return The thread exit code, if the thread is terminated. + * + * @remarks Before listening on the port, the routine will first attempt + * to connect to the user subsystem. + * + *--*/ +NTSTATUS +NTAPI +CsrApiRequestThread(IN PVOID Parameter) +{ + PTEB Teb = NtCurrentTeb(); + LARGE_INTEGER TimeOut; + PCSR_THREAD CurrentThread; + NTSTATUS Status; + PCSR_API_MESSAGE ReplyMsg = NULL; + CSR_API_MESSAGE ReceiveMsg; + PCSR_THREAD CsrThread; + PCSR_PROCESS CsrProcess; + PHARDERROR_MSG HardErrorMsg; + PVOID PortContext; + ULONG MessageType; + ULONG i; + PCSR_SERVER_DLL ServerDll; + PCLIENT_DIED_MSG ClientDiedMsg; + PDBGKM_MSG DebugMessage; + ULONG ServerId, ApiId; + ULONG Reply; + + /* Probably because of the way GDI is loaded, this has to be done here */ + Teb->GdiClientPID = HandleToUlong(Teb->Cid.UniqueProcess); + Teb->GdiClientTID = HandleToUlong(Teb->Cid.UniqueThread); + + /* Set up the timeout for the connect (30 seconds) */ + TimeOut.QuadPart = -30 * 1000 * 1000 * 10; + + /* Connect to user32 */ + while (!CsrConnectToUser()) + { + /* Keep trying until we get a response */ + Teb->Win32ClientInfo[0] = 0; + NtDelayExecution(FALSE, &TimeOut); + } + + /* Get our thread */ + CurrentThread = Teb->CsrClientThread; + + /* If we got an event... */ + if (Parameter) + { + /* Set it, to let stuff waiting on us load */ + NtSetEvent((HANDLE)Parameter, NULL); + + /* Increase the Thread Counts */ + InterlockedIncrement(&CsrpStaticThreadCount); + InterlockedIncrement(&CsrpDynamicThreadTotal); + } + + /* Now start the loop */ + while (TRUE) + { + /* Make sure the real CID is set */ + Teb->RealClientId = Teb->Cid; + + /* Wait for a message to come through */ + Status = NtReplyWaitReceivePort(CsrApiPort, + &PortContext, + (PPORT_MESSAGE)ReplyMsg, + (PPORT_MESSAGE)&ReceiveMsg); + + /* Check if we didn't get success */ + if(Status != STATUS_SUCCESS) + { + /* If we only got a warning, keep going */ + if (NT_SUCCESS(Status)) continue; + + /* We failed big time, so start out fresh */ + ReplyMsg = NULL; + continue; + } + + /* Use whatever Client ID we got */ + Teb->RealClientId = ReceiveMsg.Header.ClientId; + + /* Get the Message Type */ + MessageType = ReceiveMsg.Header.u2.s2.Type; + + /* Handle connection requests */ + if (MessageType == LPC_CONNECTION_REQUEST) + { + /* Handle the Connection Request */ + CsrApiHandleConnectionRequest(&ReceiveMsg); + ReplyMsg = NULL; + continue; + } + + /* It's some other kind of request. Get the lock for the lookup*/ + CsrAcquireProcessLock(); + + /* Now do the lookup to get the CSR_THREAD */ + CsrThread = CsrLocateThreadByClientId(&CsrProcess, + &ReceiveMsg.Header.ClientId); + + /* Did we find a thread? */ + if(!CsrThread) + { + /* This wasn't a CSR Thread, release lock */ + CsrReleaseProcessLock(); + + /* If this was an exception, handle it */ + if (MessageType == LPC_EXCEPTION) + { + ReplyMsg = &ReceiveMsg; + ReplyMsg->Status = DBG_CONTINUE; + } + else if (MessageType == LPC_PORT_CLOSED || + MessageType == LPC_CLIENT_DIED) + { + /* The Client or Port are gone, loop again */ + ReplyMsg = NULL; + } + else if (MessageType == LPC_ERROR_EVENT) + { + /* If it's a hard error, handle this too */ + HardErrorMsg = (PHARDERROR_MSG)&ReceiveMsg; + + /* Default it to unhandled */ + HardErrorMsg->Response = ResponseNotHandled; + + /* Check if there are free api threads */ + CsrCheckRequestThreads(); + if (CsrpStaticThreadCount) + { + /* Loop every Server DLL */ + for (i = 0; i < CSR_SERVER_DLL_MAX; i++) + { + /* Get the Server DLL */ + ServerDll = CsrLoadedServerDll[i]; + + /* Check if it's valid and if it has a Hard Error Callback */ + if (ServerDll && ServerDll->HardErrorCallback) + { + /* Call it */ + (*ServerDll->HardErrorCallback)(CsrThread, HardErrorMsg); + + /* If it's handled, get out of here */ + if (HardErrorMsg->Response != ResponseNotHandled) break; + } + } + } + + /* Increase the thread count */ + InterlockedIncrement(&CsrpStaticThreadCount); + + /* If the response was 0xFFFFFFFF, we'll ignore it */ + if (HardErrorMsg->Response == 0xFFFFFFFF) + { + ReplyMsg = NULL; + } + else + { + ReplyMsg = &ReceiveMsg; + } + } + else if (MessageType == LPC_REQUEST) + { + /* This is an API Message coming from a non-CSR Thread */ + ReplyMsg = &ReceiveMsg; + ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION; + } + else if (MessageType == LPC_DATAGRAM) + { + /* This is an API call, get the Server ID */ + ServerId = CSR_SERVER_ID_FROM_OPCODE(ReceiveMsg.Opcode); + + /* Make sure that the ID is within limits, and the Server DLL loaded */ + if ((ServerId >= CSR_SERVER_DLL_MAX) || + (!(ServerDll = CsrLoadedServerDll[ServerId]))) + { + /* We are beyond the Maximum Server ID */ + ReplyMsg = NULL; + } + else + { + /* Get the API ID */ + ApiId = CSR_API_ID_FROM_OPCODE(ReceiveMsg.Opcode); + + /* Normalize it with our Base ID */ + ApiId -= ServerDll->ApiBase; + + /* Make sure that the ID is within limits, and the entry exists */ + if ((ApiId >= ServerDll->HighestApiSupported)) + { + /* We are beyond the Maximum API ID, or it doesn't exist */ + ReplyMsg = NULL; + } + + /* Assume success */ + ReceiveMsg.Status = STATUS_SUCCESS; + + /* Validation complete, start SEH */ + _SEH_TRY + { + /* Make sure we have enough threads */ + CsrCheckRequestThreads(); + + /* Call the API and get the result */ + ReplyMsg = NULL; + (ServerDll->DispatchTable[ApiId])(&ReceiveMsg, &Reply); + + /* Increase the static thread count */ + InterlockedIncrement(&CsrpStaticThreadCount); + } + _SEH_EXCEPT(CsrUnhandledExceptionFilter) + { + ReplyMsg = NULL; + } + _SEH_END; + } + } + else + { + /* Some other ignored message type */ + ReplyMsg = NULL; + } + + /* Keep going */ + continue; + } + + /* We have a valid thread, was this an LPC Request? */ + if (MessageType != LPC_REQUEST) + { + /* It's not an API, check if the client died */ + if (MessageType == LPC_CLIENT_DIED) + { + /* Get the information and check if it matches our thread */ + ClientDiedMsg = (PCLIENT_DIED_MSG)&ReceiveMsg; + if (ClientDiedMsg->CreateTime.QuadPart = CsrThread->CreateTime.QuadPart) + { + /* Reference the thread */ + CsrThread->ReferenceCount++; + + /* Destroy the thread in the API Message */ + CsrDestroyThread(&ReceiveMsg.Header.ClientId); + + /* Check if the thread was actually ourselves */ + if (CsrProcess->ThreadCount == 1) + { + /* Kill the process manually here */ + CsrDestroyProcess(&CsrThread->ClientId, 0); + } + + /* Remove our extra reference */ + CsrLockedDereferenceThread(CsrThread); + } + + /* Release the lock and keep looping */ + CsrReleaseProcessLock(); + ReplyMsg = NULL; + continue; + } + + /* Reference the thread and release the lock */ + CsrThread->ReferenceCount++; + CsrReleaseProcessLock(); + + /* Check if this was an exception */ + if (MessageType == LPC_EXCEPTION) + { + /* Kill the process */ + NtTerminateProcess(CsrProcess->ProcessHandle, STATUS_ABANDONED); + + /* Destroy it from CSR */ + CsrDestroyProcess(&ReceiveMsg.Header.ClientId, STATUS_ABANDONED); + + /* Return a Debug Message */ + DebugMessage = (PDBGKM_MSG)&ReceiveMsg; + DebugMessage->Status = DBG_CONTINUE; + ReplyMsg = &ReceiveMsg; + + /* Remove our extra reference */ + CsrDereferenceThread(CsrThread); + } + else if (MessageType == LPC_ERROR_EVENT) + { + /* If it's a hard error, handle this too */ + HardErrorMsg = (PHARDERROR_MSG)&ReceiveMsg; + + /* Default it to unhandled */ + HardErrorMsg->Response = ResponseNotHandled; + + /* Check if there are free api threads */ + CsrCheckRequestThreads(); + if (CsrpStaticThreadCount) + { + /* Loop every Server DLL */ + for (i = 0; i < CSR_SERVER_DLL_MAX; i++) + { + /* Get the Server DLL */ + ServerDll = CsrLoadedServerDll[i]; + + /* Check if it's valid and if it has a Hard Error Callback */ + if (ServerDll && ServerDll->HardErrorCallback) + { + /* Call it */ + (*ServerDll->HardErrorCallback)(CsrThread, HardErrorMsg); + + /* If it's handled, get out of here */ + if (HardErrorMsg->Response != ResponseNotHandled) break; + } + } + } + + /* Increase the thread count */ + InterlockedIncrement(&CsrpStaticThreadCount); + + /* If the response was 0xFFFFFFFF, we'll ignore it */ + if (HardErrorMsg->Response == 0xFFFFFFFF) + { + ReplyMsg = NULL; + } + else + { + CsrDereferenceThread(CsrThread); + ReplyMsg = &ReceiveMsg; + } + } + else + { + /* Something else */ + CsrDereferenceThread(CsrThread); + ReplyMsg = NULL; + } + + /* Keep looping */ + continue; + } + + /* We got an API Request */ + CsrDereferenceThread(CsrThread); + CsrReleaseProcessLock(); + + /* FIXME: Handle the API */ + + } + + /* We're out of the loop for some reason, terminate! */ + NtTerminateThread(NtCurrentThread(), Status); + return Status; +} + +/*++ + * @name CsrApiHandleConnectionRequest + * + * The CsrApiHandleConnectionRequest routine handles and accepts a new + * connection request to the CSR API LPC Port. + * + * @param ApiMessage + * Pointer to the incoming CSR API Message which contains the + * connection request. + * + * @return STATUS_SUCCESS in case of success, or status code which caused + * the routine to error. + * + * @remarks This routine is responsible for attaching the Shared Section to + * new clients connecting to CSR. + * + *--*/ +NTSTATUS +NTAPI +CsrApiHandleConnectionRequest(IN PCSR_API_MESSAGE ApiMessage) +{ + PCSR_THREAD CsrThread; + PCSR_PROCESS CsrProcess; + NTSTATUS Status; + PCSR_CONNECTION_INFO ConnectInfo = &ApiMessage->ConnectionInfo; + BOOLEAN AllowConnection = FALSE; + REMOTE_PORT_VIEW RemotePortView; + HANDLE hPort; + + /* Acquire the Process Lock */ + CsrAcquireProcessLock(); + + /* Lookup the CSR Thread */ + CsrThread = CsrLocateThreadByClientId(NULL, &ApiMessage->Header.ClientId); + + /* Check if we have a thread */ + if (CsrThread) + { + /* Get the Process */ + CsrProcess = CsrThread->Process; + + /* Make sure we have a Process as well */ + if (CsrProcess) + { + /* Reference the Process */ + CsrProcess->ReferenceCount++; + + /* Release the lock */ + CsrReleaseProcessLock(); + + /* Duplicate the Object Directory */ + Status = NtDuplicateObject(NtCurrentProcess(), + CsrObjectDirectory, + CsrProcess->ProcessHandle, + &ConnectInfo->ObjectDirectory, + 0, + 0, + DUPLICATE_SAME_ACCESS | + DUPLICATE_SAME_ATTRIBUTES); + + /* Acquire the lock */ + CsrAcquireProcessLock(); + + /* Check for success */ + if (NT_SUCCESS(Status)) + { + /* Attach the Shared Section */ + Status = CsrSrvAttachSharedSection(CsrProcess, ConnectInfo); + + /* Check how this went */ + if (NT_SUCCESS(Status)) AllowConnection = TRUE; + } + + /* Dereference the project */ + CsrProcess->ReferenceCount--; + } + } + + /* Release the lock */ + CsrReleaseProcessLock(); + + /* Setup the Port View Structure */ + RemotePortView.Length = sizeof(REMOTE_PORT_VIEW); + RemotePortView.ViewSize = 0; + RemotePortView.ViewBase = NULL; + + /* Save the Process ID */ + ConnectInfo->ProcessId = NtCurrentTeb()->Cid.UniqueProcess; + + /* Accept the Connection */ + Status = NtAcceptConnectPort(&hPort, + AllowConnection ? UlongToPtr(CsrProcess->SequenceNumber) : 0, + &ApiMessage->Header, + AllowConnection, + NULL, + &RemotePortView); + + /* Check if the connection was established, or if we allowed it */ + if (NT_SUCCESS(Status) && AllowConnection) + { + /* Set some Port Data in the Process */ + CsrProcess->ClientPort = hPort; + CsrProcess->ClientViewBase = (ULONG_PTR)RemotePortView.ViewBase; + CsrProcess->ClientViewBounds = (ULONG_PTR)((ULONG_PTR)RemotePortView.ViewBase + + (ULONG_PTR)RemotePortView.ViewSize); + + /* Complete the connection */ + Status = NtCompleteConnectPort(hPort); + } + + /* The accept or complete could've failed, let debug builds know */ + if (!NT_SUCCESS(Status)) + { + DPRINT1("CSRSS: Failure to accept connection. Status: %lx\n", Status); + } + + /* Return status to caller */ + return Status; +} + +/*++ + * @name CsrSbApiRequestThread + * + * The CsrSbApiRequestThread routine handles incoming messages or connection + * requests on the SM API LPC Port. + * + * @param Parameter + * System-default user-defined parameter. Unused. + * + * @return The thread exit code, if the thread is terminated. + * + * @remarks Before listening on the port, the routine will first attempt + * to connect to the user subsystem. + * + *--*/ +VOID +NTAPI +CsrSbApiRequestThread(IN PVOID Parameter) +{ + NTSTATUS Status; + SB_API_MESSAGE ReceiveMsg; + PSB_API_MESSAGE ReplyMsg = NULL; + PVOID PortContext; + ULONG MessageType; + + /* Start the loop */ + while (TRUE) + { + /* Wait for a message to come in */ + Status = NtReplyWaitReceivePort(CsrSbApiPort, + &PortContext, + (PPORT_MESSAGE)ReplyMsg, + (PPORT_MESSAGE)&ReceiveMsg); + + /* Check if we didn't get success */ + if(Status != STATUS_SUCCESS) + { + /* If we only got a warning, keep going */ + if (NT_SUCCESS(Status)) continue; + + /* We failed big time, so start out fresh */ + ReplyMsg = NULL; + continue; + } + + /* Save the message type */ + MessageType = ReceiveMsg.Header.u2.s2.Type; + + /* Check if this is a connection request */ + if (MessageType == LPC_CONNECTION_REQUEST) + { + /* Handle connection request */ + CsrSbApiHandleConnectionRequest(&ReceiveMsg); + + /* Start over */ + ReplyMsg = NULL; + continue; + } + + /* Check if the port died */ + if (MessageType == LPC_PORT_CLOSED) + { + /* Close the handle if we have one */ + if (PortContext) NtClose((HANDLE)PortContext); + + /* Client died, start over */ + ReplyMsg = NULL; + continue; + } + else if (MessageType == LPC_CLIENT_DIED) + { + /* Client died, start over */ + ReplyMsg = NULL; + continue; + } + + /* + * It's an API Message, check if it's within limits. If it's not, the + * NT Behaviour is to set this to the Maximum API. + */ + if (ReceiveMsg.Opcode > 4) ReceiveMsg.Opcode = 4; + + /* Reuse the message */ + ReplyMsg = &ReceiveMsg; + + /* Make sure that the message is supported */ + if (ReceiveMsg.Opcode < 4) + { + /* Call the API */ + if (!(CsrServerSbApiDispatch[ReceiveMsg.Opcode])(&ReceiveMsg)) + { + /* It failed, so return nothing */ + ReplyMsg = NULL; + } + } + else + { + /* We don't support this API Number */ + ReplyMsg->Status = STATUS_NOT_IMPLEMENTED; + } + } +} + +/*++ + * @name CsrSbApiHandleConnectionRequest + * + * The CsrSbApiHandleConnectionRequest routine handles and accepts a new + * connection request to the SM API LPC Port. + * + * @param ApiMessage + * Pointer to the incoming CSR API Message which contains the + * connection request. + * + * @return STATUS_SUCCESS in case of success, or status code which caused + * the routine to error. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrSbApiHandleConnectionRequest(IN PSB_API_MESSAGE Message) +{ + NTSTATUS Status; + REMOTE_PORT_VIEW RemotePortView; + HANDLE hPort; + + /* Set the Port View Structure Length */ + RemotePortView.Length = sizeof(REMOTE_PORT_VIEW); + + /* Accept the connection */ + Status = NtAcceptConnectPort(&hPort, + NULL, + (PPORT_MESSAGE)Message, + TRUE, + NULL, + &RemotePortView); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("CSRSS: Sb Accept Connection failed %lx\n", Status); + return Status; + } + + /* Complete the Connection */ + if (!NT_SUCCESS(Status = NtCompleteConnectPort(hPort))) + { + DPRINT1("CSRSS: Sb Complete Connection failed %lx\n",Status); + } + + /* Return status */ + return Status; +} + +/* PUBLIC FUNCTIONS **********************************************************/ + +/*++ + * @name CsrCallServerFromServer + * @implemented NT4 + * + * The CsrCallServerFromServer routine calls a CSR API from within a server. + * It avoids using LPC messages since the request isn't coming from a client. + * + * @param ReceiveMsg + * Pointer to the CSR API Message to send to the server. + * + * @param ReplyMsg + * Pointer to the CSR API Message to receive from the server. + * + * @return STATUS_SUCCESS in case of success, STATUS_ILLEGAL_FUNCTION + * if the opcode is invalid, or STATUS_ACCESS_VIOLATION if there + * was a problem executing the API. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrCallServerFromServer(PCSR_API_MESSAGE ReceiveMsg, + PCSR_API_MESSAGE ReplyMsg) +{ + ULONG ServerId; + PCSR_SERVER_DLL ServerDll; + ULONG ApiId; + ULONG Reply; + NTSTATUS Status; + + /* Get the Server ID */ + ServerId = CSR_SERVER_ID_FROM_OPCODE(ReceiveMsg->Opcode); + + /* Make sure that the ID is within limits, and the Server DLL loaded */ + if ((ServerId >= CSR_SERVER_DLL_MAX) || + (!(ServerDll = CsrLoadedServerDll[ServerId]))) + { + /* We are beyond the Maximum Server ID */ + ReplyMsg->Status = (ULONG)STATUS_ILLEGAL_FUNCTION; + return STATUS_ILLEGAL_FUNCTION; + } + else + { + /* Get the API ID */ + ApiId = CSR_API_ID_FROM_OPCODE(ReceiveMsg->Opcode); + + /* Normalize it with our Base ID */ + ApiId -= ServerDll->ApiBase; + + /* Make sure that the ID is within limits, and the entry exists */ + if ((ApiId >= ServerDll->HighestApiSupported) || + (ServerDll->ValidTable && !ServerDll->ValidTable[ApiId])) + { + /* We are beyond the Maximum API ID, or it doesn't exist */ + ReplyMsg->Status = (ULONG)STATUS_ILLEGAL_FUNCTION; + return STATUS_ILLEGAL_FUNCTION; + } + } + + /* Validation complete, start SEH */ + _SEH_TRY + { + /* Call the API and get the result */ + Status = (ServerDll->DispatchTable[ApiId])(ReceiveMsg, &Reply); + + /* Return the result, no matter what it is */ + ReplyMsg->Status = Status; + } + _SEH_HANDLE + { + /* If we got an exception, return access violation */ + ReplyMsg->Status = STATUS_ACCESS_VIOLATION; + } + _SEH_END; + + /* Return success */ + return STATUS_SUCCESS; +} + +/*++ + * @name CsrConnectToUser + * @implemented NT4 + * + * The CsrConnectToUser connects to the User subsystem. + * + * @param None + * + * @return A pointer to the CSR Thread + * + * @remarks None. + * + *--*/ +PCSR_THREAD +NTAPI +CsrConnectToUser(VOID) +{ + NTSTATUS Status; + ANSI_STRING DllName; + UNICODE_STRING TempName; + HANDLE hUser32; + STRING StartupName; + PTEB Teb = NtCurrentTeb(); + PCSR_THREAD CsrThread; + + /* Check if we didn't already find it */ + if (!CsrClientThreadSetup) + { + /* Get the DLL Handle for user32.dll */ + RtlInitAnsiString(&DllName, "user32"); + RtlAnsiStringToUnicodeString(&TempName, &DllName, TRUE); + Status = LdrGetDllHandle(NULL, + NULL, + &TempName, + &hUser32); + RtlFreeUnicodeString(&TempName); + + /* If we got teh handle, get the Client Thread Startup Entrypoint */ + if (NT_SUCCESS(Status)) + { + RtlInitAnsiString(&StartupName,"ClientThreadSetup"); + Status = LdrGetProcedureAddress(hUser32, + &StartupName, + 0, + (PVOID)&CsrClientThreadSetup); + } + } + + /* Connect to user32 */ + CsrClientThreadSetup(); + + /* Save pointer to this thread in TEB */ + CsrThread = CsrLocateThreadInProcess(NULL, &Teb->Cid); + if (CsrThread) Teb->CsrClientThread = CsrThread; + + /* Return it */ + return CsrThread; +} + +/*++ + * @name CsrQueryApiPort + * @implemented NT4 + * + * The CsrQueryApiPort routine returns a handle to the CSR API LPC port. + * + * @param None. + * + * @return A handle to the port. + * + * @remarks None. + * + *--*/ +HANDLE +NTAPI +CsrQueryApiPort(VOID) +{ + DPRINT("CSRSRV: %s called\n", __FUNCTION__); + return CsrApiPort; +} + +/*++ + * @name CsrCaptureArguments + * @implemented NT5.1 + * + * The CsrCaptureArguments routine validates a CSR Capture Buffer and + * re-captures it into a server CSR Capture Buffer. + * + * @param CsrThread + * Pointer to the CSR Thread performing the validation. + * + * @param ApiMessage + * Pointer to the CSR API Message containing the Capture Buffer + * that needs to be validated. + * + * @return TRUE if validation succeeded, FALSE otherwise. + * + * @remarks None. + * + *--*/ +BOOLEAN +NTAPI +CsrCaptureArguments(IN PCSR_THREAD CsrThread, + IN PCSR_API_MESSAGE ApiMessage) +{ + PCSR_CAPTURE_BUFFER LocalCaptureBuffer; + ULONG LocalLength; + PCSR_CAPTURE_BUFFER RemoteCaptureBuffer; + SIZE_T BufferDistance; + ULONG PointerCount; + ULONG_PTR **PointerOffsets; + ULONG_PTR *CurrentPointer; + + /* Use SEH to make sure this is valid */ + _SEH_TRY + { + /* Get the buffer we got from whoever called NTDLL */ + LocalCaptureBuffer = ApiMessage->CsrCaptureData; + LocalLength = LocalCaptureBuffer->Size; + + /* Now check if the buffer is inside our mapped section */ + if (((ULONG_PTR)LocalCaptureBuffer < CsrThread->Process->ClientViewBase) || + (((ULONG_PTR)LocalCaptureBuffer + LocalLength) >= CsrThread->Process->ClientViewBounds)) + { + /* Return failure */ + ApiMessage->Status = STATUS_INVALID_PARAMETER; + return FALSE; + } + + /* Check if the Length is valid */ + if (((LocalCaptureBuffer->PointerCount * 4 + sizeof(CSR_CAPTURE_BUFFER)) > + LocalLength) ||(LocalLength > MAXWORD)) + { + /* Return failure */ + ApiMessage->Status = STATUS_INVALID_PARAMETER; + return FALSE; + } + } + _SEH_HANDLE + { + /* Return failure */ + ApiMessage->Status = STATUS_INVALID_PARAMETER; + return FALSE; + } _SEH_END; + + /* We validated the incoming buffer, now allocate the remote one */ + RemoteCaptureBuffer = RtlAllocateHeap(CsrHeap, 0, LocalLength); + if (!RemoteCaptureBuffer) + { + /* We're out of memory */ + ApiMessage->Status = STATUS_NO_MEMORY; + return FALSE; + } + + /* Copy the client's buffer */ + RtlMoveMemory(RemoteCaptureBuffer, LocalCaptureBuffer, LocalLength); + + /* Copy the length */ + RemoteCaptureBuffer->Size = LocalLength; + + /* Calculate the difference between our buffer and the client's */ + BufferDistance = (ULONG_PTR)RemoteCaptureBuffer - (ULONG_PTR)LocalCaptureBuffer; + + /* Save the pointer count and offset pointer */ + PointerCount = RemoteCaptureBuffer->PointerCount; + PointerOffsets = (ULONG_PTR**)(RemoteCaptureBuffer + 1); + + /* Start the loop */ + while (PointerCount) + { + /* Get the current pointer */ + if ((CurrentPointer = *PointerOffsets++)) + { + /* Add it to the CSR Message structure */ + CurrentPointer += (ULONG_PTR)ApiMessage; + + /* Validate the bounds of the current pointer */ + if ((*CurrentPointer >= CsrThread->Process->ClientViewBase) && + (*CurrentPointer < CsrThread->Process->ClientViewBounds)) + { + /* Modify the pointer to take into account its new position */ + *CurrentPointer += BufferDistance; + } + else + { + /* Invalid pointer, fail */ + ApiMessage->Status = (ULONG)STATUS_INVALID_PARAMETER; + } + } + + /* Move to the next Pointer */ + PointerCount--; + } + + /* Check if we got success */ + if (ApiMessage->Status != STATUS_SUCCESS) + { + /* Failure. Free the buffer and return*/ + RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer); + return FALSE; + } + else + { + /* Success, save the previous buffer */ + RemoteCaptureBuffer->PreviousCaptureBuffer = LocalCaptureBuffer; + ApiMessage->CsrCaptureData = RemoteCaptureBuffer; + } + + /* Success */ + return TRUE; +} + +/*++ + * @name CsrReleaseCapturedArguments + * @implemented NT5.1 + * + * The CsrReleaseCapturedArguments routine releases a Capture Buffer + * that was previously captured with CsrCaptureArguments. + * + * @param ApiMessage + * Pointer to the CSR API Message containing the Capture Buffer + * that needs to be released. + * + * @return None. + * + * @remarks None. + * + *--*/ +VOID +NTAPI +CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage) +{ + PCSR_CAPTURE_BUFFER RemoteCaptureBuffer; + PCSR_CAPTURE_BUFFER LocalCaptureBuffer; + SIZE_T BufferDistance; + ULONG PointerCount; + ULONG_PTR **PointerOffsets; + ULONG_PTR *CurrentPointer; + + /* Get the capture buffers */ + RemoteCaptureBuffer = ApiMessage->CsrCaptureData; + LocalCaptureBuffer = RemoteCaptureBuffer->PreviousCaptureBuffer; + + /* Free the previous one */ + RemoteCaptureBuffer->PreviousCaptureBuffer = NULL; + + /* Find out the difference between the two buffers */ + BufferDistance = (ULONG_PTR)LocalCaptureBuffer - (ULONG_PTR)RemoteCaptureBuffer; + + /* Save the pointer count and offset pointer */ + PointerCount = RemoteCaptureBuffer->PointerCount; + PointerOffsets = (ULONG_PTR**)(RemoteCaptureBuffer + 1); + + /* Start the loop */ + while (PointerCount) + { + /* Get the current pointer */ + if ((CurrentPointer = *PointerOffsets++)) + { + /* Add it to the CSR Message structure */ + CurrentPointer += (ULONG_PTR)ApiMessage; + + /* Modify the pointer to take into account its new position */ + *CurrentPointer += BufferDistance; + } + + /* Move to the next Pointer */ + PointerCount--; + } + + /* Copy the data back */ + RtlMoveMemory(LocalCaptureBuffer, + RemoteCaptureBuffer, + RemoteCaptureBuffer->Size); + + /* Free our allocated buffer */ + RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer); +} + +/*++ + * @name CsrValidateMessageBuffer + * @implemented NT5.1 + * + * The CsrValidateMessageBuffer routine validates a captured message buffer + * present in the CSR Api Message + * + * @param ApiMessage + * Pointer to the CSR API Message containing the CSR Capture Buffer. + * + * @param Buffer + * Pointer to the message buffer to validate. + * + * @param ArgumentSize + * Size of the message to check. + * + * @param ArgumentCount + * Number of messages to check. + * + * @return TRUE if validation suceeded, FALSE otherwise. + * + * @remarks None. + * + *--*/ +BOOLEAN +NTAPI +CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage, + IN PVOID *Buffer, + IN ULONG ArgumentSize, + IN ULONG ArgumentCount) +{ + PCSR_CAPTURE_BUFFER CaptureBuffer = ApiMessage->CsrCaptureData; + SIZE_T BufferDistance; + ULONG PointerCount; + ULONG_PTR **PointerOffsets; + ULONG_PTR *CurrentPointer; + ULONG i; + + /* Make sure there are some arguments */ + if (!ArgumentCount) return FALSE; + + /* Check if didn't get a buffer and there aren't any arguments to check */ + if (!(*Buffer) && (!(ArgumentCount * ArgumentSize))) return TRUE; + + /* Check if we have no capture buffer */ + if (!CaptureBuffer) + { + /* In this case, check only the Process ID */ + if (NtCurrentTeb()->Cid.UniqueProcess == + ApiMessage->Header.ClientId.UniqueProcess) + { + /* There is a match, validation succeeded */ + return TRUE; + } + } + else + { + /* Make sure that there is still space left in the buffer */ + if ((CaptureBuffer->Size - (ULONG_PTR)*Buffer + (ULONG_PTR)CaptureBuffer) < + (ArgumentCount * ArgumentSize)) + { + /* Find out the difference between the two buffers */ + BufferDistance = (ULONG_PTR)Buffer - (ULONG_PTR)ApiMessage; + + /* Save the pointer count */ + PointerCount = CaptureBuffer->PointerCount; + PointerOffsets = (ULONG_PTR**)(CaptureBuffer + 1); + + /* Start the loop */ + for (i = 0; i < PointerCount; i++) + { + /* Get the current pointer */ + CurrentPointer = *PointerOffsets++; + + /* Check if its' equal to the difference */ + if (*CurrentPointer == BufferDistance) return TRUE; + } + } + } + + /* Failure */ + return FALSE; +} + +/*++ + * @name CsrValidateMessageString + * @implemented NT5.1 + * + * The CsrValidateMessageString validates a captured Wide-Character String + * present in a CSR API Message. + * + * @param ApiMessage + * Pointer to the CSR API Message containing the CSR Capture Buffer. + * + * @param MessageString + * Pointer to the buffer containing the string to validate. + * + * @return TRUE if validation suceeded, FALSE otherwise. + * + * @remarks None. + * + *--*/ +BOOLEAN +NTAPI +CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage, + IN LPWSTR *MessageString) +{ + DPRINT("CSRSRV: %s called\n", __FUNCTION__); + return FALSE; +} + +/* EOF */ diff --git a/reactos/subsys/csr/csrsrv/csrsrv.def b/reactos/subsys/csr/csrsrv/csrsrv.def index 1a1f066b93f..0efc417b237 100644 --- a/reactos/subsys/csr/csrsrv/csrsrv.def +++ b/reactos/subsys/csr/csrsrv/csrsrv.def @@ -1,37 +1,38 @@ -; $Id$ -LIBRARY csrsrv.dll +LIBRARY CSRSRV + EXPORTS -CsrAddStaticServerThread@4 -CsrCallServerFromServer@0 -CsrCreateProcess@8 -CsrCreateRemoteThread@0 -CsrCreateThread@8 -CsrCreateWait@8 -CsrDebugProcess@4 -CsrDebugProcessStop@4 -CsrDereferenceProcess@4 -CsrDereferenceThread@4 -CsrDereferenceWait@4 -CsrDestroyProcess@4 -CsrDestroyThread@4 -CsrExecServerThread@0 -CsrGetProcessLuid@8 -CsrImpersonateClient@0 -CsrLockProcessByClientId@0 -CsrLockThreadByClientId@0 -CsrMoveSatisfiedWait@4 -CsrNotifyWait@4 -CsrQueryApiPort@0 -CsrReferenceThread@4 -CsrRevertToSelf@0 -CsrServerInitialization@8 -CsrSetBackgroundPriority@0 -CsrSetCallingSpooler@0 -CsrSetForegroundPriority@0 -CsrShutdownProcesses@4 -CsrUnhandledExceptionFilter@0 -CsrUnlockProcess@4 -CsrUnlockThread@4 -CsrValidateMessageBuffer@0 -CsrValidateMessageString@0 -; EOF +CsrAddStaticServerThread +CsrCallServerFromServer +CsrConnectToUser +CsrCreateProcess +CsrCreateRemoteThread +CsrCreateThread +CsrCreateWait +CsrDebugProcess +CsrDebugProcessStop +CsrDereferenceProcess +CsrDereferenceThread +CsrDereferenceWait +CsrDestroyProcess +CsrDestroyThread +CsrExecServerThread +CsrGetProcessLuid +CsrImpersonateClient +CsrLockProcessByClientId +CsrLockThreadByClientId +CsrMoveSatisfiedWait +CsrNotifyWait +CsrPopulateDosDevices +CsrQueryApiPort +CsrReferenceThread +CsrRevertToSelf +CsrServerInitialization +CsrSetBackgroundPriority +CsrSetCallingSpooler +CsrSetForegroundPriority +CsrShutdownProcesses +CsrUnhandledExceptionFilter +CsrUnlockProcess +CsrUnlockThread +CsrValidateMessageBuffer +CsrValidateMessageString diff --git a/reactos/subsys/csr/csrsrv/debug.c b/reactos/subsys/csr/csrsrv/debug.c deleted file mode 100644 index c5c9abdc881..00000000000 --- a/reactos/subsys/csr/csrsrv/debug.c +++ /dev/null @@ -1,53 +0,0 @@ -/* $Id$ - * - * subsys/csr/csrsrv/debug.c - CSR server - debugging management - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - */ -#include "srv.h" - -//#define NDEBUG -#include - -/*===================================================================== - * PUBLIC API - *===================================================================*/ - -NTSTATUS STDCALL CsrDebugProcess (PCSR_PROCESS pCsrProcess) -{ - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s(%08lx) called\n", __FUNCTION__, pCsrProcess); - - return Status; -} - -NTSTATUS STDCALL CsrDebugProcessStop (PCSR_PROCESS pCsrProcess) -{ - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s(%08lx) called\n", __FUNCTION__, pCsrProcess); - - return Status; -} - -/* EOF */ diff --git a/reactos/subsys/csr/csrsrv/dllmain.c b/reactos/subsys/csr/csrsrv/dllmain.c deleted file mode 100644 index 483aacfac82..00000000000 --- a/reactos/subsys/csr/csrsrv/dllmain.c +++ /dev/null @@ -1,33 +0,0 @@ -/* $Id$ - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS system libraries - * FILE: subsys/csr/csrsrv/dllmain.c - * PURPOSE: DLL entry point - */ - -/* INCLUDES ******************************************************************/ - -#include "srv.h" - -#define NDEBUG -#include - -HANDLE CsrSrvDllHandle = 0; - -/* FUNCTIONS *****************************************************************/ - -BOOL STDCALL -DllMain(HANDLE hDll, - DWORD dwReason, - LPVOID lpReserved) -{ - if (DLL_PROCESS_ATTACH == dwReason) - { - CsrSrvDllHandle = hDll; - } - - return TRUE; -} - -/* EOF */ diff --git a/reactos/subsys/csr/csrsrv/init.c b/reactos/subsys/csr/csrsrv/init.c index 2b287626452..6dabddaf0dc 100644 --- a/reactos/subsys/csr/csrsrv/init.c +++ b/reactos/subsys/csr/csrsrv/init.c @@ -1,427 +1,1232 @@ -/* $Id$ - * - * subsys/csr/csrsrv/init.c - CSR server - initialization - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS CSR Sub System + * FILE: subsys/csr/csrsrv/init.c + * PURPOSE: CSR Server DLL Initialization + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) */ +/* INCLUDES ******************************************************************/ + #include "srv.h" -//#define NDEBUG +#define NDEBUG #include +/* DATA **********************************************************************/ -typedef enum { - CSRAT_UNKNOWN=0, - CSRAT_OBJECT_DIRECTORY, - CSRAT_SUBSYSTEM_TYPE, - CSRAT_REQUEST_THREADS, /* ReactOS extension */ - CSRAT_REQUEST_THREADS_MAX, - CSRAT_PROFILE_CONTROL, - CSRAT_SHARED_SECTION, - CSRAT_SERVER_DLL, - CSRAT_WINDOWS, - CSRAT_SESSIONS, /* ReactOS extension */ - CSRAT_MAX -} CSR_ARGUMENT_TYPE, *PCSR_ARGUMENT_TYPE; +HANDLE CsrObjectDirectory; +ULONG SessionId; +BOOLEAN CsrProfileControl; +UNICODE_STRING CsrDirectoryName; +HANDLE CsrHeap; +HANDLE BNOLinksDirectory; +HANDLE SessionObjectDirectory; +HANDLE DosDevicesDirectory; +HANDLE CsrInitializationEvent; +SYSTEM_BASIC_INFORMATION CsrNtSysInfo; -typedef struct _CSR_ARGUMENT_ITEM +/* PRIVATE FUNCTIONS *********************************************************/ + +/*++ + * @name CsrPopulateDosDevicesDirectory + * + * The CsrPopulateDosDevicesDirectory routine uses the DOS Device Map from the + * Kernel to populate the Dos Devices Object Directory for the session. + * + * @param TODO. + * + * @return TODO. + * + * @remarks TODO. + * + *--*/ +NTSTATUS +NTAPI +CsrPopulateDosDevicesDirectory(IN HANDLE hDosDevicesDirectory, + IN PPROCESS_DEVICEMAP_INFORMATION DeviceMap) { - CSR_ARGUMENT_TYPE Type; - UNICODE_STRING Data; - union { - UNICODE_STRING ObjectDirectory; - CSR_SUBSYSTEM_TYPE SubSystemType; - USHORT RequestThreads; - USHORT MaxRequestThreads; - BOOL ProfileControl; - BOOL Windows; - BOOL Sessions; - CSR_SERVER_DLL ServerDll; - struct { - USHORT PortSectionSize; // 1024k; 128k..? - USHORT InteractiveDesktopHeapSize; // 3072k; 128k.. - USHORT NonInteractiveDesktopHeapSize; // (InteractiveDesktopHeapSize); 128k.. - USHORT Reserved; /* unused */ - } SharedSection; - } Item; - -} CSR_ARGUMENT_ITEM, * PCSR_ARGUMENT_ITEM; + WCHAR SymLinkBuffer[0x1000]; + UNICODE_STRING GlobalString; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE hDirectory = 0; + NTSTATUS Status; + ULONG ReturnLength = 0; + ULONG BufferLength = 0x4000; + ULONG Context; + POBJECT_DIRECTORY_INFORMATION QueryBuffer; + HANDLE hSymLink; + UNICODE_STRING LinkTarget; -/********************************************************************** - * CsrpStringToBool/3 PRIVATE - */ -static BOOL STDCALL CsrpStringToBool (LPWSTR TestString, LPWSTR TrueString, LPWSTR FalseString) -{ - if((0 == wcscmp(TestString, TrueString))) - { - return TRUE; - } - if((0 == wcscmp(TestString, FalseString))) - { - return FALSE; - } - DPRINT1("CSRSRV:%s: replacing invalid value '%S' with '%S'!\n", - __FUNCTION__, TestString, FalseString); - return FALSE; -} -/********************************************************************** - * CsrpSplitServerDll/2 PRIVATE - * - * RETURN VALUE - * 0: syntax error - * 2: ServerDll=="basesrv,1" - * 3: ServerDll=="winsrv:UserServerDllInitialization,3" - */ -static INT STDCALL CsrpSplitServerDll (LPWSTR ServerDll, PCSR_ARGUMENT_ITEM pItem) -{ - LPWSTR DllName = NULL; - LPWSTR DllEntryPoint = NULL; - LPWSTR DllId = NULL; - static LPWSTR DefaultDllEntryPoint = L"ServerDllInitialization"; - LPWSTR tmp = NULL; - INT rc = 0; - PCSR_SERVER_DLL pCsrServerDll = & pItem->Item.ServerDll; + /* Initialize the Global String */ + RtlInitUnicodeString(&GlobalString, GLOBAL_ROOT); - if (L'\0' == *ServerDll) - { - return 0; - } - /* - * DllName (required) - */ - DllName = ServerDll; - if (NULL == DllName) - { - return 0; - } - /* - * DllEntryPoint (optional) - */ - DllEntryPoint = wcschr (ServerDll, L':'); - if (NULL == DllEntryPoint) - { - DllEntryPoint = DefaultDllEntryPoint; - tmp = ServerDll; - rc = 2; - } else { - tmp = ++DllEntryPoint; - rc = 3; - } - /* - * DllId (required) - */ - DllId = wcschr (tmp, L','); - if (NULL == DllId) - { - return 0; - } - *DllId++ = L'\0'; - // OK - pCsrServerDll->ServerIndex = wcstoul (DllId, NULL, 10); - pCsrServerDll->Unused = 0; - RtlInitUnicodeString (& pCsrServerDll->DllName, DllName); - RtlInitUnicodeString (& pCsrServerDll->DllEntryPoint, DllEntryPoint); - return rc; -} -/********************************************************************** - * CsrpSplitSharedSection/2 PRIVATE - * - * RETURN VALUE - * 0: syntax error - * 1: PortSectionSize (required) - * 2: PortSection,InteractiveDesktopHeap - * 3: PortSection,InteractiveDesktopHeap,NonInteractiveDesktopHeap - */ -static INT STDCALL CsrpSplitSharedSection (LPWSTR SharedSection, PCSR_ARGUMENT_ITEM pItem) -{ - LPWSTR PortSectionSize = NULL; - LPWSTR InteractiveDesktopHeapSize = NULL; - LPWSTR NonInteractiveDesktopHeapSize = NULL; - INT rc = 1; + /* Initialize the Object Attributes */ + InitializeObjectAttributes(&ObjectAttributes, + &GlobalString, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); - DPRINT("CSRSRV:%s(%S) called\n", __FUNCTION__, SharedSection); + /* Open the directory */ + Status = NtOpenDirectoryObject(&hDirectory, + DIRECTORY_QUERY, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) return Status; - if(L'\0' == *SharedSection) - { - DPRINT("CSRSRV:%s(%S): *SharedSection == L'\\0'\n", __FUNCTION__, SharedSection); - return 0; - } + /* Allocate memory */ + QueryBuffer = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, 0x4000); + if (!QueryBuffer) return STATUS_NO_MEMORY; - // PortSectionSize (required) - PortSectionSize = SharedSection; - // InteractiveDesktopHeapSize (optional) - InteractiveDesktopHeapSize = wcschr (PortSectionSize, L','); - if (NULL == InteractiveDesktopHeapSize) - { - // Default value is 128k - InteractiveDesktopHeapSize = L"128"; - } else { - rc = 2; - } - // NonInteractiveDesktopHeapSize (optional) - NonInteractiveDesktopHeapSize = wcschr (InteractiveDesktopHeapSize, L','); - if (NULL == NonInteractiveDesktopHeapSize) - { - // Default value equals interactive one - NonInteractiveDesktopHeapSize = InteractiveDesktopHeapSize; - } else { - rc = 3; - } - // OK - normalization - pItem->Item.SharedSection.PortSectionSize = wcstoul (PortSectionSize, NULL, 10); - if (pItem->Item.SharedSection.PortSectionSize < 64) - { - pItem->Item.SharedSection.PortSectionSize = 64; - } - pItem->Item.SharedSection.InteractiveDesktopHeapSize = wcstoul (InteractiveDesktopHeapSize, NULL, 10); - if (pItem->Item.SharedSection.InteractiveDesktopHeapSize < 128) - { - pItem->Item.SharedSection.InteractiveDesktopHeapSize = 128; - } - pItem->Item.SharedSection.NonInteractiveDesktopHeapSize = wcstoul (NonInteractiveDesktopHeapSize, NULL, 10); - if (pItem->Item.SharedSection.NonInteractiveDesktopHeapSize < 128) - { - pItem->Item.SharedSection.NonInteractiveDesktopHeapSize = 128; - } - // done - return rc; -} -/********************************************************************** - * CsrpParseArgumentItem/1 PRIVATE - * - * DESCRIPTION - * - * ARGUMENTS - * Argument: argument to decode; - * - * RETURN VALUE - * STATUS_SUCCESS; otherwise, STATUS_UNSUCCESSFUL and - * pItem->Type = CSRAT_UNKNOWN. - * - * NOTE - * The command line could be as complex as the following one, - * which is the original command line for the Win32 subsystem - * in NT 5.1: - * - * %SystemRoot%\system32\csrss.exe - * ObjectDirectory=\Windows - * SharedSection=1024,3072,512 - * Windows=On - * SubSystemType=Windows - * ServerDll=basesrv,1 - * ServerDll=winsrv:UserServerDllInitialization,3 - * ServerDll=winsrv:ConServerDllInitialization,2 - * ProfileControl=Off - * MaxRequestThreads=16 - */ -static NTSTATUS FASTCALL CsrpParseArgumentItem (IN OUT PCSR_ARGUMENT_ITEM pItem) -{ - NTSTATUS Status = STATUS_SUCCESS; - LPWSTR ParameterName = NULL; - LPWSTR ParameterValue = NULL; + /* Start query loop */ + while (TRUE) + { + /* Query the Directory */ + Status = NtQueryDirectoryObject(hDirectory, + QueryBuffer, + BufferLength, + FALSE, + FALSE, + &Context, + &ReturnLength); - pItem->Type = CSRAT_UNKNOWN; + /* Check for the status */ + if (NT_SUCCESS(Status)) + { + /* Make sure it has a name */ + if (!QueryBuffer->ObjectName.Buffer[0]) continue; - if(0 == pItem->Data.Length) - { - DPRINT1("CSRSRV:%s: (0 == Data.Length)!\n", __FUNCTION__); - return STATUS_INVALID_PARAMETER; - } - //--- Seek '=' to split name and value - ParameterName = pItem->Data.Buffer; - ParameterValue = wcschr (ParameterName, L'='); - if (NULL == ParameterValue) - { - DPRINT1("CSRSRV:%s: (NULL == ParameterValue)!\n", __FUNCTION__); - return STATUS_INVALID_PARAMETER; - } - *ParameterValue++ = L'\0'; - DPRINT("Name=%S, Value=%S\n", ParameterName, ParameterValue); - //--- - if(0 == wcscmp(ParameterName, L"ObjectDirectory")) - { - RtlInitUnicodeString (& pItem->Item.ObjectDirectory, ParameterValue); - pItem->Type = CSRAT_OBJECT_DIRECTORY; - } - else if(0 == wcscmp(ParameterName, L"SubSystemType")) - { - pItem->Type = CSRAT_SUBSYSTEM_TYPE; - pItem->Item.Windows = CsrpStringToBool (ParameterValue, L"Windows", L"Text"); - } - else if(0 == wcscmp(ParameterName, L"MaxRequestThreads")) - { - pItem->Item.MaxRequestThreads = (USHORT) wcstoul (ParameterValue, NULL, 10); - pItem->Type = CSRAT_REQUEST_THREADS_MAX; - } - else if(0 == wcscmp(ParameterName, L"RequestThreads")) - { - // ROS Extension - pItem->Item.RequestThreads = (USHORT) wcstoul (ParameterValue, NULL, 10); - pItem->Type = CSRAT_REQUEST_THREADS; - } - else if(0 == wcscmp(ParameterName, L"ProfileControl")) - { - pItem->Item.ProfileControl = CsrpStringToBool (ParameterValue, L"On", L"Off"); - pItem->Type = CSRAT_PROFILE_CONTROL; - } - else if(0 == wcscmp(ParameterName, L"SharedSection")) - { - if (0 != CsrpSplitSharedSection(ParameterValue, pItem)) - { - pItem->Type = CSRAT_SHARED_SECTION; - } else { - pItem->Type = CSRAT_UNKNOWN; - return STATUS_INVALID_PARAMETER; - } - } - else if(0 == wcscmp(ParameterName, L"ServerDll")) - { - if (0 != CsrpSplitServerDll(ParameterValue, pItem)) - { - pItem->Type = CSRAT_SERVER_DLL; - } else { - pItem->Type = CSRAT_UNKNOWN; - return STATUS_INVALID_PARAMETER; - } - } - else if(0 == wcscmp(ParameterName, L"Windows")) - { - pItem->Item.Windows = CsrpStringToBool (ParameterValue, L"On", L"Off"); - pItem->Type = CSRAT_WINDOWS; - } - else if(0 == wcscmp(ParameterName, L"Sessions")) - { - // ROS Extension - pItem->Item.Sessions = CsrpStringToBool (ParameterValue, L"On", L"Off"); - pItem->Type = CSRAT_SESSIONS; - } - else - { - DPRINT1("CSRSRV:%s: unknown parameter '%S'!\n", __FUNCTION__, ParameterName); - pItem->Type = CSRAT_UNKNOWN; - Status = STATUS_INVALID_PARAMETER; + /* Check if it's actually a symbolic link */ + if (wcscmp(QueryBuffer->ObjectTypeName.Buffer, SYMLINK_NAME)) + { + /* It is, open it */ + InitializeObjectAttributes(&ObjectAttributes, + &QueryBuffer->ObjectName, + OBJ_CASE_INSENSITIVE, + NULL, + hDirectory); + Status = NtOpenSymbolicLinkObject(&hSymLink, + SYMBOLIC_LINK_QUERY, + &ObjectAttributes); + if (NT_SUCCESS(Status)) + { + /* Setup the Target String */ + LinkTarget.Length = 0; + LinkTarget.MaximumLength = sizeof(SymLinkBuffer); + LinkTarget.Buffer = SymLinkBuffer; + + /* Query the target */ + Status = NtQuerySymbolicLinkObject(hSymLink, + &LinkTarget, + &ReturnLength); + + /* Close the handle */ + NtClose(hSymLink); + + } + } } - return Status; + } } -/********************************************************************** - * CsrServerInitialization/2 - * - * DESCRIPTION - * Every environment subsystem implicitly starts where this - * routines stops. This routine is called by CSR on startup - * and then it calls the entry points in the following server - * DLLs, as per command line. - * - * ARGUMENTS - * ArgumentCount: - * Argument: - * - * RETURN VALUE - * STATUS_SUCCESS if it succeeds. Otherwise a status code. - * - * NOTE - * This is the only function explicitly called by csr.exe. - */ -NTSTATUS STDCALL CsrServerInitialization (ULONG ArgumentCount, - LPWSTR *Argument) -{ - NTSTATUS Status = STATUS_SUCCESS; - ULONG ArgumentIndex = 0; - CSR_ARGUMENT_ITEM ArgumentItem = {CSRAT_UNKNOWN,}; - // get registry bootstrap options - for (ArgumentIndex = 0; ArgumentIndex < ArgumentCount; ArgumentIndex++) - { - RtlInitUnicodeString (& ArgumentItem.Data, Argument[ArgumentIndex]); - Status = CsrpParseArgumentItem (& ArgumentItem); - if (NT_SUCCESS(Status)) - { - switch (ArgumentItem.Type) - { - case CSRAT_UNKNOWN: - // ignore unknown parameters - DPRINT1("CSRSRV: ignoring param '%s'\n", Argument[ArgumentIndex]); - break; - case CSRAT_OBJECT_DIRECTORY: - RtlDuplicateUnicodeString (1, & ArgumentItem.Item.ObjectDirectory, & CsrSrvOption.NameSpace.Root); - DPRINT("ObjectDirectory: '%S'\n", CsrSrvOption.NameSpace.Root.Buffer); - break; - case CSRAT_SUBSYSTEM_TYPE: - CsrSrvOption.SubSystemType = ArgumentItem.Item.SubSystemType; - DPRINT("SubSystemType: %u\n", CsrSrvOption.SubSystemType); - break; - case CSRAT_REQUEST_THREADS: - CsrSrvOption.Threads.RequestCount = ArgumentItem.Item.RequestThreads; - DPRINT("RequestThreads: %u\n", CsrSrvOption.Threads.RequestCount); - break; - case CSRAT_REQUEST_THREADS_MAX: - CsrSrvOption.Threads.MaxRequestCount = ArgumentItem.Item.MaxRequestThreads; - DPRINT("MaxRequestThreads: %u\n", CsrSrvOption.Threads.MaxRequestCount); - break; - case CSRAT_PROFILE_CONTROL: - CsrSrvOption.Flag.ProfileControl = ArgumentItem.Item.ProfileControl; - DPRINT("ProfileControl: %u \n", CsrSrvOption.Flag.ProfileControl); - break; - case CSRAT_SHARED_SECTION: - CsrSrvOption.PortSharedSectionSize = ArgumentItem.Item.SharedSection.PortSectionSize; - CsrSrvOption.Heap.InteractiveDesktopHeapSize = ArgumentItem.Item.SharedSection.InteractiveDesktopHeapSize; - CsrSrvOption.Heap.NonInteractiveDesktopHeapSize = ArgumentItem.Item.SharedSection.NonInteractiveDesktopHeapSize; - DPRINT("SharedSection: %u-%u-%u\n", - CsrSrvOption.PortSharedSectionSize, - CsrSrvOption.Heap.InteractiveDesktopHeapSize, - CsrSrvOption.Heap.NonInteractiveDesktopHeapSize); - break; - case CSRAT_SERVER_DLL: - Status = CsrSrvRegisterServerDll (& ArgumentItem.Item.ServerDll); - if(!NT_SUCCESS(Status)) - { - DPRINT1("CSRSRV: CsrSrvRegisterServerDll(%S) failed!\n", - Argument[ArgumentIndex]); - } else { - DPRINT("ServerDll: DLL='%S' Entrypoint='%S' ID=%u\n", - ArgumentItem.Item.ServerDll.DllName.Buffer, - ArgumentItem.Item.ServerDll.DllEntryPoint.Buffer, - ArgumentItem.Item.ServerDll.ServerIndex); - } - break; - case CSRAT_WINDOWS: - CsrSrvOption.Flag.Windows = ArgumentItem.Item.Windows; - DPRINT("Windows: %d\n", CsrSrvOption.Flag.Windows); - break; - case CSRAT_SESSIONS: - CsrSrvOption.Flag.Sessions = ArgumentItem.Item.Sessions; - DPRINT("Sessions: %d\n", CsrSrvOption.Flag.Sessions); - break; - default: - DPRINT("CSRSRV: unknown ArgumentItem->Type=%ld!\n", ArgumentItem.Type); - } - } else { - DPRINT1("CSRSRV:%s: CsrpParseArgumentItem(%S) failed with Status = %08lx\n", - __FUNCTION__, Argument[ArgumentIndex], Status); - } - } - // TODO: verify required - Status = CsrSrvBootstrap (); - return Status; +/*++ + * @name CsrLoadServerDllFromCommandLine + * + * The CsrLoadServerDllFromCommandLine routine loads a Server DLL from the + * CSRSS command-line in the registry. + * + * @param KeyValue + * Pointer to the specially formatted string for this Server DLL. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrLoadServerDllFromCommandLine(PCHAR KeyValue) +{ + PCHAR EntryPoint = NULL; + ULONG DllIndex = 0; + PCHAR ServerString = KeyValue; + NTSTATUS Status; + + /* Loop the command line */ + while (*ServerString) + { + /* Check for the Entry Point */ + if ((*ServerString == ':') && (!EntryPoint)) + { + /* Found it. Add a nullchar and save it */ + *ServerString++ = '\0'; + EntryPoint = ServerString; + } + + /* Check for the Dll Index */ + if (*ServerString++ == ',') + { + /* Convert it to a ULONG */ + Status = RtlCharToInteger(ServerString, 10, &DllIndex); + + /* Add a null char if it was valid */ + if (NT_SUCCESS(Status)) ServerString[-1] = '\0'; + + /* We're done here */ + break; + } + } + + /* We've got the name, entrypoint and index, load it */ + return CsrLoadServerDll(KeyValue, EntryPoint, DllIndex); } + +/*++ + * @name CsrpParseCommandLine + * + * The CsrpParseCommandLine routine parses the CSRSS command-line in the + * registry and performs operations for each entry found. + * + * @param ArgumentCount + * Number of arguments on the command line. + * + * @param Arguments + * Array of arguments. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +FASTCALL +CsrpParseCommandLine(IN ULONG ArgumentCount, + IN PCHAR Arguments[]) +{ + NTSTATUS Status; + PCHAR ParameterName = NULL; + PCHAR ParameterValue = NULL; + ULONG i; + + /* Set the Defaults */ + CsrTotalPerProcessDataLength = 0; + CsrObjectDirectory = 0; + CsrMaxApiRequestThreads = 16; + + /* Save our Session ID, and create a Directory for it */ + SessionId = NtCurrentPeb()->SessionId; + Status = CsrCreateSessionObjectDirectory(SessionId); + if (NT_SUCCESS(Status)) + { + DPRINT1("CSRSS: CsrCreateSessionObjectDirectory failed (%lx)\n", + Status); + + /* It's not fatal if the SID is 0 */ + if (SessionId != 0) return Status; + } + + /* Loop through every argument */ + for (i = 1; i < ArgumentCount; i++) + { + /* Split Name and Value */ + ParameterName = Arguments[i]; + ParameterValue = strchr(ParameterName, L'='); + *ParameterValue++ = '\0'; + DPRINT("Name=%S, Value=%S\n", ParameterName, ParameterValue); + + /* Check for Object Directory */ + if (!_stricmp(ParameterName, "ObjectDirectory")) + { + CsrCreateObjectDirectory(ParameterValue); + } + else if(!_stricmp(ParameterName, "SubSystemType")) + { + /* Ignored */ + Status = STATUS_SUCCESS; + } + else if (!_stricmp(ParameterName, "MaxRequestThreads")) + { + Status = RtlCharToInteger(ParameterValue, + 0, + &CsrMaxApiRequestThreads); + } + else if (!_stricmp(ParameterName, "RequestThreads")) + { + /* Ignored */ + Status = STATUS_SUCCESS; + } + else if (!_stricmp(ParameterName, "ProfileControl")) + { + CsrProfileControl = (!_stricmp(ParameterValue, "On")) ? TRUE : FALSE; + } + else if (!_stricmp(ParameterName, "SharedSection")) + { + /* Craete the Section */ + Status = CsrSrvCreateSharedSection(ParameterValue); + + /* Load us */ + Status = CsrLoadServerDll("CSRSS", NULL, CSR_SRV_SERVER); + } + else if (!_stricmp(ParameterName, "ServerDLL")) + { + /* Parse the Command-Line and load this DLL */ + Status = CsrLoadServerDllFromCommandLine(ParameterValue); + } + else if (!_stricmp(ParameterName, "Windows")) + { + /* Ignored */ + Status = STATUS_SUCCESS; + } + else + { + /* Invalid parameter on the command line */ + Status = STATUS_INVALID_PARAMETER; + } + } + + /* Return status */ + return Status; +} + +/*++ + * @name CsrCreateObjectDirectory + * + * The CsrCreateObjectDirectory creates the Object Directory on the CSRSS + * command-line from the registry. + * + * @param ObjectDirectory + * Pointer to the name of the Object Directory to create. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrCreateObjectDirectory(IN PCHAR ObjectDirectory) +{ + NTSTATUS Status = STATUS_SUCCESS; + ANSI_STRING TempString; + OBJECT_ATTRIBUTES DirectoryAttributes; + + DPRINT("CSRSRV:%s(%s) called\n", __FUNCTION__, ObjectDirectory); + + /* Convert the parameter to our Global Unicode name */ + RtlInitAnsiString(&TempString, ObjectDirectory); + Status = RtlAnsiStringToUnicodeString(&CsrDirectoryName, &TempString, TRUE); + + /* Initialize the attributes for the Directory */ + InitializeObjectAttributes(&DirectoryAttributes, + &CsrDirectoryName, + OBJ_PERMANENT | OBJ_OPENIF | OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + /* Create it */ + Status = NtCreateDirectoryObject(&CsrObjectDirectory, + DIRECTORY_ALL_ACCESS, + &DirectoryAttributes); + if (!NT_SUCCESS(Status)) + { + DPRINT1("CSRSRV:%s: fatal: NtCreateDirectoryObject failed (Status=0x%08lx)\n", + __FUNCTION__, Status); + } + + /* Set the Security */ + Status = CsrSetDirectorySecurity(CsrObjectDirectory); + + /* Return */ + return Status; +} + +/*++ + * @name CsrCreateLocalSystemSD + * + * The CsrCreateLocalSystemSD routine creates a Security Descriptor for + * the local account with PORT_ALL_ACCESS. + * + * @param LocalSystemSd + * Pointer to a pointer to the security descriptor to create. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrCreateLocalSystemSD(OUT PSECURITY_DESCRIPTOR *LocalSystemSd) +{ + SID_IDENTIFIER_AUTHORITY NtSidAuthority = SECURITY_NT_AUTHORITY; + PSID SystemSid; + ULONG SidLength; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PACL Dacl; + NTSTATUS Status; + + /* Initialize the System SID */ + RtlAllocateAndInitializeSid(&NtSidAuthority, + 1, + SECURITY_LOCAL_SYSTEM_RID, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + &SystemSid); + + /* Get the length of the SID */ + SidLength = RtlLengthSid(SystemSid); + + /* Allocate a buffer for the Security Descriptor, with SID and DACL */ + SecurityDescriptor = RtlAllocateHeap(CsrHeap, + 0, + SECURITY_DESCRIPTOR_MIN_LENGTH + + sizeof(ACL) + SidLength + + sizeof(ACCESS_ALLOWED_ACE)); + + /* Set the pointer to the DACL */ + Dacl = (PACL)((ULONG_PTR)SecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); + + /* Now create the SD itself */ + Status = RtlCreateSecurityDescriptor(SecurityDescriptor, + SECURITY_DESCRIPTOR_REVISION); + if (!NT_SUCCESS(Status)) + { + /* Fail */ + RtlFreeHeap(CsrHeap, 0, SecurityDescriptor); + return Status; + } + + /* Create the DACL for it*/ + RtlCreateAcl(Dacl, + sizeof(ACL) + SidLength + sizeof(ACCESS_ALLOWED_ACE), + ACL_REVISION2); + + /* Create the ACE */ + Status = RtlAddAccessAllowedAce(Dacl, + ACL_REVISION, + PORT_ALL_ACCESS, + SystemSid); + if (!NT_SUCCESS(Status)) + { + /* Fail */ + RtlFreeHeap(CsrHeap, 0, SecurityDescriptor); + return Status; + } + + /* Clear the DACL in the SD */ + Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, + TRUE, + Dacl, + FALSE); + if (!NT_SUCCESS(Status)) + { + /* Fail */ + RtlFreeHeap(CsrHeap, 0, SecurityDescriptor); + return Status; + } + + /* Free the SID and return*/ + RtlFreeSid(SystemSid); + *LocalSystemSd = SecurityDescriptor; + return Status; +} + +/*++ + * @name CsrGetDosDevicesSd + * + * The CsrGetDosDevicesSd creates a security descriptor for the DOS Devices + * Object Directory. + * + * @param DosDevicesSd + * Pointer to the Security Descriptor to return. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks Depending on the DOS Devices Protection Mode (set in the registry), + * regular users may or may not have full access to the directory. + * + *--*/ +NTSTATUS +NTAPI +CsrGetDosDevicesSd(OUT PSECURITY_DESCRIPTOR DosDevicesSd) +{ + SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY; + SID_IDENTIFIER_AUTHORITY CreatorAuthority = SECURITY_CREATOR_SID_AUTHORITY; + SID_IDENTIFIER_AUTHORITY NtSidAuthority = SECURITY_NT_AUTHORITY; + PSID WorldSid, CreatorSid, AdminSid, SystemSid; + UCHAR KeyValueBuffer[0x40]; + PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo; + UNICODE_STRING KeyName; + ULONG ProtectionMode = 0; + OBJECT_ATTRIBUTES ObjectAttributes; + PACL Dacl; + PACCESS_ALLOWED_ACE Ace; + HANDLE hKey; + NTSTATUS Status; + ULONG ResultLength, SidLength; + + /* Create the SD */ + RtlCreateSecurityDescriptor(DosDevicesSd, SECURITY_DESCRIPTOR_REVISION); + + /* Initialize the System SID */ + RtlAllocateAndInitializeSid(&NtSidAuthority, + 1, + SECURITY_LOCAL_SYSTEM_RID, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + &SystemSid); + + /* Initialize the World SID */ + RtlAllocateAndInitializeSid(&WorldAuthority, + 1, + SECURITY_WORLD_RID, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + &WorldSid); + + /* Initialize the Admin SID */ + RtlAllocateAndInitializeSid(&NtSidAuthority, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, + 0, + 0, + 0, + 0, + 0, + &AdminSid); + + /* Initialize the Creator SID */ + RtlAllocateAndInitializeSid(&CreatorAuthority, + 1, + SECURITY_CREATOR_OWNER_RID, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + &CreatorSid); + + /* Open the Session Manager Key */ + RtlInitUnicodeString(&KeyName, SM_REG_KEY); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + if (NT_SUCCESS(Status = NtOpenKey(&hKey, + KEY_READ, + &ObjectAttributes))) + { + /* Read the ProtectionMode. See http://support.microsoft.com/kb/q218473/ */ + RtlInitUnicodeString(&KeyName, L"ProtectionMode"); + Status = NtQueryValueKey(hKey, + &KeyName, + KeyValuePartialInformation, + KeyValueBuffer, + sizeof(KeyValueBuffer), + &ResultLength); + + /* Make sure it's what we expect it to be */ + KeyValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer; + if ((KeyValuePartialInfo->Type == REG_DWORD) && + (*(PULONG)KeyValuePartialInfo->Data != 0)) + { + /* Save the Protection Mode */ + ProtectionMode = *(PULONG)KeyValuePartialInfo->Data; + } + + /* Close the handle */ + NtClose(hKey); + } + + /* Check the Protection Mode */ + if (ProtectionMode & 3) + { + /* Calculate SID Lengths */ + SidLength = RtlLengthSid(CreatorSid) + RtlLengthSid(SystemSid) + + RtlLengthSid(AdminSid); + + /* Allocate memory for the DACL */ + Dacl = RtlAllocateHeap(CsrHeap, + HEAP_ZERO_MEMORY, + sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) + + SidLength); + + /* Create it */ + Status = RtlCreateAcl(Dacl, + sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) + + SidLength, + ACL_REVISION2); + + /* Give full access to the System */ + Status = RtlAddAccessAllowedAce(Dacl, + ACL_REVISION, + GENERIC_ALL, + SystemSid); + + /* Get the ACE back */ + Status = RtlGetAce(Dacl, 0, (PACE*)&Ace); + + /* Add some flags to it for the Admin SID */ + Ace->Header.AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE); + + /* Add the ACE to the Admin SID */ + Status = RtlAddAccessAllowedAce(Dacl, + ACL_REVISION, + GENERIC_ALL, + AdminSid); + + /* Get the ACE back */ + Status = RtlGetAce(Dacl, 1, (PACE*)&Ace); + + /* Add some flags to it for the Creator SID */ + Ace->Header.AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE); + + /* Add the ACE to the Admin SID */ + Status = RtlAddAccessAllowedAce(Dacl, + ACL_REVISION, + GENERIC_ALL, + CreatorSid); + + /* Get the ACE back */ + Status = RtlGetAce(Dacl, 2, (PACE*)&Ace); + + /* Add some flags to it for the SD */ + Ace->Header.AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | + INHERIT_ONLY_ACE); + + /* Set this DACL with the SD */ + Status = RtlSetDaclSecurityDescriptor(DosDevicesSd, + TRUE, + Dacl, + FALSE); + } + else + { + /* Calculate SID Lengths */ + SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(SystemSid); + + /* Allocate memory for the DACL */ + Dacl = RtlAllocateHeap(CsrHeap, + HEAP_ZERO_MEMORY, + sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) + + SidLength); + + /* Create it */ + Status = RtlCreateAcl(Dacl, + sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) + + SidLength, + ACL_REVISION2); + + /* Give RWE access to the World */ + Status = RtlAddAccessAllowedAce(Dacl, + ACL_REVISION, + GENERIC_READ | GENERIC_WRITE | + GENERIC_EXECUTE, + WorldSid); + + /* Give full access to the System */ + Status = RtlAddAccessAllowedAce(Dacl, + ACL_REVISION, + GENERIC_ALL, + SystemSid); + + /* Give full access to the World */ + Status = RtlAddAccessAllowedAce(Dacl, + ACL_REVISION, + GENERIC_ALL, + WorldSid); + + /* Get the ACE back */ + Status = RtlGetAce(Dacl, 2, (PACE*)&Ace); + + /* Add some flags to it for the SD */ + Ace->Header.AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | + INHERIT_ONLY_ACE); + + /* Set this DACL with the SD */ + Status = RtlSetDaclSecurityDescriptor(DosDevicesSd, + TRUE, + Dacl, + FALSE); + } + +/* FIXME: failure cases! Fail: */ + /* Free the memory */ + RtlFreeHeap(CsrHeap, 0, Dacl); + +/* FIXME: semi-failure cases! Quickie: */ + /* Free the SIDs */ + RtlFreeSid(SystemSid); + RtlFreeSid(WorldSid); + RtlFreeSid(AdminSid); + RtlFreeSid(CreatorSid); + + /* Return */ + return Status; +} + +/*++ + * @name CsrFreeDosDevicesSd + * + * The CsrFreeDosDevicesSd frees the security descriptor that was created + * by CsrGetDosDevicesSd + * + * @param DosDevicesSd + * Pointer to the security descriptor to free. + + * @return None. + * + * @remarks None. + * + *--*/ +VOID +NTAPI +CsrFreeDosDevicesSd(IN PSECURITY_DESCRIPTOR DosDevicesSd) +{ + PACL Dacl; + BOOLEAN Present, Default; + NTSTATUS Status; + + /* Get the DACL corresponding to this SD */ + Status = RtlGetDaclSecurityDescriptor(DosDevicesSd, + &Present, + &Dacl, + &Default); + + /* Free it */ + if (NT_SUCCESS(Status) && Dacl) RtlFreeHeap(CsrHeap, 0, Dacl); +} + +/*++ + * @name CsrCreateSessionObjectDirectory + * + * The CsrCreateSessionObjectDirectory routine creates the BaseNamedObjects, + * Session and Dos Devices directories for the specified session. + * + * @param Session + * Session ID for which to create the directories. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrCreateSessionObjectDirectory(IN ULONG Session) +{ + WCHAR SessionBuffer[512]; + WCHAR BnoBuffer[512]; + UNICODE_STRING SessionString; + UNICODE_STRING BnoString; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE BnoHandle; + SECURITY_DESCRIPTOR DosDevicesSd; + NTSTATUS Status; + + /* Generate the Session BNOLINKS Directory */ + swprintf(SessionBuffer, L"%ws\\BNOLINKS", SESSION_ROOT); + RtlInitUnicodeString(&SessionString, SessionBuffer); + + /* Initialize the attributes for the Directory */ + InitializeObjectAttributes(&ObjectAttributes, + &SessionString, + OBJ_PERMANENT | OBJ_OPENIF | OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + /* Create it */ + Status = NtCreateDirectoryObject(&BNOLinksDirectory, + DIRECTORY_ALL_ACCESS, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + DPRINT1("CSRSRV:%s: fatal: NtCreateDirectoryObject failed (Status=0x%08lx)\n", + __FUNCTION__, Status); + return Status; + } + + /* Now add the Session ID */ + swprintf(SessionBuffer, L"%ld", Session); + RtlInitUnicodeString(&SessionString, SessionBuffer); + + /* Check if this is the first Session */ + if (Session) + { + /* Not the first, so the name will be slighly more complex */ + swprintf(BnoBuffer, L"%ws\\%ld\\BaseNamedObjects", SESSION_ROOT, Session); + } + else + { + /* Use the direct name */ + RtlCopyMemory(BnoBuffer, L"\\BaseNamedObjects", 36); + } + + /* Create the Unicode String for the BNO SymLink */ + RtlInitUnicodeString(&BnoString, BnoBuffer); + + /* Initialize the attributes for the SymLink */ + InitializeObjectAttributes(&ObjectAttributes, + &SessionString, + OBJ_PERMANENT | OBJ_OPENIF | OBJ_CASE_INSENSITIVE, + BNOLinksDirectory, + NULL); + + /* Create it */ + Status = NtCreateSymbolicLinkObject(&BnoHandle, + SYMBOLIC_LINK_ALL_ACCESS, + &ObjectAttributes, + &BnoString); + if (!NT_SUCCESS(Status)) + { + DPRINT1("CSRSRV:%s: fatal: NtCreateSymbolicLinkObject failed (Status=0x%08lx)\n", + __FUNCTION__, Status); + return Status; + } + + /* Create the \DosDevices Security Descriptor */ + CsrGetDosDevicesSd(&DosDevicesSd); + + /* Now create a directory for this session */ + swprintf(SessionBuffer, L"%ws\\%ld", SESSION_ROOT, Session); + RtlInitUnicodeString(&SessionString, SessionBuffer); + + /* Initialize the attributes for the Directory */ + InitializeObjectAttributes(&ObjectAttributes, + &SessionString, + OBJ_PERMANENT | OBJ_OPENIF | OBJ_CASE_INSENSITIVE, + 0, + &DosDevicesSd); + + /* Create it */ + Status = NtCreateDirectoryObject(&SessionObjectDirectory, + DIRECTORY_ALL_ACCESS, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + DPRINT1("CSRSRV:%s: fatal: NtCreateDirectoryObject failed (Status=0x%08lx)\n", + __FUNCTION__, Status); + /* Release the Security Descriptor */ + CsrFreeDosDevicesSd(&DosDevicesSd); + return Status; + } + + /* Next, create a directory for this session's DOS Devices */ + /* Now create a directory for this session */ + RtlInitUnicodeString(&SessionString, L"DosDevices"); + + /* Initialize the attributes for the Directory */ + InitializeObjectAttributes(&ObjectAttributes, + &SessionString, + OBJ_PERMANENT | OBJ_OPENIF | OBJ_CASE_INSENSITIVE, + 0, + &DosDevicesSd); + + /* Create it */ + Status = NtCreateDirectoryObject(&DosDevicesDirectory, + DIRECTORY_ALL_ACCESS, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + DPRINT1("CSRSRV:%s: fatal: NtCreateDirectoryObject failed (Status=0x%08lx)\n", + __FUNCTION__, Status); + } + + /* Release the Security Descriptor */ + CsrFreeDosDevicesSd(&DosDevicesSd); + + /* Return */ + return Status; +} + +/*++ + * @name CsrSetProcessSecurity + * + * The CsrSetProcessSecurity routine protects access to the CSRSS process + * from unauthorized tampering. + * + * @param None. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrSetProcessSecurity(VOID) +{ + NTSTATUS Status; + HANDLE hToken; + ULONG ReturnLength; + PTOKEN_USER TokenUserInformation; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PACL Dacl; + + /* Open our token */ + Status = NtOpenProcessToken(NtCurrentProcess(), + TOKEN_QUERY, + &hToken); + if (!NT_SUCCESS(Status)) return Status; + + /* Get the Token User Length */ + NtQueryInformationToken(hToken, + TokenUser, + NULL, + 0, + &ReturnLength); + + /* Allocate space for it */ + TokenUserInformation = RtlAllocateHeap(CsrHeap, + HEAP_ZERO_MEMORY, + ReturnLength); + + /* Now query the data */ + Status = NtQueryInformationToken(hToken, + TokenUser, + TokenUserInformation, + ReturnLength, + &ReturnLength); + + /* Close the handle */ + NtClose(hToken); + + /* Make sure that we got the data */ + if (!NT_SUCCESS(Status)) + { + /* FAil */ + RtlFreeHeap(CsrHeap, 0, TokenUserInformation); + return Status; + } + + /* Now check the SID Length */ + ReturnLength = RtlLengthSid(TokenUserInformation->User.Sid); + + /* Allocate a buffer for the Security Descriptor, with SID and DACL */ + SecurityDescriptor = RtlAllocateHeap(CsrHeap, + HEAP_ZERO_MEMORY, + SECURITY_DESCRIPTOR_MIN_LENGTH + + sizeof(ACL) + ReturnLength + + sizeof(ACCESS_ALLOWED_ACE)); + + /* Set the pointer to the DACL */ + Dacl = (PACL)((ULONG_PTR)SecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); + + /* Now create the SD itself */ + Status = RtlCreateSecurityDescriptor(SecurityDescriptor, + SECURITY_DESCRIPTOR_REVISION); + if (!NT_SUCCESS(Status)) + { + /* Fail */ + RtlFreeHeap(CsrHeap, 0, SecurityDescriptor); + RtlFreeHeap(CsrHeap, 0, TokenUserInformation); + return Status; + } + + /* Create the DACL for it*/ + RtlCreateAcl(Dacl, + sizeof(ACL) + ReturnLength + sizeof(ACCESS_ALLOWED_ACE), + ACL_REVISION2); + + /* Create the ACE */ + Status = RtlAddAccessAllowedAce(Dacl, + ACL_REVISION, + PROCESS_VM_READ | PROCESS_VM_WRITE | + PROCESS_VM_OPERATION | PROCESS_DUP_HANDLE | + PROCESS_TERMINATE | PROCESS_SUSPEND_RESUME | + PROCESS_QUERY_INFORMATION | READ_CONTROL, + TokenUserInformation->User.Sid); + if (!NT_SUCCESS(Status)) + { + /* Fail */ + RtlFreeHeap(CsrHeap, 0, SecurityDescriptor); + RtlFreeHeap(CsrHeap, 0, TokenUserInformation); + return Status; + } + + /* Clear the DACL in the SD */ + Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, + TRUE, + Dacl, + FALSE); + if (!NT_SUCCESS(Status)) + { + /* Fail */ + RtlFreeHeap(CsrHeap, 0, SecurityDescriptor); + RtlFreeHeap(CsrHeap, 0, TokenUserInformation); + return Status; + } + + /* Write the SD into the Process */ + Status = NtSetSecurityObject(NtCurrentProcess(), + DACL_SECURITY_INFORMATION, + SecurityDescriptor); + + /* Free the memory and return */ + RtlFreeHeap(CsrHeap, 0, SecurityDescriptor); + RtlFreeHeap(CsrHeap, 0, TokenUserInformation); + return Status; +} + +/*++ + * @name CsrSetDirectorySecurity + * + * The CsrSetDirectorySecurity routine sets the security descriptor for the + * specified Object Directory. + * + * @param ObjectDirectory + * Handle fo the Object Directory to protect. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrSetDirectorySecurity(IN HANDLE ObjectDirectory) +{ + /* FIXME: Implement */ + return STATUS_SUCCESS; +} + +/* PUBLIC FUNCTIONS **********************************************************/ + +/*++ + * @name CsrServerInitialization + * @implemented NT4 + * + * The CsrServerInitialization routine is the native (not Server) entrypoint + * of this Server DLL. It serves as the entrypoint for csrss. + * + * @param ArgumentCount + * Number of arguments on the command line. + * + * @param Arguments + * Array of arguments from the command line. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrServerInitialization(ULONG ArgumentCount, + PCHAR Arguments[]) +{ + NTSTATUS Status = STATUS_SUCCESS; + ULONG i = 0; + PVOID ProcessData; + PCSR_SERVER_DLL ServerDll; + + DPRINT("CSRSRV: %s called\n", __FUNCTION__); + + /* Create the Init Event */ + Status = NtCreateEvent(&CsrInitializationEvent, + EVENT_ALL_ACCESS, + NULL, + SynchronizationEvent, + FALSE); + + /* Cache System Basic Information so we don't always request it */ + Status = NtQuerySystemInformation(SystemBasicInformation, + &CsrNtSysInfo, + sizeof(SYSTEM_BASIC_INFORMATION), + NULL); + + /* Save our Heap */ + CsrHeap = RtlGetProcessHeap(); + + /* Set our Security Descriptor to protect the process */ + CsrSetProcessSecurity(); + + /* Set up Session Support */ + Status = CsrInitializeNtSessions(); + if(!NT_SUCCESS(Status)) + { + DPRINT1("CSRSRV:%s: CsrInitializeSessions failed (Status=%08lx)\n", + __FUNCTION__, Status); + return Status; + } + + /* Set up Process Support */ + Status = CsrInitializeProcesses(); + if(!NT_SUCCESS(Status)) + { + DPRINT1("CSRSRV:%s: CsrInitializeProcesses failed (Status=%08lx)\n", + __FUNCTION__, Status); + return Status; + } + + /* Parse the command line */ + CsrpParseCommandLine(ArgumentCount, Arguments); + + /* All Server DLLs are now loaded, allocate a heap for the Root Process */ + ProcessData = RtlAllocateHeap(CsrHeap, + HEAP_ZERO_MEMORY, + CsrTotalPerProcessDataLength); + + /* + * Our Root Process was never officially initalized, so write the data + * for each Server DLL manually. + */ + for(i = 0; i < CSR_SERVER_DLL_MAX; i++) + { + /* Get the current Server */ + ServerDll = CsrLoadedServerDll[i]; + + /* Is it loaded, and does it have per process data? */ + if (ServerDll && ServerDll->SizeOfProcessData) + { + /* It does, give it part of our allocated heap */ + CsrRootProcess->ServerData[i] = ProcessData; + + /* Move to the next heap position */ + ProcessData = (PVOID)((ULONG_PTR)ProcessData + + ServerDll->SizeOfProcessData); + } + else + { + /* Nothing for this Server DLL */ + CsrRootProcess->ServerData[i] = NULL; + } + } + + /* Now initialize the Root Process manually as well */ + for(i = 0; i < CSR_SERVER_DLL_MAX; i++) + { + /* Get the current Server */ + ServerDll = CsrLoadedServerDll[i]; + + /* Is it loaded, and does it a callback for new processes? */ + if (ServerDll && ServerDll->NewProcessCallback) + { + /* Call the callback */ + (*ServerDll->NewProcessCallback)(NULL, CsrRootProcess); + } + } + + /* Now initialize our API Port */ + Status = CsrApiPortInitialize(); + if(!NT_SUCCESS(Status)) + { + DPRINT1("CSRSRV:%s: CsrApiPortInitialize failed (Status=%08lx)\n", + __FUNCTION__, Status); + return Status; + } + + /* Initialize the API Port for SM communication */ + Status = CsrSbApiPortInitialize(); + if(!NT_SUCCESS(Status)) + { + DPRINT1("CSRSRV:%s: CsrSbApiPortInitialize failed (Status=%08lx)\n", + __FUNCTION__, Status); + return Status; + } + + /* We're all set! Connect to SM! */ + Status = SmConnectToSm(&CsrSbApiPortName, + CsrSbApiPort, + IMAGE_SUBSYSTEM_WINDOWS_GUI, + &CsrSmApiPort); + if(!NT_SUCCESS(Status)) + { + DPRINT1("CSRSRV:%s: SmConnectToSm failed (Status=%08lx)\n", + __FUNCTION__, Status); + return Status; + } + + /* Finito! Signal the event */ + NtSetEvent(CsrInitializationEvent, NULL); + NtClose(CsrInitializationEvent); + + /* Have us handle Hard Errors */ + NtSetDefaultHardErrorPort(CsrApiPort); + + /* Return status */ + return Status; +} + +/*++ + * @name CsrPopulateDosDevices + * @implemented NT5.1 + * + * The CsrPopulateDosDevices routine uses the DOS Device Map from the Kernel + * to populate the Dos Devices Object Directory for the session. + * + * @param None. + * + * @return None. + * + * @remarks None. + * + *--*/ +VOID +NTAPI +CsrPopulateDosDevices(VOID) +{ + NTSTATUS Status; + PROCESS_DEVICEMAP_INFORMATION OldDeviceMap; + PROCESS_DEVICEMAP_INFORMATION NewDeviceMap; + + /* Query the Device Map */ + Status = NtQueryInformationProcess(NtCurrentProcess(), + ProcessDeviceMap, + &OldDeviceMap.Query, + sizeof(PROCESS_DEVICEMAP_INFORMATION), + NULL); + if (!NT_SUCCESS(Status)) return; + + /* Set the new one */ + NewDeviceMap.Set.DirectoryHandle = DosDevicesDirectory; + Status = NtSetInformationProcess(NtCurrentProcess(), + ProcessDeviceMap, + &NewDeviceMap, + sizeof(ULONG)); + if (!NT_SUCCESS(Status)) return; + + /* Populate the Directory */ + CsrPopulateDosDevicesDirectory(DosDevicesDirectory, &OldDeviceMap); +} + +BOOL +NTAPI +DllMain(HANDLE hDll, + DWORD dwReason, + LPVOID lpReserved) +{ + /* We don't do much */ + return TRUE; +} + /* EOF */ diff --git a/reactos/subsys/csr/csrsrv/process.c b/reactos/subsys/csr/csrsrv/process.c index 2ff3413c3b8..c6e406935fb 100644 --- a/reactos/subsys/csr/csrsrv/process.c +++ b/reactos/subsys/csr/csrsrv/process.c @@ -1,135 +1,1228 @@ -/* $Id$ - * - * subsys/csr/csrsrv/process.c - CSR server - process management - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS CSR Sub System + * FILE: subsys/csr/csrsrv/process.c + * PURPOSE: CSR Server DLL Process Implementation + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) */ + +/* INCLUDES ******************************************************************/ + #include "srv.h" -//#define NDEBUG +#define NDEBUG #include -/* LOCALS */ +/* DATA **********************************************************************/ -struct { - RTL_CRITICAL_SECTION Lock; -} Process; +PCSR_PROCESS CsrRootProcess = NULL; +RTL_CRITICAL_SECTION CsrProcessLock; +ULONG CsrProcessSequenceCount = 5; +ULONG CsrTotalPerProcessDataLength; +/* PRIVATE FUNCTIONS *********************************************************/ - -NTSTATUS STDCALL CsrSrvInitializeProcess (VOID) +/*++ + * @name CsrAllocateProcess + * @implemented NT4 + * + * The CsrAllocateProcess routine allocates a new CSR Process object. + * + * @return Pointer to the newly allocated CSR Process. + * + * @remarks None. + * + *--*/ +PCSR_PROCESS +NTAPI +CsrAllocateProcess(VOID) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; + PCSR_PROCESS CsrProcess; + ULONG TotalSize; - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - Status = RtlInitializeCriticalSection (& Process.Lock); - if(NT_SUCCESS(Status)) - { - // more process management initialization - } - return Status; + /* Calculate the amount of memory this should take */ + TotalSize = sizeof(CSR_PROCESS) + + (CSR_SERVER_DLL_MAX * sizeof(PVOID)) + + CsrTotalPerProcessDataLength; + + /* Allocate a Process */ + CsrProcess = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, TotalSize); + if (!CsrProcess) return NULL; + + /* Handle the Sequence Number */ + CsrProcess->SequenceNumber = CsrProcessSequenceCount++; + + /* Increase the reference count */ + CsrProcess->ReferenceCount++; + + /* Initialize the Thread List */ + InitializeListHead(&CsrProcess->ThreadList); + + /* Return the Process */ + return CsrProcess; } -/*===================================================================== - * PUBLIC API - *===================================================================*/ - -NTSTATUS STDCALL CsrCreateProcess (PCSR_SESSION pCsrSession, PCSR_PROCESS * ppCsrProcess) +/*++ + * @name CsrServerInitialization + * @implemented NT4 + * + * The CsrInitializeProcesses routine sets up support for CSR Processes + * and CSR Threads. + * + * @param None. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrInitializeProcesses(VOID) { - NTSTATUS Status = STATUS_SUCCESS; - PCSR_PROCESS pCsrProcess = NULL; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); + NTSTATUS Status; + ULONG i; - pCsrProcess = RtlAllocateHeap (pCsrSession->Heap, - HEAP_ZERO_MEMORY, - sizeof (CSR_PROCESS)); - if (NULL == pCsrProcess) - { - Status = STATUS_NO_MEMORY; - } else { - pCsrProcess->NtSession = pCsrSession; - if (NULL != ppCsrProcess) - { - *ppCsrProcess = pCsrProcess; - } - } - return Status; + /* Initialize the Lock */ + Status = RtlInitializeCriticalSection(&CsrProcessLock); + + /* Set up the Root Process */ + CsrRootProcess = CsrAllocateProcess(); + if (!CsrRootProcess) return STATUS_NO_MEMORY; + + /* Set up the minimal information for it */ + InitializeListHead(&CsrRootProcess->ListLink); + CsrRootProcess->ProcessHandle = (HANDLE)-1; + CsrRootProcess->ClientId = NtCurrentTeb()->Cid; + + /* Initialize the Thread Hash List */ + for (i = 0; i < 256; i++) InitializeListHead(&CsrThreadHashTable[i]); + + /* Initialize the Wait Lock */ + Status = RtlInitializeCriticalSection(&CsrWaitListsLock); + return Status; } -NTSTATUS STDCALL CsrDereferenceProcess (PCSR_PROCESS pCsrProcess) +/*++ + * @name CsrDeallocateProcess + * + * The CsrDeallocateProcess frees the memory associated with a CSR Process. + * + * @param CsrProcess + * Pointer to the CSR Process to be freed. + * + * @return None. + * + * @remarks Do not call this routine. It is reserved for the internal + * thread management routines when a CSR Process has been cleanly + * dereferenced and killed. + * + *--*/ +VOID +NTAPI +CsrDeallocateProcess(IN PCSR_PROCESS CsrProcess) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return Status; + /* Free the process object from the heap */ + RtlFreeHeap(CsrHeap, 0, CsrProcess); } -NTSTATUS STDCALL CsrDestroyProcess (PCSR_PROCESS pCsrProcess) +/*++ + * @name CsrInsertProcess + * + * The CsrInsertProcess routine inserts a CSR Process into the Process List + * and notifies Server DLLs of the creation of a new CSR Process. + * + * @param Parent + * Optional pointer to the CSR Process creating this CSR Process. + * + * @param CurrentProcess + * Optional pointer to the current CSR Process. + * + * @param CsrProcess + * Pointer to the CSR Process which is to be inserted. + * + * @return None. + * + * @remarks None. + * + *--*/ +VOID +NTAPI +CsrInsertProcess(IN PCSR_PROCESS Parent OPTIONAL, + IN PCSR_PROCESS CurrentProcess OPTIONAL, + IN PCSR_PROCESS CsrProcess) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return Status; + PCSR_SERVER_DLL ServerDll; + ULONG i; + + /* Set the parent */ + CsrProcess->Parent = Parent; + + /* Insert it into the Root List */ + InsertTailList(&CsrRootProcess->ListLink, &CsrProcess->ListLink); + + /* Notify the Server DLLs */ + for (i = 0; i < CSR_SERVER_DLL_MAX; i++) + { + /* Get the current Server DLL */ + ServerDll = CsrLoadedServerDll[i]; + + /* Make sure it's valid and that it has callback */ + if (ServerDll && ServerDll->NewProcessCallback) + { + (*ServerDll->NewProcessCallback)(CurrentProcess, CsrProcess); + } + } } -NTSTATUS STDCALL CsrGetProcessLuid (PCSR_PROCESS pCsrProcess, PLUID pLuid) +/*++ + * @name CsrLockedDereferenceProcess + * + * The CsrLockedDereferenceProcess dereferences a CSR Process while the + * Process Lock is already being held. + * + * @param CsrProcess + * Pointer to the CSR Process to be dereferenced. + * + * @return None. + * + * @remarks This routine will return with the Process Lock held. + * + *--*/ +VOID +NTAPI +CsrLockedDereferenceProcess(PCSR_PROCESS CsrProcess) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return Status; + /* Decrease reference count */ + if (!(--CsrProcess->ReferenceCount)) + { + /* Call the generic cleanup code */ + CsrAcquireProcessLock(); + CsrProcessRefcountZero(CsrProcess); + } } -NTSTATUS STDCALL CsrLockProcessByClientId () +/*++ + * @name CsrRemoveProcess + * + * The CsrRemoveProcess function undoes a CsrInsertProcess operation and + * removes the CSR Process from the Process List and notifies Server DLLs + * of this removal. + * + * @param CsrProcess + * Pointer to the CSR Process to remove. + * + * @return None. + * + * @remarks None. + * + *--*/ +VOID +NTAPI +CsrRemoveProcess(IN PCSR_PROCESS CsrProcess) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return Status; + PCSR_SERVER_DLL ServerDll; + ULONG i; + + /* Remove us from the Process List */ + RemoveEntryList(&CsrProcess->ListLink); + + /* Release the lock */ + CsrReleaseProcessLock(); + + /* Loop every Server DLL */ + for (i = 0; i < CSR_SERVER_DLL_MAX; i++) + { + /* Get the Server DLL */ + ServerDll = CsrLoadedServerDll[i]; + + /* Check if it's valid and if it has a Disconnect Callback */ + if (ServerDll && ServerDll->DisconnectCallback) + { + /* Call it */ + (ServerDll->DisconnectCallback)(CsrProcess); + } + } } -NTSTATUS STDCALL CsrShutdownProcesses (PCSR_SESSION pCsrSession OPTIONAL) +/*++ + * @name CsrProcessRefcountZero + * + * The CsrProcessRefcountZero routine is executed when a CSR Process has lost + * all its active references. It removes and de-allocates the CSR Process. + * + * @param CsrProcess + * Pointer to the CSR Process that is to be deleted. + * + * @return None. + * + * @remarks Do not call this routine. It is reserved for the internal + * thread management routines when a CSR Process has lost all + * its references. + * + * This routine is called with the Process Lock held. + * + *--*/ +VOID +NTAPI +CsrProcessRefcountZero(IN PCSR_PROCESS CsrProcess) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); + /* Remove the Process from the list */ + CsrRemoveProcess(CsrProcess); - if (NULL == pCsrSession) - { - // TODO: shutdown every session - } else { - // TODO: shutdown every process in pCsrSession - } - return Status; + /* Check if there's a session */ + if (CsrProcess->NtSession) + { + /* Dereference the Session */ + CsrDereferenceNtSession(CsrProcess->NtSession, 0); + } + + /* Close the Client Port if there is one */ + if (CsrProcess->ClientPort ) NtClose(CsrProcess->ClientPort); + + /* Close the process handle */ + NtClose(CsrProcess->ProcessHandle); + + /* Free the Proces Object */ + CsrDeallocateProcess(CsrProcess); } -NTSTATUS STDCALL CsrUnlockProcess (PCSR_PROCESS pCsrProcess) +/*++ + * @name CsrSetToNormalPriority + * + * The CsrSetToNormalPriority routine sets the current NT Process' + * priority to the normal priority for CSR Processes. + * + * @param None. + * + * @return None. + * + * @remarks The "Normal" Priority corresponds to the Normal Forground + * Priority (9) plus a boost of 4. + * + *--*/ +VOID +NTAPI +CsrSetToNormalPriority(VOID) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return Status; + KPRIORITY BasePriority = (8 + 1) + 4; + + /* Set the Priority */ + NtSetInformationProcess(NtCurrentProcess(), + ProcessBasePriority, + &BasePriority, + sizeof(KPRIORITY)); +} + +/*++ + * @name CsrSetToShutdownPriority + * + * The CsrSetToShutdownPriority routine sets the current NT Process' + * priority to the boosted priority for CSR Processes doing shutdown. + * Additonally, it acquires the Shutdown Privilege required for shutdown. + * + * @param None. + * + * @return None. + * + * @remarks The "Shutdown" Priority corresponds to the Normal Forground + * Priority (9) plus a boost of 6. + * + *--*/ +VOID +NTAPI +CsrSetToShutdownPriority(VOID) +{ + KPRIORITY SetBasePriority = (8 + 1) + 6; + BOOLEAN Old; + + /* Get the shutdown privilege */ + if (NT_SUCCESS(RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, + TRUE, + FALSE, + &Old))) + { + /* Set the Priority */ + NtSetInformationProcess(NtCurrentProcess(), + ProcessBasePriority, + &SetBasePriority, + sizeof(KPRIORITY)); + } +} + +/*++ + * @name FindProcessForShutdown + * + * The FindProcessForShutdown routine returns a CSR Process which is ready + * to be shutdown, and sets the appropriate shutdown flags for it. + * + * @param CallerLuid + * Pointer to the LUID of the CSR Process calling this routine. + * + * @return Pointer to a CSR Process which is ready to be shutdown. + * + * @remarks None. + * + *--*/ +PCSR_PROCESS +NTAPI +FindProcessForShutdown(PLUID CallerLuid) +{ + PLIST_ENTRY ListHead, NextEntry; + LUID ProcessLuid; + NTSTATUS Status; + LUID SystemLuid = SYSTEM_LUID; + PCSR_PROCESS CsrProcess; + PCSR_THREAD CsrThread; + BOOLEAN IsSystemLuid = FALSE, IsOurLuid = FALSE; + PCSR_PROCESS ReturnCsrProcess = NULL; + ULONG Level = 0; + + /* Set the List Pointers */ + ListHead = &CsrRootProcess->ListLink; + NextEntry = ListHead->Flink; + + /* Start looping */ + while (NextEntry != ListHead) + { + /* Get the process */ + CsrProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink); + + /* Move to the next entry */ + NextEntry = NextEntry->Flink; + + /* Skip this process if it's already been processed*/ + if (CsrProcess->Flags & CsrProcessSkipShutdown) continue; + + /* Get the LUID of this Process */ + Status = CsrGetProcessLuid(CsrProcess->ProcessHandle, &ProcessLuid); + + /* Check if we didn't get access to the LUID */ + if (Status == STATUS_ACCESS_DENIED) + { + /* Check if we have any threads */ + if (CsrProcess->ThreadCount) + { + /* Impersonate one of the threads and retry */ + CsrThread = CONTAINING_RECORD(CsrProcess->ThreadList.Flink, + CSR_THREAD, + Link); + CsrImpersonateClient(CsrThread); + Status = CsrGetProcessLuid(NULL, &ProcessLuid); + CsrRevertToSelf(); + } + } + + if (!NT_SUCCESS(Status)) + { + /* We didn't have access, so skip it */ + CsrProcess->Flags |= CsrProcessSkipShutdown; + continue; + } + + /* Check if this is the System LUID */ + if ((IsSystemLuid = RtlEqualLuid(&ProcessLuid, &SystemLuid))) + { + /* Mark this process */ + CsrProcess->ShutdownFlags |= CsrShutdownSystem; + } + else if (!(IsOurLuid = RtlEqualLuid(&ProcessLuid, CallerLuid))) + { + /* Our LUID doesn't match with the caller's */ + CsrProcess->ShutdownFlags |= CsrShutdownOther; + } + + /* Check if we're past the previous level */ + if (CsrProcess->ShutdownLevel > Level) + { + /* Update the level */ + Level = CsrProcess->ShutdownLevel; + + /* Set the final process */ + ReturnCsrProcess = CsrProcess; + } + } + + /* Check if we found a process */ + if (ReturnCsrProcess) + { + /* Skip this one next time */ + ReturnCsrProcess->Flags |= CsrProcessSkipShutdown; + } + + return ReturnCsrProcess; +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + +/*++ + * @name CsrCreateProcess + * @implemented NT4 + * + * Do nothing for 500ms. + * + * @param ArgumentCount + * Description of the parameter. Wrapped to more lines on ~70th + * column. + * + * @param Arguments + * Description of the parameter. Wrapped to more lines on ~70th + * column. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrCreateProcess(IN HANDLE hProcess, + IN HANDLE hThread, + IN PCLIENT_ID ClientId, + IN PCSR_NT_SESSION NtSession, + IN ULONG Flags, + IN PCLIENT_ID DebugCid) +{ + PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread; + CLIENT_ID CurrentCid; + PCSR_PROCESS CurrentProcess; + PVOID ProcessData; + ULONG i; + PCSR_PROCESS CsrProcess; + NTSTATUS Status; + PCSR_THREAD CsrThread; + KERNEL_USER_TIMES KernelTimes; + + /* Get the current CID and lock Processes */ + CurrentCid = CurrentThread->ClientId; + CsrAcquireProcessLock(); + + /* Get the current CSR Thread */ + CurrentThread = CsrLocateThreadByClientId(&CurrentProcess, &CurrentCid); + if (!CurrentThread) + { + /* We've failed to locate the thread */ + CsrReleaseProcessLock(); + return STATUS_THREAD_IS_TERMINATING; + } + + /* Allocate a new Process Object */ + if (!(CsrProcess = CsrAllocateProcess())) + { + /* Couldn't allocate Process */ + CsrReleaseProcessLock(); + return STATUS_NO_MEMORY; + } + + /* Setup Process Data */ + CsrProcess->ClientId = *ClientId; + CsrProcess->ProcessHandle = hProcess; + CsrProcess->ShutdownLevel = 0x280; + + /* Inherit the Process Data */ + ProcessData = &CurrentProcess->ServerData[CSR_SERVER_DLL_MAX]; + for (i = 0; i < CSR_SERVER_DLL_MAX; i++) + { + /* Check if the DLL is Loaded and has Per Process Data */ + if (CsrLoadedServerDll[i] && CsrLoadedServerDll[i]->SizeOfProcessData) + { + /* Set the pointer */ + CsrProcess->ServerData[i] = ProcessData; + + /* Copy the Data */ + RtlMoveMemory(ProcessData, + CurrentProcess->ServerData[i], + CsrLoadedServerDll[i]->SizeOfProcessData); + + /* Update next data pointer */ + ProcessData = (PVOID)((ULONG_PTR)ProcessData + + CsrLoadedServerDll[i]->SizeOfProcessData); + } + else + { + /* No data for this Server */ + CsrProcess->ServerData[i] = NULL; + } + } + + /* Set the Exception port to us */ + Status = NtSetInformationProcess(hProcess, + ProcessExceptionPort, + &CsrApiPort, + sizeof(HANDLE)); + if (!NT_SUCCESS(Status)) + { + /* Failed */ + CsrDeallocateProcess(CsrProcess); + CsrReleaseProcessLock(); + return STATUS_NO_MEMORY; + } + + /* If Check if CreateProcess got CREATE_NEW_PROCESS_GROUP */ + if (!(Flags & CsrProcessCreateNewGroup)) + { + /* Create new data */ + CsrProcess->ProcessGroupId = HandleToUlong(ClientId->UniqueProcess); + CsrProcess->ProcessGroupSequence = CsrProcess->SequenceNumber; + } + else + { + /* Copy it from the current process */ + CsrProcess->ProcessGroupId = CurrentProcess->ProcessGroupId; + CsrProcess->ProcessGroupSequence = CurrentProcess->ProcessGroupSequence; + } + + /* Check if this is a console process */ + if(Flags & CsrProcessIsConsoleApp) CsrProcess->Flags |= CsrProcessIsConsoleApp; + + /* Mask out non-debug flags */ + Flags &= ~(CsrProcessIsConsoleApp | CsrProcessCreateNewGroup); + + /* Check if every process will be debugged */ + if (!Flags && CurrentProcess->DebugFlags & CsrDebugProcessChildren) + { + /* Pass it on to the current process */ + CsrProcess->DebugFlags = CsrDebugProcessChildren; + CsrProcess->DebugCid = CurrentProcess->DebugCid; + } + + /* Check if Debugging was used on this process */ + if (Flags & (CsrDebugOnlyThisProcess | CsrDebugProcessChildren)) + { + /* Save the debug flag used */ + CsrProcess->DebugFlags = Flags; + + /* Save the CID */ + if (DebugCid) CsrProcess->DebugCid = *DebugCid; + } + + /* Check if we debugging is enabled */ + if (CsrProcess->DebugFlags) + { + /* Set the Debug Port to us */ + Status = NtSetInformationProcess(hProcess, + ProcessDebugPort, + &CsrApiPort, + sizeof(HANDLE)); + if (!NT_SUCCESS(Status)) + { + /* Failed */ + CsrDeallocateProcess(CsrProcess); + CsrReleaseProcessLock(); + return STATUS_NO_MEMORY; + } + } + + /* Get the Thread Create Time */ + Status = NtQueryInformationThread(hThread, + ThreadTimes, + (PVOID)&KernelTimes, + sizeof(KernelTimes), + NULL); + + /* Allocate a CSR Thread Structure */ + CsrThread = CsrAllocateThread(CsrProcess); + if (CsrThread == NULL) + { + /* Failed */ + CsrDeallocateProcess(CsrProcess); + CsrReleaseProcessLock(); + return STATUS_NO_MEMORY; + } + + /* Save the data we have */ + CsrThread->CreateTime = KernelTimes.CreateTime; + CsrThread->ClientId = *ClientId; + CsrThread->ThreadHandle = hThread; + CsrThread->Flags = 0; + + /* Insert the Thread into the Process */ + CsrInsertThread(CsrProcess, CsrThread); + + /* Reference the session */ + CsrReferenceNtSession(NtSession); + CsrProcess->NtSession = NtSession; + + /* Set the Priority to Background */ + CsrSetBackgroundPriority(CsrProcess); + + /* Insert the Process */ + CsrInsertProcess(NULL, CurrentProcess, CsrProcess); + + /* Release lock and return */ + CsrReleaseProcessLock(); + return Status; +} + +/*++ + * @name CsrDebugProcess + * @implemented NT4 + * + * The CsrDebugProcess routine is deprecated in NT 5.1 and higher. It is + * exported only for compatibility with older CSR Server DLLs. + * + * @param CsrProcess + * Deprecated. + * + * @return Deprecated + * + * @remarks Deprecated. + * + *--*/ +NTSTATUS +NTAPI +CsrDebugProcess(PCSR_PROCESS CsrProcess) +{ + /* CSR does not handle debugging anymore */ + DPRINT("CSRSRV: %s(%08lx) called\n", __FUNCTION__, CsrProcess); + return STATUS_UNSUCCESSFUL; +} + +/*++ + * @name CsrServerInitialization + * @implemented NT4 + * + * The CsrDebugProcessStop routine is deprecated in NT 5.1 and higher. It is + * exported only for compatibility with older CSR Server DLLs. + * + * @param CsrProcess + * Deprecated. + * + * @return Deprecated + * + * @remarks Deprecated. + * + *--*/ +NTSTATUS +NTAPI +CsrDebugProcessStop(PCSR_PROCESS CsrProcess) +{ + /* CSR does not handle debugging anymore */ + DPRINT("CSRSRV: %s(%08lx) called\n", __FUNCTION__, CsrProcess); + return STATUS_UNSUCCESSFUL; +} + +/*++ + * @name CsrDereferenceProcess + * @implemented NT4 + * + * The CsrDereferenceProcess routine removes a reference from a CSR Process. + * + * @param CsrThread + * Pointer to the CSR Process to dereference. + * + * @return None. + * + * @remarks If the reference count has reached zero (ie: the CSR Process has + * no more active references), it will be deleted. + * + *--*/ +VOID +NTAPI +CsrDereferenceProcess(PCSR_PROCESS CsrProcess) +{ + /* Acquire process lock */ + CsrAcquireProcessLock(); + + /* Decrease reference count */ + if (!(--CsrProcess->ReferenceCount)) + { + /* Call the generic cleanup code */ + CsrProcessRefcountZero(CsrProcess); + } + else + { + /* Just release the lock */ + CsrReleaseProcessLock(); + } +} + +/*++ + * @name CsrDestroyProcess + * @implemented NT4 + * + * The CsrDestroyProcess routine destroys the CSR Process corresponding to + * a given Client ID. + * + * @param Cid + * Pointer to the Client ID Structure corresponding to the CSR + * Process which is about to be destroyed. + * + * @param ExitStatus + * Unused. + * + * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING + * if the CSR Process is already terminating. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrDestroyProcess(IN PCLIENT_ID Cid, + IN NTSTATUS ExitStatus) +{ + PCSR_THREAD CsrThread; + PCSR_PROCESS CsrProcess; + CLIENT_ID ClientId = *Cid; + PLIST_ENTRY ListHead, NextEntry; + + /* Acquire lock */ + CsrAcquireProcessLock(); + + /* Find the thread */ + CsrThread = CsrLocateThreadByClientId(&CsrProcess, + &ClientId); + + /* Make sure we got one back, and that it's not already gone */ + if (!CsrThread || CsrProcess->Flags & CsrProcessTerminating) + { + /* Release the lock and return failure */ + CsrReleaseProcessLock(); + return STATUS_THREAD_IS_TERMINATING; + } + + /* Set the terminated flag */ + CsrProcess->Flags |= CsrProcessTerminating; + + /* Get the List Pointers */ + ListHead = &CsrProcess->ThreadList; + NextEntry = ListHead->Flink; + + /* Loop the list */ + while (NextEntry != ListHead) + { + /* Get the current thread entry */ + CsrThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link); + + /* Move to the next entry */ + NextEntry = NextEntry->Flink; + + /* Make sure the thread isn't already dead */ + if (CsrThread->Flags & CsrThreadTerminated) continue; + + /* Set the Terminated flag */ + CsrThread->Flags |= CsrThreadTerminated; + + /* Acquire the Wait Lock */ + CsrAcquireWaitLock(); + + /* Do we have an active wait block? */ + if (CsrThread->WaitBlock) + { + /* Notify waiters of termination */ + CsrNotifyWaitBlock(CsrThread->WaitBlock, + NULL, + NULL, + NULL, + CsrProcessTerminating, + TRUE); + } + + /* Release the Wait Lock */ + CsrReleaseWaitLock(); + + /* Dereference the thread */ + CsrLockedDereferenceThread(CsrThread); + } + + /* Release the Process Lock and return success */ + CsrReleaseProcessLock(); + return STATUS_SUCCESS; +} + +/*++ + * @name CsrGetProcessLuid + * @implemented NT4 + * + * Do nothing for 500ms. + * + * @param hProcess + * Optional handle to the process whose LUID should be returned. + * + * @param Luid + * Pointer to a LUID Pointer which will receive the CSR Process' LUID + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks If hProcess is not supplied, then the current thread's token will + * be used. If that too is missing, then the current process' token + * will be used. + * + *--*/ +NTSTATUS +NTAPI +CsrGetProcessLuid(HANDLE hProcess OPTIONAL, + PLUID Luid) +{ + HANDLE hToken = NULL; + NTSTATUS Status; + ULONG Length; + PTOKEN_STATISTICS TokenStats; + + /* Check if we have a handle to a CSR Process */ + if (!hProcess) + { + /* We don't, so try opening the Thread's Token */ + Status = NtOpenThreadToken(NtCurrentThread(), + TOKEN_QUERY, + FALSE, + &hToken); + + /* Check for success */ + if (!NT_SUCCESS(Status)) + { + /* If we got some other failure, then return and quit */ + if (Status != STATUS_NO_TOKEN) return Status; + + /* We don't have a Thread Token, use a Process Token */ + hProcess = NtCurrentProcess(); + hToken = NULL; + } + } + + /* Check if we have a token by now */ + if (!hToken) + { + /* No token yet, so open the Process Token */ + Status = NtOpenProcessToken(hProcess, + TOKEN_QUERY, + &hToken); + if (!NT_SUCCESS(Status)) + { + /* Still no token, return the error */ + return Status; + } + } + + /* Now get the size we'll need for the Token Information */ + Status = NtQueryInformationToken(hToken, + TokenStatistics, + NULL, + 0, + &Length); + + /* Allocate memory for the Token Info */ + if (!(TokenStats = RtlAllocateHeap(CsrHeap, 0, Length))) + { + /* Fail and close the token */ + NtClose(hToken); + return STATUS_NO_MEMORY; + } + + /* Now query the information */ + Status = NtQueryInformationToken(hToken, + TokenStatistics, + &TokenStats, + Length, + &Length); + + /* Close the handle */ + NtClose(hToken); + + /* Check for success */ + if (NT_SUCCESS(Status)) + { + /* Return the LUID */ + *Luid = TokenStats->AuthenticationId; + } + + /* Free the query information */ + RtlFreeHeap(CsrHeap, 0, TokenStats); + + /* Return the Status */ + return Status; +} + +/*++ + * @name CsrLockProcessByClientId + * @implemented NT4 + * + * The CsrLockProcessByClientId routine locks the CSR Process corresponding + * to the given Process ID and optionally returns it. + * + * @param Pid + * Process ID corresponding to the CSR Process which will be locked. + * + * @param CsrProcess + * Optional pointer to a CSR Process pointer which will hold the + * CSR Process corresponding to the given Process ID. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks Locking a CSR Process is defined as acquiring an extra + * reference to it and returning with the Process Lock held. + * + *--*/ +NTSTATUS +NTAPI +CsrLockProcessByClientId(IN HANDLE Pid, + OUT PCSR_PROCESS *CsrProcess OPTIONAL) +{ + PLIST_ENTRY ListHead, NextEntry; + PCSR_PROCESS CurrentProcess = NULL; + NTSTATUS Status = STATUS_UNSUCCESSFUL; + + /* Acquire the lock */ + CsrAcquireProcessLock(); + + /* Setup the List Pointers */ + ListHead = &CsrRootProcess->ListLink; + NextEntry = ListHead; + + /* Start Loop */ + while (NextEntry != ListHead) + { + /* Get the Process */ + CurrentProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink); + + /* Check for PID Match */ + if (CurrentProcess->ClientId.UniqueProcess == Pid) + { + /* Get out of here with success */ + Status = STATUS_SUCCESS; + break; + } + + /* Next entry */ + NextEntry = NextEntry->Flink; + } + + /* Did the loop find something? */ + if (NT_SUCCESS(Status)) + { + /* Lock the found process */ + CurrentProcess->ReferenceCount++; + } + else + { + /* Nothing found, release the lock */ + CsrReleaseProcessLock(); + } + + /* Return the status and process */ + if (CsrProcess) *CsrProcess = CurrentProcess; + return Status; +} + +/*++ + * @name CsrSetForegroundPriority + * @implemented NT4 + * + * The CsrSetForegroundPriority routine sets the priority for the given CSR + * Process as a Foreground priority. + * + * @param CsrProcess + * Pointer to the CSR Process whose priority will be modified. + * + * @return None. + * + * @remarks None. + * + *--*/ +VOID +NTAPI +CsrSetForegroundPriority(IN PCSR_PROCESS CsrProcess) +{ + PROCESS_PRIORITY_CLASS PriorityClass; + + /* Set the Foreground bit on */ + PriorityClass.Foreground = TRUE; + + /* Set the new Priority */ + NtSetInformationProcess(CsrProcess->ProcessHandle, + ProcessPriorityClass, + &PriorityClass, + sizeof(PriorityClass)); +} + +/*++ + * @name CsrSetBackgroundPriority + * @implemented NT4 + * + * The CsrSetBackgroundPriority routine sets the priority for the given CSR + * Process as a Background priority. + * + * @param CsrProcess + * Pointer to the CSR Process whose priority will be modified. + * + * @return None. + * + * @remarks None. + * + *--*/ +VOID +NTAPI +CsrSetBackgroundPriority(IN PCSR_PROCESS CsrProcess) +{ + PROCESS_PRIORITY_CLASS PriorityClass; + + /* Set the Foreground bit off */ + PriorityClass.Foreground = FALSE; + + /* Set the new Priority */ + NtSetInformationProcess(CsrProcess->ProcessHandle, + ProcessPriorityClass, + &PriorityClass, + sizeof(PriorityClass)); +} + +/*++ + * @name CsrShutdownProcesses + * @implemented NT4 + * + * The CsrShutdownProcesses routine shuts down every CSR Process possible + * and calls each Server DLL's shutdown notification. + * + * @param CallerLuid + * Pointer to the LUID of the CSR Process that is ordering the + * shutdown. + * + * @param Flags + * Flags to send to the shutdown notification routine. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrShutdownProcesses(PLUID CallerLuid, + ULONG Flags) +{ + PLIST_ENTRY ListHead, NextEntry; + PCSR_PROCESS CsrProcess; + NTSTATUS Status = STATUS_UNSUCCESSFUL; + BOOLEAN FirstTry = TRUE; + ULONG i; + PCSR_SERVER_DLL ServerDll; + ULONG Result; + + /* Acquire process lock */ + CsrAcquireProcessLock(); + + /* Add shutdown flag */ + CsrRootProcess->ShutdownFlags |= CsrShutdownSystem; + + /* Get the list pointers */ + ListHead = &CsrRootProcess->ListLink; + NextEntry = ListHead->Flink; + + /* Start the loop */ + while (NextEntry != ListHead) + { + /* Get the Process */ + CsrProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink); + + /* Remove the skip flag, set shutdown flags to 0*/ + CsrProcess->Flags &= ~CsrProcessSkipShutdown; + CsrProcess->ShutdownFlags = 0; + + /* Move to the next */ + NextEntry = NextEntry->Flink; + } + + /* Set shudown Priority */ + CsrSetToShutdownPriority(); + + /* Start looping */ + while (TRUE) + { + /* Find the next process to shutdown */ + if (!(CsrProcess = FindProcessForShutdown(CallerLuid))) + { + /* Done, quit */ + CsrReleaseProcessLock(); + Status = STATUS_SUCCESS; + goto Quickie; + } + + /* Increase reference to process */ + CsrProcess->ReferenceCount++; + +LoopAgain: + /* Loop all the servers */ + for (i = 0; i < CSR_SERVER_DLL_MAX; i++) + { + /* Get the current server */ + ServerDll = CsrLoadedServerDll[i]; + if (ServerDll && ServerDll->ShutdownProcessCallback) + { + /* Release the lock, make the callback, and acquire it back */ + CsrReleaseProcessLock(); + Result = (*ServerDll->ShutdownProcessCallback)(CsrProcess, + Flags, + FirstTry); + CsrAcquireProcessLock(); + + /* Check the result */ + if (Result == CsrShutdownCsrProcess) + { + /* The callback unlocked the process */ + break; + } + else if (Result == CsrShutdownNonCsrProcess) + { + /* A non-CSR process, the callback didn't touch it */ + continue; + } + else if (Result == CsrShutdownCancelled) + { + /* Shutdown was cancelled, unlock and exit */ + CsrReleaseProcessLock(); + Status = STATUS_CANCELLED; + goto Quickie; + } + } + } + + /* No matches during the first try, so loop again */ + if (FirstTry && Result == CsrShutdownNonCsrProcess) + { + FirstTry = FALSE; + goto LoopAgain; + } + + /* We've reached the final loop here, so dereference */ + if (i == CSR_SERVER_DLL_MAX) CsrLockedDereferenceProcess(CsrProcess); + } + +Quickie: + /* Return to normal priority */ + CsrSetToNormalPriority(); + return Status; +} + +/*++ + * @name CsrUnlockProcess + * @implemented NT4 + * + * The CsrUnlockProcess undoes a previous CsrLockProcessByClientId operation. + * + * @param CsrProcess + * Pointer to a previously locked CSR Process. + * + * @return STATUS_SUCCESS. + * + * @remarks This routine must be called with the Process Lock held. + * + *--*/ +NTSTATUS +NTAPI +CsrUnlockProcess(PCSR_PROCESS CsrProcess) +{ + /* Dereference the process */ + CsrLockedDereferenceProcess(CsrProcess); + + /* Release the lock and return */ + CsrReleaseProcessLock(); + return STATUS_SUCCESS; } /* EOF */ diff --git a/reactos/subsys/csr/csrsrv/server.c b/reactos/subsys/csr/csrsrv/server.c index 0b66dd58cd9..883de7cb2d6 100644 --- a/reactos/subsys/csr/csrsrv/server.c +++ b/reactos/subsys/csr/csrsrv/server.c @@ -1,419 +1,667 @@ -/* $Id$ - * - * subsys/csr/csrsrv/server.c - CSR server - subsystem default server - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS CSR Sub System + * FILE: subsys/csr/csrsrv/server.c + * PURPOSE: CSR Server DLL Server Functions + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) */ + +/* INCLUDES ******************************************************************/ #include "srv.h" -//#define NDEBUG +#define NDEBUG #include -typedef NTSTATUS (STDCALL * CSR_SERVER_DLL_INIT_PROC)(ULONG,LPWSTR*); +/* DATA **********************************************************************/ -typedef struct _CSRSRV_SERVER_DLL +PCSR_API_ROUTINE CsrServerApiDispatchTable[5] = { - USHORT ServerIndex; - USHORT Sequence; // initialization order - UNICODE_STRING DllName; - UNICODE_STRING DllEntryPoint; - CSR_SERVER_THREAD ServerThread; // NULL ==> inactive + CsrSrvClientConnect, + CsrSrvUnusedFunction, + CsrSrvUnusedFunction, + CsrSrvIdentifyAlertableThread, + CsrSrvSetPriorityClass +}; -} CSRSRV_SERVER_DLL, *PCSRSRV_SERVER_DLL; - -/*===================================================================== - * GLOBALS - *===================================================================*/ - -CSRSRV_OPTION CsrSrvOption; - -HANDLE CsrSrvApiPortHandle = (HANDLE) 0; - -/*===================================================================== - * LOCALS - *===================================================================*/ - -static HANDLE CsrSrvSbApiPortHandle = (HANDLE) 0; - -static CSRSRV_SERVER_DLL ServerThread [CSR_SERVER_DLL_MAX]; - -VOID CALLBACK CsrSrvServerThread (PVOID); - -/********************************************************************** - * CsrSrvRegisterServerDll/1 - */ -NTSTATUS STDCALL CsrSrvRegisterServerDll (PCSR_SERVER_DLL pServerDll) +BOOLEAN CsrServerApiServerValidTable[5] = { - static USHORT NextInSequence = 0; - USHORT ServerIndex = 0; + TRUE, + FALSE, + TRUE, + TRUE, + TRUE +}; - // 1st call? - if (0 == NextInSequence) - { - RtlZeroMemory (ServerThread, sizeof ServerThread); - } - // We can not register more than CSR_SERVER_DLL_MAX servers. - // Note: # servers >= # DLLs (MS Win32 has 3 servers in 2 DLLs). - if (NextInSequence >= CSR_SERVER_DLL_MAX) - { - return STATUS_NO_MEMORY; - } - // Validate the ServerIndex from the command line: - // it may be 0, 1, 2, or 3. - ServerIndex = pServerDll->ServerIndex; - if (ServerIndex >= CSR_SERVER_DLL_MAX) - { - return STATUS_INVALID_PARAMETER; - } - // Register the DLL server. - ServerThread [ServerIndex].ServerIndex = ServerIndex; - ServerThread [ServerIndex].Sequence = NextInSequence ++; - if (0 != ServerIndex) - { - RtlDuplicateUnicodeString (1, & pServerDll->DllName, & ServerThread [ServerIndex].DllName); - RtlDuplicateUnicodeString (1, & pServerDll->DllEntryPoint, & ServerThread [ServerIndex].DllEntryPoint); - } else { - // CSRSRV.DLL own static server thread - ServerThread [ServerIndex].ServerThread = CsrSrvServerThread; - } - return STATUS_SUCCESS; -} -/********************************************************************** - * CsrSrvInitializeServerDll/1 PRIVATE +PCHAR CsrServerApiNameTable[5] = +{ + "ClientConnect", + "ThreadConnect", + "ProfileControl", + "IdentifyAlertableThread", + "SetPriorityClass" +}; + +PCSR_SERVER_DLL CsrLoadedServerDll[CSR_SERVER_DLL_MAX]; +PVOID CsrSrvSharedSectionHeap; +PVOID CsrSrvSharedSectionBase; +PVOID *CsrSrvSharedStaticServerData; +ULONG CsrSrvSharedSectionSize; +HANDLE CsrSrvSharedSection; + +/* PRIVATE FUNCTIONS**********************************************************/ + +/*++ + * @name CsrLoadServerDll + * @implemented NT4 * - * NOTE - * Code dapted from CsrpInitWin32Csr. - */ -static NTSTATUS CsrSrvInitializeServerDll (USHORT ServerIndex) -{ - NTSTATUS Status = STATUS_SUCCESS; - HINSTANCE hInst; - ANSI_STRING ProcName; - CSR_SERVER_DLL_INIT_PROC InitProc; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - Status = LdrLoadDll (NULL, 0, & ServerThread[ServerIndex].DllName, (PVOID *) &hInst); - if (!NT_SUCCESS(Status)) - { - DPRINT1("CSRSRV:%s: loading ServerDll '%S' failed (Status=%08lx)\n", - __FUNCTION__, ServerThread[ServerIndex].DllName.Buffer, Status); - return Status; - } - RtlInitAnsiString (& ProcName, "ServerDllInitialization"); - Status = LdrGetProcedureAddress(hInst, &ProcName, 0, (PVOID *) &InitProc); - if (!NT_SUCCESS(Status)) - { - DPRINT1("CSRSRV:%s: ServerDll '%S!%s' not found (Status=%08lx)\n", - __FUNCTION__, - ServerThread[ServerIndex].DllName.Buffer, - "ServerDllInitialization", - Status); - return Status; - } - Status = InitProc (0, NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("CSRSRV:%s: %S.%s failed with Status=%08lx\n", - __FUNCTION__, - ServerThread[ServerIndex].DllName.Buffer, - "ServerDllInitialization", - Status); - } - return Status; -} - -/********************************************************************** - * CsrpCreateObjectDirectory/1 PRIVATE - */ -NTSTATUS STDCALL CsrpCreateObjectDirectory (PUNICODE_STRING pObjectDirectory) -{ - NTSTATUS Status = STATUS_SUCCESS; - OBJECT_ATTRIBUTES DirectoryAttributes; - - DPRINT("CSRSRV:%s(%S) called\n", __FUNCTION__, pObjectDirectory->Buffer); - - InitializeObjectAttributes (& DirectoryAttributes, - pObjectDirectory, - OBJ_OPENIF, - NULL, - NULL); - - Status = NtCreateDirectoryObject (& CsrSrvOption.NameSpace.RootHandle, - (DIRECTORY_CREATE_OBJECT|DIRECTORY_CREATE_SUBDIRECTORY), - & DirectoryAttributes); - if (NT_SUCCESS(Status)) - { - Status = RtlDuplicateUnicodeString (0, pObjectDirectory, & CsrSrvOption.NameSpace.Root); - if (!NT_SUCCESS(Status)) - { - DPRINT1("CSRSRV:%s: RtlDuplicateUnicodeString failed (Status=0x%08lx)\n", - __FUNCTION__, Status); - } - } else { - DPRINT1("CSRSRV:%s: fatal: NtCreateDirectoryObject failed (Status=0x%08lx)\n", - __FUNCTION__, Status); - } - return Status; -} -/********************************************************************** - * CsrSrvBootstrap/0 + * The CsrLoadServerDll routine loads a CSR Server DLL and calls its entrypoint * - * DESCRIPTION - * This is where a subsystem begins living. - */ -NTSTATUS STDCALL CsrSrvBootstrap (VOID) -{ - NTSTATUS Status = STATUS_SUCCESS; - ULONG ServerIndex = 0; - ULONG ServerSequence = 0; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - CsrSrvSbApiPortHandle = CsrSrvSbApiPortHandle; //FIXME - - // OBJECT DIRECTORY - Status = CsrpCreateObjectDirectory (& CsrSrvOption.NameSpace.Root); - if(!NT_SUCCESS(Status)) - { - DPRINT1("CSRSRV:%s: CsrpCreateObjectDirectory failed (Status=%08lx)\n", - __FUNCTION__, Status); - return Status; - } - // SESSIONS - Status = CsrSrvInitializeSession (); - if(!NT_SUCCESS(Status)) - { - DPRINT1("CSRSRV:%s: CsrSrvInitializeSession failed (Status=%08lx)\n", - __FUNCTION__, Status); - return Status; - } - // PROCESSES - // TODO - // THREADS - // TODO - // WAITS - // TODO - // Hosted servers - for (ServerSequence = 0; ServerSequence < CSR_SERVER_DLL_MAX; ServerSequence ++) - { - for (ServerIndex = 0; (ServerIndex < CSR_SERVER_DLL_MAX); ++ ServerIndex) - { - if (ServerSequence == ServerThread [ServerIndex].Sequence) - { - if (NULL == ServerThread [ServerIndex].ServerThread) - { - Status = CsrSrvInitializeServerDll (ServerIndex); - if (!NT_SUCCESS(Status)) - { - DPRINT1("CSRSRV:%s: server thread #%d init failed!\n", - __FUNCTION__, ServerIndex); - } - } else { - DPRINT1("CSRSRV:%s: server thread #%d initialized more than once!\n", - __FUNCTION__, ServerIndex); - } - } - } - } - return Status; -} -/********************************************************************** - * CsrSrvServerThread/1 + * @param DllString + * Pointer to the CSR Server DLL to load and call. * - * DESCRIPTION - * This is actually a function called by the CsrSrvMainServerThread - * when the server index is 0. Other server DLLs register their - * function with CsrAddStaticServerThread. - */ -VOID STDCALL CsrSrvServerThread (PVOID x) -{ - NTSTATUS Status = STATUS_SUCCESS; - PPORT_MESSAGE Request = (PPORT_MESSAGE) x; - PPORT_MESSAGE Reply = NULL; - ULONG MessageType = 0; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - MessageType = Request->u2.s2.Type; - DPRINT("CSRSRV: %s received a message (Type=%d)\n", - __FUNCTION__, MessageType); - switch (MessageType) - { - //TODO - default: - Reply = Request; - Status = NtReplyPort (CsrSrvApiPortHandle, Reply); - break; - } -} - -/********************************************************************** - * PUBLIC API - *********************************************************************/ - -/********************************************************************** - * CsrAddStaticServerThread/1 - */ -NTSTATUS STDCALL CsrAddStaticServerThread (CSR_SERVER_THREAD ServerThread) -{ - static ULONG StaticServerThreadCount = 0; - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s(%08lx) called\n", __FUNCTION__, ServerThread); - - if (StaticServerThreadCount > CSR_SERVER_DLL_MAX) - { - DPRINT1("CSRSRV: subsystem tries to add mode than %d static threads!\n", - CSR_SERVER_DLL_MAX); - return STATUS_NO_MEMORY; - } - if (NT_SUCCESS(Status)) - { - // FIXME: do we need to make it reentrant? - ++ StaticServerThreadCount; - } - return Status; -} - -/********************************************************************** - * CsrCallServerFromServer - */ -NTSTATUS STDCALL CsrCallServerFromServer () -{ - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return Status; -} - -/********************************************************************** - * CsrExecServerThread - */ -NTSTATUS STDCALL CsrExecServerThread () -{ - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return Status; -} - -/********************************************************************** - * CsrImpersonateClient - */ -NTSTATUS STDCALL CsrImpersonateClient () -{ - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return Status; -} - -/********************************************************************** - * CsrQueryApiPort/0 + * @param EntryPoint + * Pointer to the name of the server's initialization function. If + * this parameter is NULL, the default ServerDllInitialize will be + * assumed. * - * @implemented - */ -HANDLE STDCALL CsrQueryApiPort (VOID) + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrLoadServerDll(IN PCHAR DllString, + IN PCHAR EntryPoint OPTIONAL, + IN ULONG ServerId) { - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return CsrSrvApiPortHandle; + NTSTATUS Status; + ANSI_STRING DllName; + UNICODE_STRING TempString; + HANDLE hServerDll = NULL; + ULONG Size; + PCSR_SERVER_DLL ServerDll; + STRING EntryPointString; + PCSR_SERVER_DLL_INIT_CALLBACK ServerDllInitProcedure; + + /* Check if it's beyond the maximum we support */ + if (ServerId >= CSR_SERVER_DLL_MAX) return(STATUS_TOO_MANY_NAMES); + + /* Check if it's already been loaded */ + if (CsrLoadedServerDll[ServerId]) return(STATUS_INVALID_PARAMETER); + + /* Convert the name to Unicode */ + RtlInitAnsiString(&DllName, DllString); + Status = RtlAnsiStringToUnicodeString(&TempString, &DllName, TRUE); + + /* If we are loading ourselves, don't actually load us */ + if (ServerId != CSR_SRV_SERVER) + { + /* Load the DLL */ + Status = LdrLoadDll(NULL, 0, &TempString, &hServerDll); + + /* Get rid of the string */ + RtlFreeUnicodeString(&TempString); + if (!NT_SUCCESS(Status)) + { + return Status; + } + } + + /* Allocate a CSR DLL Object */ + Size = sizeof(CSR_SERVER_DLL) + DllName.MaximumLength; + if (!(ServerDll = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, Size))) + { + if (hServerDll) LdrUnloadDll(hServerDll); + return STATUS_NO_MEMORY; + } + + /* Set up the Object */ + ServerDll->Length = Size; + ServerDll->SharedSection = CsrSrvSharedSectionHeap; + ServerDll->Event = CsrInitializationEvent; + ServerDll->Name.Length = DllName.Length; + ServerDll->Name.MaximumLength = DllName.MaximumLength; + ServerDll->Name.Buffer = (PCHAR)(ServerDll + 1); + if (DllName.Length) + { + strncpy(ServerDll->Name.Buffer, DllName.Buffer, DllName.Length); + } + ServerDll->ServerId = ServerId; + ServerDll->ServerHandle = hServerDll; + + /* Now get the entrypoint */ + if (hServerDll) + { + /* Initialize a string for the entrypoint, or use the default */ + RtlInitAnsiString(&EntryPointString, + !(EntryPoint) ? "ServerDllInitialization" : + EntryPoint); + + /* Get a pointer to it */ + Status = LdrGetProcedureAddress(hServerDll, + &EntryPointString, + 0, + (PVOID)&ServerDllInitProcedure); + } + else + { + /* No handle, so we are loading ourselves */ + ServerDllInitProcedure = CsrServerDllInitialization; + Status = STATUS_SUCCESS; + } + + /* Check if we got the pointer, and call it */ + if (NT_SUCCESS(Status)) + { + /* Get the result from the Server DLL */ + Status = (*ServerDllInitProcedure)(ServerDll); + + /* Check for Success */ + if (NT_SUCCESS(Status)) + { + /* + * Add this Server's Per-Process Data Size to the total that each + * process will need. + */ + CsrTotalPerProcessDataLength += ServerDll->SizeOfProcessData; + + /* Save the pointer in our list */ + CsrLoadedServerDll[ServerDll->ServerId] = ServerDll; + + /* Does it use our generic heap? */ + if (ServerDll->SharedSection != CsrSrvSharedSectionHeap) + { + /* No, save the pointer to its shared section in our list */ + CsrSrvSharedStaticServerData[ServerDll->ServerId] = ServerDll->SharedSection; + } + } + else + { + /* Use shared failure code */ + goto LoadFailed; + } + } + else + { +LoadFailed: + /* Server Init failed, unload it */ + if (hServerDll) LdrUnloadDll(hServerDll); + + /* Delete the Object */ + RtlFreeHeap(CsrHeap, 0, ServerDll); + } + + /* Return to caller */ + return Status; } -/********************************************************************** - * CsrRevertToSelf - */ -NTSTATUS STDCALL CsrRevertToSelf () +/*++ + * @name CsrServerDllInitialization + * @implemented NT4 + * + * The CsrServerDllInitialization is the initialization routine for + * the this Server DLL. + * + * @param LoadedServerDll + * Pointer to the CSR Server DLL structure representing this Server DLL. + * + * @return STATUS_SUCCESS. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrServerDllInitialization(IN PCSR_SERVER_DLL LoadedServerDll) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return Status; + /* Setup the DLL Object */ + LoadedServerDll->ApiBase = 0; + LoadedServerDll->HighestApiSupported = 5; + LoadedServerDll->DispatchTable = CsrServerApiDispatchTable; + LoadedServerDll->ValidTable = CsrServerApiServerValidTable; + LoadedServerDll->NameTable = CsrServerApiNameTable; + LoadedServerDll->SizeOfProcessData = 0; + LoadedServerDll->ConnectCallback = NULL; + LoadedServerDll->DisconnectCallback = NULL; + + /* All done */ + return STATUS_SUCCESS; } -/********************************************************************** - * CsrSetBackgroundPriority - */ -NTSTATUS STDCALL CsrSetBackgroundPriority () +/*++ + * @name CsrSrvClientConnect + * + * The CsrSrvClientConnect CSR API handles a new connection to a server DLL. + * + * @param ApiMessage + * Pointer to the CSR API Message for this request. + * + * @param Reply + * Optional reply to this request. + * + * @return STATUS_SUCCESS in case of success, STATUS_INVALID_PARAMETER + * or STATUS_TOO_MANY_NAMES in case of failure. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrSrvClientConnect(IN OUT PCSR_API_MESSAGE ApiMessage, + IN OUT PULONG Reply OPTIONAL) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return Status; + NTSTATUS Status; + PCSR_CLIENT_CONNECT ClientConnect; + PCSR_SERVER_DLL ServerDll; + + /* Load the Message, set default reply */ + ClientConnect = (PCSR_CLIENT_CONNECT)&ApiMessage->CsrClientConnect; + *Reply = 0; + + /* Validate the ServerID */ + if (ClientConnect->ServerId >= CSR_SERVER_DLL_MAX) + { + return STATUS_TOO_MANY_NAMES; + } + else if (!(CsrLoadedServerDll[ClientConnect->ServerId])) + { + return STATUS_INVALID_PARAMETER; + } + + /* Validate the Message Buffer */ + if (!(CsrValidateMessageBuffer(ApiMessage, + ClientConnect->ConnectionInfo, + ClientConnect->ConnectionInfoSize, + 1))) + { + /* Fail due to buffer overflow or other invalid buffer */ + return STATUS_INVALID_PARAMETER; + } + + /* Load the Server DLL */ + ServerDll = CsrLoadedServerDll[ClientConnect->ServerId]; + + /* Check if it has a Connect Callback */ + if (ServerDll->ConnectCallback) + { + /* Call the callback */ + Status = (ServerDll->ConnectCallback)(((PCSR_THREAD)NtCurrentTeb()->CsrClientThread)->Process, + ClientConnect->ConnectionInfo, + &ClientConnect->ConnectionInfoSize); + } + else + { + /* Assume success */ + Status = STATUS_SUCCESS; + } + + /* Return status */ + return Status; } -/********************************************************************** - * CsrSetCallingSpooler - */ -NTSTATUS STDCALL CsrSetCallingSpooler () +/*++ + * @name CsrSrvCreateSharedSection + * + * The CsrSrvCreateSharedSection creates the Shared Section that all CSR Server + * DLLs and Clients can use to share data. + * + * @param ParameterValue + * Specially formatted string from our registry command-line which + * specifies various arguments for the shared section. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrSrvCreateSharedSection(IN PCHAR ParameterValue) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return Status; + PCHAR SizeValue = ParameterValue; + ULONG Size; + NTSTATUS Status; + LARGE_INTEGER SectionSize; + ULONG ViewSize = 0; + PPEB Peb = NtCurrentPeb(); + + /* Find the first comma, and null terminate */ + while (*SizeValue) + { + if (*SizeValue == ',') + { + *SizeValue++ = '\0'; + break; + } + else + { + SizeValue++; + } + } + + /* Make sure it's valid */ + if (!*SizeValue) return(STATUS_INVALID_PARAMETER); + + /* Convert it to an integer */ + Status = RtlCharToInteger(SizeValue, + 0, + &Size); + if (!NT_SUCCESS(Status)) return Status; + + /* Multiply by 1024 entries and round to page size */ + CsrSrvSharedSectionSize = ROUND_UP(Size * 1024, CsrNtSysInfo.PageSize); + + /* Create the Secion */ + SectionSize.LowPart = CsrSrvSharedSectionSize; + SectionSize.HighPart = 0; + Status = NtCreateSection(&CsrSrvSharedSection, + SECTION_ALL_ACCESS, + NULL, + &SectionSize, + PAGE_EXECUTE_READWRITE, + SEC_BASED | SEC_RESERVE, + NULL); + if (!NT_SUCCESS(Status)) return Status; + + /* Map the section */ + Status = NtMapViewOfSection(CsrSrvSharedSection, + NtCurrentProcess(), + &CsrSrvSharedSectionBase, + 0, + 0, + NULL, + &ViewSize, + ViewUnmap, + MEM_TOP_DOWN, + PAGE_EXECUTE_READWRITE); + if(!NT_SUCCESS(Status)) + { + /* Fail */ + NtClose(CsrSrvSharedSection); + return(Status); + } + + /* FIXME: Write the value to registry */ + + /* The Heap is the same place as the Base */ + CsrSrvSharedSectionHeap = CsrSrvSharedSectionBase; + + /* Create the heap */ + if (!(RtlCreateHeap(HEAP_ZERO_MEMORY, + CsrSrvSharedSectionHeap, + CsrSrvSharedSectionSize, + PAGE_SIZE, + 0, + 0))) + { + /* Failure, unmap section and return */ + NtUnmapViewOfSection(NtCurrentProcess(), + CsrSrvSharedSectionBase); + NtClose(CsrSrvSharedSection); + return STATUS_NO_MEMORY; + } + + /* Now allocate space from the heap for the Shared Data */ + CsrSrvSharedStaticServerData = RtlAllocateHeap(CsrSrvSharedSectionHeap, + 0, + CSR_SERVER_DLL_MAX * + sizeof(PVOID)); + + /* Write the values to the PEB */ + Peb->ReadOnlySharedMemoryBase = CsrSrvSharedSectionBase; + Peb->ReadOnlySharedMemoryHeap = CsrSrvSharedSectionHeap; + Peb->ReadOnlyStaticServerData = CsrSrvSharedStaticServerData; + + /* Return */ + return STATUS_SUCCESS; } -/********************************************************************** - * CsrSetForegroundPriority - */ -NTSTATUS STDCALL CsrSetForegroundPriority () +/*++ + * @name CsrSrvAttachSharedSection + * + * The CsrSrvAttachSharedSection maps the CSR Shared Section into a new + * CSR Process' address space, and returns the pointers to the section + * through the Connection Info structure. + * + * @param CsrProcess + * Pointer to the CSR Process that is attempting a connection. + * + * @param ConnectInfo + * Pointer to the CSR Connection Info structure for the incoming + * connection. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrSrvAttachSharedSection(IN PCSR_PROCESS CsrProcess OPTIONAL, + OUT PCSR_CONNECTION_INFO ConnectInfo) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return Status; + NTSTATUS Status; + ULONG ViewSize = 0; + + /* Check if we have a process */ + if (CsrProcess) + { + /* Map the sectio into this process */ + Status = NtMapViewOfSection(CsrSrvSharedSection, + CsrProcess->ProcessHandle, + &CsrSrvSharedSectionBase, + 0, + 0, + NULL, + &ViewSize, + ViewUnmap, + SEC_NO_CHANGE, + PAGE_EXECUTE_READ); + if (!NT_SUCCESS(Status)) return Status; + } + + /* Write the values in the Connection Info structure */ + ConnectInfo->SharedSectionBase = CsrSrvSharedSectionBase; + ConnectInfo->SharedSectionHeap = CsrSrvSharedSectionHeap; + ConnectInfo->SharedSectionData = CsrSrvSharedStaticServerData; + + /* Return success */ + return STATUS_SUCCESS; } -/********************************************************************** - * CsrUnhandledExceptionFilter - */ -NTSTATUS STDCALL CsrUnhandledExceptionFilter () +/*++ + * @name CsrSrvIdentifyAlertableThread + * @implemented NT4 + * + * The CsrSrvIdentifyAlertableThread CSR API marks a CSR Thread as alertable. + * + * @param ApiMessage + * Pointer to the CSR API Message for this request. + * + * @param Reply + * Pointer to an optional reply to this request. + * + * @return STATUS_SUCCESS. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrSrvIdentifyAlertableThread(IN OUT PCSR_API_MESSAGE ApiMessage, + IN OUT PULONG Reply) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return Status; + PCSR_THREAD CsrThread = NtCurrentTeb()->CsrClientThread; + + /* Set the alertable flag */ + CsrThread->Flags |= CsrThreadAltertable; + + /* Return success */ + return STATUS_SUCCESS; } -/********************************************************************** - * CsrValidateMessageBuffer - */ -NTSTATUS STDCALL CsrValidateMessageBuffer () +/*++ + * @name CsrSrvSetPriorityClass + * @implemented NT4 + * + * The CsrSrvSetPriorityClass CSR API is deprecated. + * + * @param ApiMessage + * Pointer to the CSR API Message for this request. + * + * @param Reply + * Pointer to an optional reply to this request. + * + * @return STATUS_SUCCESS. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrSrvSetPriorityClass(IN OUT PCSR_API_MESSAGE ApiMessage, + IN OUT PULONG Reply) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return Status; + /* Deprecated */ + return STATUS_SUCCESS; } -/********************************************************************** - * CsrValidateMessageString - */ -NTSTATUS STDCALL CsrValidateMessageString () +/*++ + * @name CsrSrvUnusedFunction + * @implemented NT4 + * + * The CsrSrvUnusedFunction CSR API is a stub for deprecated APIs. + * + * The CsrSrvSetPriorityClass CSR API is deprecated. + * + * @param ApiMessage + * Pointer to the CSR API Message for this request. + * + * @param Reply + * Pointer to an optional reply to this request. + * + * @return STATUS_INVALID_PARAMETER. + * + * @remarks CsrSrvSetPriorityClass does not use this stub because it must + * return success. + * + *--*/ +NTSTATUS +NTAPI +CsrSrvUnusedFunction(IN OUT PCSR_API_MESSAGE ApiMessage, + IN OUT PULONG Reply) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; + /* Deprecated */ + return STATUS_INVALID_PARAMETER; +} - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - return Status; +/* PUBLIC FUNCTIONS***********************************************************/ + +/*++ + * @name CsrSetCallingSpooler + * @implemented NT4 + * + * the CsrSetCallingSpooler routine is deprecated. + * + * @param Reserved + * Deprecated + * + * @return None. + * + * @remarks This routine was used in archaic versions of NT for Printer Drivers. + * + *--*/ +VOID +NTAPI +CsrSetCallingSpooler(ULONG Reserved) +{ + /* Deprecated */ + return; +} + +/*++ + * @name CsrUnhandledExceptionFilter + * @implemented NT5 + * + * The CsrUnhandledExceptionFilter routine handles all exceptions + * within SEH-protected blocks. + * + * @param ExceptionPointers + * System-defined Argument. + * + * @return EXCEPTION_EXECUTE_HANDLER. + * + * @remarks None. + * + *--*/ +_SEH_FILTER(CsrUnhandledExceptionFilter) +{ + struct _EXCEPTION_POINTERS *ExceptionInfo = _SEH_GetExceptionPointers(); + SYSTEM_KERNEL_DEBUGGER_INFORMATION DebuggerInfo; + EXCEPTION_DISPOSITION Result = EXCEPTION_EXECUTE_HANDLER; + BOOLEAN OldValue; + NTSTATUS Status; + UNICODE_STRING ErrorSource; + ULONG_PTR ErrorParameters[4]; + ULONG Response; + + /* Check if a debugger is installed */ + Status = NtQuerySystemInformation(SystemKernelDebuggerInformation, + &DebuggerInfo, + sizeof(DebuggerInfo), + NULL); + + /* Check if this is Session 0, and the Debugger is Enabled */ + if ((NtCurrentPeb()->SessionId) && (NT_SUCCESS(Status)) && + (DebuggerInfo.KernelDebuggerEnabled)) + { + /* Call the Unhandled Exception Filter */ + if ((Result = RtlUnhandledExceptionFilter(ExceptionInfo)) != + EXCEPTION_CONTINUE_EXECUTION) + { + /* We're going to raise an error. Get Shutdown Privilege first */ + Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, + TRUE, + TRUE, + &OldValue); + + /* Use the Process token if that failed */ + if (Status == STATUS_NO_TOKEN) + { + Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, + TRUE, + FALSE, + &OldValue); + } + + /* Initialize our Name String */ + RtlInitUnicodeString(&ErrorSource, L"Windows SubSystem"); + + /* Set the parameters */ + ErrorParameters[0] = PtrToUlong(&ErrorSource); + ErrorParameters[1] = ExceptionInfo->ExceptionRecord->ExceptionCode; + ErrorParameters[2] = PtrToUlong(ExceptionInfo->ExceptionRecord->ExceptionAddress); + ErrorParameters[3] = PtrToUlong(ExceptionInfo->ContextRecord); + + /* Bugcheck */ + Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, + 4, + 1, + ErrorParameters, + OptionShutdownSystem, + &Response); + } + + /* Just terminate us */ + NtTerminateProcess(NtCurrentProcess(), + ExceptionInfo->ExceptionRecord->ExceptionCode); + } + + return Result; } /* EOF */ diff --git a/reactos/subsys/csr/csrsrv/session.c b/reactos/subsys/csr/csrsrv/session.c index 59c4eae3709..5f06e6136c2 100644 --- a/reactos/subsys/csr/csrsrv/session.c +++ b/reactos/subsys/csr/csrsrv/session.c @@ -1,178 +1,351 @@ -/* $Id$ - * - * subsys/csr/csrsrv/session.c - CSR server - session management - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS CSR Sub System + * FILE: subsys/csr/csrsrv/session.c + * PURPOSE: CSR Server DLL Session Implementation + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) */ + +/* INCLUDES ******************************************************************/ + #include "srv.h" -//#define NDEBUG +#define NDEBUG #include -//TODO: when CsrSrvSessionsFlag is FALSE, create just one session and -//TODO: fail for more sessions requests. +/* DATA **********************************************************************/ +RTL_CRITICAL_SECTION CsrNtSessionLock; +LIST_ENTRY CsrNtSessionList; +HANDLE CsrSmApiPort; -/* LOCALS */ - -struct { - RTL_CRITICAL_SECTION Lock; - HANDLE Heap; - ULONG LastUnusedId; -} Session; - - - -NTSTATUS STDCALL CsrSrvInitializeSession (VOID) +PSB_API_ROUTINE CsrServerSbApiDispatch[5] = { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; + CsrSbCreateSession, + CsrSbForeignSessionComplete, + CsrSbForeignSessionComplete, + CsrSbCreateProcess, + NULL +}; - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - Status = RtlInitializeCriticalSection (& Session.Lock); - if (NT_SUCCESS(Status)) - { - Session.Heap = RtlCreateHeap (HEAP_GROWABLE, - NULL, - 65536, - 65536, - NULL, - NULL); - if (NULL == Session.Heap) - { - RtlDeleteCriticalSection (& Session.Lock); - Status = STATUS_NO_MEMORY; - } - Session.LastUnusedId = 0; - } - return Status; +PCHAR CsrServerSbApiName[5] = +{ + "SbCreateSession", + "SbTerminateSEssion", + "SbForeignSessionComplete", + "SbCreateProcess", + "Unknown Csr Sb Api Number" +}; + +/* PRIVATE FUNCTIONS *********************************************************/ + +/*++ + * @name CsrInitializeNtSessions + * + * The CsrInitializeNtSessions routine sets up support for CSR Sessions. + * + * @param None + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrInitializeNtSessions(VOID) +{ + NTSTATUS Status; + DPRINT("CSRSRV: %s called\n", __FUNCTION__); + + /* Initialize the Session List */ + InitializeListHead(&CsrNtSessionList); + + /* Initialize the Session Lock */ + Status = RtlInitializeCriticalSection(&CsrNtSessionLock); + return Status; } -static NTSTATUS STDCALL CsrpCreateSessionDirectories (PCSR_SESSION pCsrSession) +/*++ + * @name CsrAllocateNtSession + * + * The CsrAllocateNtSession routine allocates a new CSR NT Session. + * + * @param SessionId + * Session ID of the CSR NT Session to allocate. + * + * @return Pointer to the newly allocated CSR NT Session. + * + * @remarks None. + * + *--*/ +PCSR_NT_SESSION +NTAPI +CsrAllocateNtSession(ULONG SessionId) { - NTSTATUS Status = STATUS_SUCCESS; - CHAR SessionIdBuffer [8]; - ANSI_STRING SessionIdNameA; - UNICODE_STRING SessionIdNameW; - UNICODE_STRING SessionDirectoryName; - OBJECT_ATTRIBUTES DirectoryAttributes; - HANDLE DirectoryHAndle; + PCSR_NT_SESSION NtSession; - DPRINT("CSRSRV: %s(%08lx) called\n", __FUNCTION__, pCsrSession); + /* Allocate an NT Session Object */ + NtSession = RtlAllocateHeap(CsrHeap, + 0, + sizeof(CSR_NT_SESSION)); - sprintf (SessionIdBuffer, "\\Sessions\\%ld", pCsrSession->SessionId); - RtlInitAnsiString (& SessionIdNameA, SessionIdBuffer); - RtlAnsiStringToUnicodeString (& SessionIdNameW, & SessionIdNameA, TRUE); - RtlCopyUnicodeString (& SessionDirectoryName, & CsrSrvOption.NameSpace.Root); - RtlAppendUnicodeStringToString (& SessionDirectoryName, & SessionIdNameW); + /* Setup the Session Object */ + if (NtSession) + { + NtSession->SessionId = SessionId; + NtSession->ReferenceCount = 1; - DPRINT("CSRSRV: %s(%08lx): %S\n", __FUNCTION__, pCsrSession, - SessionDirectoryName.Buffer); + /* Insert it into the Session List */ + CsrAcquireNtSessionLock(); + InsertHeadList(&CsrNtSessionList, &NtSession->SessionList); + CsrReleaseNtSessionLock(); + } - InitializeObjectAttributes (& DirectoryAttributes, - & SessionDirectoryName, - OBJ_OPENIF, - NULL, - NULL); - Status = NtCreateDirectoryObject (& DirectoryHAndle, - (DIRECTORY_CREATE_OBJECT|DIRECTORY_CREATE_SUBDIRECTORY), - & DirectoryAttributes); - if (NT_SUCCESS(Status)) - { - DPRINT1("CSRSRV: session %ld root directory not created (Status=%08lx)\n", - pCsrSession->SessionId, Status); - } - // TODO - return Status; + /* Return the Session (or NULL) */ + return NtSession; } -static NTSTATUS STDCALL CsrpDestroySessionDirectories (PCSR_SESSION pCsrSession) +/*++ + * @name CsrReferenceNtSession + * + * The CsrReferenceNtSession increases the reference count of a CSR NT Session. + * + * @param Session + * Pointer to the CSR NT Session to reference. + * + * @return None. + * + * @remarks None. + * + *--*/ +VOID +NTAPI +CsrReferenceNtSession(PCSR_NT_SESSION Session) { - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - return STATUS_NOT_IMPLEMENTED; + /* Acquire the lock */ + CsrAcquireNtSessionLock(); + + /* Increase the reference count */ + Session->ReferenceCount++; + + /* Release the lock */ + CsrReleaseNtSessionLock(); } -/*===================================================================== - * PUBLIC API - *===================================================================*/ - -NTSTATUS STDCALL CsrDestroySession (PCSR_SESSION pCsrSession) +/*++ + * @name CsrDereferenceNtSession + * + * The CsrDereferenceNtSession decreases the reference count of a + * CSR NT Session. + * + * @param Session + * Pointer to the CSR NT Session to reference. + * + * @param ExitStatus + * If this is the last reference to the session, this argument + * specifies the exit status. + * + * @return None. + * + * @remarks CsrDereferenceNtSession will complete the session if + * the last reference to it has been closed. + * + *--*/ +VOID +NTAPI +CsrDereferenceNtSession(PCSR_NT_SESSION Session, + NTSTATUS ExitStatus) { - NTSTATUS Status = STATUS_SUCCESS; + /* Acquire the lock */ + CsrAcquireNtSessionLock(); - DPRINT("CSRSRV: %s(%08lx) called\n", __FUNCTION__, pCsrSession); - - if (NULL == pCsrSession) - { - Status = STATUS_INVALID_PARAMETER; - } else { - Status = CsrShutdownProcesses (pCsrSession); - Status = CsrpDestroySessionDirectories (pCsrSession); - RtlDestroyHeap (pCsrSession->Heap); - RtlFreeHeap (Session.Heap, 0, pCsrSession); - } - return Status; + /* Dereference the Session Object */ + if (!(--Session->ReferenceCount)) + { + /* Remove it from the list */ + RemoveEntryList(&Session->SessionList); + + /* Release the lock */ + CsrReleaseNtSessionLock(); + + /* Tell SM that we're done here */ + SmSessionComplete(CsrSmApiPort, Session->SessionId, ExitStatus); + + /* Free the Session Object */ + RtlFreeHeap(CsrHeap, 0, Session); + } + else + { + /* Release the lock, the Session is still active */ + CsrReleaseNtSessionLock(); + } } -NTSTATUS STDCALL CsrCreateSession (PCSR_SESSION * ppCsrSession) -{ - NTSTATUS Status = STATUS_SUCCESS; - PCSR_SESSION pCsrSession = NULL; - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - if (NULL == ppCsrSession) - { - Status = STATUS_INVALID_PARAMETER; - } else { - RtlEnterCriticalSection (& Session.Lock); - pCsrSession = RtlAllocateHeap (Session.Heap, - HEAP_ZERO_MEMORY, - sizeof (CSR_SESSION)); - if (NULL == pCsrSession) - { - Status = STATUS_NO_MEMORY; - } else { - pCsrSession->SessionId = Session.LastUnusedId ++; - Status = CsrpCreateSessionDirectories (pCsrSession); - if(NT_SUCCESS(Status)) - { - pCsrSession->Heap = RtlCreateHeap(HEAP_GROWABLE, - NULL, - 65536, - 65536, - NULL, - NULL); - if (NULL == pCsrSession->Heap) - { - Status = STATUS_NO_MEMORY; - CsrpDestroySessionDirectories (pCsrSession); - -- Session.LastUnusedId; - } - } - } - RtlLeaveCriticalSection (& Session.Lock); - } - return Status; +/* SESSION MANAGER FUNCTIONS**************************************************/ + +/*++ + * @name CsrSbCreateSession + * + * The CsrSbCreateSession API is called by the Session Manager whenever a new + * session is created. + * + * @param ApiMessage + * Pointer to the Session Manager API Message. + * + * @return TRUE in case of success, FALSE othwerwise. + * + * @remarks The CsrSbCreateSession routine will initialize a new CSR NT + * Session and allocate a new CSR Process for the subsystem process. + * + *--*/ +BOOLEAN +NTAPI +CsrSbCreateSession(IN PSB_API_MESSAGE ApiMessage) +{ + PSB_CREATE_SESSION CreateSession = &ApiMessage->SbCreateSession; + HANDLE hProcess, hThread; + PCSR_PROCESS CsrProcess; + NTSTATUS Status; + KERNEL_USER_TIMES KernelTimes; + PCSR_THREAD CsrThread; + PVOID ProcessData; + ULONG i; + + /* Save the Process and Thread Handles */ + hProcess = CreateSession->ProcessInfo.ProcessHandle; + hThread = CreateSession->ProcessInfo.ThreadHandle; + + /* Lock the Processes */ + CsrAcquireProcessLock(); + + /* Allocate a new process */ + if (!(CsrProcess = CsrAllocateProcess())) + { + /* Fail */ + ApiMessage->Status = STATUS_NO_MEMORY; + CsrReleaseProcessLock(); + return TRUE; + } + + /* Setup Process Data */ + CsrProcess->ClientId = CreateSession->ProcessInfo.ClientId; + CsrProcess->ProcessHandle = hProcess; + + /* Set the exception port */ + Status = NtSetInformationProcess(hProcess, + ProcessExceptionPort, + &CsrApiPort, + sizeof(HANDLE)); + + /* Check for success */ + if (!NT_SUCCESS(Status)) + { + /* Fail the request */ + CsrDeallocateProcess(CsrProcess); + CsrReleaseProcessLock(); + + /* Strange as it seems, NTSTATUSes are actually returned */ + return (BOOLEAN)STATUS_NO_MEMORY; + } + + /* Get the Create Time */ + Status = NtQueryInformationThread(hThread, + ThreadTimes, + &KernelTimes, + sizeof(KERNEL_USER_TIMES), + NULL); + + /* Check for success */ + if (!NT_SUCCESS(Status)) + { + /* Fail the request */ + CsrDeallocateProcess(CsrProcess); + CsrReleaseProcessLock(); + + return (BOOLEAN)Status; + } + + /* Allocate a new Thread */ + if (!(CsrThread = CsrAllocateThread(CsrProcess))) + { + /* Fail the request */ + CsrDeallocateProcess(CsrProcess); + ApiMessage->Status = STATUS_NO_MEMORY; + CsrReleaseProcessLock(); + return TRUE; + } + + /* Setup the Thread Object */ + CsrThread->CreateTime = KernelTimes.CreateTime; + CsrThread->ClientId = CreateSession->ProcessInfo.ClientId; + CsrThread->ThreadHandle = hThread; + CsrThread->Flags = 0; + + /* Insert it into the Process List */ + CsrInsertThread(CsrProcess, CsrThread); + + /* Allocate a new Session */ + CsrProcess->NtSession = CsrAllocateNtSession(CreateSession->SessionId); + + /* Set the Process Priority */ + CsrSetBackgroundPriority(CsrProcess); + + /* Get the first data location */ + ProcessData = &CsrProcess->ServerData[CSR_SERVER_DLL_MAX]; + + /* Loop every DLL */ + for (i = 0; i < CSR_SERVER_DLL_MAX; i++) + { + /* Check if the DLL is loaded and has Process Data */ + if (CsrLoadedServerDll[i] && CsrLoadedServerDll[i]->SizeOfProcessData) + { + /* Write the pointer to the data */ + CsrProcess->ServerData[i] = ProcessData; + + /* Move to the next data location */ + ProcessData = (PVOID)((ULONG_PTR)ProcessData + + CsrLoadedServerDll[i]->SizeOfProcessData); + } + else + { + /* Nothing for this Process */ + CsrProcess->ServerData[i] = NULL; + } + } + + /* Insert the Process */ + CsrInsertProcess(NULL, NULL, CsrProcess); + + /* Activate the Thread */ + ApiMessage->Status = NtResumeThread(hThread, NULL); + + /* Release lock and return */ + CsrReleaseProcessLock(); + return TRUE; } +/*++ + * @name CsrSbForeignSessionComplete + * + * The CsrSbForeignSessionComplete API is called by the Session Manager + * whenever a foreign session is completed (ie: terminated). + * + * @param ApiMessage + * Pointer to the Session Manager API Message. + * + * @return TRUE in case of success, FALSE othwerwise. + * + * @remarks The CsrSbForeignSessionComplete API is not yet implemented. + * + *--*/ +BOOLEAN +NTAPI +CsrSbForeignSessionComplete(IN PSB_API_MESSAGE ApiMessage) +{ + /* Deprecated/Unimplemented in NT */ + ApiMessage->Status = STATUS_NOT_IMPLEMENTED; + return TRUE; +} /* EOF */ diff --git a/reactos/subsys/csr/csrsrv/srv.h b/reactos/subsys/csr/csrsrv/srv.h index 283e8f5ff7e..d1b0550b1f0 100644 --- a/reactos/subsys/csr/csrsrv/srv.h +++ b/reactos/subsys/csr/csrsrv/srv.h @@ -1,72 +1,348 @@ -#if !defined(_INCLUDE_CSR_CSRSRV_SRV_H) -#define _INCLUDE_CSR_CSRSRV_SRV_H +#ifndef _CSRSRV_H +#define _CSRSRV_H /* PSDK/NDK Headers */ +#define NTOS_MODE_USER #include #include - -#define NTOS_MODE_USER #include -/* CSR Headers */ +/* CSR Header */ #include -/* Maximum number of hosted servers, included the one in csrsrv.dll */ +/* PSEH for SEH Support */ +#include + +/* DEFINES *******************************************************************/ + #define CSR_SERVER_DLL_MAX 4 -typedef enum { - CSRSST_NONE=0, - CSRSST_TEXT, - CSRSST_WINDOWS, - CSRSST_MAX - -} CSR_SUBSYSTEM_TYPE, * PCSR_SUBSYSTEM_TYPE; +#define CsrAcquireProcessLock() \ + RtlEnterCriticalSection(&CsrProcessLock); -typedef struct _CSR_SERVER_DLL -{ - USHORT ServerIndex; - USHORT Unused; - UNICODE_STRING DllName; - UNICODE_STRING DllEntryPoint; -} CSR_SERVER_DLL, * PCSR_SERVER_DLL; +#define CsrReleaseProcessLock() \ + RtlLeaveCriticalSection(&CsrProcessLock); -/* dllmain.c */ -extern HANDLE CsrSrvDllHandle; +#define CsrAcquireWaitLock() \ + RtlEnterCriticalSection(&CsrWaitListsLock); -/* process.c */ +#define CsrReleaseWaitLock() \ + RtlLeaveCriticalSection(&CsrWaitListsLock); -/* server.c */ -typedef struct -{ - struct { - UNICODE_STRING Root; - HANDLE RootHandle; - } NameSpace; - CSR_SUBSYSTEM_TYPE SubSystemType; - struct { - USHORT RequestCount; - USHORT MaxRequestCount; - } Threads; - struct { - BOOL ProfileControl; - BOOL Windows; - BOOL Sessions; - } Flag; - USHORT PortSharedSectionSize; - struct { - USHORT InteractiveDesktopHeapSize; - USHORT NonInteractiveDesktopHeapSize; - } Heap; -} CSRSRV_OPTION, * PCSRSRV_OPTION; +#define CsrAcquireNtSessionLock() \ + RtlEnterCriticalSection(&CsrNtSessionLock) -extern CSRSRV_OPTION CsrSrvOption; -extern HANDLE CsrSrvApiPortHandle; +#define CsrReleaseNtSessionLock() \ + RtlLeaveCriticalSection(&CsrNtSessionLock) -NTSTATUS STDCALL CsrSrvRegisterServerDll (PCSR_SERVER_DLL); -NTSTATUS STDCALL CsrSrvBootstrap (VOID); +#define CsrHashThread(t) \ + (HandleToUlong(t)&(256 - 1)) -/* session.c */ -NTSTATUS STDCALL CsrSrvInitializeSession (VOID); +#define SM_REG_KEY \ + L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager" +#define SESSION_ROOT L"\\Sessions" +#define GLOBAL_ROOT L"\\GLOBAL??" +#define SYMLINK_NAME L"SymbolicLink" +#define SB_PORT_NAME L"SbAbiPort" +#define CSR_PORT_NAME L"ApiPort" +#define UNICODE_PATH_SEP L"\\" -#endif /* !def _INCLUDE_CSR_CSRSRV_SRV_H */ +/* DATA **********************************************************************/ + +extern ULONG CsrTotalPerProcessDataLength; +extern ULONG CsrMaxApiRequestThreads; +extern PCSR_SERVER_DLL CsrLoadedServerDll[CSR_SERVER_DLL_MAX]; +extern PCSR_PROCESS CsrRootProcess; +extern UNICODE_STRING CsrSbApiPortName; +extern UNICODE_STRING CsrApiPortName; +extern HANDLE CsrSbApiPort; +extern HANDLE CsrSmApiPort; +extern HANDLE CsrApiPort; +extern HANDLE CsrHeap; +extern RTL_CRITICAL_SECTION CsrProcessLock; +extern RTL_CRITICAL_SECTION CsrWaitListsLock; +extern LIST_ENTRY CsrThreadHashTable[256]; +extern HANDLE CsrInitializationEvent; +extern SYSTEM_BASIC_INFORMATION CsrNtSysInfo; +extern UNICODE_STRING CsrDirectoryName; +extern HANDLE CsrObjectDirectory; +extern PSB_API_ROUTINE CsrServerSbApiDispatch[5]; + +/* FUNCTIONS *****************************************************************/ + +/* FIXME: Public APIs should go in the CSR Server Include */ +NTSTATUS +NTAPI +CsrLoadServerDll( + IN PCHAR DllString, + IN PCHAR EntryPoint, + IN ULONG ServerId +); + +NTSTATUS +NTAPI +CsrCreateSessionObjectDirectory(IN ULONG SessionId); + +NTSTATUS +NTAPI +CsrCreateObjectDirectory(IN PCHAR ObjectDirectory); + +NTSTATUS +NTAPI +CsrSrvCreateSharedSection(IN PCHAR ParameterValue); + +NTSTATUS +NTAPI +CsrInitializeNtSessions(VOID); + +NTSTATUS +NTAPI +CsrInitializeProcesses(VOID); + +NTSTATUS +NTAPI +CsrApiPortInitialize(VOID); + +NTSTATUS +NTAPI +CsrSbApiPortInitialize(VOID); + +BOOLEAN +NTAPI +CsrSbCreateSession(IN PSB_API_MESSAGE ApiMessage); + +BOOLEAN +NTAPI +CsrSbForeignSessionComplete(IN PSB_API_MESSAGE ApiMessage); + +BOOLEAN +NTAPI +CsrSbCreateProcess(IN PSB_API_MESSAGE ApiMessage); + +PCSR_PROCESS +NTAPI +CsrAllocateProcess(VOID); + +PCSR_THREAD +NTAPI +CsrAllocateThread(IN PCSR_PROCESS CsrProcess); + +VOID +NTAPI +CsrInsertThread( + IN PCSR_PROCESS Process, + IN PCSR_THREAD Thread +); + +VOID +NTAPI +CsrSetBackgroundPriority(IN PCSR_PROCESS CsrProcess); + +VOID +NTAPI +CsrDeallocateProcess(IN PCSR_PROCESS CsrProcess); + +NTSTATUS +NTAPI +CsrGetProcessLuid( + HANDLE hProcess, + PLUID Luid +); + +BOOLEAN +NTAPI +CsrImpersonateClient(IN PCSR_THREAD CsrThread); + +BOOLEAN +NTAPI +CsrRevertToSelf(VOID); + +PCSR_THREAD +NTAPI +CsrLocateThreadByClientId( + OUT PCSR_PROCESS *Process, + IN PCLIENT_ID ClientId +); + +VOID +NTAPI +CsrDereferenceNtSession( + IN PCSR_NT_SESSION Session, + NTSTATUS ExitStatus +); + +VOID +NTAPI +CsrReferenceNtSession(PCSR_NT_SESSION Session); + +VOID +NTAPI +CsrLockedDereferenceThread(PCSR_THREAD CsrThread); + +VOID +NTAPI +CsrLockedDereferenceProcess(PCSR_PROCESS CsrProcess); + +NTSTATUS +NTAPI +CsrLockProcessByClientId( + IN HANDLE Pid, + OUT PCSR_PROCESS *CsrProcess OPTIONAL +); + +NTSTATUS +NTAPI +CsrUnlockProcess(PCSR_PROCESS CsrProcess); + +NTSTATUS +NTAPI +CsrSrvClientConnect( + IN OUT PCSR_API_MESSAGE ApiMessage, + IN OUT PULONG Reply +); + +NTSTATUS +NTAPI +CsrSrvUnusedFunction( + IN OUT PCSR_API_MESSAGE ApiMessage, + IN OUT PULONG Reply +); + +NTSTATUS +NTAPI +CsrSrvIdentifyAlertableThread( + IN OUT PCSR_API_MESSAGE ApiMessage, + IN OUT PULONG Reply +); + +NTSTATUS +NTAPI +CsrSrvSetPriorityClass( + IN OUT PCSR_API_MESSAGE ApiMessage, + IN OUT PULONG Reply +); + +NTSTATUS +NTAPI +CsrServerDllInitialization(IN PCSR_SERVER_DLL LoadedServerDll); + +VOID +NTAPI +CsrDereferenceThread(PCSR_THREAD CsrThread); + +VOID +NTAPI +CsrSbApiRequestThread(IN PVOID Parameter); + +NTSTATUS +NTAPI +CsrApiRequestThread(IN PVOID Parameter); + +PCSR_THREAD +NTAPI +CsrAddStaticServerThread( + IN HANDLE hThread, + IN PCLIENT_ID ClientId, + IN ULONG ThreadFlags +); + +PCSR_THREAD +NTAPI +CsrConnectToUser(VOID); + +PCSR_THREAD +NTAPI +CsrLocateThreadInProcess( + IN PCSR_PROCESS CsrProcess OPTIONAL, + IN PCLIENT_ID Cid +); + +NTSTATUS +NTAPI +CsrSbApiHandleConnectionRequest(IN PSB_API_MESSAGE Message); + +NTSTATUS +NTAPI +CsrApiHandleConnectionRequest(IN PCSR_API_MESSAGE ApiMessage); + +NTSTATUS +NTAPI +CsrSrvAttachSharedSection( + IN PCSR_PROCESS CsrProcess OPTIONAL, + OUT PCSR_CONNECTION_INFO ConnectInfo +); + +VOID +NTAPI +CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage); + +BOOLEAN +NTAPI +CsrNotifyWaitBlock( + IN PCSR_WAIT_BLOCK WaitBlock, + IN PLIST_ENTRY WaitList, + IN PVOID WaitArgument1, + IN PVOID WaitArgument2, + IN ULONG WaitFlags, + IN BOOLEAN DereferenceThread +); + +VOID +NTAPI +CsrDereferenceProcess(PCSR_PROCESS CsrProcess); + +VOID +NTAPI +CsrInsertProcess( + IN PCSR_PROCESS Parent OPTIONAL, + IN PCSR_PROCESS CurrentProcess OPTIONAL, + IN PCSR_PROCESS CsrProcess +); + +NTSTATUS +NTAPI +CsrPopulateDosDevicesDirectory( + IN HANDLE DosDevicesDirectory, + IN PPROCESS_DEVICEMAP_INFORMATION DeviceMap +); + +BOOLEAN +NTAPI +CsrValidateMessageBuffer( + IN PCSR_API_MESSAGE ApiMessage, + IN PVOID *Buffer, + IN ULONG ArgumentSize, + IN ULONG ArgumentCount +); + +NTSTATUS +NTAPI +CsrCreateLocalSystemSD(OUT PSECURITY_DESCRIPTOR *LocalSystemSd); + +NTSTATUS +NTAPI +CsrDestroyThread(IN PCLIENT_ID Cid); + +NTSTATUS +NTAPI +CsrDestroyProcess( + IN PCLIENT_ID Cid, + IN NTSTATUS ExitStatus +); + +_SEH_FILTER(CsrUnhandledExceptionFilter); + +VOID +NTAPI +CsrProcessRefcountZero(IN PCSR_PROCESS CsrProcess); + +VOID +NTAPI +CsrThreadRefcountZero(IN PCSR_THREAD CsrThread); + +NTSTATUS +NTAPI +CsrSetDirectorySecurity(IN HANDLE ObjectDirectory); + +#endif diff --git a/reactos/subsys/csr/csrsrv/status.h b/reactos/subsys/csr/csrsrv/status.h new file mode 100644 index 00000000000..f2ded0f247d --- /dev/null +++ b/reactos/subsys/csr/csrsrv/status.h @@ -0,0 +1,111 @@ +/* + * CSRSRV Status + */ + +/* Organization + * + * api.c - Handles the LPC Reply/Request Threads which wait on Sb and Csr APIs. + * Also in charge of creating those threads and setting up the ports. + * Finally, it provides external APIs for validating the API buffers + * and doing server-to-server API calls. + * + * init.c - Handles initialization of CSRSRV, including command-line parsing, + * loading the Server DLLs, creating the Session Directories, setting + * up the DosDevices Object Directory, and initializing each component. + * + * process.c - Handles all internal functions dealing with the CSR Process Object, + * including de/allocation, de/referencing, un/locking, prority, and + * lookups. Also handles all external APIs which touch the CSR Process Object. + * + * server.c - Handles all internal functions related to loading and managing Server + * DLLs, as well as the routines handling the Shared Static Memory Section. + * Holds the API Dispatch/Valid/Name Tables and the public CSR_SERVER API + * interface. Also home of the SEH handler. + * + * session.c - Handles all internal functions dealing with the CSR Session Object, + * including de/allocation, de/referencing, and un/locking. Holds the SB API + * Dispatch/Name Tables and the public CsrSv API Interface for commmunication + * with the Session Manager. + * + * thread.c - Handles all internal functions dealing with the CSR Thread Object, + * including de/allocation, de/referencing, un/locking, impersonation, and + * lookups. Also handles all external APIs which touch the CSR Thread Object. + * + * wait.c - Handles all internal functions dealing with the CSR Wait Object, + * including de/allocation, de/referencing and un/locking. Also implements + * the external Wait API for creating, removing and/or notifying waits. + */ + +/* Exported APIs, their location, and their status + * CsrAddStaticServerThread 753E679E 1 - server.c - IMPLEMENTED + * CsrCallServerFromServer 753E4FD9 2 - api.c - IMPLEMENTED + * CsrConnectToUser 753E4E48 3 - api.c - IMPLEMENTED + * CsrCreateProcess 753E6FD3 4 - process.c - IMPLEMENTED + * CsrCreateRemoteThread 753E73BD 5 - thread.c - IMPLEMENTED + * CsrCreateThread 753E72DA 6 - thread.c - IMPLEMENTED + * CsrCreateWait 753E770E 7 - wait.c - IMPLEMENTED + * CsrDebugProcess 753E7682 8 - process.c - IMPLEMENTED + * CsrDebugProcessStop 753E768A 9 - process.c - IMPLEMENTED + * CsrDereferenceProcess 753E6281 10 - process.c - IMPLEMENTED + * CsrDereferenceThread 753E6964 11 - thread.c - IMPLEMENTED + * CsrDereferenceWait 753E7886 12 - wait.c - IMPLEMENTED + * CsrDestroyProcess 753E7225 13 - process.c - IMPLEMENTED + * CsrDestroyThread 753E7478 14 - thread.c - IMPLEMENTED + * CsrExecServerThread 753E6841 15 - thread.c - IMPLEMENTED + * CsrGetProcessLuid 753E632F 16 - process.c - IMPLEMENTED + * CsrImpersonateClient 753E60F8 17 - thread.c - IMPLEMENTED + * CsrLockProcessByClientId 753E668F 18 - process.c - IMPLEMENTED + * CsrLockThreadByClientId 753E6719 19 - thread.c - IMPLEMENTED + * CsrMoveSatisfiedWait 753E7909 20 - wait.c - IMPLEMENTED + * CsrNotifyWait 753E782F 21 - wait.c - IMPLEMENTED + * CsrPopulateDosDevices 753E37A5 22 - init.c - IMPLEMENTED + * CsrQueryApiPort 753E4E42 23 - api.c - IMPLEMENTED + * CsrReferenceThread 753E61E5 24 - thread.c - IMPLEMENTED + * CsrRevertToSelf 753E615A 25 - thread.c - IMPLEMENTED + * CsrServerInitialization 753E3D75 26 - server.c - IMPLEMENTED + * CsrSetBackgroundPriority 753E5E87 27 - process.c - IMPLEMENTED + * CsrSetCallingSpooler 753E6425 28 - server.c - IMPLEMENTED + * CsrSetForegroundPriority 753E5E67 29 - process.c - IMPLEMENTED + * CsrShutdownProcesses 753E7547 30 - process.c - IMPLEMENTED + * CsrUnhandledExceptionFilter 753E3FE3 31 - server.c - IMPLEMENTED + * CsrUnlockProcess 753E66FD 32 - process.c - IMPLEMENTED + * CsrUnlockThread 753E7503 33 - thread.c - IMPLEMENTED + * CsrValidateMessageBuffer 753E528D 34 - api.c - IMPLEMENTED + * CsrValidateMessageString 753E5323 35 - api.c - UNIMPLEMENTED + */ + +/* Public CSR API Interface Status (server.c) + * CsrSrvClientConnect - IMPLEMENTED + * CsrSrvUnusedFunction - IMPLEMENTED + * CsrSrvIdentifyAlertableThread - IMPLEMENTED + * CsrSrvSetPriorityClass - IMPLEMENTED + */ + +/* Public SB API Interface Status (session.c) + * CsrSbCreateSession - IMPLEMENTED + * CsrSbForeignSessionComplete - IMPLEMENTED + * CsrSbTerminateSession - IMPLEMENTED + * CsrSbCreateProcess - UNIMPLEMENTED + */ + +/* What's missing: + * + * - SMSS needs to be partly re-written to match some things done here. + * Among other things, SmConnectToSm, SmCompleteSession and the other + * Sm* Exported APIs have to be properly implemented, as well as the + * callback calling and SM LPC APIs. [NOT DONE] + * + * - NTDLL needs to get the Csr* routines properly implemented. [DONE!] + * + * - KERNEL32, USER32 need to register with their servers properly. + * Additionally, user32 needs to have ClientThreadStartup implemented + * properly and do the syscall NtUserInitialize (I think) which also + * needs to be implemented in win32k.sys. All this should be less then + * 100 lines of code. [KERNEL32 50% DONE, USER32 NOT DONE] + * + * - The skeleton code for winsrv and basesrv which connects with CSR/CSRSRV + * needs to be written. [NOT DONE] + * + * - The kernel's LPC implementation needs to be made compatible. [NOT DONE] + */ + diff --git a/reactos/subsys/csr/csrsrv/thread.c b/reactos/subsys/csr/csrsrv/thread.c index c06c539e694..ca7c632e8af 100644 --- a/reactos/subsys/csr/csrsrv/thread.c +++ b/reactos/subsys/csr/csrsrv/thread.c @@ -1,114 +1,991 @@ -/* $Id$ - * - * subsys/csr/csrsrv/thread.c - CSR server - thread management - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS CSR Sub System + * FILE: subsys/csr/csrsrv/thread.c + * PURPOSE: CSR Server DLL Thread Implementation + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) */ + +/* INCLUDES ******************************************************************/ + #include "srv.h" -//#define NDEBUG +#define NDEBUG #include -/*===================================================================== - * PUBLIC API - *===================================================================*/ +/* DATA **********************************************************************/ -NTSTATUS STDCALL CsrCreateRemoteThread () +LIST_ENTRY CsrThreadHashTable[256]; +SECURITY_QUALITY_OF_SERVICE CsrSecurityQos = { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - return Status; + sizeof(SECURITY_QUALITY_OF_SERVICE), + SecurityImpersonation, + SECURITY_STATIC_TRACKING, + FALSE +}; + +/* PRIVATE FUNCTIONS *********************************************************/ + +/*++ + * @name CsrAllocateThread + * + * The CsrAllocateThread routine allocates a new CSR Thread object. + * + * @param CsrProcess + * Pointer to the CSR Process which will contain this CSR Thread. + * + * @return Pointer to the newly allocated CSR Thread. + * + * @remarks None. + * + *--*/ +PCSR_THREAD +NTAPI +CsrAllocateThread(IN PCSR_PROCESS CsrProcess) +{ + PCSR_THREAD CsrThread; + + /* Allocate the structure */ + CsrThread = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, sizeof(CSR_THREAD)); + if (!CsrThread) return(NULL); + + /* Reference the Thread and Process */ + CsrThread->ReferenceCount++; + CsrProcess->ReferenceCount++; + + /* Set the Parent Process */ + CsrThread->Process = CsrProcess; + + /* Return Thread */ + return CsrThread; } -NTSTATUS STDCALL CsrCreateThread (PCSR_PROCESS pCsrProcess, PCSR_THREAD *ppCsrThread) +/*++ + * @name CsrLocateThreadByClientId + * + * The CsrLocateThreadByClientId routine locates the CSR Thread and, + * optionally, its parent CSR Process, corresponding to a Client ID. + * + * @param Process + * Optional pointer to a CSR Process pointer which will contain + * the CSR Thread's parent. + * + * @param ClientId + * Pointer to a Client ID structure containing the Unique Thread ID + * to look up. + * + * @return Pointer to the CSR Thread corresponding to this CID, or NULL if + * none was found. + * + * @remarks None. + * + *--*/ +PCSR_THREAD +NTAPI +CsrLocateThreadByClientId(OUT PCSR_PROCESS *Process OPTIONAL, + IN PCLIENT_ID ClientId) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - PCSR_THREAD pCsrThread = NULL; - PCSR_SESSION pCsrSession = NULL; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); + ULONG i; + PLIST_ENTRY ListHead, NextEntry; + PCSR_THREAD FoundThread; - if (NULL == pCsrProcess || NULL == ppCsrThread) - { - return STATUS_INVALID_PARAMETER; - } - pCsrSession = pCsrProcess->NtSession; - pCsrThread = RtlAllocateHeap (pCsrSession->Heap, - HEAP_ZERO_MEMORY, - sizeof (CSR_THREAD)); - if (NULL == pCsrThread) - { - DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__); - return STATUS_NO_MEMORY; - } - pCsrThread->Process = pCsrProcess; - return Status; + /* Hash the Thread */ + i = CsrHashThread(ClientId->UniqueThread); + + /* Set the list pointers */ + ListHead = &CsrThreadHashTable[i]; + NextEntry = ListHead->Flink; + + /* Star the loop */ + while (NextEntry != ListHead) + { + /* Get the thread */ + FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks); + + /* Compare the CID */ + if (FoundThread->ClientId.UniqueThread == ClientId->UniqueThread) + { + /* Match found, return the process */ + *Process = FoundThread->Process; + + /* Return thread too */ + return FoundThread; + } + + /* Next */ + NextEntry = NextEntry->Flink; + } + + /* Nothing found */ + return NULL; } -NTSTATUS STDCALL CsrDereferenceThread (PCSR_THREAD pCsrThread) +/*++ + * @name CsrLocateThreadInProcess + * + * The CsrLocateThreadInProcess routine locates the CSR Thread + * corresponding to a Client ID inside a specific CSR Process. + * + * @param Process + * Optional pointer to the CSR Process which contains the CSR Thread + * that will be looked up. + * + * @param ClientId + * Pointer to a Client ID structure containing the Unique Thread ID + * to look up. + * + * @return Pointer to the CSR Thread corresponding to this CID, or NULL if + * none was found. + * + * @remarks If the CsrProcess argument is NULL, the lookup will be done inside + * CsrRootProcess. + * + *--*/ +PCSR_THREAD +NTAPI +CsrLocateThreadInProcess(IN PCSR_PROCESS CsrProcess OPTIONAL, + IN PCLIENT_ID Cid) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - return Status; + PLIST_ENTRY ListHead, NextEntry; + PCSR_THREAD FoundThread = NULL; + + /* Use the Root Process if none was specified */ + if (!CsrProcess) CsrProcess = CsrRootProcess; + + /* Save the List pointers */ + ListHead = &CsrProcess->ThreadList; + NextEntry = ListHead->Flink; + + /* Start the Loop */ + while (NextEntry != NextEntry) + { + /* Get Thread Entry */ + FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link); + + /* Check for TID Match */ + if (FoundThread->ClientId.UniqueThread == Cid->UniqueThread) break; + + /* Next entry */ + NextEntry = NextEntry->Flink; + } + + /* Return what we found */ + return FoundThread; } -NTSTATUS STDCALL CsrDestroyThread (PCSR_THREAD pCsrThread) +/*++ + * @name CsrInsertThread + * + * The CsrInsertThread routine inserts a CSR Thread into its parent's + * Thread List and into the Thread Hash Table. + * + * @param Process + * Pointer to the CSR Process containing this CSR Thread. + * + * @param Thread + * Pointer to the CSR Thread to be inserted. + * + * @return None. + * + * @remarks None. + * + *--*/ +VOID +NTAPI +CsrInsertThread(IN PCSR_PROCESS Process, + IN PCSR_THREAD Thread) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - return Status; + ULONG i; + + /* Insert it into the Regular List */ + InsertTailList(&Process->ThreadList, &Thread->Link); + + /* Increase Thread Count */ + Process->ThreadCount++; + + /* Hash the Thread */ + i = CsrHashThread(Thread->ClientId.UniqueThread); + + /* Insert it there too */ + InsertHeadList(&CsrThreadHashTable[i], &Thread->HashLinks); } -NTSTATUS STDCALL CsrLockThreadByClientId () +/*++ + * @name CsrDeallocateThread + * + * The CsrDeallocateThread frees the memory associated with a CSR Thread. + * + * @param CsrThread + * Pointer to the CSR Thread to be freed. + * + * @return None. + * + * @remarks Do not call this routine. It is reserved for the internal + * thread management routines when a CSR Thread has been cleanly + * dereferenced and killed. + * + *--*/ +VOID +NTAPI +CsrDeallocateThread(IN PCSR_THREAD CsrThread) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - return Status; + /* Free the process object from the heap */ + RtlFreeHeap(CsrHeap, 0, CsrThread); } -NTSTATUS STDCALL CsrReferenceThread (PCSR_THREAD pCsrThread) +/*++ + * @name CsrLockedDereferenceThread + * + * The CsrLockedDereferenceThread derefences a CSR Thread while the + * Process Lock is already being held. + * + * @param CsrThread + * Pointer to the CSR Thread to be dereferenced. + * + * @return None. + * + * @remarks This routine will return with the Process Lock held. + * + *--*/ +VOID +NTAPI +CsrLockedDereferenceThread(PCSR_THREAD CsrThread) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - return Status; + /* Decrease reference count */ + if (!(--CsrThread->ReferenceCount)) + { + /* Call the generic cleanup code */ + CsrThreadRefcountZero(CsrThread); + CsrAcquireProcessLock(); + } } -NTSTATUS STDCALL CsrUnlockThread (PCSR_THREAD pCsrThread) +/*++ + * @name CsrRemoveThread + * + * The CsrRemoveThread function undoes a CsrInsertThread operation and + * removes the CSR Thread from the the Hash Table and Thread List. + * + * @param CsrThread + * Pointer to the CSR Thread to remove. + * + * @return None. + * + * @remarks If this CSR Thread is the last one inside a CSR Process, the + * parent will be dereferenced and the CsrProcessLastThreadTerminated + * flag will be set. + * + * After executing this routine, the CSR Thread will have the + * CsrThreadInTermination flag set. + * + *--*/ +VOID +NTAPI +CsrRemoveThread(IN PCSR_THREAD CsrThread) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - return Status; + /* Remove it from the List */ + RemoveEntryList(&CsrThread->Link); + + /* Decreate the thread count of the process */ + CsrThread->Process->ThreadCount--; + + /* Remove it from the Hash List as well */ + if (CsrThread->HashLinks.Flink) RemoveEntryList(&CsrThread->HashLinks); + + /* Check if this is the last Thread */ + if (!CsrThread->Process->ThreadCount) + { + /* Check if it's not already been marked for deletion */ + if (!(CsrThread->Process->Flags & CsrProcessLastThreadTerminated)) + { + /* Let everyone know this process is about to lose the thread */ + CsrThread->Process->Flags |= CsrProcessLastThreadTerminated; + + /* Reference the Process */ + CsrLockedDereferenceProcess(CsrThread->Process); + } + } + + /* Mark the thread for deletion */ + CsrThread->Flags |= CsrThreadInTermination; +} + +/*++ + * @name CsrThreadRefcountZero + * + * The CsrThreadRefcountZero routine is executed when a CSR Thread has lost + * all its active references. It removes and de-allocates the CSR Thread. + * + * @param CsrThread + * Pointer to the CSR Thread that is to be deleted. + * + * @return None. + * + * @remarks Do not call this routine. It is reserved for the internal + * thread management routines when a CSR Thread has lost all + * its references. + * + * This routine is called with the Process Lock held. + * + *--*/ +VOID +NTAPI +CsrThreadRefcountZero(IN PCSR_THREAD CsrThread) +{ + PCSR_PROCESS CsrProcess = CsrThread->Process; + + /* Remove this thread */ + CsrRemoveThread(CsrThread); + + /* Release the Process Lock */ + CsrReleaseProcessLock(); + + /* Close the NT Thread Handle */ + NtClose(CsrThread->ThreadHandle); + + /* De-allocate the CSR Thread Object */ + CsrDeallocateThread(CsrThread); + + /* Remove a reference from the process */ + CsrDereferenceProcess(CsrProcess); +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + +/*++ + * @name CsrAddStaticServerThread + * @implemented NT4 + * + * The CsrAddStaticServerThread routine adds a new CSR Thread to the + * CSR Server Process (CsrRootProcess). + * + * @param hThread + * Handle to an existing NT Thread to which to associate this + * CSR Thread. + * + * @param ClientId + * Pointer to the Client ID structure of the NT Thread to associate + * with this CSR Thread. + * + * @param ThreadFlags + * Initial CSR Thread Flags to associate to this CSR Thread. Usually + * CsrThreadIsServerThread. + * + * @return Pointer to the newly allocated CSR Thread. + * + * @remarks None. + * + *--*/ +PCSR_THREAD +NTAPI +CsrAddStaticServerThread(IN HANDLE hThread, + IN PCLIENT_ID ClientId, + IN ULONG ThreadFlags) +{ + PCSR_THREAD CsrThread; + + /* Get the Lock */ + CsrAcquireProcessLock(); + + /* Allocate the Server Thread */ + if ((CsrThread = CsrAllocateThread(CsrRootProcess))) + { + /* Setup the Object */ + CsrThread->ThreadHandle = hThread; + CsrThread->ClientId = *ClientId; + CsrThread->Flags = ThreadFlags; + + /* Insert it into the Thread List */ + InsertTailList(&CsrRootProcess->ThreadList, &CsrThread->Link); + + /* Increment the thread count */ + CsrRootProcess->ThreadCount++; + } + + /* Release the Process Lock and return */ + CsrReleaseProcessLock(); + return CsrThread; +} + +/*++ + * @name CsrCreateRemoteThread + * @implemented NT4 + * + * The CsrCreateRemoteThread routine creates a CSR Thread object for + * an NT Thread which is not part of the current NT Process. + * + * @param hThread + * Handle to an existing NT Thread to which to associate this + * CSR Thread. + * + * @param ClientId + * Pointer to the Client ID structure of the NT Thread to associate + * with this CSR Thread. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrCreateRemoteThread(IN HANDLE hThread, + IN PCLIENT_ID ClientId) +{ + NTSTATUS Status; + HANDLE ThreadHandle; + PCSR_THREAD CsrThread; + PCSR_PROCESS CsrProcess; + KERNEL_USER_TIMES KernelTimes; + + DPRINT("CSRSRV: %s called\n", __FUNCTION__); + + /* Get the Thread Create Time */ + Status = NtQueryInformationThread(hThread, + ThreadTimes, + (PVOID)&KernelTimes, + sizeof(KernelTimes), + NULL); + + /* Lock the Owner Process */ + Status = CsrLockProcessByClientId(&ClientId->UniqueProcess, + &CsrProcess); + + /* Make sure the thread didn't terminate */ + if (KernelTimes.ExitTime.QuadPart) + { + /* Unlock the process and return */ + CsrUnlockProcess(CsrProcess); + return STATUS_THREAD_IS_TERMINATING; + } + + /* Allocate a CSR Thread Structure */ + if (!(CsrThread = CsrAllocateThread(CsrProcess))) + { + DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__); + CsrUnlockProcess(CsrProcess); + return STATUS_NO_MEMORY; + } + + /* Duplicate the Thread Handle */ + Status = NtDuplicateObject(NtCurrentProcess(), + hThread, + NtCurrentProcess(), + &ThreadHandle, + 0, + 0, + DUPLICATE_SAME_ACCESS); + /* Allow failure */ + if (!NT_SUCCESS(Status)) ThreadHandle = hThread; + + /* Save the data we have */ + CsrThread->CreateTime = KernelTimes.CreateTime; + CsrThread->ClientId = *ClientId; + CsrThread->ThreadHandle = ThreadHandle; + CsrThread->Flags = 0; + + /* Insert the Thread into the Process */ + CsrInsertThread(CsrProcess, CsrThread); + + /* Release the lock and return */ + CsrUnlockProcess(CsrProcess); + return STATUS_SUCCESS; +} + +/*++ + * @name CsrCreateThread + * @implemented NT4 + * + * The CsrCreateThread routine creates a CSR Thread object for an NT Thread. + * + * @param CsrProcess + * Pointer to the CSR Process which will contain the CSR Thread. + * + * @param hThread + * Handle to an existing NT Thread to which to associate this + * CSR Thread. + * + * @param ClientId + * Pointer to the Client ID structure of the NT Thread to associate + * with this CSR Thread. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrCreateThread(IN PCSR_PROCESS CsrProcess, + IN HANDLE hThread, + IN PCLIENT_ID ClientId) +{ + NTSTATUS Status; + PCSR_THREAD CsrThread; + PCSR_PROCESS CurrentProcess; + PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread; + CLIENT_ID CurrentCid; + KERNEL_USER_TIMES KernelTimes; + + DPRINT("CSRSRV: %s called\n", __FUNCTION__); + + /* Get the current thread and CID */ + CurrentCid = CurrentThread->ClientId; + + /* Acquire the Process Lock */ + CsrAcquireProcessLock(); + + /* Get the current Process and make sure the Thread is valid with this CID */ + CurrentThread = CsrLocateThreadByClientId(&CurrentProcess, + &CurrentCid); + + /* Something is wrong if we get an empty thread back */ + if (!CurrentThread) + { + DPRINT1("CSRSRV:%s: invalid thread!\n", __FUNCTION__); + CsrReleaseProcessLock(); + return STATUS_THREAD_IS_TERMINATING; + } + + /* Get the Thread Create Time */ + Status = NtQueryInformationThread(hThread, + ThreadTimes, + (PVOID)&KernelTimes, + sizeof(KernelTimes), + NULL); + + /* Allocate a CSR Thread Structure */ + if (!(CsrThread = CsrAllocateThread(CsrProcess))) + { + DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__); + CsrReleaseProcessLock(); + return STATUS_NO_MEMORY; + } + + /* Save the data we have */ + CsrThread->CreateTime = KernelTimes.CreateTime; + CsrThread->ClientId = *ClientId; + CsrThread->ThreadHandle = hThread; + CsrThread->Flags = 0; + + /* Insert the Thread into the Process */ + CsrInsertThread(CsrProcess, CsrThread); + + /* Release the lock and return */ + CsrReleaseProcessLock(); + return STATUS_SUCCESS; +} + +/*++ + * @name CsrDereferenceThread + * @implemented NT4 + * + * The CsrDereferenceThread routine removes a reference from a CSR Thread. + * + * @param CsrThread + * Pointer to the CSR Thread to dereference. + * + * @return None. + * + * @remarks If the reference count has reached zero (ie: the CSR Thread has + * no more active references), it will be deleted. + * + *--*/ +VOID +NTAPI +CsrDereferenceThread(PCSR_THREAD CsrThread) +{ + /* Acquire process lock */ + CsrAcquireProcessLock(); + + /* Decrease reference count */ + if (!(--CsrThread->ReferenceCount)) + { + /* Call the generic cleanup code */ + CsrThreadRefcountZero(CsrThread); + } + else + { + /* Just release the lock */ + CsrReleaseProcessLock(); + } +} + +/*++ + * @name CsrExecServerThread + * @implemented NT4 + * + * The CsrExecServerThread routine creates an NT Thread and then + * initializes a CSR Thread for it. + * + * @param ThreadHandler + * Pointer to the thread's startup routine. + * + * @param Flags + * Initial CSR Thread Flags to set to the CSR Thread. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks This routine is similar to CsrAddStaticServerThread, but it + * also creates an NT Thread instead of expecting one to already + * exist. + * + *--*/ +NTSTATUS +NTAPI +CsrExecServerThread(IN PVOID ThreadHandler, + IN ULONG Flags) +{ + PCSR_THREAD CsrThread; + HANDLE hThread; + CLIENT_ID ClientId; + NTSTATUS Status; + + /* Acquire process lock */ + CsrAcquireProcessLock(); + + /* Allocate a CSR Thread in the Root Process */ + if (!(CsrThread = CsrAllocateThread(CsrRootProcess))) + { + /* Fail */ + CsrReleaseProcessLock(); + return STATUS_NO_MEMORY; + } + + /* Create the Thread */ + Status = RtlCreateUserThread(NtCurrentProcess(), + NULL, + FALSE, + 0, + 0, + 0, + ThreadHandler, + NULL, + &hThread, + &ClientId); + if (!NT_SUCCESS(Status)) + { + /* Fail */ + CsrDeallocateThread(CsrThread); + CsrReleaseProcessLock(); + return Status; + } + + /* Setup the Thread Object */ + CsrThread->ThreadHandle = hThread; + CsrThread->ClientId = ClientId; + CsrThread->Flags = Flags; + + /* Insert it into the Thread List */ + InsertHeadList(&CsrRootProcess->ThreadList, &CsrThread->Link); + + /* Increase the thread count */ + CsrRootProcess->ThreadCount++; + + /* Return */ + CsrReleaseProcessLock(); + return Status; +} + +/*++ + * @name CsrDestroyThread + * @implemented NT4 + * + * The CsrDestroyThread routine destroys the CSR Thread corresponding to + * a given Thread ID. + * + * @param Cid + * Pointer to the Client ID Structure corresponding to the CSR + * Thread which is about to be destroyed. + * + * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING + * if the CSR Thread is already terminating. + * + * @remarks None. + * + *--*/ +NTSTATUS +NTAPI +CsrDestroyThread(IN PCLIENT_ID Cid) +{ + CLIENT_ID ClientId = *Cid; + PCSR_THREAD CsrThread; + PCSR_PROCESS CsrProcess; + + /* Acquire lock */ + CsrAcquireProcessLock(); + + /* Find the thread */ + CsrThread = CsrLocateThreadByClientId(&CsrProcess, + &ClientId); + + /* Make sure we got one back, and that it's not already gone */ + if (!CsrThread || CsrThread->Flags & CsrThreadTerminated) + { + /* Release the lock and return failure */ + CsrReleaseProcessLock(); + return STATUS_THREAD_IS_TERMINATING; + } + + /* Set the terminated flag */ + CsrThread->Flags |= CsrThreadTerminated; + + /* Acquire the Wait Lock */ + CsrAcquireWaitLock(); + + /* Do we have an active wait block? */ + if (CsrThread->WaitBlock) + { + /* Notify waiters of termination */ + CsrNotifyWaitBlock(CsrThread->WaitBlock, + NULL, + NULL, + NULL, + CsrProcessTerminating, + TRUE); + } + + /* Release the Wait Lock */ + CsrReleaseWaitLock(); + + /* Dereference the thread */ + CsrLockedDereferenceThread(CsrThread); + + /* Release the Process Lock and return success */ + CsrReleaseProcessLock(); + return STATUS_SUCCESS; +} + +/*++ + * @name CsrImpersonateClient + * @implemented NT4 + * + * The CsrImpersonateClient will impersonate the given CSR Thread. + * + * @param CsrThread + * Pointer to the CSR Thread to impersonate. + * + * @return TRUE if impersionation suceeded, false otherwise. + * + * @remarks Impersonation can be recursive. + * + *--*/ +BOOLEAN +NTAPI +CsrImpersonateClient(IN PCSR_THREAD CsrThread) +{ + NTSTATUS Status; + PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread; + + /* Use the current thread if none given */ + if (!CsrThread) CsrThread = CurrentThread; + + /* Still no thread, something is wrong */ + if (!CsrThread) + { + /* Failure */ + return FALSE; + } + + /* Make the call */ + Status = NtImpersonateThread(NtCurrentThread(), + CsrThread->ThreadHandle, + &CsrSecurityQos); + + if (!NT_SUCCESS(Status)) + { + /* Failure */ + return FALSE; + } + + /* Increase the impersonation count for the current thread */ + if (CurrentThread) ++CurrentThread->ImpersonationCount; + + /* Return Success */ + return TRUE; +} + +/*++ + * @name CsrRevertToSelf + * @implemented NT4 + * + * The CsrRevertToSelf routine will attempt to remove an active impersonation. + * + * @param None. + * + * @return TRUE if the reversion was succesful, false otherwise. + * + * @remarks Impersonation can be recursive; as such, the impersonation token + * will only be deleted once the CSR Thread's impersonaton count + * has reached zero. + * + *--*/ +BOOLEAN +NTAPI +CsrRevertToSelf(VOID) +{ + NTSTATUS Status; + PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread; + HANDLE ImpersonationToken = NULL; + + /* Check if we have a Current Thread */ + if (CurrentThread) + { + /* Make sure impersonation is on */ + if (!CurrentThread->ImpersonationCount) + { + return FALSE; + } + else if (--CurrentThread->ImpersonationCount > 0) + { + /* Success; impersonation count decreased but still not zero */ + return TRUE; + } + } + + /* Impersonation has been totally removed, revert to ourselves */ + Status = NtSetInformationThread(NtCurrentThread(), + ThreadImpersonationToken, + &ImpersonationToken, + sizeof(HANDLE)); + + /* Return TRUE or FALSE */ + return NT_SUCCESS(Status); +} + +/*++ + * @name CsrLockThreadByClientId + * @implemented NT4 + * + * The CsrLockThreadByClientId routine locks the CSR Thread corresponding + * to the given Thread ID and optionally returns it. + * + * @param Tid + * Thread ID corresponding to the CSR Thread which will be locked. + * + * @param CsrThread + * Optional pointer to a CSR Thread pointer which will hold the + * CSR Thread corresponding to the given Thread ID. + * + * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL + * othwerwise. + * + * @remarks Locking a CSR Thread is defined as acquiring an extra + * reference to it and returning with the Process Lock held. + * + *--*/ +NTSTATUS +NTAPI +CsrLockThreadByClientId(IN HANDLE Tid, + OUT PCSR_THREAD *CsrThread OPTIONAL) +{ + PLIST_ENTRY ListHead, NextEntry; + PCSR_THREAD CurrentThread = NULL; + NTSTATUS Status = STATUS_UNSUCCESSFUL; + ULONG i; + + /* Acquire the lock */ + CsrAcquireProcessLock(); + + /* Convert to Hash */ + i = CsrHashThread(Tid); + + /* Setup the List Pointers */ + ListHead = &CsrThreadHashTable[i]; + NextEntry = ListHead; + + /* Start Loop */ + while (NextEntry != ListHead) + { + /* Get the Process */ + CurrentThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks); + + /* Check for PID Match */ + if ((CurrentThread->ClientId.UniqueThread == Tid) && + !(CurrentThread->Flags & CsrThreadTerminated)) + { + /* Get out of here with success */ + Status = STATUS_SUCCESS; + break; + } + + /* Next entry */ + NextEntry = NextEntry->Flink; + } + + /* Did the loop find something? */ + if (NT_SUCCESS(Status)) + { + /* Reference the found thread */ + CurrentThread->ReferenceCount++; + } + else + { + /* Nothing found, release the lock */ + CsrReleaseProcessLock(); + } + + /* Return the status and thread */ + if (CsrThread) *CsrThread = CurrentThread; + return Status; +} + +/*++ + * @name CsrReferenceThread + * @implemented NT4 + * + * The CsrReferenceThread routine increases the active reference count of + * a CSR Thread. + * + * @param CsrThread + * Pointer to the CSR Thread whose reference count will be increased. + * + * @return None. + * + * @remarks Do not use this routine if the Process Lock is already held. + * + *--*/ +VOID +NTAPI +CsrReferenceThread(PCSR_THREAD CsrThread) +{ + /* Acquire process lock */ + CsrAcquireProcessLock(); + + /* Increment reference count */ + CsrThread->ReferenceCount++; + + /* Release the lock */ + CsrReleaseProcessLock(); +} + +/*++ + * @name CsrUnlockThread + * @implemented NT4 + * + * The CsrUnlockThread undoes a previous CsrLockThreadByClientId operation. + * + * @param CsrThread + * Pointer to a previously locked CSR Thread. + * + * @return STATUS_SUCCESS. + * + * @remarks This routine must be called with the Process Lock held. + * + *--*/ +NTSTATUS +NTAPI +CsrUnlockThread(PCSR_THREAD CsrThread) +{ + /* Dereference the Thread */ + CsrLockedDereferenceThread(CsrThread); + + /* Release the lock and return */ + CsrReleaseProcessLock(); + return STATUS_SUCCESS; } /* EOF */ diff --git a/reactos/subsys/csr/csrsrv/wait.c b/reactos/subsys/csr/csrsrv/wait.c index e836407ba9d..08a840245d0 100644 --- a/reactos/subsys/csr/csrsrv/wait.c +++ b/reactos/subsys/csr/csrsrv/wait.c @@ -1,72 +1,451 @@ -/* $Id$ - * - * subsys/csr/csrsrv/wait.c - CSR server - wait management - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS CSR Sub System + * FILE: subsys/csr/csrsrv/wait.c + * PURPOSE: CSR Server DLL Wait Implementation + * PROGRAMMERS: Emanuele Aliberti + * Alex Ionescu (alex@relsoft.net) */ + +/* INCLUDES ******************************************************************/ + #include "srv.h" -//#define NDEBUG +#define NDEBUG #include -/*===================================================================== - * PUBLIC API - *===================================================================*/ +/* DATA **********************************************************************/ -NTSTATUS STDCALL CsrCreateWait (PCSR_THREAD pCsrThread, PCSR_WAIT * ppCsrWait) +RTL_CRITICAL_SECTION CsrWaitListsLock; + +/* PRIVATE FUNCTIONS *********************************************************/ + +/*++ + * @name CsrInitializeWait + * + * The CsrInitializeWait routine initializes a CSR Wait Object. + * + * @param WaitFunction + * Pointer to the function that will handle this wait. + * + * @param CsrWaitThread + * Pointer to the CSR Thread that will perform the wait. + * + * @param WaitApiMessage + * Pointer to the CSR API Message associated to this wait. + * + * @param WaitContext + * Pointer to a user-defined parameter associated to this wait. + * + * @param NewWaitBlock + * Pointed to the initialized CSR Wait Block for this wait. + * + * @return TRUE in case of success, FALSE othwerwise. + * + * @remarks None. + * + *--*/ +BOOLEAN +NTAPI +CsrInitializeWait(IN CSR_WAIT_FUNCTION WaitFunction, + IN PCSR_THREAD CsrWaitThread, + IN OUT PCSR_API_MESSAGE WaitApiMessage, + IN PVOID WaitContext, + OUT PCSR_WAIT_BLOCK *NewWaitBlock) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - return Status; + ULONG Size; + PCSR_WAIT_BLOCK WaitBlock; + + /* Calculate the size of the wait block */ + Size = sizeof(CSR_WAIT_BLOCK) - + sizeof(WaitBlock->WaitApiMessage) + + WaitApiMessage->Header.u1.s1.TotalLength; + + /* Allocate the Wait Block */ + if (!(WaitBlock = RtlAllocateHeap(CsrHeap, 0, Size))) + { + /* Fail */ + WaitApiMessage->Status = STATUS_NO_MEMORY; + return FALSE; + } + + /* Initialize it */ + WaitBlock->Size = Size; + WaitBlock->WaitThread = CsrWaitThread; + WaitBlock->WaitContext = WaitContext; + WaitBlock->WaitFunction = WaitFunction; + InitializeListHead(&WaitBlock->UserWaitList); + InitializeListHead(&WaitBlock->WaitList); + + /* Copy the message */ + RtlMoveMemory(&WaitBlock->WaitApiMessage, + WaitApiMessage, + WaitApiMessage->Header.u1.s1.TotalLength); + + /* Return the block */ + *NewWaitBlock = WaitBlock; + return TRUE; } -NTSTATUS STDCALL CsrDereferenceWait (PCSR_WAIT pCsrWait) +/*++ + * @name CsrNotifyWaitBlock + * + * The CsrNotifyWaitBlock routine calls the wait function for a registered + * CSR Wait Block, and replies to the attached CSR API Message, if any. + * + * @param WaitBlock + * Pointer to the CSR Wait Block + * + * @param WaitList + * Pointer to the wait list for this wait. + * + * @param WaitArgument[1-2] + * User-defined values to pass to the wait function. + * + * @param WaitFlags + * Wait flags for this wait. + * + * @param DereferenceThread + * Specifies whether the CSR Thread should be dereferenced at the + * end of this wait. + * + * @return TRUE in case of success, FALSE otherwise. + * + * @remarks After a wait block is notified, the wait function becomes invalid. + * + *--*/ +BOOLEAN +NTAPI +CsrNotifyWaitBlock(IN PCSR_WAIT_BLOCK WaitBlock, + IN PLIST_ENTRY WaitList, + IN PVOID WaitArgument1, + IN PVOID WaitArgument2, + IN ULONG WaitFlags, + IN BOOLEAN DereferenceThread) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - return Status; + /* Call the wait function */ + if ((WaitBlock->WaitFunction)(WaitList, + WaitBlock->WaitThread, + &WaitBlock->WaitApiMessage, + WaitBlock->WaitContext, + WaitArgument1, + WaitArgument2, + WaitFlags)) + { + /* The wait is done, clear the block */ + WaitBlock->WaitThread->WaitBlock = NULL; + + /* Check for captured arguments */ + if (WaitBlock->WaitApiMessage.CsrCaptureData) + { + /* Release them */ + CsrReleaseCapturedArguments(&WaitBlock->WaitApiMessage); + } + + /* Reply to the port */ + NtReplyPort(WaitBlock->WaitThread->Process->ClientPort, + (PPORT_MESSAGE)&WaitBlock->WaitApiMessage); + + /* Check if we should dereference the thread */ + if (DereferenceThread) + { + /* Remove it from the Wait List */ + if (WaitBlock->WaitList.Flink) + { + RemoveEntryList(&WaitBlock->WaitList); + } + + /* Remove it from the User Wait List */ + if (WaitBlock->UserWaitList.Flink) + { + RemoveEntryList(&WaitBlock->UserWaitList); + } + + /* Dereference teh thread */ + CsrDereferenceThread(WaitBlock->WaitThread); + + /* Free the wait block */ + RtlFreeHeap(CsrHeap, 0, WaitBlock); + } + else + { + /* The wait is complete, but the thread is being kept alive */ + WaitBlock->WaitFunction = NULL; + } + + /* The wait suceeded*/ + return TRUE; + } + + /* The wait failed */ + return FALSE; } -NTSTATUS STDCALL CsrMoveSatisfiedWait (PCSR_WAIT pCsrWait) +/* PUBLIC FUNCTIONS **********************************************************/ + +/*++ + * @name CsrCreateWait + * @implemented NT4 + * + * The CsrCreateWait routine creates a CSR Wait. + * + * @param WaitList + * Pointer to a list entry of the waits to associate. + * + * @param WaitFunction + * Pointer to the function that will handle this wait. + * + * @param CsrWaitThread + * Pointer to the CSR Thread that will perform the wait. + * + * @param WaitApiMessage + * Pointer to the CSR API Message associated to this wait. + * + * @param WaitContext + * Pointer to a user-defined parameter associated to this wait. + * + * @param UserWaitList + * Pointer to a list entry of the user-defined waits to associate. + * + * @return TRUE in case of success, FALSE otherwise. + * + * @remarks None. + * + *--*/ +BOOLEAN +NTAPI +CsrCreateWait(IN PLIST_ENTRY WaitList, + IN CSR_WAIT_FUNCTION WaitFunction, + IN PCSR_THREAD CsrWaitThread, + IN OUT PCSR_API_MESSAGE WaitApiMessage, + IN PVOID WaitContext, + IN PLIST_ENTRY UserWaitList OPTIONAL) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - return Status; + PCSR_WAIT_BLOCK WaitBlock; + + /* Initialize the wait */ + if (!CsrInitializeWait(WaitFunction, + CsrWaitThread, + WaitApiMessage, + WaitContext, + &WaitBlock)) + { + return FALSE; + } + + /* Acquire the Wait Lock */ + CsrAcquireWaitLock(); + + /* Make sure the thread wasn't destroyed */ + if (CsrWaitThread && (CsrWaitThread->Flags & CsrThreadTerminated)) + { + /* Fail the wait */ + CsrWaitThread->WaitBlock = NULL; + RtlFreeHeap(CsrHeap, 0, WaitBlock); + CsrReleaseWaitLock(); + return FALSE; + } + + /* Insert the wait in the queue */ + InsertTailList(WaitList, &WaitBlock->WaitList); + + /* Insert the User Wait too, if one was given */ + if (UserWaitList) InsertTailList(UserWaitList, &WaitBlock->UserWaitList); + + /* Return */ + CsrReleaseWaitLock(); + return TRUE; } -NTSTATUS STDCALL CsrNotifyWait (PCSR_WAIT pCsrWait) +/*++ + * @name CsrDereferenceWait + * @implemented NT4 + * + * The CsrDereferenceWait routine derefences a CSR Wait Block. + * + * @param WaitList + * Pointer to the Wait List associated to the wait. + + * @return None. + * + * @remarks None. + * + *--*/ +VOID +NTAPI +CsrDereferenceWait(IN PLIST_ENTRY WaitList) { - NTSTATUS Status = STATUS_NOT_IMPLEMENTED; - - DPRINT("CSRSRV: %s called\n", __FUNCTION__); - - return Status; + PLIST_ENTRY ListHead, NextEntry; + PCSR_WAIT_BLOCK WaitBlock; + + /* Acquire the Process and Wait Locks */ + CsrAcquireProcessLock(); + CsrAcquireWaitLock(); + + /* Set the list pointers */ + ListHead = WaitList; + NextEntry = ListHead->Flink; + + /* Start the loop */ + while (NextEntry != ListHead) + { + /* Get the wait block */ + WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList); + + /* Move to the next entry */ + NextEntry = NextEntry->Flink; + + /* Check if there's no Wait Routine */ + if (!WaitBlock->WaitFunction) + { + /* Remove it from the Wait List */ + if (WaitBlock->WaitList.Flink) + { + RemoveEntryList(&WaitBlock->WaitList); + } + + /* Remove it from the User Wait List */ + if (WaitBlock->UserWaitList.Flink) + { + RemoveEntryList(&WaitBlock->UserWaitList); + } + + /* Dereference the thread waiting on it */ + CsrDereferenceThread(WaitBlock->WaitThread); + + /* Free the block */ + RtlFreeHeap(CsrHeap, 0, WaitBlock); + } + } + + /* Release the locks */ + CsrReleaseWaitLock(); + CsrReleaseProcessLock(); } +/*++ + * @name CsrMoveSatisfiedWait + * @implemented NT5 + * + * The CsrMoveSatisfiedWait routine moves satisfied waits from a wait list + * to another list entry. + * + * @param NewEntry + * Pointer to a list entry where the satisfied waits will be added. + * + * @param WaitList + * Pointer to a list entry to analyze for satisfied waits. + * + * @return None. + * + * @remarks None. + * + *--*/ +VOID +NTAPI +CsrMoveSatisfiedWait(IN PLIST_ENTRY NewEntry, + IN PLIST_ENTRY WaitList) +{ + PLIST_ENTRY ListHead, NextEntry; + PCSR_WAIT_BLOCK WaitBlock; + + /* Acquire the Wait Lock */ + CsrAcquireWaitLock(); + + /* Set the List pointers */ + ListHead = WaitList; + NextEntry = ListHead->Flink; + + /* Start looping */ + while (NextEntry != ListHead) + { + /* Get the Wait block */ + WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList); + + /* Go to the next entry */ + NextEntry = NextEntry->Flink; + + /* Check if there is a Wait Callback */ + if (WaitBlock->WaitFunction) + { + /* Remove it from the Wait Block Queue */ + RemoveEntryList(&WaitBlock->WaitList); + + /* Insert the new entry */ + InsertTailList(&WaitBlock->WaitList, NewEntry); + } + } + + /* Release the wait lock */ + CsrReleaseWaitLock(); +} + +/*++ + * @name CsrNotifyWait + * @implemented NT4 + * + * The CsrNotifyWait notifies a CSR Wait Block. + * + * @param WaitList + * Pointer to the list entry for this wait. + * + * @param WaitType + * Type of the wait to perform, either WaitAny or WaitAll. + * + * @param WaitArgument[1-2] + * User-defined argument to pass on to the wait function. + * + * @return TRUE in case of success, FALSE othwerwise. + * + * @remarks None. + * + *--*/ +BOOLEAN +NTAPI +CsrNotifyWait(IN PLIST_ENTRY WaitList, + IN ULONG WaitType, + IN PVOID WaitArgument1, + IN PVOID WaitArgument2) +{ + PLIST_ENTRY ListHead, NextEntry; + PCSR_WAIT_BLOCK WaitBlock; + BOOLEAN NotifySuccess = FALSE; + + /* Acquire the Wait Lock */ + CsrAcquireWaitLock(); + + /* Set the List pointers */ + ListHead = WaitList; + NextEntry = ListHead->Flink; + + /* Start looping */ + while (NextEntry != ListHead) + { + /* Get the Wait block */ + WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList); + + /* Go to the next entry */ + NextEntry = NextEntry->Flink; + + /* Check if there is a Wait Callback */ + if (WaitBlock->WaitFunction) + { + /* Notify the Waiter */ + NotifySuccess |= CsrNotifyWaitBlock(WaitBlock, + WaitList, + WaitArgument1, + WaitArgument2, + 0, + FALSE); + + /* We've already done a wait, so leave unless this is a Wait All */ + if (WaitType != WaitAll) break; + } + } + + /* Release the wait lock and return */ + CsrReleaseWaitLock(); + return NotifySuccess; +} /* EOF */ diff --git a/reactos/subsys/csr/main.c b/reactos/subsys/csr/main.c index bbb96de7292..c488521a7b7 100644 --- a/reactos/subsys/csr/main.c +++ b/reactos/subsys/csr/main.c @@ -1,104 +1,87 @@ -/* $Id$ - * - * main.c - Client/Server Runtime - entry point - * - * ReactOS Operating System - * - * -------------------------------------------------------------------- - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; see the file COPYING.LIB. If not, write - * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, - * MA 02139, USA. - * - * -------------------------------------------------------------------- - * - * 19990417 (Emanuele Aliberti) - * Do nothing native application skeleton - * 19990528 (Emanuele Aliberti) - * Compiled successfully with egcs 1.1.2 - * 19990605 (Emanuele Aliberti) - * First standalone run under ReactOS (it - * actually does nothing but running). - * 20050329 (Emanuele Aliberti) - * C/S run-time moved to CSRSRV.DLL - * Win32 emulation moved to server DLLs basesrv+winsrv - * (previously code was already in win32csr.dll) +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS CSR Sub System + * FILE: subsys/csr/csrss.c + * PURPOSE: CSR Executable + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) */ -#include "csr.h" + +/* INCLUDES ******************************************************************/ + +#include +#define NTOS_MODE_USER +#include #define NDEBUG #include -COMMAND_LINE_ARGUMENT Argument; +/* PRIVATE FUNCTIONS *********************************************************/ -/* never fail or so */ - -VOID STDCALL CsrpSetDefaultProcessHardErrorMode (VOID) +VOID +NTAPI +CsrpSetDefaultProcessHardErrorMode (VOID) { - DWORD DefaultHardErrorMode = 0; - NtSetInformationProcess (NtCurrentProcess(), - ProcessDefaultHardErrorMode, - & DefaultHardErrorMode, - sizeof DefaultHardErrorMode); + ULONG DefaultHardErrorMode = 0; + + /* Disable hard errors */ + NtSetInformationProcess(NtCurrentProcess(), + ProcessDefaultHardErrorMode, + &DefaultHardErrorMode, + sizeof(DefaultHardErrorMode); } -/* Native process' entry point */ - -VOID STDCALL NtProcessStartup (PPEB Peb) +int +_cdecl +main(int argc, + char *argv[], + char *envp[], + int DebugFlag) { - NTSTATUS Status = STATUS_SUCCESS; + KPRIORITY BasePriority = (8 + 1) + 4; + NTSTATUS Status; + ULONG Response; - /* - * Parse the command line. - */ - Status = CsrParseCommandLine (Peb, & Argument); - if (STATUS_SUCCESS != Status) - { - DPRINT1("CSR: %s: CsrParseCommandLine failed (Status=0x%08lx)\n", - __FUNCTION__, Status); - } - /* - * Initialize the environment subsystem server. - */ - Status = CsrServerInitialization (Argument.Count, Argument.Vector); - if (!NT_SUCCESS(Status)) - { - /* FATAL! */ - DPRINT1("CSR: %s: CSRSRV!CsrServerInitialization failed (Status=0x%08lx)\n", - __FUNCTION__, Status); + /* Set the Priority */ + NtSetInformationProcess(NtCurrentProcess(), + ProcessBasePriority, + &BasePriority, + sizeof(KPRIORITY)); - CsrFreeCommandLine (Peb, & Argument); - /* - * Tell the SM we failed. If we are a required - * subsystem, SM will halt the system. - */ - NtTerminateProcess (NtCurrentProcess(), Status); - } - /* - * The server booted OK: never stop on error! - */ - CsrpSetDefaultProcessHardErrorMode (); - /* - * Cleanup command line - */ - CsrFreeCommandLine (Peb, & Argument); - /* - * Terminate the current thread only (server's - * threads that serve the LPC port continue - * running and keep the process alive). - */ - NtTerminateThread (NtCurrentThread(), Status); + /* Give us IOPL so that we can access the VGA registers */ + Status = NtSetInformationProcess(NtCurrentProcess(), + ProcessUserModeIOPL, + NULL, + 0); + if (NT_SUCCESS(Status)) + { + /* Raise a hard error */ + DPRINT1("CSRSS: Could not raise IOPL: %x\n", Status); + Status = NtRaiseHardError(STATUS_IO_PRIVILEGE_FAILED, + 0, + 0, + NULL, + OptionOk, + &Response); + } + + /* Initialize CSR through CSRSRV */ + Status = CsrServerInitialization(argc, argv); + if (!NT_SUCCESS(Status)) + { + /* Kill us */ + DPRINT1("CSRSS: CsrServerInitialization failed:% lx\n", Status); + NtTerminateProcess (NtCurrentProcess(), Status); + } + + /* Disable errors */ + CsrpSetDefaultProcessHardErrorMode(); + + /* If this is Session 0, make sure killing us bugchecks the system */ + if (!NtCurrentPeb()->SessionId) RtlSetProcessIsCritical(TRUE, NULL, FALSE); + + /* Kill this thread. CSRSRV keeps us going */ + NtTerminateThread (NtCurrentThread(), Status); + return 0; } /* EOF */