You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
908 lines
28 KiB
908 lines
28 KiB
/**************************** 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)
|
|
);
|
|
}
|