-/* $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 <debug.h>
-/*=====================================================================
- * PUBLIC API
- *===================================================================*/
+/* DATA **********************************************************************/
+
+LIST_ENTRY CsrThreadHashTable[256];
+SECURITY_QUALITY_OF_SERVICE CsrSecurityQos =
+{
+ 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;
+}
+
+/*++
+ * @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)
+{
+ ULONG i;
+ PLIST_ENTRY ListHead, NextEntry;
+ PCSR_THREAD FoundThread;
+
+ /* 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;
+}
+
+/*++
+ * @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)
+{
+ 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;
+}
+
+/*++
+ * @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)
+{
+ 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);
+}
+
+/*++
+ * @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)
+{
+ /* Free the process object from the heap */
+ RtlFreeHeap(CsrHeap, 0, CsrThread);
+}
+
+/*++
+ * @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)
+{
+ /* Decrease reference count */
+ if (!(--CsrThread->ReferenceCount))
+ {
+ /* Call the generic cleanup code */
+ CsrThreadRefcountZero(CsrThread);
+ CsrAcquireProcessLock();
+ }
+}
+
+/*++
+ * @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)
+{
+ /* 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;
-NTSTATUS STDCALL CsrCreateRemoteThread ()
+ /* 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 = STATUS_NOT_IMPLEMENTED;
-
- DPRINT("CSRSRV: %s called\n", __FUNCTION__);
-
- return Status;
+ 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;
}
-NTSTATUS STDCALL CsrCreateThread (PCSR_PROCESS pCsrProcess, PCSR_THREAD *ppCsrThread)
+/*++
+ * @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)
{
- NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
- PCSR_THREAD pCsrThread = NULL;
- PCSR_SESSION pCsrSession = NULL;
-
- DPRINT("CSRSRV: %s called\n", __FUNCTION__);
+ /* Acquire process lock */
+ CsrAcquireProcessLock();
- 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;
+ /* Decrease reference count */
+ if (!(--CsrThread->ReferenceCount))
+ {
+ /* Call the generic cleanup code */
+ CsrThreadRefcountZero(CsrThread);
+ }
+ else
+ {
+ /* Just release the lock */
+ CsrReleaseProcessLock();
+ }
}
-NTSTATUS STDCALL CsrDereferenceThread (PCSR_THREAD pCsrThread)
+/*++
+ * @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)
{
- NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
-
- DPRINT("CSRSRV: %s called\n", __FUNCTION__);
-
- return Status;
+ 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;
}
-NTSTATUS STDCALL CsrDestroyThread (PCSR_THREAD pCsrThread)
+/*++
+ * @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)
{
- NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
-
- DPRINT("CSRSRV: %s called\n", __FUNCTION__);
-
- return Status;
+ 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;
}
-NTSTATUS STDCALL CsrLockThreadByClientId ()
+/*++
+ * @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 = STATUS_NOT_IMPLEMENTED;
-
- DPRINT("CSRSRV: %s called\n", __FUNCTION__);
-
- return Status;
+ 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;
}
-NTSTATUS STDCALL CsrReferenceThread (PCSR_THREAD pCsrThread)
+/*++
+ * @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 = STATUS_NOT_IMPLEMENTED;
-
- DPRINT("CSRSRV: %s called\n", __FUNCTION__);
-
- return Status;
+ 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);
}
-NTSTATUS STDCALL CsrUnlockThread (PCSR_THREAD pCsrThread)
+/*++
+ * @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)
{
- NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
-
- DPRINT("CSRSRV: %s called\n", __FUNCTION__);
-
- return Status;
+ 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 */