Esempio n. 1
0
BOOL FASTCALL
CheckWinstaAttributeAccess(ACCESS_MASK DesiredAccess)
{
    PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
    if ( gpidLogon != PsGetCurrentProcessId() )
    {
        if (!(ppi->W32PF_flags & W32PF_IOWINSTA))
        {
            ERR("Requires Interactive Window Station\n");
            EngSetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
            return FALSE;
        }
        if (!RtlAreAllAccessesGranted(ppi->amwinsta, DesiredAccess))
        {
            ERR("Access Denied\n");
            EngSetLastError(ERROR_ACCESS_DENIED);
            return FALSE;
        }
    }
    return TRUE;
}
Esempio n. 2
0
BOOL FASTCALL
UserSetProcessWindowStation(HWINSTA hWindowStation)
{
    PPROCESSINFO ppi;
    NTSTATUS Status;
    HWINSTA hwinstaOld;
    OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
    PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;

    ppi = PsGetCurrentProcessWin32Process();

    /* Reference the new window station */
    if(hWindowStation !=NULL)
    {
        Status = IntValidateWindowStationHandle(hWindowStation,
                                                UserMode,
                                                0,
                                                &NewWinSta,
                                                &ObjectHandleInfo);
        if (!NT_SUCCESS(Status))
        {
            TRACE("Validation of window station handle (%p) failed\n",
                  hWindowStation);
            SetLastNtError(Status);
            return FALSE;
        }
    }

    OldWinSta = ppi->prpwinsta;
    hwinstaOld = PsGetProcessWin32WindowStation(ppi->peProcess);

    /* Dereference the previous window station */
    if(OldWinSta != NULL)
    {
        ObDereferenceObject(OldWinSta);
    }

    /* Check if we have a stale handle (it should happen for console apps) */
    if(hwinstaOld != ppi->hwinsta)
    {
        ObCloseHandle(hwinstaOld, UserMode);
    }

    /*
     * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
     */

    PsSetProcessWindowStation(ppi->peProcess, hWindowStation);

    ppi->prpwinsta = NewWinSta;
    ppi->hwinsta = hWindowStation;
    ppi->amwinsta = hWindowStation != NULL ? ObjectHandleInfo.GrantedAccess : 0;
    TRACE("WS : Granted Access 0x%08lx\n",ppi->amwinsta);

    if (RtlAreAllAccessesGranted(ppi->amwinsta, WINSTA_READSCREEN))
    {
        ppi->W32PF_flags |= W32PF_READSCREENACCESSGRANTED;
    }
    else
    {
        ppi->W32PF_flags &= ~W32PF_READSCREENACCESSGRANTED;
    }

    if (NewWinSta && !(NewWinSta->Flags & WSS_NOIO) )
    {
        ppi->W32PF_flags |= W32PF_IOWINSTA;
    }
    else // Might be closed if the handle is null.
    {
        ppi->W32PF_flags &= ~W32PF_IOWINSTA;
    }
    return TRUE;
}
Esempio n. 3
0
NTSTATUS InitiateShutdown(
    PETHREAD Thread,
    PULONG lpdwFlags)
{
    static PRIVILEGE_SET psShutdown = {
        1, PRIVILEGE_SET_ALL_NECESSARY, { SE_SHUTDOWN_PRIVILEGE, 0 }
    };
    PEPROCESS Process;
    LUID luidCaller;
    LUID luidSystem = SYSTEM_LUID;
    PPROCESSINFO ppi;
    PWINDOWSTATION pwinsta;
    HWINSTA hwinsta;
    PTHREADINFO ptiClient;
    NTSTATUS Status;
    DWORD dwFlags;

    /*
     * Find out the callers sid. Only want to shutdown processes in the
     * callers sid.
     */
    Process = THREAD_TO_PROCESS(Thread);
    ptiClient = PtiFromThread(Thread);
    Status = GetProcessLuid(Thread, &luidCaller);

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

    /*
     * Set the system flag if the caller is a system process.
     * Winlogon uses this to determine in which context to perform
     * a shutdown operation.
     */
    dwFlags = *lpdwFlags;
    if (RtlEqualLuid(&luidCaller, &luidSystem)) {
        dwFlags |= EWX_SYSTEM_CALLER;
    } else {
        dwFlags &= ~EWX_SYSTEM_CALLER;
    }

    /*
     * Find a windowstation.  If the process does not have one
     * assigned, use the standard one.
     */
    ppi = PpiFromProcess(Process);
    if (ppi == NULL) {
        /*
         * We ran into a case where the thread was terminated and had already
         * been cleaned up by USER.  Thus, the ppi and ptiClient was NULL.
         */
        return STATUS_INVALID_HANDLE;
    }

    pwinsta = ppi->rpwinsta;
    hwinsta = ppi->hwinsta;

    /*
     * If we're not being called by Winlogon, validate the call and
     * notify the logon process to do the actual shutdown.
     */
    if (Thread->Cid.UniqueProcess != gpidLogon) {
        dwFlags &= ~EWX_WINLOGON_CALLER;
        *lpdwFlags = dwFlags;

        if (pwinsta == NULL) {
#ifndef LATER
            return STATUS_INVALID_HANDLE;
#else
            hwinsta = ppi->pOpenObjectTable[HI_WINDOWSTATION].h;
            if (hwinsta == NULL) {
                return STATUS_INVALID_HANDLE;
            }
            pwinsta = (PWINDOWSTATION)ppi->pOpenObjectTable[HI_WINDOWSTATION].phead;
#endif
        }

        /*
         * Check security first - does this thread have access?
         */
        if (!RtlAreAllAccessesGranted(ppi->amwinsta, WINSTA_EXITWINDOWS)) {
            return STATUS_ACCESS_DENIED;
        }

        /*
         * If the client requested shutdown, reboot, or poweroff they must have
         * the shutdown privilege.
         */
        if (dwFlags & EWX_SHUTDOWN) {
            if (!IsPrivileged(&psShutdown) ) {
                return STATUS_PRIVILEGE_NOT_HELD;
            }
        } else {

            /*
             * If this is a non-IO windowstation and we are not shutting down,
             * fail the call.
             */
            if (pwinsta->dwFlags & WSF_NOIO) {
                return STATUS_INVALID_DEVICE_REQUEST;
            }
        }
    }

    /*
     * Is there a shutdown already in progress?
     */
    if (dwThreadEndSession != 0) {
        DWORD dwNew;

        /*
         * Calculate new flags
         */
        dwNew = dwFlags & OPTIONMASK & (~gdwShutdownFlags);

        /*
         * Should we override the other shutdown?  Make sure
         * winlogon does not recurse.
         */
        if (dwNew && (DWORD)PsGetCurrentThread()->Cid.UniqueThread !=
                dwThreadEndSession) {
            /*
             * Only one windowstation can be logged off at a time.
             */
            if (!(dwFlags & EWX_SHUTDOWN) &&
                    pwinsta != gpwinstaLogoff) {
                return STATUS_DEVICE_BUSY;
            }

            /*
             * Set the new flags
             */
            gdwShutdownFlags = dwFlags;

            if (dwNew & EWX_FORCE) {
                return STATUS_RETRY;
            } else {
                return STATUS_PENDING;
            }
        } else {
            /*
             * Don't override
             */
            return STATUS_PENDING;
        }
    }

    /*
     * If the caller is not winlogon, signal winlogon to start
     * the real shutdown.
     */
    if (Thread->Cid.UniqueProcess != gpidLogon) {
        if (dwFlags & EWX_NOTIFY) {
            if (ptiClient && ptiClient->TIF_flags & TIF_16BIT)
                gptiShutdownNotify = ptiClient;
            dwFlags &= ~EWX_NOTIFY;
            *lpdwFlags = dwFlags;
        }

        if (NotifyLogon(pwinsta, &luidCaller, dwFlags))
            return STATUS_PENDING;
        else if (ptiClient && ptiClient->cWindows)
            return STATUS_CANT_WAIT;
    }

    /*
     * Mark this thread as the one that is currently processing
     * exit windows, and set the global saying someone is exiting
     */
    dwFlags |= EWX_WINLOGON_CALLER;
    *lpdwFlags = dwFlags;
    gdwShutdownFlags = dwFlags;

    dwThreadEndSession = (DWORD)PsGetCurrentThread()->Cid.UniqueThread;
    gpwinstaLogoff = pwinsta;
    pwinsta->luidEndSession = luidCaller;

    /*
     * Lock the windowstation to prevent apps from starting
     * while we're doing shutdown processing.
     */
    gdwLocks = pwinsta->dwFlags & (WSF_SWITCHLOCK | WSF_OPENLOCK);
    pwinsta->dwFlags |= (WSF_OPENLOCK | WSF_SHUTDOWN);

    return STATUS_SUCCESS;
}