reactos/subsystems/win32/csrss/csrsrv/procsup.c
Jérôme Gardou c16ad873a6 sync with trunk (r46275)
svn path=/branches/reactos-yarotows/; revision=46279
2010-03-19 21:09:21 +00:00

448 lines
12 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS CSR Sub System
* FILE: subsys/csr/csrsrv/procsup.c
* PURPOSE: CSR Process Management
* PROGRAMMERS: ReactOS Portable Systems Group
* Alex Ionescu
*/
/* INCLUDES *******************************************************************/
#include <srv.h>
#define NDEBUG
#include <debug.h>
#define LOCK RtlEnterCriticalSection(&ProcessDataLock)
#define UNLOCK RtlLeaveCriticalSection(&ProcessDataLock)
#define CsrHeap RtlGetProcessHeap()
#define CsrAcquireProcessLock() LOCK
#define CsrReleaseProcessLock() UNLOCK
/* GLOBALS ********************************************************************/
extern RTL_CRITICAL_SECTION ProcessDataLock;
extern PCSRSS_PROCESS_DATA ProcessData[256];
PCSRSS_PROCESS_DATA CsrRootProcess;
LIST_ENTRY CsrThreadHashTable[256];
SECURITY_QUALITY_OF_SERVICE CsrSecurityQos =
{
sizeof(SECURITY_QUALITY_OF_SERVICE),
SecurityImpersonation,
SECURITY_STATIC_TRACKING,
FALSE
};
/* FUNCTIONS ******************************************************************/
VOID
NTAPI
CsrSetToNormalPriority(VOID)
{
KPRIORITY BasePriority = (8 + 1) + 4;
/* Set the Priority */
NtSetInformationProcess(NtCurrentProcess(),
ProcessBasePriority,
&BasePriority,
sizeof(KPRIORITY));
}
VOID
NTAPI
CsrSetToShutdownPriority(VOID)
{
KPRIORITY SetBasePriority = (8 + 1) + 6;
BOOLEAN Old;
/* Get the shutdown privilege */
if (NT_SUCCESS(RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
TRUE,
FALSE,
&Old)))
{
/* Set the Priority */
NtSetInformationProcess(NtCurrentProcess(),
ProcessBasePriority,
&SetBasePriority,
sizeof(KPRIORITY));
}
}
NTSTATUS
NTAPI
CsrGetProcessLuid(HANDLE hProcess OPTIONAL,
PLUID Luid)
{
HANDLE hToken = NULL;
NTSTATUS Status;
ULONG Length;
PTOKEN_STATISTICS TokenStats;
/* Check if we have a handle to a CSR Process */
if (!hProcess)
{
/* We don't, so try opening the Thread's Token */
Status = NtOpenThreadToken(NtCurrentThread(),
TOKEN_QUERY,
FALSE,
&hToken);
/* Check for success */
if (!NT_SUCCESS(Status))
{
/* If we got some other failure, then return and quit */
if (Status != STATUS_NO_TOKEN) return Status;
/* We don't have a Thread Token, use a Process Token */
hProcess = NtCurrentProcess();
hToken = NULL;
}
}
/* Check if we have a token by now */
if (!hToken)
{
/* No token yet, so open the Process Token */
Status = NtOpenProcessToken(hProcess,
TOKEN_QUERY,
&hToken);
if (!NT_SUCCESS(Status))
{
/* Still no token, return the error */
return Status;
}
}
/* Now get the size we'll need for the Token Information */
Status = NtQueryInformationToken(hToken,
TokenStatistics,
NULL,
0,
&Length);
/* Allocate memory for the Token Info */
if (!(TokenStats = RtlAllocateHeap(CsrHeap, 0, Length)))
{
/* Fail and close the token */
NtClose(hToken);
return STATUS_NO_MEMORY;
}
/* Now query the information */
Status = NtQueryInformationToken(hToken,
TokenStatistics,
TokenStats,
Length,
&Length);
/* Close the handle */
NtClose(hToken);
/* Check for success */
if (NT_SUCCESS(Status))
{
/* Return the LUID */
*Luid = TokenStats->AuthenticationId;
}
/* Free the query information */
RtlFreeHeap(CsrHeap, 0, TokenStats);
/* Return the Status */
return Status;
}
BOOLEAN
NTAPI
CsrImpersonateClient(IN PCSR_THREAD CsrThread)
{
NTSTATUS Status;
PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
/* Use the current thread if none given */
if (!CsrThread) CsrThread = CurrentThread;
/* Still no thread, something is wrong */
if (!CsrThread)
{
/* Failure */
return FALSE;
}
/* Make the call */
Status = NtImpersonateThread(NtCurrentThread(),
CsrThread->ThreadHandle,
&CsrSecurityQos);
if (!NT_SUCCESS(Status))
{
/* Failure */
return FALSE;
}
/* Increase the impersonation count for the current thread */
if (CurrentThread) ++CurrentThread->ImpersonationCount;
/* Return Success */
return TRUE;
}
BOOLEAN
NTAPI
CsrRevertToSelf(VOID)
{
NTSTATUS Status;
PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
HANDLE ImpersonationToken = NULL;
/* Check if we have a Current Thread */
if (CurrentThread)
{
/* Make sure impersonation is on */
if (!CurrentThread->ImpersonationCount)
{
return FALSE;
}
else if (--CurrentThread->ImpersonationCount > 0)
{
/* Success; impersonation count decreased but still not zero */
return TRUE;
}
}
/* Impersonation has been totally removed, revert to ourselves */
Status = NtSetInformationThread(NtCurrentThread(),
ThreadImpersonationToken,
&ImpersonationToken,
sizeof(HANDLE));
/* Return TRUE or FALSE */
return NT_SUCCESS(Status);
}
PCSRSS_PROCESS_DATA
NTAPI
FindProcessForShutdown(IN PLUID CallerLuid)
{
ULONG Hash;
PCSRSS_PROCESS_DATA CsrProcess, ReturnCsrProcess = NULL;
NTSTATUS Status;
ULONG Level = 0;
LUID ProcessLuid;
LUID SystemLuid = SYSTEM_LUID;
BOOLEAN IsSystemLuid = FALSE, IsOurLuid = FALSE;
for (Hash = 0; Hash < (sizeof(ProcessData) / sizeof(*ProcessData)); Hash++)
{
/* Get this process hash bucket */
CsrProcess = ProcessData[Hash];
while (CsrProcess)
{
/* Skip this process if it's already been processed*/
if (CsrProcess->Flags & CsrProcessSkipShutdown) goto Next;
/* Get the LUID of this Process */
Status = CsrGetProcessLuid(CsrProcess->Process, &ProcessLuid);
/* Check if we didn't get access to the LUID */
if (Status == STATUS_ACCESS_DENIED)
{
/* FIXME:Check if we have any threads */
}
if (!NT_SUCCESS(Status))
{
/* We didn't have access, so skip it */
CsrProcess->Flags |= CsrProcessSkipShutdown;
goto Next;
}
/* Check if this is the System LUID */
if ((IsSystemLuid = RtlEqualLuid(&ProcessLuid, &SystemLuid)))
{
/* Mark this process */
CsrProcess->ShutdownFlags |= CsrShutdownSystem;
}
else if (!(IsOurLuid = RtlEqualLuid(&ProcessLuid, CallerLuid)))
{
/* Our LUID doesn't match with the caller's */
CsrProcess->ShutdownFlags |= CsrShutdownOther;
}
/* Check if we're past the previous level */
if (CsrProcess->ShutdownLevel > Level)
{
/* Update the level */
Level = CsrProcess->ShutdownLevel;
/* Set the final process */
ReturnCsrProcess = CsrProcess;
}
Next:
/* Next process */
CsrProcess = CsrProcess->next;
}
}
/* Check if we found a process */
if (ReturnCsrProcess)
{
/* Skip this one next time */
ReturnCsrProcess->Flags |= CsrProcessSkipShutdown;
}
return ReturnCsrProcess;
}
/* This is really "CsrShutdownProcess", mostly */
NTSTATUS
WINAPI
CsrEnumProcesses(IN CSRSS_ENUM_PROCESS_PROC EnumProc,
IN PVOID Context)
{
PVOID* RealContext = (PVOID*)Context;
PLUID CallerLuid = RealContext[0];
PCSRSS_PROCESS_DATA CsrProcess = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
BOOLEAN FirstTry;
ULONG Result = 0;
ULONG Hash;
/* Acquire process lock */
CsrAcquireProcessLock();
/* Start the loop */
for (Hash = 0; Hash < (sizeof(ProcessData) / sizeof(*ProcessData)); Hash++)
{
/* Get the Process */
CsrProcess = ProcessData[Hash];
while (CsrProcess)
{
/* Remove the skip flag, set shutdown flags to 0*/
CsrProcess->Flags &= ~CsrProcessSkipShutdown;
CsrProcess->ShutdownFlags = 0;
/* Move to the next */
CsrProcess = CsrProcess->next;
}
}
/* 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->ProcessId);
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;
}
NTSTATUS
NTAPI
CsrLockProcessByClientId(IN HANDLE Pid,
OUT PCSRSS_PROCESS_DATA *CsrProcess OPTIONAL)
{
ULONG Hash;
PCSRSS_PROCESS_DATA CurrentProcess = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
/* Acquire the lock */
CsrAcquireProcessLock();
/* Start the loop */
for (Hash = 0; Hash < (sizeof(ProcessData) / sizeof(*ProcessData)); Hash++)
{
/* Get the Process */
CurrentProcess = ProcessData[Hash];
while (CurrentProcess)
{
/* Check for PID match */
if (CurrentProcess->ProcessId == Pid)
{
/* Get out of here with success */
// DPRINT1("Found %p for PID %lx\n", CurrentProcess, Pid);
Status = STATUS_SUCCESS;
goto Found;
}
/* Move to the next */
CurrentProcess = CurrentProcess->next;
}
}
/* Nothing found, release the lock */
Found:
if (!CurrentProcess) CsrReleaseProcessLock();
/* Return the status and process */
if (CsrProcess) *CsrProcess = CurrentProcess;
return Status;
}
NTSTATUS
NTAPI
CsrUnlockProcess(IN PCSRSS_PROCESS_DATA CsrProcess)
{
/* Dereference the process */
//CsrLockedDereferenceProcess(CsrProcess);
/* Release the lock and return */
CsrReleaseProcessLock();
return STATUS_SUCCESS;
}
/* EOF */