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; }
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; }
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; }