Example #1
0
/*++
 * @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;
    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)
        {
            /* 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);
                if (CsrImpersonateClient(CsrThread))
                {
                    Status = CsrGetProcessLuid(NULL, &ProcessLuid);
                    CsrRevertToSelf();
                }
                else
                {
                    Status = STATUS_BAD_IMPERSONATION_LEVEL;
                }
            }
        }

        if (!NT_SUCCESS(Status))
        {
            /* We didn't have access, so skip it */
            CsrProcess->Flags |= CsrProcessSkipShutdown;
            continue;
        }

        /* Check if this is the System LUID */
        if (RtlEqualLuid(&ProcessLuid, &SystemLuid))
        {
            /* Mark this process */
            CsrProcess->ShutdownFlags |= CsrShutdownSystem;
        }
        else if (!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) || !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;
}
Example #2
0
NTSTATUS _ExitWindowsEx(
    PCSR_THREAD pcsrt,
    UINT dwFlags,
    DWORD dwReserved)
{
    BOOL fDoEndSession = FALSE;
    LUID luidCaller;
    NTSTATUS Status = STATUS_SUCCESS;
    UNREFERENCED_PARAMETER(dwReserved);

    if ((dwFlags & EWX_REBOOT) || (dwFlags & EWX_POWEROFF)) {
        dwFlags |= EWX_SHUTDOWN;
    }

    /*
     * Find out the callers sid. Only want to shutdown processes in the
     * callers sid.
     */
    if (!CsrImpersonateClient(NULL)) {
        return STATUS_BAD_IMPERSONATION_LEVEL;
    }

    Status = CsrGetProcessLuid(NULL, &luidCaller);

    if (!NT_SUCCESS(Status)) {
        CsrRevertToSelf();
        return Status;
    }

    try {

        while (1) {
            LARGE_INTEGER li;

            LeaveCrit();
            Status = NtUserSetInformationThread(
                    pcsrt->ThreadHandle,
                    UserThreadInitiateShutdown,
                    &dwFlags, sizeof(dwFlags));
            EnterCrit();
            switch (Status) {
            case STATUS_PENDING:

                /*
                 * The logoff/shutdown is in progress and nothing
                 * more needs to be done.
                 */
                goto fastexit;

            case STATUS_RETRY:

                /*
                 * Another logoff/shutdown is in progress and we need
                 * to cancel it so we can do an override.
                 *
                 * if someone else is trying to cancel shutdown, exit
                 */
                li.QuadPart  = 0;
                if (NtWaitForSingleObject(heventCancel, FALSE, &li) == 0) {
                    Status = STATUS_PENDING;
                    goto fastexit;
                }

                /*
                 * Cancel the old shutdown
                 */
                NtClearEvent(heventCancelled);
                NtSetEvent(heventCancel, NULL);

                /*
                 * Wait for the other guy to be cancelled
                 */
                LeaveCrit();
                NtWaitForSingleObject(heventCancelled, FALSE, NULL);
                EnterCrit();

                /*
                 * This signals that we are no longer trying to cancel a
                 * shutdown
                 */
                NtClearEvent(heventCancel);
                continue;

            case STATUS_CANT_WAIT:

                /*
                 * There is no notify window and the calling thread has
                 * windows that prevent this request from succeeding.
                 * The client handles this by starting another thread
                 * to recall ExitWindowsEx.
                 */
                goto fastexit;

            default:
                if (!NT_SUCCESS(Status))
                    goto fastexit;
            }
            break;
        }

        gdwFlags = dwFlags;
        dwThreadEndSession = (DWORD)pcsrt->ClientId.UniqueThread;
        fDoEndSession = TRUE;

        /*
         * Sometimes the console calls the dialog box when not in shutdown
         * if now is one of those times cancel the dialog box.
         */
        while (gcInternalDoEndTaskDialog > 0) {
            LARGE_INTEGER li;

            NtPulseEvent(heventCancel, NULL);

            LeaveCrit();
            li.QuadPart = (LONGLONG)-10000 * CMSSLEEP;
            NtDelayExecution(FALSE, &li);
            EnterCrit();
        }

        /*
         * Call csr to loop through the processes shutting them down.
         */
        LeaveCrit();
        Status = CsrShutdownProcesses(&luidCaller, dwFlags);

        NtUserSetInformationThread(
                pcsrt->ThreadHandle,
                UserThreadEndShutdown, &Status, sizeof(Status));
        EnterCrit();
fastexit:;
    } finally {
        /*
         * Only turn off dwThreadEndSession if this is the
         * thread doing shutdown.
         */
        if (fDoEndSession) {
            dwThreadEndSession = 0;
            NtSetEvent(heventCancelled, NULL);
        }
    }

    CsrRevertToSelf();

    return Status;
}