--- /dev/null
+/*
+ * 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 <debug.h>
+
+/* DATA **********************************************************************/
+BOOLEAN (*CsrClientThreadSetup)(VOID) = NULL;
+ULONG CsrMaxApiRequestThreads;
+UNICODE_STRING CsrSbApiPortName;
+UNICODE_STRING CsrApiPortName;
+HANDLE CsrSbApiPort;
+HANDLE CsrApiPort;
+PCSR_THREAD CsrSbApiRequestThreadPtr;
+volatile LONG CsrpStaticThreadCount;
+volatile LONG CsrpDynamicThreadTotal;
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+/*++
+ * @name CsrpCheckRequestThreads
+ *
+ * The CsrpCheckRequestThreads 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
+CsrpCheckRequestThreads(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,
+ (PVOID)CsrApiRequestThread,
+ NULL,
+ &hThread,
+ &ClientId);
+ /* Check success */
+ if (NT_SUCCESS(Status))
+ {
+ /* Increase the thread counts */
+ _InterlockedIncrement(&CsrpStaticThreadCount);
+ _InterlockedIncrement(&CsrpDynamicThreadTotal);
+
+ /* Add a new server thread */
+ if (CsrAddStaticServerThread(hThread,
+ &ClientId,
+ CsrThreadIsServerThread))
+ {
+ /* Activate it */
+ NtResumeThread(hThread,NULL);
+ }
+ else
+ {
+ /* Failed to create a new static thread */
+ _InterlockedDecrement(&CsrpStaticThreadCount);
+ _InterlockedDecrement(&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);
+
+ /* Create the buffer for it */
+ CsrSbApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
+ if (!CsrSbApiPortName.Buffer) return STATUS_NO_MEMORY;
+
+ /* Setup the rest of the empty string */
+ CsrSbApiPortName.Length = 0;
+ CsrSbApiPortName.MaximumLength = (USHORT)Size;
+
+ /* Now append the full port name */
+ RtlAppendUnicodeStringToString(&CsrSbApiPortName, &CsrDirectoryName);
+ RtlAppendUnicodeToString(&CsrSbApiPortName, UNICODE_PATH_SEP);
+ RtlAppendUnicodeToString(&CsrSbApiPortName, SB_PORT_NAME);
+ if (CsrDebug & 2) DPRINT1("CSRSS: Creating %wZ port and associated thread\n", &CsrSbApiPortName);
+
+ /* Create Security Descriptor for this Port */
+ Status = CsrCreateLocalSystemSD(&PortSd);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Initialize the Attributes */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &CsrSbApiPortName,
+ 0,
+ NULL,
+ PortSd);
+
+ /* Create the Port Object */
+ Status = NtCreatePort(&CsrSbApiPort,
+ &ObjectAttributes,
+ sizeof(SB_CONNECTION_INFO),
+ sizeof(SB_API_MSG),
+ 32 * sizeof(SB_API_MSG));
+ if (PortSd) RtlFreeHeap(CsrHeap, 0, PortSd);
+
+ 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 */
+ Status = NtResumeThread(hRequestThread, NULL);
+ }
+ }
+
+ return Status;
+}
+
+/*++
+ * @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);
+
+ /* Create the buffer for it */
+ CsrApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
+ if (!CsrApiPortName.Buffer) return STATUS_NO_MEMORY;
+
+ /* Setup the rest of the empty string */
+ CsrApiPortName.Length = 0;
+ CsrApiPortName.MaximumLength = (USHORT)Size;
+ RtlAppendUnicodeStringToString(&CsrApiPortName, &CsrDirectoryName);
+ RtlAppendUnicodeToString(&CsrApiPortName, UNICODE_PATH_SEP);
+ RtlAppendUnicodeToString(&CsrApiPortName, CSR_PORT_NAME);
+ if (CsrDebug & 1)
+ {
+ DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName);
+ DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
+ sizeof(CSR_CONNECTION_INFO), sizeof(CSR_API_MESSAGE));
+ }
+
+ /* 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 */
+ Status = NtWaitForSingleObject(hRequestEvent, FALSE, NULL);
+ ASSERT(NT_SUCCESS(Status));
+ }
+
+ /* 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, CsrThread;
+ NTSTATUS Status;
+ PCSR_API_MESSAGE ReplyMsg;
+ CSR_API_MESSAGE ReceiveMsg;
+ PCSR_PROCESS CsrProcess;
+ PHARDERROR_MSG HardErrorMsg;
+ PVOID PortContext;
+ PCSR_SERVER_DLL ServerDll;
+ PCLIENT_DIED_MSG ClientDiedMsg;
+ PDBGKM_MSG DebugMessage;
+ ULONG ServerId, ApiId, Reply, MessageType, i;
+ HANDLE ReplyPort;
+
+ /* Setup LPC loop port and message */
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+
+ /* Connect to user32 */
+ while (!CsrConnectToUser())
+ {
+ /* Set up the timeout for the connect (30 seconds) */
+ TimeOut.QuadPart = -30 * 1000 * 1000 * 10;
+
+ /* 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 */
+ Status = NtSetEvent((HANDLE)Parameter, NULL);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Increase the Thread Counts */
+ _InterlockedIncrement(&CsrpStaticThreadCount);
+ _InterlockedIncrement(&CsrpDynamicThreadTotal);
+ }
+
+ /* Now start the loop */
+ while (TRUE)
+ {
+ /* Make sure the real CID is set */
+ Teb->RealClientId = Teb->ClientId;
+
+ /* Debug check */
+ if (Teb->CountOfOwnedCriticalSections)
+ {
+ DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
+ Teb->CountOfOwnedCriticalSections);
+ DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
+ &ReceiveMsg, ReplyMsg);
+ DbgBreakPoint();
+ }
+
+ /* Wait for a message to come through */
+ Status = NtReplyWaitReceivePort(ReplyPort,
+ &PortContext,
+ &ReplyMsg->Header,
+ &ReceiveMsg.Header);
+
+ /* Check if we didn't get success */
+ if (Status != STATUS_SUCCESS)
+ {
+ /* Was it a failure or another success code? */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Check for specific status cases */
+ if ((Status != STATUS_INVALID_CID) &&
+ (Status != STATUS_UNSUCCESSFUL) &&
+ ((Status == STATUS_INVALID_HANDLE) || (ReplyPort == CsrApiPort)))
+ {
+ /* Notify the debugger */
+ DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status);
+ DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort, CsrApiPort);
+ }
+
+ /* We failed big time, so start out fresh */
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+ continue;
+ }
+ else
+ {
+ /* A bizare "success" code, just try again */
+ DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status);
+ 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);
+ ReplyPort = CsrApiPort;
+ 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;
+ ReplyPort = CsrApiPort;
+ ReplyMsg->Status = DBG_CONTINUE;
+ }
+ else if (MessageType == LPC_PORT_CLOSED ||
+ MessageType == LPC_CLIENT_DIED)
+ {
+ /* The Client or Port are gone, loop again */
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+ }
+ 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 */
+ CsrpCheckRequestThreads();
+ 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(NULL, 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;
+ ReplyPort = CsrApiPort;
+ }
+ else
+ {
+ ReplyMsg = &ReceiveMsg;
+ }
+ }
+ else if (MessageType == LPC_REQUEST)
+ {
+ /* This is an API Message coming from a non-CSR Thread */
+ ReplyMsg = &ReceiveMsg;
+ ReplyPort = CsrApiPort;
+ 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 */
+ ServerDll = NULL;
+ if ((ServerId >= CSR_SERVER_DLL_MAX) ||
+ (!(ServerDll = CsrLoadedServerDll[ServerId])))
+ {
+ /* We are beyond the Maximum Server ID */
+ DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
+ ServerId, ServerDll);
+ DbgBreakPoint();
+ ReplyPort = CsrApiPort;
+ ReplyMsg = NULL;
+ continue;
+ }
+
+ /* 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 */
+ DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
+ CSR_API_ID_FROM_OPCODE(ReceiveMsg.Opcode),
+ &ServerDll->Name);
+ ReplyPort = CsrApiPort;
+ ReplyMsg = NULL;
+ continue;
+ }
+
+ if (CsrDebug & 2)
+ {
+ DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
+ Teb->ClientId.UniqueThread,
+ ReceiveMsg.Header.ClientId.UniqueProcess,
+ ReceiveMsg.Header.ClientId.UniqueThread,
+ ServerDll->NameTable[ApiId],
+ NULL);
+ }
+
+ /* Assume success */
+ ReceiveMsg.Status = STATUS_SUCCESS;
+
+ /* Validation complete, start SEH */
+ _SEH2_TRY
+ {
+ /* Make sure we have enough threads */
+ CsrpCheckRequestThreads();
+
+ /* Call the API and get the result */
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+ ServerDll->DispatchTable[ApiId](&ReceiveMsg, &Reply);
+
+ /* Increase the static thread count */
+ _InterlockedIncrement(&CsrpStaticThreadCount);
+ }
+ _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
+ {
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+ }
+ _SEH2_END;
+ }
+ else
+ {
+ /* Some other ignored message type */
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+ }
+
+ /* 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 */
+ CsrLockedReferenceThread(CsrThread);
+
+ /* 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;
+ ReplyPort = CsrApiPort;
+ continue;
+ }
+
+ /* Reference the thread and release the lock */
+ CsrLockedReferenceThread(CsrThread);
+ 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->ReturnedStatus = DBG_CONTINUE;
+ ReplyMsg = &ReceiveMsg;
+ ReplyPort = CsrApiPort;
+
+ /* 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 */
+ CsrpCheckRequestThreads();
+ 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;
+ ReplyPort = CsrApiPort;
+ }
+ else
+ {
+ CsrDereferenceThread(CsrThread);
+ ReplyMsg = &ReceiveMsg;
+ ReplyPort = CsrApiPort;
+ }
+ }
+ else
+ {
+ /* Something else */
+ CsrDereferenceThread(CsrThread);
+ ReplyMsg = NULL;
+ }
+
+ /* Keep looping */
+ continue;
+ }
+
+ /* We got an API Request */
+ CsrLockedReferenceThread(CsrThread);
+ CsrReleaseProcessLock();
+
+ /* 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 */
+ ServerDll = NULL;
+ if ((ServerId >= CSR_SERVER_DLL_MAX) ||
+ (!(ServerDll = CsrLoadedServerDll[ServerId])))
+ {
+ /* We are beyond the Maximum Server ID */
+ DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
+ ServerId, ServerDll);
+ DbgBreakPoint();
+
+ ReplyPort = CsrApiPort;
+ ReplyMsg = &ReceiveMsg;
+ ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
+ CsrDereferenceThread(CsrThread);
+ continue;
+ }
+
+ /* 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 */
+ DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
+ CSR_API_ID_FROM_OPCODE(ReceiveMsg.Opcode),
+ &ServerDll->Name);
+
+ ReplyPort = CsrApiPort;
+ ReplyMsg = &ReceiveMsg;
+ ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
+ CsrDereferenceThread(CsrThread);
+ continue;
+ }
+
+ if (CsrDebug & 2)
+ {
+ DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
+ Teb->ClientId.UniqueThread,
+ ReceiveMsg.Header.ClientId.UniqueProcess,
+ ReceiveMsg.Header.ClientId.UniqueThread,
+ ServerDll->NameTable[ApiId],
+ CsrThread);
+ }
+
+ /* Assume success */
+ ReplyMsg = &ReceiveMsg;
+ ReceiveMsg.Status = STATUS_SUCCESS;
+
+ /* Now we reply to a particular client */
+ ReplyPort = CsrThread->Process->ClientPort;
+
+ /* Check if there's a capture buffer */
+ if (ReceiveMsg.CsrCaptureData)
+ {
+ /* Capture the arguments */
+ if (!CsrCaptureArguments(CsrThread, &ReceiveMsg))
+ {
+ /* Ignore this message if we failed to get the arguments */
+ CsrDereferenceThread(CsrThread);
+ continue;
+ }
+ }
+
+ /* Validation complete, start SEH */
+ _SEH2_TRY
+ {
+ /* Make sure we have enough threads */
+ CsrpCheckRequestThreads();
+
+ Teb->CsrClientThread = CsrThread;
+
+ /* Call the API and get the result */
+ Reply = 0;
+ ServerDll->DispatchTable[ApiId](&ReceiveMsg, &Reply);
+
+ /* Increase the static thread count */
+ _InterlockedIncrement(&CsrpStaticThreadCount);
+
+ Teb->CsrClientThread = CurrentThread;
+
+ if (Reply == 3)
+ {
+ ReplyMsg = NULL;
+ if (ReceiveMsg.CsrCaptureData)
+ {
+ CsrReleaseCapturedArguments(&ReceiveMsg);
+ }
+ CsrDereferenceThread(CsrThread);
+ ReplyPort = CsrApiPort;
+ }
+ else if (Reply == 2)
+ {
+ NtReplyPort(ReplyPort, &ReplyMsg->Header);
+ ReplyPort = CsrApiPort;
+ ReplyMsg = NULL;
+ CsrDereferenceThread(CsrThread);
+ }
+ else if (Reply == 1)
+ {
+ ReplyPort = CsrApiPort;
+ ReplyMsg = NULL;
+ }
+ else
+ {
+ if (ReceiveMsg.CsrCaptureData)
+ {
+ CsrReleaseCapturedArguments(&ReceiveMsg);
+ }
+ CsrDereferenceThread(CsrThread);
+ }
+ }
+ _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
+ {
+ ReplyMsg = NULL;
+ ReplyPort = CsrApiPort;
+ }
+ _SEH2_END;
+ }
+
+ /* 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 = NULL;
+ PCSR_PROCESS CsrProcess = NULL;
+ NTSTATUS Status = STATUS_SUCCESS;
+ 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 */
+ CsrLockedReferenceProcess(CsrThread->Process);
+
+ /* 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 */
+ CsrLockedDereferenceProcess(CsrProcess);
+ }
+ }
+
+ /* 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()->ClientId.UniqueProcess;
+
+ /* Accept the Connection */
+ Status = NtAcceptConnectPort(&hPort,
+ AllowConnection ? UlongToPtr(CsrProcess->SequenceNumber) : 0,
+ &ApiMessage->Header,
+ AllowConnection,
+ NULL,
+ &RemotePortView);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status);
+ }
+ else if (AllowConnection)
+ {
+ if (CsrDebug & 2)
+ {
+ DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
+ ApiMessage->Header.ClientId.UniqueProcess,
+ ApiMessage->Header.ClientId.UniqueThread,
+ RemotePortView.ViewBase,
+ RemotePortView.ViewSize);
+ }
+
+ /* 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);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status);
+ }
+ }
+ else
+ {
+ DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
+ ApiMessage->Header.ClientId.UniqueProcess,
+ ApiMessage->Header.ClientId.UniqueThread);
+ }
+
+ /* 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_MSG ReceiveMsg;
+ PSB_API_MSG ReplyMsg = NULL;
+ PVOID PortContext;
+ ULONG MessageType;
+
+ /* Start the loop */
+ while (TRUE)
+ {
+ /* Wait for a message to come in */
+ Status = NtReplyWaitReceivePort(CsrSbApiPort,
+ &PortContext,
+ &ReplyMsg->h,
+ &ReceiveMsg.h);
+
+ /* 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;
+ DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status);
+ continue;
+ }
+
+ /* Save the message type */
+ MessageType = ReceiveMsg.h.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.ApiNumber > SbpMaxApiNumber)
+ {
+ ReceiveMsg.ApiNumber = SbpMaxApiNumber;
+ DPRINT1("CSRSS: %lx is invalid Sb ApiNumber\n", ReceiveMsg.ApiNumber);
+ }
+
+ /* Reuse the message */
+ ReplyMsg = &ReceiveMsg;
+
+ /* Make sure that the message is supported */
+ if (ReceiveMsg.ApiNumber < SbpMaxApiNumber)
+ {
+ /* Call the API */
+ if (!CsrServerSbApiDispatch[ReceiveMsg.ApiNumber](&ReceiveMsg))
+ {
+ /* It failed, so return nothing */
+ ReplyMsg = NULL;
+ }
+ }
+ else
+ {
+ /* We don't support this API Number */
+ ReplyMsg->ReturnValue = 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_MSG 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 */
+ Status = NtCompleteConnectPort(hPort);
+ if (!NT_SUCCESS(Status))
+ {
+ 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 */
+ DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n", ServerId, ServerDll);
+ 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 */
+ DPRINT1("CSRSS: %lx (%s) is invalid ApiTableIndex for %Z or is an "
+ "invalid API to call from the server.\n",
+ ServerDll->ValidTable[ApiId],
+ ((ServerDll->NameTable) && (ServerDll->NameTable[ApiId])) ?
+ ServerDll->NameTable[ApiId] : "*** UNKNOWN ***", &ServerDll->Name);
+ DbgBreakPoint();
+ ReplyMsg->Status = (ULONG)STATUS_ILLEGAL_FUNCTION;
+ return STATUS_ILLEGAL_FUNCTION;
+ }
+ }
+
+ if (CsrDebug & 2)
+ {
+ DPRINT1("CSRSS: %s Api Request received from server process\n",
+ ServerDll->NameTable[ApiId]);
+ }
+
+ /* Validation complete, start SEH */
+ _SEH2_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;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* If we got an exception, return access violation */
+ ReplyMsg->Status = STATUS_ACCESS_VIOLATION;
+ }
+ _SEH2_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;
+ BOOLEAN Connected;
+
+ /* 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 */
+ _SEH2_TRY
+ {
+ Connected = CsrClientThreadSetup();
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Connected = FALSE;
+ } _SEH2_END;
+
+ if (!Connected)
+ {
+ DPRINT1("CSRSS: CsrConnectToUser failed\n");
+ return NULL;
+ }
+
+ /* Save pointer to this thread in TEB */
+ CsrAcquireProcessLock();
+ CsrThread = CsrLocateThreadInProcess(NULL, &Teb->ClientId);
+ CsrReleaseProcessLock();
+ 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 = NULL, RemoteCaptureBuffer = NULL;
+ ULONG LocalLength = 0, PointerCount = 0;
+ SIZE_T BufferDistance = 0;
+ ULONG_PTR **PointerOffsets = NULL, *CurrentPointer = NULL;
+
+ /* Use SEH to make sure this is valid */
+ _SEH2_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 */
+ DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView\n");
+ ApiMessage->Status = STATUS_INVALID_PARAMETER;
+ _SEH2_YIELD(return FALSE);
+ }
+
+ /* Check if the Length is valid */
+ if (((LocalCaptureBuffer->PointerCount * 4 + sizeof(CSR_CAPTURE_BUFFER)) >
+ LocalLength) ||(LocalLength > MAXWORD))
+ {
+ /* Return failure */
+ DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", LocalCaptureBuffer);
+ DbgBreakPoint();
+ ApiMessage->Status = STATUS_INVALID_PARAMETER;
+ _SEH2_YIELD(return FALSE);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Return failure */
+ ApiMessage->Status = STATUS_INVALID_PARAMETER;
+ _SEH2_YIELD(return FALSE);
+ } _SEH2_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 */
+ DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n");
+ DbgBreakPoint();
+ ApiMessage->Status = 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, LocalCaptureBuffer;
+ SIZE_T BufferDistance;
+ ULONG PointerCount;
+ ULONG_PTR **PointerOffsets, *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 */
+ CurrentPointer = *PointerOffsets++;
+ if (CurrentPointer)
+ {
+ /* 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, i;
+ ULONG_PTR **PointerOffsets, *CurrentPointer;
+
+ /* 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()->ClientId.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 */
+ DbgPrint("CSRSRV: Bad message buffer %p\n", ApiMessage);
+ DbgBreakPoint();
+ 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)
+{
+ DPRINT1("CSRSRV: %s called\n", __FUNCTION__);
+ return FALSE;
+}
+
+/* EOF */