reactos/subsystems/win32/csrsrv/procsup.c
Hermès Bélusca-Maïto 6716529b84 [CSRSRV]
- Comments formatting.
- Correct a nasty initialization bug which unveiled itself as, eg., critical sections being already initialized in consoles, whereas we were creating new ones. It was because we didn't copy correctly per-process server data from parent process to child process. Now consoles initialize finely.

Now, only modifications to the console subsystem remain to make it totally conform to the new messaging structures of csrss (I mean, using the capture buffers).

svn path=/branches/ros-csrss/; revision=57703
2012-11-13 23:45:02 +00:00

1495 lines
40 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Client/Server Runtime SubSystem
* FILE: subsystems/win32/csrsrv/procsup.c
* PURPOSE: CSR Server DLL Process Management
* PROGRAMMERS: ReactOS Portable Systems Group
* Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES *******************************************************************/
#include <srv.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
RTL_CRITICAL_SECTION CsrProcessLock;
PCSR_PROCESS CsrRootProcess = NULL;
SECURITY_QUALITY_OF_SERVICE CsrSecurityQos =
{
sizeof(SECURITY_QUALITY_OF_SERVICE),
SecurityImpersonation,
SECURITY_STATIC_TRACKING,
FALSE
};
ULONG CsrProcessSequenceCount = 5;
extern ULONG CsrTotalPerProcessDataLength;
/* PRIVATE FUNCTIONS **********************************************************/
/*++
* @name CsrpSetToNormalPriority
*
* The CsrpSetToNormalPriority 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) // CsrpSetToNormalPriority
{
KPRIORITY BasePriority = (8 + 1) + 4;
/* Set the Priority */
NtSetInformationProcess(NtCurrentProcess(),
ProcessBasePriority,
&BasePriority,
sizeof(KPRIORITY));
}
/*++
* @name CsrpSetToShutdownPriority
*
* The CsrpSetToShutdownPriority 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) // CsrpSetToShutdownPriority
{
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(IN PLUID CallerLuid)
{
PCSR_PROCESS CsrProcess, ReturnCsrProcess = NULL;
// PCSR_THREAD CsrThread;
NTSTATUS Status;
ULONG Level = 0;
LUID ProcessLuid;
LUID SystemLuid = SYSTEM_LUID;
// BOOLEAN IsSystemLuid = FALSE, IsOurLuid = FALSE;
PLIST_ENTRY NextEntry;
/* Set the List Pointers */
NextEntry = CsrRootProcess->ListLink.Flink;
while (NextEntry != &CsrRootProcess->ListLink)
{
/* 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)
{
/* FIXME: Check if we have any threads */
/*
/\* 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 */
// FIXME: if ((CsrProcess->ShutdownLevel > Level) || !(ReturnCsrProcess))
if (CsrProcess->ShutdownLevel > Level /* || !ReturnCsrProcess */)
{
/* 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;
}
/*++
* @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)
{
ASSERT(ProcessStructureListLocked());
/* Remove the Process from the list */
CsrRemoveProcess(CsrProcess);
/* 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);
}
/*++
* @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)
{
LONG LockCount;
/* Decrease reference count */
LockCount = --CsrProcess->ReferenceCount;
ASSERT(LockCount >= 0);
if (!LockCount)
{
/* Call the generic cleanup code */
DPRINT1("Should kill process: %p\n", CsrProcess);
CsrProcessRefcountZero(CsrProcess);
CsrAcquireProcessLock();
}
}
/*++
* @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)
{
PCSR_PROCESS CsrProcess;
ULONG TotalSize;
/* 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 and protect against overflow */
CsrProcess->SequenceNumber = CsrProcessSequenceCount++;
if (CsrProcessSequenceCount < 5) CsrProcessSequenceCount = 5;
/* Increase the reference count */
CsrProcess->ReferenceCount++;
/* Initialize the Thread List */
InitializeListHead(&CsrProcess->ThreadList);
/* Return the Process */
return CsrProcess;
}
/*++
* @name CsrLockedReferenceProcess
*
* The CsrLockedReferenceProcess references a CSR Process while the
* Process Lock is already being held.
*
* @param CsrProcess
* Pointer to the CSR Process to be referenced.
*
* @return None.
*
* @remarks This routine will return with the Process Lock held.
*
*--*/
VOID
NTAPI
CsrLockedReferenceProcess(IN PCSR_PROCESS CsrProcess)
{
/* Increment the reference count */
++CsrProcess->ReferenceCount;
}
/*++
* @name CsrInitializeProcessStructure
* @implemented NT4
*
* The CsrInitializeProcessStructure routine sets up support for CSR Processes
* and CSR Threads by initializing our own CSR Root Process.
*
* @param None.
*
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
* otherwise.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
CsrInitializeProcessStructure(VOID)
{
NTSTATUS Status;
ULONG i;
/* Initialize the Lock */
Status = RtlInitializeCriticalSection(&CsrProcessLock);
if (!NT_SUCCESS(Status)) return Status;
/* 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()->ClientId;
/* Initialize the Thread Hash List */
for (i = 0; i < 256; i++) InitializeListHead(&CsrThreadHashTable[i]);
/* Initialize the Wait Lock */
return RtlInitializeCriticalSection(&CsrWaitListsLock);
}
/*++
* @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)
{
/* Free the process object from the heap */
RtlFreeHeap(CsrHeap, 0, CsrProcess);
}
/*++
* @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)
{
PCSR_SERVER_DLL ServerDll;
ULONG i;
ASSERT(ProcessStructureListLocked());
/* 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);
}
}
}
/*++
* @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, // ParentProcess
IN PCSR_PROCESS CurrentProcess OPTIONAL, // CallingProcess
IN PCSR_PROCESS CsrProcess) // Process
{
PCSR_SERVER_DLL ServerDll;
ULONG i;
ASSERT(ProcessStructureListLocked());
/* 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);
}
}
}
/* 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
* otherwise.
*
* @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 = CsrGetClientThread();
CLIENT_ID CurrentCid;
PCSR_PROCESS CurrentProcess;
PCSR_SERVER_DLL ServerDll;
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 */
CsrProcess = CsrAllocateProcess();
if (!CsrProcess)
{
/* Couldn't allocate Process */
CsrReleaseProcessLock();
return STATUS_NO_MEMORY;
}
/* Inherit the Process Data */
CurrentProcess = CurrentThread->Process;
ProcessData = &CsrProcess->ServerData[CSR_SERVER_DLL_MAX];
for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
{
/* Get the current Server */
ServerDll = CsrLoadedServerDll[i];
/* Check if the DLL is Loaded and has Per Process Data */
if (ServerDll && ServerDll->SizeOfProcessData)
{
/* Set the pointer */
CsrProcess->ServerData[i] = ProcessData;
/* Copy the Data */
RtlMoveMemory(ProcessData,
CurrentProcess->ServerData[i],
ServerDll->SizeOfProcessData);
/* Update next data pointer */
ProcessData = (PVOID)((ULONG_PTR)ProcessData +
ServerDll->SizeOfProcessData);
}
else
{
/* No data for this Server */
CsrProcess->ServerData[i] = NULL;
}
}
/* Set the Exception port for us */
Status = NtSetInformationProcess(hProcess,
ProcessExceptionPort,
&CsrApiPort,
sizeof(HANDLE));
if (!NT_SUCCESS(Status))
{
/* Failed */
CsrDeallocateProcess(CsrProcess);
CsrReleaseProcessLock();
return STATUS_NO_MEMORY;
}
/* 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 | CsrProcessPriorityFlags);
/* 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)) && (DebugCid))
{
/* Save the debug flag used */
CsrProcess->DebugFlags = Flags;
/* Save the CID */
CsrProcess->DebugCid = *DebugCid;
}
/* Check if Debugging is enabled */
if (CsrProcess->DebugFlags)
{
/* Set the Debug Port for us */
Status = NtSetInformationProcess(hProcess,
ProcessDebugPort,
&CsrApiPort,
sizeof(HANDLE));
ASSERT(NT_SUCCESS(Status));
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);
if (!NT_SUCCESS(Status))
{
/* Failed */
CsrDeallocateProcess(CsrProcess);
CsrReleaseProcessLock();
return STATUS_NO_MEMORY;
}
/* Allocate a CSR Thread Structure */
CsrThread = CsrAllocateThread(CsrProcess);
if (!CsrThread)
{
/* Failed */
CsrDeallocateProcess(CsrProcess);
CsrReleaseProcessLock();
return STATUS_NO_MEMORY;
}
/* Save the data we have */
CsrThread->CreateTime = KernelTimes.CreateTime;
CsrThread->ClientId = *ClientId;
CsrThread->ThreadHandle = hThread;
ProtectHandle(hThread);
CsrThread->Flags = 0;
/* Insert the Thread into the Process */
CsrInsertThread(CsrProcess, CsrThread);
/* Reference the session */
CsrReferenceNtSession(NtSession);
CsrProcess->NtSession = NtSession;
/* Setup Process Data */
CsrProcess->ClientId = *ClientId;
CsrProcess->ProcessHandle = hProcess;
CsrProcess->ShutdownLevel = 0x280;
/* 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(IN PCSR_PROCESS CsrProcess)
{
/* CSR does not handle debugging anymore */
DPRINT("CSRSRV: %s(%08lx) called\n", __FUNCTION__, CsrProcess);
return STATUS_UNSUCCESSFUL;
}
/*++
* @name CsrDebugProcessStop
* @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(IN 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(IN PCSR_PROCESS CsrProcess)
{
LONG LockCount;
/* Acquire process lock */
CsrAcquireProcessLock();
/* Decrease reference count */
LockCount = --CsrProcess->ReferenceCount;
ASSERT(LockCount >= 0);
if (!LockCount)
{
/* 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 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 */
NextEntry = CsrProcess->ThreadList.Flink;
while (NextEntry != &CsrProcess->ThreadList)
{
/* Get the current thread entry */
CsrThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
/* Make sure the thread isn't already dead */
if (CsrThread->Flags & CsrThreadTerminated)
{
NextEntry = NextEntry->Flink;
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);
NextEntry = CsrProcess->ThreadList.Flink;
}
/* 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
* otherwise.
*
* @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(IN HANDLE hProcess OPTIONAL,
OUT 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 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 = CsrGetClientThread();
/* 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 */
/*
DPRINT1("CSRSS: Can't impersonate client thread - Status = %lx\n", Status);
if (Status != STATUS_BAD_IMPERSONATION_LEVEL) DbgBreakPoint();
*/
return FALSE;
}
/* Increase the impersonation count for the current thread */
if (CurrentThread) ++CurrentThread->ImpersonationCount;
/* Return Success */
return TRUE;
}
/*++
* @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
* otherwise.
*
* @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)
{
PLIST_ENTRY NextEntry;
PCSR_PROCESS CurrentProcess = NULL;
NTSTATUS Status;
/* Acquire the lock */
CsrAcquireProcessLock();
/* Assume failure */
ASSERT(CsrProcess != NULL);
*CsrProcess = NULL;
/* Setup the List Pointers */
NextEntry = &CsrRootProcess->ListLink;
do
{
/* Get the Process */
CurrentProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink);
/* Check for PID Match */
if (CurrentProcess->ClientId.UniqueProcess == Pid)
{
Status = STATUS_SUCCESS;
break;
}
/* Next entry */
NextEntry = NextEntry->Flink;
} while (NextEntry != &CsrRootProcess->ListLink);
/* Check if we didn't find it in the list */
if (!NT_SUCCESS(Status))
{
/* Nothing found, release the lock */
CsrReleaseProcessLock();
}
else
{
/* Lock the found process and return it */
CsrLockedReferenceProcess(CurrentProcess);
*CsrProcess = CurrentProcess;
}
/* Return the result */
return Status;
}
/*++
* @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 = CsrGetClientThread();
HANDLE ImpersonationToken = NULL;
/* Check if we have a Current Thread */
if (CurrentThread)
{
/* Make sure impersonation is on */
if (!CurrentThread->ImpersonationCount)
{
// DPRINT1("CSRSS: CsrRevertToSelf called while not impersonating\n");
// DbgBreakPoint();
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 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 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 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
* otherwise.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
CsrShutdownProcesses(IN PLUID CallerLuid,
IN ULONG Flags)
{
PLIST_ENTRY NextEntry;
PCSR_PROCESS CsrProcess;
NTSTATUS Status;
BOOLEAN FirstTry;
ULONG i;
PCSR_SERVER_DLL ServerDll;
ULONG Result = 0; /* Intentionally invalid enumeratee to silence compiler warning */
/* Acquire process lock */
CsrAcquireProcessLock();
/* Add shutdown flag */
CsrRootProcess->ShutdownFlags |= CsrShutdownSystem;
/* Get the list pointers */
NextEntry = CsrRootProcess->ListLink.Flink;
while (NextEntry != &CsrRootProcess->ListLink)
{
/* 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 */
// CsrpSetToShutdownPriority();
CsrSetToShutdownPriority();
/* Start looping */
while (TRUE)
{
/* Find the next process to shutdown */
CsrProcess = FindProcessForShutdown(CallerLuid);
if (!CsrProcess) break;
/* Increase reference to process */
CsrProcess->ReferenceCount++;
FirstTry = TRUE;
while (TRUE)
{
/* Loop all the servers */
for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
{
/* Get the current server */
ServerDll = CsrLoadedServerDll[i];
/* Check if it's valid and if it has a Shutdown Process Callback */
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 == CsrShutdownCancelled)
{
/* Check if this was a forced shutdown */
if (Flags & EWX_FORCE)
{
DPRINT1("Process %x cancelled forced shutdown (Dll = %d)\n",
CsrProcess->ClientId.UniqueProcess, i);
DbgBreakPoint();
}
/* 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;
continue;
}
/* Second try, break out */
break;
}
/* We've reached the final loop here, so dereference */
if (i == CSR_SERVER_DLL_MAX) CsrLockedDereferenceProcess(CsrProcess);
}
/* Success path */
CsrReleaseProcessLock();
Status = STATUS_SUCCESS;
Quickie:
/* Return to normal priority */
// CsrpSetToNormalPriority();
CsrSetToNormalPriority();
return Status;
}
/* FIXME: Temporary hack. This is really "CsrShutdownProcess", mostly. Used by winsrv */
#if 0
NTSTATUS
WINAPI
CsrEnumProcesses(IN CSRSS_ENUM_PROCESS_PROC EnumProc,
IN PVOID Context)
{
PVOID* RealContext = (PVOID*)Context;
PLUID CallerLuid = RealContext[0];
PCSR_PROCESS CsrProcess = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
BOOLEAN FirstTry;
PLIST_ENTRY NextEntry;
ULONG Result = 0;
/* Acquire process lock */
CsrAcquireProcessLock();
/* Get the list pointers */
NextEntry = CsrRootProcess->ListLink.Flink;
while (NextEntry != &CsrRootProcess->ListLink)
{
/* 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();
/* Loop all processes */
//DPRINT1("Enumerating for LUID: %lx %lx\n", CallerLuid->HighPart, CallerLuid->LowPart);
/* Start looping */
while (TRUE)
{
/* Find the next process to shutdown */
FirstTry = TRUE;
if (!(CsrProcess = FindProcessForShutdown(CallerLuid)))
{
/* Done, quit */
CsrReleaseProcessLock();
Status = STATUS_SUCCESS;
goto Quickie;
}
LoopAgain:
/* Release the lock, make the callback, and acquire it back */
//DPRINT1("Found process: %lx\n", CsrProcess->ClientId.UniqueProcess);
CsrReleaseProcessLock();
Result = (ULONG)EnumProc(CsrProcess, (PVOID)((ULONG_PTR)Context | FirstTry));
CsrAcquireProcessLock();
/* Check the result */
//DPRINT1("Result: %d\n", 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;
}
}
Quickie:
/* Return to normal priority */
CsrSetToNormalPriority();
return Status;
}
#endif
/*++
* @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(IN PCSR_PROCESS CsrProcess)
{
/* Dereference the process */
CsrLockedDereferenceProcess(CsrProcess);
/* Release the lock and return */
CsrReleaseProcessLock();
return STATUS_SUCCESS;
}
/* EOF */