ULONG PsGetThreadSessionId( __in PETHREAD Thread ) { return MmGetSessionId (THREAD_TO_PROCESS(Thread)); }
PEPROCESS PsGetCurrentThreadProcess( VOID ) { return THREAD_TO_PROCESS(_PsGetCurrentThread()); }
PEPROCESS PsGetThreadProcess( __in PETHREAD Thread ) { return THREAD_TO_PROCESS(Thread); }
NTSTATUS PsLookupProcessThreadByCid( __in PCLIENT_ID Cid, __deref_opt_out PEPROCESS *Process, __deref_out PETHREAD *Thread ) /*++ Routine Description: This function accepts The Client ID of a thread, and returns a referenced pointer to the thread, and possibly a referenced pointer to the process. Arguments: Cid - Specifies the Client ID of the thread. Process - If specified, returns a referenced pointer to the process specified in the Cid. Thread - Returns a referenced pointer to the thread specified in the Cid. Return Value: STATUS_SUCCESS - A process and thread were located based on the contents of the Cid. STATUS_INVALID_CID - The specified Cid is invalid. --*/ { PHANDLE_TABLE_ENTRY CidEntry; PETHREAD lThread; PETHREAD CurrentThread; PEPROCESS lProcess; NTSTATUS Status; PAGED_CODE(); lThread = NULL; CurrentThread = PsGetCurrentThread (); KeEnterCriticalRegionThread (&CurrentThread->Tcb); CidEntry = ExMapHandleToPointer(PspCidTable, Cid->UniqueThread); if (CidEntry != NULL) { lThread = (PETHREAD)CidEntry->Object; if (!ObReferenceObjectSafe (lThread)) { lThread = NULL; } ExUnlockHandleTableEntry(PspCidTable, CidEntry); } KeLeaveCriticalRegionThread (&CurrentThread->Tcb); Status = STATUS_INVALID_CID; if (lThread != NULL) { // // This could be a thread or a process. Check its a thread. // if (lThread->Tcb.Header.Type != ThreadObject || lThread->Cid.UniqueProcess != Cid->UniqueProcess || lThread->GrantedAccess == 0) { ObDereferenceObject (lThread); } else { *Thread = lThread; if (ARGUMENT_PRESENT (Process)) { lProcess = THREAD_TO_PROCESS (lThread); *Process = lProcess; // // Since the thread holds a reference to the process this reference does not have to // be protected. // ObReferenceObject (lProcess); } Status = STATUS_SUCCESS; } } return Status; }
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; }