/* * 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 #define NDEBUG #include #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 */