/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Client/Server Runtime SubSystem * FILE: subsystems/win32/csrsrv/server.c * PURPOSE: CSR Server DLL Server Functions * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) */ /* INCLUDES *******************************************************************/ #include "srv.h" #include #define NDEBUG #include /* DATA ***********************************************************************/ PCSR_SERVER_DLL CsrLoadedServerDll[CSR_SERVER_DLL_MAX]; PVOID CsrSrvSharedSectionHeap = NULL; PVOID CsrSrvSharedSectionBase = NULL; PVOID *CsrSrvSharedStaticServerData = NULL; ULONG CsrSrvSharedSectionSize = 0; HANDLE CsrSrvSharedSection = NULL; PCSR_API_ROUTINE CsrServerApiDispatchTable[CsrpMaxApiNumber] = { CsrSrvClientConnect, CsrSrvUnusedFunction, CsrSrvUnusedFunction, CsrSrvIdentifyAlertableThread, CsrSrvSetPriorityClass }; BOOLEAN CsrServerApiServerValidTable[CsrpMaxApiNumber] = { TRUE, FALSE, TRUE, TRUE, TRUE }; /* * On Windows Server 2003, CSR Servers contain * the API Names Table only in Debug Builds. */ #ifdef CSR_DBG PCHAR CsrServerApiNameTable[CsrpMaxApiNumber] = { "ClientConnect", "ThreadConnect", "ProfileControl", "IdentifyAlertableThread", "SetPriorityClass" }; #endif /* PRIVATE FUNCTIONS **********************************************************/ /*++ * @name CsrServerDllInitialization * @implemented NT4 * * The CsrServerDllInitialization is the initialization routine * for this Server DLL. * * @param LoadedServerDll * Pointer to the CSR Server DLL structure representing this Server DLL. * * @return STATUS_SUCCESS. * * @remarks None. * *--*/ CSR_SERVER_DLL_INIT(CsrServerDllInitialization) { /* Setup the DLL Object */ LoadedServerDll->ApiBase = CSRSRV_FIRST_API_NUMBER; LoadedServerDll->HighestApiSupported = CsrpMaxApiNumber; LoadedServerDll->DispatchTable = CsrServerApiDispatchTable; LoadedServerDll->ValidTable = CsrServerApiServerValidTable; #ifdef CSR_DBG LoadedServerDll->NameTable = CsrServerApiNameTable; #endif LoadedServerDll->SizeOfProcessData = 0; LoadedServerDll->ConnectCallback = NULL; LoadedServerDll->DisconnectCallback = NULL; /* All done */ return STATUS_SUCCESS; } /*++ * @name CsrLoadServerDll * @implemented NT4 * * The CsrLoadServerDll routine loads a CSR Server DLL and calls its entrypoint. * * @param DllString * Pointer to the CSR Server DLL to load and call. * * @param EntryPoint * Pointer to the name of the server's initialization function. * If this parameter is NULL, the default ServerDllInitialize * will be assumed. * * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise. * * @remarks None. * *--*/ NTSTATUS NTAPI CsrLoadServerDll(IN PCHAR DllString, IN PCHAR EntryPoint OPTIONAL, IN ULONG ServerId) { NTSTATUS Status; ANSI_STRING DllName; UNICODE_STRING TempString, ErrorString; ULONG_PTR Parameters[2]; HANDLE hServerDll = NULL; ULONG Size; PCSR_SERVER_DLL ServerDll; STRING EntryPointString; PCSR_SERVER_DLL_INIT_CALLBACK ServerDllInitProcedure; ULONG Response; /* 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 */ ASSERT(DllString != NULL); RtlInitAnsiString(&DllName, DllString); Status = RtlAnsiStringToUnicodeString(&TempString, &DllName, TRUE); if (!NT_SUCCESS(Status)) return Status; /* If we are loading ourselves, don't actually load us */ if (ServerId != CSRSRV_SERVERDLL_INDEX) { /* Load the DLL */ Status = LdrLoadDll(NULL, 0, &TempString, &hServerDll); if (!NT_SUCCESS(Status)) { /* Setup error parameters */ Parameters[0] = (ULONG_PTR)&TempString; Parameters[1] = (ULONG_PTR)&ErrorString; RtlInitUnicodeString(&ErrorString, L"Default Load Path"); /* Send a hard error */ NtRaiseHardError(Status, 2, 3, Parameters, OptionOk, &Response); } /* 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; ServerDll = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, Size); if (!ServerDll) { if (hServerDll) LdrUnloadDll(hServerDll); return STATUS_NO_MEMORY; } /* Set up the Object */ ServerDll->Length = Size; ServerDll->SizeOfProcessData = 0; ServerDll->SharedSection = CsrSrvSharedSectionHeap; // Send to the server dll our shared heap pointer. 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 ? EntryPoint : "ServerDllInitialization"); /* 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); 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; } } } if (!NT_SUCCESS(Status)) { /* Server Init failed, unload it */ if (hServerDll) LdrUnloadDll(hServerDll); /* Delete the Object */ RtlFreeHeap(CsrHeap, 0, ServerDll); } /* Return to caller */ return Status; } /*++ * @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 ReplyCode * 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. * *--*/ CSR_API(CsrSrvClientConnect) { NTSTATUS Status; PCSR_CLIENT_CONNECT ClientConnect = &ApiMessage->Data.CsrClientConnect; PCSR_SERVER_DLL ServerDll; PCSR_PROCESS CurrentProcess = CsrGetClientThread()->Process; /* Set default reply */ *ReplyCode = CsrReplyImmediately; /* 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, sizeof(BYTE)))) { /* 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(CurrentProcess, ClientConnect->ConnectionInfo, &ClientConnect->ConnectionInfoSize); } else { /* Assume success */ Status = STATUS_SUCCESS; } /* Return status */ return Status; } /*++ * @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 otherwise. * * @remarks None. * *--*/ NTSTATUS NTAPI CsrSrvCreateSharedSection(IN PCHAR ParameterValue) { PCHAR SizeValue = ParameterValue; ULONG Size; NTSTATUS Status; LARGE_INTEGER SectionSize; SIZE_T ViewSize = 0; PPEB Peb = NtCurrentPeb(); /* If there's no parameter, fail */ if (!ParameterValue) return STATUS_INVALID_PARAMETER; /* Find the first comma, and null terminate */ while (*SizeValue) { if (*SizeValue == ',') { *SizeValue++ = ANSI_NULL; 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 | HEAP_CLASS_7, 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, HEAP_ZERO_MEMORY, CSR_SERVER_DLL_MAX * sizeof(PVOID)); if (!CsrSrvSharedStaticServerData) return STATUS_NO_MEMORY; /* Write the values to the PEB */ Peb->ReadOnlySharedMemoryBase = CsrSrvSharedSectionBase; Peb->ReadOnlySharedMemoryHeap = CsrSrvSharedSectionHeap; Peb->ReadOnlyStaticServerData = CsrSrvSharedStaticServerData; /* Return */ return STATUS_SUCCESS; } /*++ * @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 otherwise. * * @remarks None. * *--*/ NTSTATUS NTAPI CsrSrvAttachSharedSection(IN PCSR_PROCESS CsrProcess OPTIONAL, OUT PCSR_API_CONNECTINFO ConnectInfo) { NTSTATUS Status; SIZE_T ViewSize = 0; /* Check if we have a process */ if (CsrProcess) { /* Map the section 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->SharedStaticServerData = CsrSrvSharedStaticServerData; /* Return success */ return STATUS_SUCCESS; } /*++ * @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 ReplyCode * Pointer to an optional reply to this request. * * @return STATUS_SUCCESS. * * @remarks None. * *--*/ CSR_API(CsrSrvIdentifyAlertableThread) { PCSR_THREAD CsrThread = CsrGetClientThread(); /* Set the alertable flag */ CsrThread->Flags |= CsrThreadAlertable; /* Return success */ return STATUS_SUCCESS; } /*++ * @name CsrSrvSetPriorityClass * @implemented NT4 * * The CsrSrvSetPriorityClass CSR API is deprecated. * * @param ApiMessage * Pointer to the CSR API Message for this request. * * @param ReplyCode * Pointer to an optional reply to this request. * * @return STATUS_SUCCESS. * * @remarks None. * *--*/ CSR_API(CsrSrvSetPriorityClass) { /* Deprecated */ return STATUS_SUCCESS; } /*++ * @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 ReplyCode * Pointer to an optional reply to this request. * * @return STATUS_INVALID_PARAMETER. * * @remarks CsrSrvSetPriorityClass does not use this stub because * it must return success. * *--*/ CSR_API(CsrSrvUnusedFunction) { /* Deprecated */ return STATUS_INVALID_PARAMETER; } /* 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. * *--*/ EXCEPTION_DISPOSITION NTAPI CsrUnhandledExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo) { SYSTEM_KERNEL_DEBUGGER_INFORMATION DebuggerInfo; EXCEPTION_DISPOSITION Result = EXCEPTION_EXECUTE_HANDLER; BOOLEAN OldValue; NTSTATUS Status; UNICODE_STRING ErrorSource; ULONG_PTR ErrorParameters[4]; ULONG Response; DPRINT1("CsrUnhandledExceptionFilter called\n"); /* 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 != 0) && (NT_SUCCESS(Status)) && (DebuggerInfo.KernelDebuggerEnabled)) { /* Call the Unhandled Exception Filter */ Result = RtlUnhandledExceptionFilter(ExceptionInfo); if (Result != 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] = (ULONG_PTR)&ErrorSource; ErrorParameters[1] = ExceptionInfo->ExceptionRecord->ExceptionCode; ErrorParameters[2] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress; ErrorParameters[3] = (ULONG_PTR)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 */