Beispiel #1
0
BOOL WowExitTask(
    PCSR_THREAD pcsrt)
{
    HANDLE ahandle[2];
    USERTHREAD_WOW_INFORMATION WowInfo;
    NTSTATUS Status;

    ahandle[1] = heventCancel;

    /*
     * Query task id and exit function.
     */
    LeaveCrit();
    Status = NtUserQueryInformationThread(pcsrt->ThreadHandle,
            UserThreadWOWInformation, &WowInfo, sizeof(WowInfo), NULL);
    EnterCrit();
    if (!NT_SUCCESS(Status))
        return FALSE;

    /*
     * If no task id was returned, it is not a WOW task
     */
    if (WowInfo.hTaskWow == 0)
        return FALSE;

    /*
     * The created thread needs to be able to reenter user because this
     * call will grab the CSR critical section and whoever has that
     * may need to grab the USER critical section before it can
     * release it.
     */
    LeaveCrit();

    /*
     * Try to make it exit itself. This will work most of the time.
     * If this doesn't work, terminate this process.
     */
    ahandle[0] = InternalCreateCallbackThread(pcsrt->Process->ProcessHandle,
                                              (DWORD)WowInfo.lpfnWowExitTask,
                                              (DWORD)WowInfo.hTaskWow);
    if (ahandle[0] == NULL) {
        NtTerminateProcess(pcsrt->Process->ProcessHandle, 0);
        pcsrt->Process->Flags |= CSR_PROCESS_TERMINATED;
        goto Exit;
    }

    WaitForMultipleObjects(2, ahandle, FALSE, INFINITE);
    NtClose(ahandle[0]);

Exit:
    EnterCrit();
    return TRUE;
}
Beispiel #2
0
int DoEndTaskDialog(
    WCHAR* pszTitle,
    HANDLE h,
    UINT type,
    int cSeconds)
{
    int result;
    ENDDLGPARAMS edp;

    if (gfAutoEndTask)
        return IDABORT;

    edp.pszTitle = pszTitle;
    edp.h = h;
    edp.type = type;
    edp.cSeconds = cSeconds;

    LeaveCrit();
    result = DialogBoxParam(hModuleWin,
                            MAKEINTRESOURCE(IDD_ENDTASK),
                            NULL,
                            EndTaskDlgProc,
                            (DWORD)(&edp));
    EnterCrit();

    return result;
}
Beispiel #3
0
void PH_DumpInternalReal(CommonBuffer * common, ThreadBuffer * thread, BOOL toDisk)
{
    // Same as before, just unrolled to prevent doing this outer level if check a bunch of times inside the loop
    // This is used by the Buddhabrot render
    while (thread->left < thread->total)
    {
        int count;
        int level;
        double a;
        double b;
        double c;

        TD_GET(int, count);
        TD_GET(int, level);
        TD_GET(double, a);
        TD_GET(double, b);
        TD_GET(double, c);

#ifdef USE_CRIT_SECTION
        EnterCrit();
#endif

        while (count > 0)
        {
            unsigned long long xy;
            TD_GET(unsigned long long, xy);

#ifdef USE_CRIT_SECTION
            common->m_levelsData[xy]++;

            common->m_levelsPlotReal[xy] += a;
            common->m_levelsPlotImaginary[xy] += b;
#else
            for (;;)
            {
                LONGLONG levelsData = InterlockedExchangeNoFence64((LONGLONG*)&common->m_levelsData[xy], OWNED_VALUE);
                if (levelsData != OWNED_VALUE)
                {
                    levelsData++;
                    common->m_levelsPlotReal[xy] += a;
                    common->m_levelsPlotImaginary[xy] += b;
                    InterlockedExchangeNoFence64((LONGLONG*)&common->m_levelsData[xy], levelsData);
                    break;
                }
            }
#endif

            count--;
        }

#ifdef USE_CRIT_SECTION
        LeaveCrit();
#endif
    }
}
Beispiel #4
0
void PH_DumpInternalLevel(CommonBuffer * common, ThreadBuffer * thread, BOOL toDisk)
{
    // And same as the other three if clauses, but only store level data.  This is for a simple B/W 
    // Mandelbrot render

    while (thread->left < thread->total)
    {
        int count;
        int level;
        double a;
        double b;
        double c;

        TD_GET(int, count);
        TD_GET(int, level);
        TD_GET(double, a);
        TD_GET(double, b);
        TD_GET(double, c);

#ifdef USE_CRIT_SECTION
        EnterCrit();
#endif

        while (count > 0)
        {
            unsigned long long xy;
            TD_GET(unsigned long long, xy);

#ifdef USE_CRIT_SECTION
            common->m_levelsData[xy]++;
#else
            // This is different than the other clauses.  No need to 'own' a 
            // pixel here, we can just increment the value directly using 
            // InterlockedIncrement since we won't be touching anything else
            InterlockedIncrementNoFence((ULONGLONG*)&common->m_levelsData[xy]);
#endif

            count--;
        }

#ifdef USE_CRIT_SECTION
        LeaveCrit();
#endif
    }
}
Beispiel #5
0
int InternalDoEndTaskDialog(
    TCHAR* pszTitle,
    HANDLE h,
    int cSeconds)
{
    int iRet;

    EnterCrit();

    gcInternalDoEndTaskDialog++;

    try {
        iRet = DoEndTaskDialog(pszTitle, h, TYPE_CONSOLE_ID, cSeconds);
    } finally {
        gcInternalDoEndTaskDialog--;
    }

    LeaveCrit();

    return iRet;
}
Beispiel #6
0
VOID UserRedrawDesktop(VOID)
{
    TL   tlpwnd;
    PWND pwndDesk;

    EnterCrit();

    pwndDesk = PtiCurrent()->rpdesk->pDeskInfo->spwnd;

    ThreadLockAlways(pwndDesk, &tlpwnd);

    xxxInternalInvalidate(pwndDesk,
                          HRGN_FULL,
                          RDW_INVALIDATE |
                              RDW_ERASE  |
                              RDW_FRAME  |
                              RDW_ALLCHILDREN);

    ThreadUnlock(&tlpwnd);

    LeaveCrit();
}
Beispiel #7
0
NTSTATUS UserServerDllInitialization(
    PCSR_SERVER_DLL psrvdll)
{
    CLIENT_ID ClientId;
    DWORD cbAllocated;
    NTSTATUS Status;
    int i;

    /*
     * Initialize a critical section structure that will be used to protect
     * all of the User Server's critical sections (except a few special
     * cases like the RIT -- see below).
     */
    RtlInitializeCriticalSection(&gcsUserSrv);
    EnterCrit(); // synchronize heap calls

    /*
     * Remember WINSRV.DLL's hmodule so we can grab resources from it later.
     */
    hModuleWin = psrvdll->ModuleHandle;

    psrvdll->ApiNumberBase = USERK_FIRST_API_NUMBER;
    psrvdll->MaxApiNumber = UserpMaxApiNumber;
    psrvdll->ApiDispatchTable = UserServerApiDispatchTable;
    psrvdll->ApiServerValidTable = UserServerApiServerValidTable;
#if DBG
    psrvdll->ApiNameTable = UserServerApiNameTable;
#else
    psrvdll->ApiNameTable = NULL;
#endif
    psrvdll->PerProcessDataLength   = CHANDLES * sizeof(HANDLE);
    psrvdll->PerThreadDataLength    = 0;
    psrvdll->ConnectRoutine         = UserClientConnect;
    psrvdll->DisconnectRoutine      = UserClientDisconnect;
    psrvdll->HardErrorRoutine       = UserHardError;
    psrvdll->ShutdownProcessRoutine = UserClientShutdown;

    /*
     * Create these events used by shutdown
     */
    NtCreateEvent(&heventCancel, EVENT_ALL_ACCESS, NULL,
                  NotificationEvent, FALSE);
    NtCreateEvent(&heventCancelled, EVENT_ALL_ACCESS, NULL,
                  NotificationEvent, FALSE);

    /*
     * Tell the base what user address to call when it is creating a process
     * (but before the process starts running).
     */
    BaseSetProcessCreateNotify(NtUserNotifyProcessCreate);

    /*
     * Set up translation tables.
     */
    InitOemXlateTables();

    /*
     * Get timeout values from registry
     */
    GetTimeouts();

    /*
     * Load some strings.
     */
    pszaSUCCESS            = (LPSTR)RtlLoadStringOrError(hModuleWin,
                                STR_SUCCESS, NULL, &cbAllocated, TRUE);
    pszaSYSTEM_INFORMATION = (LPSTR)RtlLoadStringOrError(hModuleWin,
                                STR_SYSTEM_INFORMATION, NULL, &cbAllocated, TRUE);
    pszaSYSTEM_WARNING     = (LPSTR)RtlLoadStringOrError(hModuleWin,
                                STR_SYSTEM_WARNING, NULL, &cbAllocated, TRUE);
    pszaSYSTEM_ERROR       = (LPSTR)RtlLoadStringOrError(hModuleWin,
                                STR_SYSTEM_ERROR, NULL, &cbAllocated, TRUE);

    /*
     * Add marlett font and make it permanent
     */
    i = GdiAddFontResourceW(L"marlett.ttf", AFRW_ADD_LOCAL_FONT);

    /*
     * Initialize USER
     */
    {
        HANDLE hModBase;

        LeaveCrit();
        hModBase = GetModuleHandle(TEXT("kernel32"));
        EnterCrit();
        UserAssert(hModBase);
        gpfnAttachRoutine = GetProcAddress(hModBase,"BaseAttachCompleteThunk");
        UserAssert(gpfnAttachRoutine);

        Status = NtUserInitialize(USERCURRENTVERSION, gpfnAttachRoutine);
        if (!NT_SUCCESS(Status)) {
            goto ExitUserInit;
        }
    }

    /*
     * Start registry notification thread
     */
    Status = RtlCreateUserThread(NtCurrentProcess(), NULL, FALSE, 0, 0, 4*0x1000,
            (PUSER_THREAD_START_ROUTINE)NotificationThread, NULL, &hThreadNotification,
            &ClientId);
    CsrAddStaticServerThread(hThreadNotification, &ClientId, 0);

ExitUserInit:
    LeaveCrit();
    return Status;
}
Beispiel #8
0
BOOL xxxActivateDebugger(
    UINT fsModifiers)
{
    ULONG ArgLength;
    USER_API_MSG m;
    PACTIVATEDEBUGGERMSG a = &m.u.ActivateDebugger;
    PEPROCESS Process;
    HANDLE hDebugPort;
    NTSTATUS Status;

    if (fsModifiers & MOD_CONTROL) {
#ifdef DEBUG
        if (RipOutput(0, RIP_WARNING, "User debugger", 0, "Debug prompt", NULL)) {
            DbgBreakPoint();
        }
#endif
        return FALSE;
    } else if (fsModifiers & MOD_SHIFT) {

        /*
         * Bail out if the process is not being debugged.
         */
        if (gpepCSRSS->DebugPort == NULL)
            return FALSE;

        a->ClientId.UniqueProcess = gpepCSRSS->UniqueProcessId;
    } else {

        if ((gpqForeground == NULL) || (gpqForeground->ptiKeyboard == NULL))
            return FALSE;

        a->ClientId = gpqForeground->ptiKeyboard->Thread->Cid;

        /*
         * Bail out if the process is not being debugged.
         */
        if (!NT_SUCCESS(LockProcessByClientId(a->ClientId.UniqueProcess,
                &Process)))
            return FALSE;
        hDebugPort = Process->DebugPort;
        UnlockProcess(Process);

        if (hDebugPort == NULL)
            return FALSE;
    }

    /*
     * Send the datagram to CSR
     */
    if (CsrApiPort != NULL) {
        ArgLength = sizeof(*a);
        ArgLength |= (ArgLength << 16);
        ArgLength +=     ((sizeof( CSR_API_MSG ) - sizeof( m.u )) << 16) |
                        (FIELD_OFFSET( CSR_API_MSG, u ) - sizeof( m.h ));
        m.h.u1.Length = ArgLength;
        m.h.u2.ZeroInit = 0;
        m.CaptureBuffer = NULL;
        m.ApiNumber = CSR_MAKE_API_NUMBER( USERSRV_SERVERDLL_INDEX,
                                           UserpActivateDebugger);
        LeaveCrit();
        Status = LpcRequestPort(CsrApiPort, (PPORT_MESSAGE)&m);
        EnterCrit();
        UserAssert(NT_SUCCESS(Status));
    }

    /*
     * Don't eat this event unless we are breaking into CSR! Since we have
     * choosen an arbitrary hot key like F12 for the debug key, we need to
     * pass on the key to the application, or apps that want this key would
     * never see it. If we had an api for installing a debug hot key
     * (export or MOD_DEBUG flag to RegisterHotKey()), then it would be ok
     * to eat because the user selected the hot key. But it is not ok to
     * eat it as long as we've picked an arbitrary hot key. scottlu.
     */
    if (fsModifiers & MOD_SHIFT)
        return TRUE;
    else
        return FALSE;
}
Beispiel #9
0
NTSTATUS EndShutdown(
    PETHREAD Thread,
    NTSTATUS StatusShutdown)
{
    PWINDOWSTATION pwinsta = gpwinstaLogoff;
    PDESKTOP pdesk;
    LUID luidCaller;

    UserAssert(gpwinstaLogoff);

    gpwinstaLogoff = NULL;
    dwThreadEndSession = 0;
    pwinsta->dwFlags &= ~WSF_SHUTDOWN;

    if (!NT_SUCCESS(GetProcessLuid(Thread, &luidCaller))) {
        luidCaller = RtlConvertUlongToLuid(0);     // null luid
    }

    if (!NT_SUCCESS(StatusShutdown)) {

        /*
         * We need to notify the process that called ExitWindows that
         * the logoff was aborted.
         */
        if (gptiShutdownNotify) {
            _PostThreadMessage(gptiShutdownNotify, WM_ENDSESSION, FALSE, 0);
            gptiShutdownNotify = NULL;
        }

        /*
         * Reset the windowstation lock flags so apps can start
         * again.
         */
        pwinsta->dwFlags =
                (pwinsta->dwFlags & ~WSF_OPENLOCK) |
                gdwLocks;

        return STATUS_SUCCESS;
    }

    gptiShutdownNotify = NULL;

    /*
     * If logoff is occuring for the user set by winlogon, perform
     * the normal logoff cleanup.  Otherwise, clear the open lock
     * and continue.
     */
    if (((pwinsta->luidUser.LowPart != 0) || (pwinsta->luidUser.HighPart != 0)) &&
            RtlEqualLuid(&pwinsta->luidUser, &luidCaller)) {

        /*
         * Save the current user's NumLock state
         */
        if (FastOpenProfileUserMapping()) {
            RegisterPerUserKeyboardIndicators();
            FastCloseProfileUserMapping();
        }

        /*
         * Zero out the free blocks in all desktop heaps.
         */
        for (pdesk = pwinsta->rpdeskList; pdesk != NULL; pdesk = pdesk->rpdeskNext) {
            RtlZeroHeap(pdesk->hheapDesktop, 0);
        }

        /*
         * Logoff/shutdown was successful. In case this is a logoff, remove
         * everything from the clipboard so the next logged on user can't get
         * at this stuff.
         */
        ForceEmptyClipboard(pwinsta);

        /*
         * Destroy all non-pinned atoms in the global atom table.  User can't
         * create pinned atoms.  Currently only the OLE atoms are pinned.
         */
        RtlEmptyAtomTable(pwinsta->pGlobalAtomTable, FALSE);

        // this code path is hit only on logoff and also on shutdown
        // We do not want to unload fonts twice when we attempt shutdown
        // so we mark that the fonts have been unloaded at a logoff time

        if (bFontsAreLoaded) {
            LeaveCrit();
            GreRemoveAllButPermanentFonts();
            EnterCrit();
            bFontsAreLoaded = FALSE;
        }
    } else {
        pwinsta->dwFlags &= ~WSF_OPENLOCK;
    }

    /*
     * Tell winlogon that we successfully shutdown/logged off.
     */
    NotifyLogon(pwinsta, &luidCaller, gdwShutdownFlags);

    return STATUS_SUCCESS;
}
Beispiel #10
0
void PH_DumpInternalRealImOther(CommonBuffer * common, ThreadBuffer * thread, BOOL toDisk)
{
    // While there's data
    while (thread->left < thread->total)
    {
        int count;
        int level;
        double a;
        double b;
        double c;

        // Get the value to apply
        TD_GET(int, count);
        TD_GET(int, level);
        TD_GET(double, a);
        TD_GET(double, b);
        TD_GET(double, c);

#ifdef USE_CRIT_SECTION
        EnterCrit();
#endif

        // And for each point to apply it to
        while (count > 0)
        {
            // Get the index of the point in question
            unsigned long long xy;
            TD_GET(unsigned long long, xy);

            // Note: in each of these we're adding the final exit point of the point trail to each point along the point trail
            // For Mandelbrot renders, this just means we're storing RGB values
            // For Buddhabrot renders this lets us determine which 'direction' each of those points averages 
            // out to, for coloring purposes. 
            // In either case the level data lets us know how often it was 'hit', for brightness purposes.

#ifdef USE_CRIT_SECTION
            // The critical section version is easy, just enter the critical section
            // And update the memory
            common->m_levelsData[xy]++;

            common->m_levelsPlotReal[xy] += a;
            common->m_levelsPlotImaginary[xy] += b;
            common->m_levelsPlotOther[xy] += c;
#else
            // The interlocked version is quicker, but odder
            for (;;)
            {
                // Set the levels data to the OWNED_VALUE sentinel value
                LONGLONG levelsData = InterlockedExchangeNoFence64((LONGLONG*)&common->m_levelsData[xy], OWNED_VALUE);

                // Was the value that was already in memory not owned by another thread
                if (levelsData != OWNED_VALUE)
                {
                    // It was!  Go ahead and add one to the number of levels, and update
                    // the other values as necessary
                    levelsData++;
                    common->m_levelsPlotReal[xy] += a;
                    common->m_levelsPlotImaginary[xy] += b;
                    common->m_levelsPlotOther[xy] += c;

                    // And we're done, so put the correct value back in memory, we no longer "own"
                    // this pixel now
                    InterlockedExchangeNoFence64((LONGLONG*)&common->m_levelsData[xy], levelsData);
                    break;
                }
            }
#endif

            count--;
        }

#ifdef USE_CRIT_SECTION
        LeaveCrit();
#endif
    }
}
Beispiel #11
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;
}
Beispiel #12
0
DWORD MySendEndSessionMessages(
    HWND hwnd,
    PCSR_THREAD pcsrt,
    BOOL fEndTask,
    DWORD dwClientFlags)
{
    HWND hwndOwner;
    LARGE_INTEGER li;
    DWORD dwRet;
    int cLoops;
    int cSeconds;
    WCHAR achName[CCHBODYMAX];
    BOOL fPostedClose;
    BOOL fDialogFirst;
    DWORD dwFlags;
    DWORD dwHungApp;
    HANDLE hNull = NULL;
    NTSTATUS Status;

    /*
     * We've got a random top level window for this application. Find the
     * root owner, because that's who we want to send the WM_CLOSE to.
     */
    while ((hwndOwner = GetWindow(hwnd, GW_OWNER)) != NULL)
        hwnd = hwndOwner;

    /*
     * We expect this application to process this shutdown request,
     * so make it the foreground window so it has foreground priority.
     * This won't leave the critical section.
     */
    SetForegroundWindow(hwnd);

    /*
     * Send the WM_CLIENTSHUTDOWN message for end-session. When the app
     * receives this, it'll then get WM_QUERYENDSESSION and WM_ENDSESSION
     * messages.
     */
    if (!fEndTask) {
        USERTHREAD_FLAGS Flags;

        Flags.dwFlags = 0;
        Flags.dwMask = (TIF_SHUTDOWNCOMPLETE | TIF_ALLOWSHUTDOWN);
        LeaveCrit();
        Status = NtUserSetInformationThread(pcsrt->ThreadHandle,
                UserThreadFlags, &Flags, sizeof(Flags));
        EnterCrit();
        if (!NT_SUCCESS(Status))
            return CMDEND_APPSAYSOK;

        SendNotifyMessage(hwnd, WM_CLIENTSHUTDOWN, dwClientFlags, 0);
    }

    /*
     * If the main window is disabled, bring up the end-task window first,
     * right away, only if this the WM_CLOSE case.
     */
    fDialogFirst = FALSE;
    if (fEndTask && (GetWindowLong(hwnd, GWL_STYLE) & WS_DISABLED))
        fDialogFirst = TRUE;

    fPostedClose = FALSE;
    while (TRUE) {
        if (fEndTask) {
            cLoops   = (CMSHUNGAPPTIMEOUT / CMSSLEEP);
            cSeconds = (CMSHUNGAPPTIMEOUT / 1000);
        }
        else {
            cLoops   = (CMSWAITTOKILLTIMEOUT / CMSSLEEP);
            cSeconds = (CMSWAITTOKILLTIMEOUT / 1000);
        }

        /*
         * If end-task and not shutdown, must give this app a WM_CLOSE
         * message. Can't do this if it has a dialog up because it is in
         * the wrong processing loop. We detect this by seeing if the window
         * is disabled - if it is, we don't send it a WM_CLOSE and instead
         * bring up the end task dialog right away (this is exactly compatible
         * with win3.1 taskmgr.exe).
         */
        if (fEndTask) {
            if (!fPostedClose && IsWindow(hwnd) &&
                    !(GetWindowLong(hwnd, GWL_STYLE) & WS_DISABLED)) {
                PostMessage(hwnd, WM_CLOSE, 0, 0L);
                fPostedClose = TRUE;
            }
        }

        /*
         * Every so often wake up to see if the app is hung, and if not go
         * back to sleep until we've run through our timeout.
         */
        while (cLoops--) {
            /*
             * If a WM_QUERY/ENDSESSION has been answered to, return.
             */
            if (!fEndTask) {
                LeaveCrit();
                NtUserQueryInformationThread(pcsrt->ThreadHandle,
                        UserThreadFlags, &dwFlags, sizeof(DWORD), NULL);
                EnterCrit();
                if (dwFlags & TIF_SHUTDOWNCOMPLETE) {
                    if (dwFlags & TIF_ALLOWSHUTDOWN)
                        return CMDEND_APPSAYSOK;
                    return CMDEND_APPSAYSNOTOK;
                }
            }

            /*
             * If the thread is gone, we're done.
             */
            if (pcsrt->Flags & CSR_THREAD_DESTROYED) {
                return CMDEND_APPSAYSOK;
            }

            /*
             * If the dialog should be brought up first (because the window
             * was initially disabled), do it.
             */
            if (fDialogFirst) {
                fDialogFirst = FALSE;
                break;
            }

            /*
             * if we we're externally cancelled get out
             */
            li.QuadPart = 0;
            if (NtWaitForSingleObject(heventCancel, FALSE, &li) == 0) {

                /*
                 * !!! JimA - We may want to call the kernel to
                 * set TIF_SHUTDOWNCOMPLETE in this case.
                 */
                return CMDEND_USERSAYSCANCEL;
            }

            /*
             * If hung, bring up the endtask dialog right away.
             */
            dwHungApp = (fEndTask ? CMSHUNGAPPTIMEOUT : CMSWAITTOKILLTIMEOUT);
            LeaveCrit();
            Status = NtUserQueryInformationThread(pcsrt->ThreadHandle,
                    UserThreadHungStatus, &dwHungApp, sizeof(dwHungApp), NULL);
            EnterCrit();
            if (!NT_SUCCESS(Status) || dwHungApp == TRUE)
                break;

            /*
             * Sleep for a second.
             */
            LeaveCrit();
            li.QuadPart = (LONGLONG)-10000 * CMSSLEEP;
            NtDelayExecution(FALSE, &li);
            EnterCrit();
        }

        achName[0] = 0;
        if (IsWindow(hwnd)) {
            GetWindowText(hwnd, achName, CCHMSGMAX);
        }

        /*
         * If there's a hard error, put it on top.
         */
        BoostHardError((DWORD)pcsrt->ClientId.UniqueProcess, FALSE);

        if (achName[0] == 0) {

            /*
             * If the thread is gone, we're done.
             */
            if (pcsrt->Flags & CSR_THREAD_DESTROYED) {
                return CMDEND_APPSAYSOK;
            }

            /*
             * pti is valid right now. Use the name in the pti.
             */
            LeaveCrit();
            NtUserQueryInformationThread(pcsrt->ThreadHandle,
                    UserThreadTaskName, achName, CCHMSGMAX * sizeof(WCHAR),
                    NULL);
            EnterCrit();
        }

        /*
         * Set this thread to use the desktop of the
         * thread being shutdown.
         */
        if (NT_SUCCESS(NtUserSetInformationThread(NtCurrentThread(),
                UserThreadUseDesktop, &pcsrt->ThreadHandle, sizeof(HANDLE)))) {

            /*
             * Bring up the dialog
             */
            dwRet = DoEndTaskDialog(achName, pcsrt,
                                        TYPE_THREADINFO, cSeconds);

            /*
             * Release the desktop that was used.
             */
            NtUserSetInformationThread(NtCurrentThread(), UserThreadUseDesktop,
                    &hNull, sizeof(HANDLE));
        } else {

            /*
             * We were unable to get the thread's desktop.  All we
             * can do is kill the task.
             */
            dwRet = IDABORT;
        }

        switch(dwRet) {
        case IDCANCEL:
            /*
             * Cancel the shutdown process... Get out of here. Signify that
             * we're cancelling the shutdown request.
             *
             * !!! JimA - We may want to call the kernel to
             * set TIF_SHUTDOWNCOMPLETE in this case.
             */
            return CMDEND_USERSAYSCANCEL;
            break;

        case IDABORT:
            /*
             * End this guy's task...
             */
            BoostHardError((DWORD)pcsrt->ClientId.UniqueProcess, TRUE);

            /*
             * !!! JimA - We may want to call the kernel to
             * set TIF_SHUTDOWNCOMPLETE in this case.
             */
            return CMDEND_USERSAYSKILL;
            break;

        case IDRETRY:
            /*
             * Just continue to wait. Reset this app so it doesn't think it's
             * hung. This'll cause us to wait again.
             */
            if (!(pcsrt->Flags & CSR_THREAD_DESTROYED)) {
                LeaveCrit();
                NtUserSetInformationThread(pcsrt->ThreadHandle,
                        UserThreadHungStatus, NULL, 0);
                EnterCrit();
            }
            fPostedClose = FALSE;
            break;
        }
    }
}
Beispiel #13
0
NTSTATUS UserClientShutdown(
    PCSR_PROCESS pcsrp,
    ULONG dwFlags,
    BOOLEAN fFirstPass)
{
    PLIST_ENTRY ListHead, ListNext;
    PCSR_PROCESS Process;
    PCSR_THREAD Thread;
    USERTHREAD_SHUTDOWN_INFORMATION ShutdownInfo;
    BOOL fNoRetry;
    DWORD cmd, dwClientFlags;
    NTSTATUS Status;
    UINT cThreads;
    BOOL fSendEndSession = FALSE;

    /*
     * If this is a logoff and the process does not belong to
     * the account doing the logoff and is not LocalSystem,
     * do not send end-session messages.  Console will notify
     * the app of the logoff.
     */
    if (!(dwFlags & EWX_SHUTDOWN) && (pcsrp->ShutdownFlags & SHUTDOWN_OTHERCONTEXT))
        return SHUTDOWN_UNKNOWN_PROCESS;

    /*
     * Calculate whether to allow exit and force-exit this process before
     * we unlock pcsrp.
     */
    fNoRetry = (pcsrp->ShutdownFlags & SHUTDOWN_NORETRY) ||
            (dwFlags & EWX_FORCE);

    /*
     * Setup flags for WM_CLIENTSHUTDOWN
     * -Assume the process is going to OK the WM_QUERYENDSESSION (WMCS_EXIT)
     * -NT's shutdown always starts with a logoff.
     * -Shutdown or logoff? (WMCS_SHUTDOWN)
     * -is this process in the context being logged off? (WMCS_CONTEXTLOGOFF)
     */
    dwClientFlags = WMCS_EXIT | WMCS_LOGOFF;
    if (dwFlags & EWX_SHUTDOWN) {
        /*
         * Apps will never see this set because shutdown starts with a logoff;
         * later the actual shutdown uses EWX_FORCE so WM_CLIENTSHUTDOWN is not sent.
         * If we need apps to see this when we're about to shutdown, then we should
         * check for (dwFlags & (EWX_WINLOGON_OLD_REBOOT | EWX_WINLOGON_OLD_SHUTDOWN))
         * (EWX_WINLOGON_OLD_* corresponds to the original request)
         */
        dwClientFlags |= WMCS_SHUTDOWN;
    }
    if (!(pcsrp->ShutdownFlags & (SHUTDOWN_SYSTEMCONTEXT | SHUTDOWN_OTHERCONTEXT))) {
        dwClientFlags |= WMCS_CONTEXTLOGOFF;
    }


    /*
     * Lock the process while we walk the thread list.  We know
     * that the process is valid and therefore do not need to
     * check the return status.
     */
    CsrLockProcessByClientId(pcsrp->ClientId.UniqueProcess, &Process);

    EnterCrit();

    ShutdownInfo.StatusShutdown = SHUTDOWN_UNKNOWN_PROCESS;

    /*
     * Go through the thread list and mark them as not
     * shutdown yet.
     */
    ListHead = &pcsrp->ThreadList;
    ListNext = ListHead->Flink;
    while (ListNext != ListHead) {
        Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link );
        Thread->Flags &= ~CSR_THREAD_SHUTDOWNSKIP;
        ListNext = ListNext->Flink;
    }

    /*
     * Perform the proper shutdown operation on each thread.  Keep
     * a count of the number of gui threads found.
     */
    cThreads = 0;
    while (TRUE) {
        ListNext = ListHead->Flink;
        while (ListNext != ListHead) {
            Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link );

            /*
             * Skip the thread doing the shutdown.  Assume that it's
             * ready.
             */
            if (Thread->ClientId.UniqueThread == (HANDLE)dwThreadEndSession)
                Thread->Flags |= CSR_THREAD_SHUTDOWNSKIP;

            if (!(Thread->Flags &
                    (CSR_THREAD_DESTROYED | CSR_THREAD_SHUTDOWNSKIP))) {
                break;
            }
            ListNext = ListNext->Flink;
        }
        if (ListNext == ListHead)
            break;

        Thread->Flags |= CSR_THREAD_SHUTDOWNSKIP;
        LeaveCrit();
        Status = NtUserQueryInformationThread(Thread->ThreadHandle,
                UserThreadShutdownInformation, &ShutdownInfo, sizeof(ShutdownInfo), NULL);
        EnterCrit();
        if (!NT_SUCCESS(Status))
            continue;
        if (ShutdownInfo.StatusShutdown == SHUTDOWN_UNKNOWN_PROCESS)
            continue;
        if (ShutdownInfo.StatusShutdown == SHUTDOWN_KNOWN_PROCESS) {
            CsrUnlockProcess(Process);
            LeaveCrit();
            CsrDereferenceProcess(pcsrp);
            return SHUTDOWN_KNOWN_PROCESS;
        }

        /*
         * If this process is not in the account being logged off and it
         * is not on the windowstation being logged off, don't send
         * the end session messages.
         */
        if (!(dwClientFlags & WMCS_CONTEXTLOGOFF) && (ShutdownInfo.hwndDesktop == NULL)) {
            /*
             * This process is not in the context being logged off.  Do
             * not terminate it and let console send an event to the process.
             */
            ShutdownInfo.StatusShutdown = SHUTDOWN_UNKNOWN_PROCESS;
            continue;
        }

        /*
         * Shut down this process.
         */
        cThreads++;
        if (fNoRetry || !(ShutdownInfo.dwFlags & USER_THREAD_GUI)) {

            /*
             * Dispose of any hard errors.
             */
            BoostHardError((DWORD)Thread->ClientId.UniqueProcess, TRUE);
        } else {

            CsrReferenceThread(Thread);
            CsrUnlockProcess(Process);

            /*
             * There are problems in changing shutdown to send all the
             * QUERYENDSESSIONs at once before doing any ENDSESSIONs, like
             * Windows does. The whole machine needs to be modal if you do this.
             * If it isn't modal, then you have this problem. Imagine app 1 and 2.
             * 1 gets the queryendsession, no problem. 2 gets it and brings up a
             * dialog. Now being a simple user, you decide you need to change the
             * document in app 1. Now you switch back to app 2, hit ok, and
             * everything goes away - including app 1 without saving its changes.
             * Also, apps expect that once they've received the QUERYENDSESSION,
             * they are not going to get anything else of any particular interest
             * (unless it is a WM_ENDSESSION with FALSE) We had bugs pre 511 where
             * apps were blowing up because of this.
             * If this change is made, the entire system must be modal
             * while this is going on. - ScottLu 6/30/94
             */
            cmd = SendShutdownMessages(ShutdownInfo.hwndDesktop, Thread,
                    dwClientFlags | WMCS_QUERYEND);

            CsrLockProcessByClientId(pcsrp->ClientId.UniqueProcess, &Process);
            CsrDereferenceThread(Thread);

            /*
             * If shutdown has been cancelled, let csr know about it.
             */
            switch (cmd) {
            case CMDEND_USERSAYSCANCEL:
            case CMDEND_APPSAYSNOTOK:
                /*
                 * Only allow cancelling if this is not a forced shutdown (if
                 * !fNoRetry)
                 */
                if (!fNoRetry) {
                    dwClientFlags &= ~WMCS_EXIT;
                }

                /*
                 * Fall through.
                 */
            case CMDEND_APPSAYSOK:
                fSendEndSession = TRUE;
                break;
            case CMDEND_USERSAYSKILL:
                break;
            case CMDEND_NOWINDOW:
                /*
                 * Did this process have a window?
                 * If this is the second pass we terminate the process even if it did
                 * not have any windows in case the app was just starting up.
                 * WOW hits this often when because it takes so long to start up.
                 * Logon (with WOW auto-starting) then logoff WOW won't die but will
                 * lock some files open so you can't logon next time.
                 */
                if (fFirstPass) {
                    cThreads--;
                }
                break;
            }
        }
    }

    /*
     * If end session message need to be sent, do it now.
     */
    if (fSendEndSession) {

        /*
         * Go through the thread list and mark them as not
         * shutdown yet.
         */
        ListNext = ListHead->Flink;
        while (ListNext != ListHead) {
            Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link );
            Thread->Flags &= ~CSR_THREAD_SHUTDOWNSKIP;
            ListNext = ListNext->Flink;
        }

        /*
         * Perform the proper shutdown operation on each thread.
         */
        while (TRUE) {
            ListHead = &pcsrp->ThreadList;
            ListNext = ListHead->Flink;
            while (ListNext != ListHead) {
                Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link );
                if (!(Thread->Flags &
                        (CSR_THREAD_DESTROYED | CSR_THREAD_SHUTDOWNSKIP))) {
                    break;
                }
                ListNext = ListNext->Flink;
            }
            if (ListNext == ListHead)
                break;

            Thread->Flags |= CSR_THREAD_SHUTDOWNSKIP;
            LeaveCrit();
            Status = NtUserQueryInformationThread(Thread->ThreadHandle,
                    UserThreadShutdownInformation, &ShutdownInfo, sizeof(ShutdownInfo), NULL);
            EnterCrit();
            if (!NT_SUCCESS(Status))
                continue;
            if (ShutdownInfo.StatusShutdown == SHUTDOWN_UNKNOWN_PROCESS ||
                    !(ShutdownInfo.dwFlags & USER_THREAD_GUI))
                continue;

            /*
             * Send the end session messages to the thread.
             */
            CsrReferenceThread(Thread);
            CsrUnlockProcess(Process);

            /*
             * If the user says kill it, the user wants it to go away now
             * no matter what. If the user didn't say kill, then call again
             * because we need to send WM_ENDSESSION messages.
             */
            SendShutdownMessages(ShutdownInfo.hwndDesktop, Thread, dwClientFlags);

            CsrLockProcessByClientId(pcsrp->ClientId.UniqueProcess, &Process);
            CsrDereferenceThread(Thread);
        }
    }

    CsrUnlockProcess(Process);

    if (!fNoRetry && !(dwClientFlags & WMCS_EXIT)) {
        LeaveCrit();
        CsrDereferenceProcess(pcsrp);
        return SHUTDOWN_CANCEL;
    }

    /*
     * Set the final shutdown status according to the number of gui
     * threads found.  If the count is zero, we have an unknown process.
     */
    if (cThreads == 0)
        ShutdownInfo.StatusShutdown = SHUTDOWN_UNKNOWN_PROCESS;
    else
        ShutdownInfo.StatusShutdown = SHUTDOWN_KNOWN_PROCESS;

    if (ShutdownInfo.StatusShutdown == SHUTDOWN_UNKNOWN_PROCESS ||
            !(dwClientFlags & WMCS_CONTEXTLOGOFF)) {

        /*
         * This process is not in the context being logged off.  Do
         * not terminate it and let console send an event to the process.
         */
        LeaveCrit();
        return SHUTDOWN_UNKNOWN_PROCESS;
    }

    /*
     * Calling ExitProcess() in the app's context will not always work
     * because the app may have .dll termination deadlocks: so the thread
     * will hang with the rest of the process. To ensure apps go away,
     * we terminate the process with NtTerminateProcess().
     *
     * Pass this special value, DBG_TERMINATE_PROCESS, which tells
     * NtTerminateProcess() to return failure if it can't terminate the
     * process because the app is being debugged.
     */
    NtTerminateProcess(pcsrp->ProcessHandle, DBG_TERMINATE_PROCESS);
    pcsrp->Flags |= CSR_PROCESS_TERMINATED;

    /*
     * Let csr know we know about this process - meaning it was our
     * responsibility to shut it down.
     */
    LeaveCrit();

    /*
     * Now that we're done with the process handle, derefence the csr
     * process structure.
     */
    CsrDereferenceProcess(pcsrp);
    return SHUTDOWN_KNOWN_PROCESS;
}
Beispiel #14
0
HANDLE InternalCreateCallbackThread(
    HANDLE hProcess,
    DWORD lpfn,
    DWORD dwData)
{
    LONG BasePriority;
    HANDLE hThread, hToken;
    PTOKEN_DEFAULT_DACL lpDaclDefault;
    TOKEN_DEFAULT_DACL daclDefault;
    ULONG cbDacl;
    SECURITY_ATTRIBUTES attrThread;
    SECURITY_DESCRIPTOR sd;
    DWORD idThread;
    NTSTATUS Status;

    hThread = NULL;

    Status = NtOpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
    if (!NT_SUCCESS(Status)) {
        KdPrint(("NtOpenProcessToken failed, status = %x\n", Status));
        return NULL;
    }

    cbDacl = 0;
    NtQueryInformationToken(hToken,
            TokenDefaultDacl,
            &daclDefault,
            sizeof(daclDefault),
            &cbDacl);

    EnterCrit();  // to synchronize heap
    lpDaclDefault = (PTOKEN_DEFAULT_DACL)LocalAlloc(LMEM_FIXED, cbDacl);
    LeaveCrit();

    if (lpDaclDefault == NULL) {
        KdPrint(("LocalAlloc failed for lpDaclDefault"));
        goto closeexit;
    }

    Status = NtQueryInformationToken(hToken,
            TokenDefaultDacl,
            lpDaclDefault,
            cbDacl,
            &cbDacl);
    if (!NT_SUCCESS(Status)) {
        KdPrint(("NtQueryInformationToken failed, status = %x\n", Status));
        goto freeexit;
    }

    if (!NT_SUCCESS(RtlCreateSecurityDescriptor(&sd,
            SECURITY_DESCRIPTOR_REVISION1))) {
        UserAssert(FALSE);
        goto freeexit;
    }

    RtlSetDaclSecurityDescriptor(&sd, TRUE, lpDaclDefault->DefaultDacl, TRUE);

    attrThread.nLength = sizeof(attrThread);
    attrThread.lpSecurityDescriptor = &sd;
    attrThread.bInheritHandle = FALSE;

    GetLastError();
    hThread = CreateRemoteThread(hProcess,
        &attrThread,
        0L,
        (LPTHREAD_START_ROUTINE)lpfn,
        (LPVOID)dwData,
        0,
        &idThread);

    if (hThread != NULL) {
        BasePriority = THREAD_PRIORITY_HIGHEST;
        NtSetInformationThread(hThread,
                               ThreadBasePriority,
                               &BasePriority,
                               sizeof(LONG));
    }

freeexit:
    EnterCrit();  // to synchronize heap
    LocalFree((HANDLE)lpDaclDefault);
    LeaveCrit();

closeexit:
    NtClose(hToken);

    return hThread;
}
Beispiel #15
0
BOOL _EndTask(
    HWND hwnd,
    BOOL fShutdown,
    BOOL fMeanKill)
{
    PCSR_THREAD pcsrt = CSR_SERVER_QUERYCLIENTTHREAD();
    PCSR_THREAD pcsrtKill;
    DWORD dwThreadId;
    DWORD dwProcessId;
    LPWSTR lpszMsg;
    BOOL fAllocated;
    DWORD dwCmd;

    /*
     * Note: fShutdown isn't used for anything in this routine!
     * They are still there because I haven't removed them: the old endtask
     * code relied on them.
     */
    UNREFERENCED_PARAMETER(fShutdown);

    /*
     * Get the process and thread that owns hwnd.
     */
    dwThreadId = GetWindowThreadProcessId(hwnd, &dwProcessId);
    if (dwThreadId == 0)
        return TRUE;

    /*
     * If this is a console window, then just send the close message to
     * it, and let console clean up the processes in it.
     */
    if ((HANDLE)GetWindowLong(hwnd, GWL_HINSTANCE) == hModuleWin) {
        PostMessage(hwnd, WM_CLOSE, 0, 0);
        return TRUE;
    }

    /*
     * Find the CSR_THREAD for the window.
     */
    LeaveCrit();
    CsrLockThreadByClientId((HANDLE)dwThreadId, &pcsrtKill);
    EnterCrit();
    if (pcsrtKill == NULL)
        return TRUE;
    CsrReferenceThread(pcsrtKill);
    CsrUnlockThread(pcsrtKill);

    /*
     * If this is a WOW app, then shutdown just this wow application.
     */
    if (!fMeanKill) {
        /*
         * Find out what to do now - did the user cancel or the app cancel,
         * etc? Only allow cancelling if we are not forcing the app to
         * exit.
         */
        dwCmd = MySendEndSessionMessages(hwnd, pcsrtKill, TRUE, 0);
        switch (dwCmd) {
        case CMDEND_APPSAYSNOTOK:
            /*
             * App says not ok - this'll let taskman bring up the "are you sure?"
             * dialog to the user.
             */
            CsrDereferenceThread(pcsrtKill);
            return FALSE;

        case CMDEND_USERSAYSCANCEL:
            /*
             * User hit cancel on the timeout dialog - so the user really meant
             * it. Let taskman know everything is ok by returning TRUE.
             */
            CsrDereferenceThread(pcsrtKill);
            return TRUE;
        }
    }

    /*
     * Kill the application now.  If the thread has not been destroyed,
     * nuke the task.  If WowExitTask returns that the thread is not
     * a WOW task, terminate the process.
     */
    if (!(pcsrtKill->Flags & CSR_THREAD_DESTROYED) && !WowExitTask(pcsrtKill)) {

        /*
         * Calling ExitProcess() in the app's context will not always work
         * because the app may have .dll termination deadlocks: so the thread
         * will hang with the rest of the process. To ensure apps go away,
         * we terminate the process with NtTerminateProcess().
         *
         * Pass this special value, DBG_TERMINATE_PROCESS, which tells
         * NtTerminateProcess() to return failure if it can't terminate the
         * process because the app is being debugged.
         */
        if (!NT_SUCCESS(NtTerminateProcess(pcsrtKill->Process->ProcessHandle,
                DBG_TERMINATE_PROCESS))) {
            /*
             * If the app is being debugged, don't close it - because that can
             * cause a hang to the NtTerminateProcess() call.
             */
            lpszMsg = ServerLoadString(hModuleWin, STR_APPDEBUGGED,
                    NULL, &fAllocated);
            if (lpszMsg) {
                if (NT_SUCCESS(NtUserSetInformationThread(NtCurrentThread(),
                        UserThreadUseDesktop, &pcsrt->ThreadHandle, sizeof(HANDLE)))) {
                    HANDLE hNull = NULL;

                    LeaveCrit();
                    MessageBoxEx(NULL, lpszMsg, NULL,
                                    MB_OK | MB_SETFOREGROUND, 0);
                    EnterCrit();
                    NtUserSetInformationThread(NtCurrentThread(), UserThreadUseDesktop,
                            &hNull, sizeof(HANDLE));
                }
                LocalFree(lpszMsg);
            }
        } else {
            pcsrtKill->Process->Flags |= CSR_PROCESS_TERMINATED;
        }
    }
    CsrDereferenceThread(pcsrtKill);

    return TRUE;
}