/**************************** Module Header ********************************\ * Module Name: security.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * Securable Object Routines * * History: * 12-31-90 JimA Created. * 04-14-92 RichardW Changed ACE_HEADER \***************************************************************************/ #define _SECURITY 1 #include "precomp.h" #pragma hdrstop #pragma alloc_text(INIT, InitSecurity) /* * General security stuff */ PSECURITY_DESCRIPTOR gpsdInitWinSta; PRIVILEGE_SET psTcb = { 1, PRIVILEGE_SET_ALL_NECESSARY, { SE_TCB_PRIVILEGE, 0 } }; /***************************************************************************\ * AllocAce * * Allocates and initializes an ACE list. * * History: * 04-25-91 JimA Created. \***************************************************************************/ PACCESS_ALLOWED_ACE AllocAce( PACCESS_ALLOWED_ACE pace, BYTE bType, BYTE bFlags, ACCESS_MASK am, PSID psid, LPDWORD lpdwLength) { PACCESS_ALLOWED_ACE paceNew; DWORD iEnd; DWORD dwLength, dwLengthSid; /* * Allocate space for the ACE. */ dwLengthSid = RtlLengthSid(psid); dwLength = dwLengthSid + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK); if (pace == NULL) { iEnd = 0; pace = UserAllocPoolWithQuota(dwLength, TAG_SECURITY); if (pace == NULL) return NULL; } else { iEnd = *lpdwLength; paceNew = UserAllocPoolWithQuota(iEnd + dwLength, TAG_SECURITY); if (paceNew == NULL) return NULL; RtlCopyMemory(paceNew, pace, iEnd); UserFreePool(pace); pace = paceNew; } *lpdwLength = dwLength + iEnd; /* * Insert the new ACE. */ paceNew = (PACCESS_ALLOWED_ACE)((PBYTE)pace + iEnd); paceNew->Header.AceType = bType; paceNew->Header.AceSize = (USHORT)dwLength; paceNew->Header.AceFlags = bFlags; paceNew->Mask = am; RtlCopySid(dwLengthSid, &paceNew->SidStart, psid); return pace; } /***************************************************************************\ * CreateSecurityDescriptor * * Allocates and initializes a security descriptor. * * History: * 04-25-91 JimA Created. \***************************************************************************/ PSECURITY_DESCRIPTOR CreateSecurityDescriptor( PACCESS_ALLOWED_ACE paceList, DWORD cbAce, BOOLEAN fDaclDefaulted) { PSECURITY_DESCRIPTOR psd; PACL pacl; NTSTATUS Status; /* * Allocate the security descriptor */ psd = (PSECURITY_DESCRIPTOR)UserAllocPoolWithQuota( cbAce + sizeof(ACL) + SECURITY_DESCRIPTOR_MIN_LENGTH, TAG_SECURITY); if (psd == NULL) return NULL; RtlCreateSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION); /* * Initialize the ACL */ pacl = (PACL)((PBYTE)psd + SECURITY_DESCRIPTOR_MIN_LENGTH); Status = RtlCreateAcl(pacl, sizeof(ACL) + cbAce, ACL_REVISION); if (NT_SUCCESS(Status)) { /* * Add the ACEs to the ACL. */ Status = RtlAddAce(pacl, ACL_REVISION, MAXULONG, paceList, cbAce); if (NT_SUCCESS(Status)) { /* * Initialize the SD */ Status = RtlSetDaclSecurityDescriptor(psd, (BOOLEAN)TRUE, pacl, fDaclDefaulted); RtlSetSaclSecurityDescriptor(psd, (BOOLEAN)FALSE, NULL, (BOOLEAN)FALSE); RtlSetOwnerSecurityDescriptor(psd, NULL, (BOOLEAN)FALSE); RtlSetGroupSecurityDescriptor(psd, NULL, (BOOLEAN)FALSE); } } if (!NT_SUCCESS(Status)) { UserFreePool(psd); return NULL; } return psd; } /***************************************************************************\ * InitSecurity * * Initialize global security information. * * History: * 01-29-91 JimA Created. \***************************************************************************/ BOOL InitSecurity( VOID) { PACCESS_ALLOWED_ACE paceList = NULL, pace; DWORD dwLength; /* * Create ACE list. */ paceList = AllocAce(NULL, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | NO_PROPAGATE_INHERIT_ACE, WinStaMapping.GenericAll, SeExports->SeWorldSid, &dwLength); if (paceList == NULL) return FALSE; pace = AllocAce(paceList, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | NO_PROPAGATE_INHERIT_ACE, WinStaMapping.GenericAll, SeExports->SeRestrictedSid, &dwLength); if (pace == NULL) { UserFreePool(paceList); return FALSE; } paceList = pace; pace = AllocAce(paceList, ACCESS_ALLOWED_ACE_TYPE, OBJECT_INHERIT_ACE | INHERIT_ONLY_ACE, GENERIC_ALL, SeExports->SeWorldSid, &dwLength); if (pace == NULL) { UserFreePool(paceList); return FALSE; } paceList = pace; pace = AllocAce(paceList, ACCESS_ALLOWED_ACE_TYPE, OBJECT_INHERIT_ACE | INHERIT_ONLY_ACE, GENERIC_ALL, SeExports->SeRestrictedSid, &dwLength); if (pace == NULL) { UserFreePool(paceList); return FALSE; } paceList = pace; pace = AllocAce(paceList, ACCESS_ALLOWED_ACE_TYPE, 0, DIRECTORY_QUERY | DIRECTORY_CREATE_OBJECT, SeExports->SeAliasAdminsSid, &dwLength); if (pace == NULL) { UserFreePool(paceList); return FALSE; } paceList = pace; pace = AllocAce(paceList, ACCESS_ALLOWED_ACE_TYPE, 0, DIRECTORY_TRAVERSE, SeExports->SeWorldSid, &dwLength); if (pace == NULL) { UserFreePool(paceList); return FALSE; } paceList = pace; pace = AllocAce(paceList, ACCESS_ALLOWED_ACE_TYPE, 0, DIRECTORY_TRAVERSE, SeExports->SeRestrictedSid, &dwLength); if (pace == NULL) { UserFreePool(paceList); return FALSE; } paceList = pace; /* * Create the SD */ gpsdInitWinSta = CreateSecurityDescriptor(paceList, dwLength, FALSE); UserFreePool(paceList); if (gpsdInitWinSta == NULL) { RIPMSG0(RIP_WARNING, "Initial windowstation security was not created!"); } return (BOOL)(gpsdInitWinSta != NULL); } /***************************************************************************\ * TestForInteractiveUser * * Returns STATUS_SUCCESS if the LUID passed represents an * interactiveUser user logged on by winlogon, otherwise FALSE * * History: * 03-08-95 JimA Created. \***************************************************************************/ NTSTATUS TestForInteractiveUser( PLUID pluidCaller ) { PWINDOWSTATION pwinsta; UserAssert(grpWinStaList != NULL); /* * !!! * * This relies on the fact that there is only ONE interactive * windowstation and that it is the first one in the list. * If multiple windowstations are ever supported * a lookup will have to be done here. */ pwinsta = grpWinStaList; /* * Compare it with the id of the logged on user. */ if (RtlEqualLuid(pluidCaller, &pwinsta->luidUser)) return STATUS_SUCCESS; else return STATUS_ACCESS_DENIED; } /***************************************************************************\ * _UserTestForWinStaAccess * * Returns STATUS_SUCCESS if the current user has GENERIC_EXECUTE access on * WindowStation pstrWinSta * * * History: * 06-05-96 Created SalimC * 01-02-02 Modified Mohamed Changed pstrWinSta to be a kernel mode address * and later copied to a dynamically allocated * user mode address. \***************************************************************************/ NTSTATUS _UserTestForWinStaAccess( PUNICODE_STRING pstrWinSta, BOOL fInherit ) { PTOKEN_STATISTICS pStats; ULONG BytesRequired; PWINDOWSTATION pwinsta; HWINSTA hwsta = NULL; POBJECT_ATTRIBUTES pObjAttr = NULL; PUNICODE_STRING pstrStatic; NTSTATUS Status = STATUS_SUCCESS; SIZE_T cbObjA; UNICODE_STRING strDefWinSta; HANDLE htoken; BOOLEAN fDefWinSta; CheckCritIn(); /* * If we are testing against Default WindowStation (WinSta0) retreive * pwinsta from the top of the grpwinstaList instead of doing an * _OpenWindowStation. * * NOTE: This relies on the fact that there is only ONE interactive * windowstation and that it is the first one in the list. If multiple * windowstations are ever supported a lookup will have to be done * instead. */ RtlInitUnicodeString(&strDefWinSta, DEFAULT_WINSTA); fDefWinSta = RtlEqualUnicodeString(pstrWinSta, &strDefWinSta, TRUE); if (fDefWinSta) { if (!NT_SUCCESS(Status = OpenEffectiveToken(&htoken))) { return Status; } Status = ZwQueryInformationToken(htoken, TokenStatistics, NULL, 0, &BytesRequired); if (Status != STATUS_BUFFER_TOO_SMALL) { ZwClose(htoken); return Status; } // // Allocate space for the user info // pStats = (PTOKEN_STATISTICS)UserAllocPoolWithQuota(BytesRequired, TAG_SECURITY); if (pStats == NULL) { Status = STATUS_NO_MEMORY; ZwClose(htoken); return Status; } // // Read in the user info // Status = ZwQueryInformationToken(htoken, TokenStatistics, pStats, BytesRequired, &BytesRequired); if (!NT_SUCCESS(Status)) { ZwClose(htoken); UserFreePool(pStats); return Status; } /* * Make sure that current process has access to this window station */ Status = STATUS_ACCESS_DENIED; if (grpWinStaList != NULL) { /* * !!! * * This relies on the fact that there is only ONE interactive * windowstation and that it is the first one in the list. * If multiple windowstations are ever supported * a lookup will have to be done here. */ pwinsta = grpWinStaList; /* * For now we will just do the user luid test till we figure out * what fInherit means for a Multi-User system */ if (fInherit) { if ( (RtlEqualLuid(&pStats->AuthenticationId, &pwinsta->luidUser)) || (RtlEqualLuid(&pStats->AuthenticationId, &luidSystem)) || (AccessCheckObject(pwinsta, GENERIC_EXECUTE, UserMode, &WinStaMapping)) ) { Status = STATUS_SUCCESS; } } else { /* Bug 42905. Service Controller clears the flag * ScStartupInfo.dwFlags &= (~STARTF_DESKTOPINHERIT) to make services * running under the context of system non-interactive. Hence if fInherit * is false don't do the SystemLuid and AccessCheckObject tests. */ if (RtlEqualLuid(&pStats->AuthenticationId, &pwinsta->luidUser)) { Status = STATUS_SUCCESS; } } } ZwClose(htoken); UserFreePool(pStats); return Status; } /* * Since we don't have a pointer to the WindowStation Object we will do * a _OpenWindowStation() to make sure we have the desired access. */ cbObjA = sizeof(*pObjAttr) + sizeof(*pstrStatic) + STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR); Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &pObjAttr, 0, &cbObjA, MEM_COMMIT, PAGE_READWRITE); pstrStatic = (PUNICODE_STRING)((PBYTE)pObjAttr + sizeof(*pObjAttr)); if (NT_SUCCESS(Status)) { /* * Note -- the string must be in client-space or the address * validation in _OpenWindowStation will fail. */ try { pstrStatic->Length = 0; pstrStatic->MaximumLength = STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR); pstrStatic->Buffer = (PWSTR)((PBYTE)pstrStatic + sizeof(*pstrStatic)); RtlCopyUnicodeString(pstrStatic, pstrWinSta); InitializeObjectAttributes(pObjAttr, pstrStatic, OBJ_CASE_INSENSITIVE, NULL, NULL); } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { Status = GetExceptionCode(); } if (NT_SUCCESS(Status)) { /* * In order to be able to verify access rights, we will pass * UserMode for KPROCESSOR_MODE. Passing KernelMode would bypass * all security checks. As a side-effect, hwsta is created * as a UserMode handle and is not a trusted/protected handle. */ hwsta = _OpenWindowStation(pObjAttr, GENERIC_EXECUTE, UserMode); } } else { return Status; } if (pObjAttr != NULL) { ZwFreeVirtualMemory(NtCurrentProcess(), &pObjAttr, &cbObjA, MEM_RELEASE); } if (!hwsta) { return STATUS_ACCESS_DENIED; } Status = ObCloseHandle(hwsta, UserMode); UserAssert(NT_SUCCESS(Status)); return Status; } /***************************************************************************\ * CheckGrantedAccess * * Confirms all requested accesses are granted and sets error status. * * History: * 06-26-95 JimA Created. \***************************************************************************/ BOOL CheckGrantedAccess( ACCESS_MASK amGranted, ACCESS_MASK amRequest) { /* * Check the granted access. */ if (!RtlAreAllAccessesGranted(amGranted, amRequest)) { RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, ""); return FALSE; } return TRUE; } /***************************************************************************\ * CheckWinstaWriteAttributesAccess * * Checks if the current process has WINSTA_WRITEATTRIBUTES access * to its windowstation, and whether that windowstation is an * interactive windowstation. * * History: * 06-Jun-1996 adams Created. \***************************************************************************/ BOOL CheckWinstaWriteAttributesAccess( VOID) { PPROCESSINFO ppiCurrent = PpiCurrent(); /* * winlogon has rights to all windowstations. */ if (PsGetCurrentProcessId() == gpidLogon) return TRUE; if (!(ppiCurrent->W32PF_Flags & W32PF_IOWINSTA)) { RIPERR0(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION, RIP_WARNING, "Operation invalid on a non-interactive WindowStation."); return FALSE; } if (!RtlAreAllAccessesGranted(ppiCurrent->amwinsta, WINSTA_WRITEATTRIBUTES)) { RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "WINSTA_WRITEATTRIBUTES access to WindowStation denied."); return FALSE; } return TRUE; } /***************************************************************************\ * AccessCheckObject * * Performs an access check on an object * * History: * 12-31-90 JimA Created. \***************************************************************************/ BOOL AccessCheckObject( PVOID pobj, ACCESS_MASK amRequest, KPROCESSOR_MODE AccessMode, CONST GENERIC_MAPPING *pGenericMapping) { NTSTATUS Status; ACCESS_STATE AccessState; BOOLEAN fAccessGranted; AUX_ACCESS_DATA AuxData; BOOLEAN bMutexLocked = (pGenericMapping == (&KeyMapping)); /* * Due to a resource problem in the object manager, we must pass in a TRUE * when checking access for registry keys, even if we do not explicitly have * the object type mutex. If we do not, we can get into a deadlock situation with this mutex * and the CmpRegistry lock. */ SeCreateAccessState(&AccessState, &AuxData, amRequest, (PGENERIC_MAPPING)pGenericMapping); fAccessGranted = ObCheckObjectAccess( pobj, &AccessState, bMutexLocked, AccessMode, &Status); SeDeleteAccessState(&AccessState); return (BOOL)(fAccessGranted == TRUE); } /***************************************************************************\ * IsPrivileged * * Check to see if the client has the specified privileges * * History: * 01-02-91 JimA Created. \***************************************************************************/ BOOL IsPrivileged( PPRIVILEGE_SET ppSet) { SECURITY_SUBJECT_CONTEXT Context; BOOLEAN bHeld; SeCaptureSubjectContext(&Context); SeLockSubjectContext(&Context); bHeld = SePrivilegeCheck(ppSet, &Context, UserMode); SePrivilegeObjectAuditAlarm(NULL, &Context, 0, ppSet, bHeld, UserMode); SeUnlockSubjectContext(&Context); SeReleaseSubjectContext(&Context); if (!bHeld) RIPERR0(ERROR_PRIVILEGE_NOT_HELD, RIP_VERBOSE, ""); /* * Return result of privilege check */ return (BOOL)bHeld; } /***************************************************************************\ * _GetUserObjectInformation (API) * * Gets information about a secure USER object * * History: * 04-25-94 JimA Created. \***************************************************************************/ BOOL _GetUserObjectInformation( HANDLE h, int nIndex, PVOID ccxpvInfo, DWORD nLength, LPDWORD lpnLengthNeeded) { PUSEROBJECTFLAGS puof; BOOL fSuccess = TRUE; PVOID pObject; POBJECT_HEADER pHead; DWORD dwLengthNeeded = 0; OBJECT_HANDLE_INFORMATION ohi; PUNICODE_STRING pstrInfo; PWINDOWSTATION pwinsta; NTSTATUS Status; ACCESS_MASK amDesiredAccess = 0; /* * Validate the object and get a pointer with whatever * access is granted. */ Status = ObReferenceObjectByHandle( h, 0, NULL, UserMode, &pObject, NULL); if (!NT_SUCCESS(Status)) { RIPNTERR0(Status, RIP_VERBOSE, "ObReferenceObjectByHandle Failed"); return FALSE; } /* * Determine the correct access mask given the object type. */ pHead = OBJECT_TO_OBJECT_HEADER(pObject); if (pHead->Type == *ExWindowStationObjectType) { amDesiredAccess = WINSTA_READATTRIBUTES; } else if (pHead->Type == *ExDesktopObjectType) { amDesiredAccess = DESKTOP_READOBJECTS; } ObDereferenceObject(pObject); if (!amDesiredAccess) { RIPERR0(ERROR_INVALID_FUNCTION, RIP_WARNING, "Object is not a USER object"); return FALSE; } /* * Re-open the object with the proper access. */ Status = ObReferenceObjectByHandle( h, amDesiredAccess, NULL, UserMode, &pObject, &ohi); if (!NT_SUCCESS(Status)) { RIPNTERR0(Status, RIP_VERBOSE, "ObReferenceObjectByHandle Failed"); return FALSE; } #ifdef LOGDESKTOPLOCKS if (OBJECT_TO_OBJECT_HEADER(pObject)->Type == *ExDesktopObjectType) { LogDesktop(pObject, LD_REF_FN_GETUSEROBJECTINFORMATION, TRUE, (ULONG_PTR)PtiCurrentShared()); } #endif try { switch (nIndex) { case UOI_FLAGS: dwLengthNeeded = sizeof(USEROBJECTFLAGS); if (nLength < sizeof(USEROBJECTFLAGS)) { RIPERR0(ERROR_INSUFFICIENT_BUFFER, RIP_VERBOSE, ""); fSuccess = FALSE; break; } puof = ccxpvInfo; puof->fInherit = (ohi.HandleAttributes & OBJ_INHERIT) ? TRUE : FALSE; puof->fReserved = 0; puof->dwFlags = 0; if (pHead->Type == *ExDesktopObjectType) { if (CheckHandleFlag(NULL, ((PDESKTOP)pObject)->dwSessionId, h, HF_DESKTOPHOOK)) { puof->dwFlags |= DF_ALLOWOTHERACCOUNTHOOK; } } else { if (!(((PWINDOWSTATION)pObject)->dwWSF_Flags & WSF_NOIO)) puof->dwFlags |= WSF_VISIBLE; } break; case UOI_NAME: pstrInfo = POBJECT_NAME(pObject); goto docopy; case UOI_TYPE: pstrInfo = &pHead->Type->Name; docopy: if (pstrInfo) { dwLengthNeeded = pstrInfo->Length + sizeof(WCHAR); if (dwLengthNeeded > nLength) { RIPERR0(ERROR_INSUFFICIENT_BUFFER, RIP_VERBOSE, ""); fSuccess = FALSE; break; } RtlCopyMemory(ccxpvInfo, pstrInfo->Buffer, pstrInfo->Length); *(PWCHAR)((PBYTE)ccxpvInfo + pstrInfo->Length) = 0; } else { dwLengthNeeded = 0; } break; case UOI_USER_SID: if (pHead->Type == *ExWindowStationObjectType) pwinsta = pObject; else pwinsta = ((PDESKTOP)pObject)->rpwinstaParent; if (pwinsta->psidUser == NULL) { dwLengthNeeded = 0; } else { dwLengthNeeded = RtlLengthSid(pwinsta->psidUser); if (dwLengthNeeded > nLength) { RIPERR0(ERROR_INSUFFICIENT_BUFFER, RIP_VERBOSE, ""); fSuccess = FALSE; break; } RtlCopyMemory(ccxpvInfo, pwinsta->psidUser, dwLengthNeeded); } break; default: RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, ""); fSuccess = FALSE; break; } } except (W32ExceptionHandler(TRUE, RIP_WARNING)) { fSuccess = FALSE; } *lpnLengthNeeded = dwLengthNeeded; #ifdef LOGDESKTOPLOCKS if (OBJECT_TO_OBJECT_HEADER(pObject)->Type == *ExDesktopObjectType) { LogDesktop(pObject, LD_DEREF_FN_GETUSEROBJECTINFORMATION, FALSE, (ULONG_PTR)PtiCurrentShared()); } #endif ObDereferenceObject(pObject); return fSuccess; } /***************************************************************************\ * _SetUserObjectInformation (API) * * Sets information about a secure USER object * * History: * 04-25-94 JimA Created. \***************************************************************************/ BOOL _SetUserObjectInformation( HANDLE h, int nIndex, PVOID ccxpvInfo, DWORD nLength) { PUSEROBJECTFLAGS puof; BOOL fSuccess = TRUE; PVOID pObject; POBJECT_HEADER pHead; DWORD dwLengthNeeded = 0; OBJECT_HANDLE_INFORMATION ohi; OBJECT_HANDLE_FLAG_INFORMATION ofi; NTSTATUS Status; ACCESS_MASK amDesiredAccess = 0; /* * Validate the object and get a pointer with whatever * access is granted. */ Status = ObReferenceObjectByHandle( h, 0, NULL, UserMode, &pObject, NULL); if (!NT_SUCCESS(Status)) { RIPNTERR0(Status, RIP_VERBOSE, "ObReferenceObjectByHandle Failed"); return FALSE; } /* * Determine the correct access mask given the object type. */ pHead = OBJECT_TO_OBJECT_HEADER(pObject); if (pHead->Type == *ExWindowStationObjectType) { amDesiredAccess = WINSTA_WRITEATTRIBUTES; } else if (pHead->Type == *ExDesktopObjectType) { amDesiredAccess = DESKTOP_WRITEOBJECTS; } ObDereferenceObject(pObject); if (!amDesiredAccess) { RIPERR0(ERROR_INVALID_FUNCTION, RIP_WARNING, "Object is not a USER object"); return FALSE; } /* * Re-open the object with the proper access. */ Status = ObReferenceObjectByHandle( h, amDesiredAccess, NULL, UserMode, &pObject, &ohi); if (!NT_SUCCESS(Status)) { RIPNTERR0(Status, RIP_VERBOSE, "ObReferenceObjectByHandle Failed"); return FALSE; } #ifdef LOGDESKTOPLOCKS if (OBJECT_TO_OBJECT_HEADER(pObject)->Type == *ExDesktopObjectType) { LogDesktop(pObject, LD_REF_FN_SETUSEROBJECTINFORMATION, TRUE, (ULONG_PTR)PtiCurrent()); } #endif try { switch (nIndex) { case UOI_FLAGS: if (nLength < sizeof(USEROBJECTFLAGS)) { RIPERR0(ERROR_INVALID_DATA, RIP_VERBOSE, ""); fSuccess = FALSE; break; } puof = ccxpvInfo; ofi.Inherit = (puof->fInherit != FALSE); ofi.ProtectFromClose = (ohi.HandleAttributes & OBJ_PROTECT_CLOSE) ? TRUE : FALSE; ObSetHandleAttributes(h, &ofi, UserMode); if (pHead->Type == *ExDesktopObjectType) { SetHandleFlag(h, HF_DESKTOPHOOK, puof->dwFlags & DF_ALLOWOTHERACCOUNTHOOK); } break; default: RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, ""); fSuccess = FALSE; break; } } except (W32ExceptionHandler(TRUE, RIP_WARNING)) { fSuccess = FALSE; } #ifdef LOGDESKTOPLOCKS if (OBJECT_TO_OBJECT_HEADER(pObject)->Type == *ExDesktopObjectType) { LogDesktop(pObject, LD_DEREF_FN_SETUSEROBJECTINFORMATION, FALSE, (ULONG_PTR)PtiCurrent()); } #endif ObDereferenceObject(pObject); return fSuccess; } /***************************************************************************\ * UserScreenAccessCheck * * Called from the engine to determine if the thread's desktop is * active and the process has WINSTA_READSCREEN access. * * Note that we may or may not be in USER's critical section when this * is called. This is OK as long as we don't reference thing belonging * to other threads. If we did try to enter the critical section here, * a deadlock may occur between the engine and user. * * History: * 05-20-1993 JimA Created. * 11-22-1996 BradG Brought back to life. * 05-07-2001 JasonSch CSRSS threads aren't always attached to a desktop, * but they need to draw anyway (for console). \***************************************************************************/ BOOL FASTCALL UserScreenAccessCheck(VOID) { PTHREADINFO ptiCurrent = PtiCurrentShared(); UserAssert(ptiCurrent != NULL); return (ptiCurrent != NULL && (ptiCurrent->rpdesk == grpdeskRitInput || (ptiCurrent->TIF_flags & TIF_CSRSSTHREAD) != 0) && (W32GetCurrentProcess()->W32PF_Flags & (W32PF_READSCREENACCESSGRANTED | W32PF_IOWINSTA)) == (W32PF_READSCREENACCESSGRANTED | W32PF_IOWINSTA) ); }