2008-03-09 14:11:42 +00:00
|
|
|
/*
|
2005-01-26 13:58:37 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: ntoskrnl/se/semgr.c
|
|
|
|
* PURPOSE: Security manager
|
2005-05-09 01:38:29 +00:00
|
|
|
*
|
2005-01-26 13:58:37 +00:00
|
|
|
* PROGRAMMERS: No programmer listed.
|
1998-08-25 04:27:26 +00:00
|
|
|
*/
|
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* INCLUDES *******************************************************************/
|
1998-08-25 04:27:26 +00:00
|
|
|
|
2004-08-15 16:39:12 +00:00
|
|
|
#include <ntoskrnl.h>
|
2004-08-29 15:50:53 +00:00
|
|
|
#define NDEBUG
|
2008-04-23 20:38:37 +00:00
|
|
|
#include <debug.h>
|
1998-08-25 04:27:26 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* GLOBALS ********************************************************************/
|
2002-02-20 20:16:49 +00:00
|
|
|
|
2005-06-21 23:42:58 +00:00
|
|
|
PSE_EXPORTS SeExports = NULL;
|
2005-05-25 04:16:56 +00:00
|
|
|
SE_EXPORTS SepExports;
|
2010-05-28 16:28:27 +00:00
|
|
|
ULONG SidInTokenCalls = 0;
|
2002-02-20 20:16:49 +00:00
|
|
|
|
2007-01-25 01:13:09 +00:00
|
|
|
extern ULONG ExpInitializationPhase;
|
2008-04-23 20:38:37 +00:00
|
|
|
extern ERESOURCE SepSubjectContextLock;
|
2004-09-14 11:04:48 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* PRIVATE FUNCTIONS **********************************************************/
|
2002-02-20 20:16:49 +00:00
|
|
|
|
2010-05-28 16:28:27 +00:00
|
|
|
static BOOLEAN
|
|
|
|
INIT_FUNCTION
|
2008-04-23 20:38:37 +00:00
|
|
|
SepInitExports(VOID)
|
|
|
|
{
|
|
|
|
SepExports.SeCreateTokenPrivilege = SeCreateTokenPrivilege;
|
|
|
|
SepExports.SeAssignPrimaryTokenPrivilege = SeAssignPrimaryTokenPrivilege;
|
|
|
|
SepExports.SeLockMemoryPrivilege = SeLockMemoryPrivilege;
|
|
|
|
SepExports.SeIncreaseQuotaPrivilege = SeIncreaseQuotaPrivilege;
|
|
|
|
SepExports.SeUnsolicitedInputPrivilege = SeUnsolicitedInputPrivilege;
|
|
|
|
SepExports.SeTcbPrivilege = SeTcbPrivilege;
|
|
|
|
SepExports.SeSecurityPrivilege = SeSecurityPrivilege;
|
|
|
|
SepExports.SeTakeOwnershipPrivilege = SeTakeOwnershipPrivilege;
|
|
|
|
SepExports.SeLoadDriverPrivilege = SeLoadDriverPrivilege;
|
|
|
|
SepExports.SeCreatePagefilePrivilege = SeCreatePagefilePrivilege;
|
|
|
|
SepExports.SeIncreaseBasePriorityPrivilege = SeIncreaseBasePriorityPrivilege;
|
|
|
|
SepExports.SeSystemProfilePrivilege = SeSystemProfilePrivilege;
|
|
|
|
SepExports.SeSystemtimePrivilege = SeSystemtimePrivilege;
|
|
|
|
SepExports.SeProfileSingleProcessPrivilege = SeProfileSingleProcessPrivilege;
|
|
|
|
SepExports.SeCreatePermanentPrivilege = SeCreatePermanentPrivilege;
|
|
|
|
SepExports.SeBackupPrivilege = SeBackupPrivilege;
|
|
|
|
SepExports.SeRestorePrivilege = SeRestorePrivilege;
|
|
|
|
SepExports.SeShutdownPrivilege = SeShutdownPrivilege;
|
|
|
|
SepExports.SeDebugPrivilege = SeDebugPrivilege;
|
|
|
|
SepExports.SeAuditPrivilege = SeAuditPrivilege;
|
|
|
|
SepExports.SeSystemEnvironmentPrivilege = SeSystemEnvironmentPrivilege;
|
|
|
|
SepExports.SeChangeNotifyPrivilege = SeChangeNotifyPrivilege;
|
|
|
|
SepExports.SeRemoteShutdownPrivilege = SeRemoteShutdownPrivilege;
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
SepExports.SeNullSid = SeNullSid;
|
|
|
|
SepExports.SeWorldSid = SeWorldSid;
|
|
|
|
SepExports.SeLocalSid = SeLocalSid;
|
|
|
|
SepExports.SeCreatorOwnerSid = SeCreatorOwnerSid;
|
|
|
|
SepExports.SeCreatorGroupSid = SeCreatorGroupSid;
|
|
|
|
SepExports.SeNtAuthoritySid = SeNtAuthoritySid;
|
|
|
|
SepExports.SeDialupSid = SeDialupSid;
|
|
|
|
SepExports.SeNetworkSid = SeNetworkSid;
|
|
|
|
SepExports.SeBatchSid = SeBatchSid;
|
|
|
|
SepExports.SeInteractiveSid = SeInteractiveSid;
|
|
|
|
SepExports.SeLocalSystemSid = SeLocalSystemSid;
|
|
|
|
SepExports.SeAliasAdminsSid = SeAliasAdminsSid;
|
|
|
|
SepExports.SeAliasUsersSid = SeAliasUsersSid;
|
|
|
|
SepExports.SeAliasGuestsSid = SeAliasGuestsSid;
|
|
|
|
SepExports.SeAliasPowerUsersSid = SeAliasPowerUsersSid;
|
|
|
|
SepExports.SeAliasAccountOpsSid = SeAliasAccountOpsSid;
|
|
|
|
SepExports.SeAliasSystemOpsSid = SeAliasSystemOpsSid;
|
|
|
|
SepExports.SeAliasPrintOpsSid = SeAliasPrintOpsSid;
|
|
|
|
SepExports.SeAliasBackupOpsSid = SeAliasBackupOpsSid;
|
|
|
|
SepExports.SeAuthenticatedUsersSid = SeAuthenticatedUsersSid;
|
|
|
|
SepExports.SeRestrictedSid = SeRestrictedSid;
|
|
|
|
SepExports.SeAnonymousLogonSid = SeAnonymousLogonSid;
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
SepExports.SeUndockPrivilege = SeUndockPrivilege;
|
|
|
|
SepExports.SeSyncAgentPrivilege = SeSyncAgentPrivilege;
|
|
|
|
SepExports.SeEnableDelegationPrivilege = SeEnableDelegationPrivilege;
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
SeExports = &SepExports;
|
|
|
|
return TRUE;
|
|
|
|
}
|
2002-02-20 20:16:49 +00:00
|
|
|
|
|
|
|
|
2007-01-25 01:13:09 +00:00
|
|
|
BOOLEAN
|
2005-09-13 23:28:21 +00:00
|
|
|
NTAPI
|
2010-11-02 16:29:06 +00:00
|
|
|
INIT_FUNCTION
|
2007-01-25 01:13:09 +00:00
|
|
|
SepInitializationPhase0(VOID)
|
2002-02-20 20:16:49 +00:00
|
|
|
{
|
2009-09-02 13:02:30 +00:00
|
|
|
PAGED_CODE();
|
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
ExpInitLuid();
|
2007-01-25 01:13:09 +00:00
|
|
|
if (!SepInitSecurityIDs()) return FALSE;
|
|
|
|
if (!SepInitDACLs()) return FALSE;
|
|
|
|
if (!SepInitSDs()) return FALSE;
|
|
|
|
SepInitPrivileges();
|
|
|
|
if (!SepInitExports()) return FALSE;
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2007-01-25 01:13:09 +00:00
|
|
|
/* Initialize the subject context lock */
|
|
|
|
ExInitializeResource(&SepSubjectContextLock);
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2007-01-25 01:13:09 +00:00
|
|
|
/* Initialize token objects */
|
|
|
|
SepInitializeTokenImplementation();
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2007-01-25 01:13:09 +00:00
|
|
|
/* Clear impersonation info for the idle thread */
|
|
|
|
PsGetCurrentThread()->ImpersonationInfo = NULL;
|
|
|
|
PspClearCrossThreadFlag(PsGetCurrentThread(),
|
|
|
|
CT_ACTIVE_IMPERSONATION_INFO_BIT);
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2007-01-25 01:13:09 +00:00
|
|
|
/* Initialize the boot token */
|
|
|
|
ObInitializeFastReference(&PsGetCurrentProcess()->Token, NULL);
|
|
|
|
ObInitializeFastReference(&PsGetCurrentProcess()->Token,
|
|
|
|
SepCreateSystemProcessToken());
|
|
|
|
return TRUE;
|
|
|
|
}
|
2002-02-20 20:16:49 +00:00
|
|
|
|
2007-01-25 01:13:09 +00:00
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
2010-11-02 16:29:06 +00:00
|
|
|
INIT_FUNCTION
|
2007-01-25 01:13:09 +00:00
|
|
|
SepInitializationPhase1(VOID)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
2010-05-28 16:28:27 +00:00
|
|
|
|
2007-01-25 01:13:09 +00:00
|
|
|
PAGED_CODE();
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2007-01-25 01:13:09 +00:00
|
|
|
/* Insert the system token into the tree */
|
|
|
|
Status = ObInsertObject((PVOID)(PsGetCurrentProcess()->Token.Value &
|
|
|
|
~MAX_FAST_REFS),
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2007-01-25 01:13:09 +00:00
|
|
|
/* FIXME: TODO \\ Security directory */
|
|
|
|
return TRUE;
|
|
|
|
}
|
2002-02-20 20:16:49 +00:00
|
|
|
|
2007-01-25 01:13:09 +00:00
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
2010-11-02 16:29:06 +00:00
|
|
|
INIT_FUNCTION
|
2008-08-17 18:34:37 +00:00
|
|
|
SeInitSystem(VOID)
|
2007-01-25 01:13:09 +00:00
|
|
|
{
|
|
|
|
/* Check the initialization phase */
|
|
|
|
switch (ExpInitializationPhase)
|
|
|
|
{
|
2008-04-23 20:38:37 +00:00
|
|
|
case 0:
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* Do Phase 0 */
|
|
|
|
return SepInitializationPhase0();
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
case 1:
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* Do Phase 1 */
|
|
|
|
return SepInitializationPhase1();
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
default:
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* Don't know any other phase! Bugcheck! */
|
|
|
|
KeBugCheckEx(UNEXPECTED_INITIALIZATION_CALL,
|
|
|
|
0,
|
|
|
|
ExpInitializationPhase,
|
|
|
|
0,
|
|
|
|
0);
|
|
|
|
return FALSE;
|
2007-01-25 01:13:09 +00:00
|
|
|
}
|
2002-02-20 20:16:49 +00:00
|
|
|
}
|
|
|
|
|
2003-02-15 21:07:49 +00:00
|
|
|
BOOLEAN
|
2005-09-13 23:28:21 +00:00
|
|
|
NTAPI
|
2010-11-02 16:29:06 +00:00
|
|
|
INIT_FUNCTION
|
2003-02-15 21:07:49 +00:00
|
|
|
SeInitSRM(VOID)
|
|
|
|
{
|
2008-04-23 20:38:37 +00:00
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
UNICODE_STRING Name;
|
|
|
|
HANDLE DirectoryHandle;
|
|
|
|
HANDLE EventHandle;
|
|
|
|
NTSTATUS Status;
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* Create '\Security' directory */
|
|
|
|
RtlInitUnicodeString(&Name,
|
|
|
|
L"\\Security");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&Name,
|
|
|
|
OBJ_PERMANENT,
|
|
|
|
0,
|
|
|
|
NULL);
|
|
|
|
Status = ZwCreateDirectoryObject(&DirectoryHandle,
|
|
|
|
DIRECTORY_ALL_ACCESS,
|
|
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Failed to create 'Security' directory!\n");
|
|
|
|
return FALSE;
|
2003-02-15 21:07:49 +00:00
|
|
|
}
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* Create 'LSA_AUTHENTICATION_INITALIZED' event */
|
|
|
|
RtlInitUnicodeString(&Name,
|
|
|
|
L"\\LSA_AUTHENTICATION_INITALIZED");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&Name,
|
|
|
|
OBJ_PERMANENT,
|
|
|
|
DirectoryHandle,
|
|
|
|
SePublicDefaultSd);
|
|
|
|
Status = ZwCreateEvent(&EventHandle,
|
|
|
|
EVENT_ALL_ACCESS,
|
|
|
|
&ObjectAttributes,
|
|
|
|
SynchronizationEvent,
|
|
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Failed to create 'LSA_AUTHENTICATION_INITALIZED' event!\n");
|
|
|
|
NtClose(DirectoryHandle);
|
|
|
|
return FALSE;
|
2003-02-15 21:07:49 +00:00
|
|
|
}
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
ZwClose(EventHandle);
|
|
|
|
ZwClose(DirectoryHandle);
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* FIXME: Create SRM port and listener thread */
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
return TRUE;
|
2000-01-05 21:57:00 +00:00
|
|
|
}
|
|
|
|
|
2005-08-07 18:38:37 +00:00
|
|
|
NTSTATUS
|
2008-03-31 20:07:02 +00:00
|
|
|
NTAPI
|
|
|
|
SeDefaultObjectMethod(IN PVOID Object,
|
|
|
|
IN SECURITY_OPERATION_CODE OperationType,
|
|
|
|
IN PSECURITY_INFORMATION SecurityInformation,
|
|
|
|
IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
|
|
IN OUT PULONG ReturnLength OPTIONAL,
|
|
|
|
IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
|
|
|
|
IN POOL_TYPE PoolType,
|
|
|
|
IN PGENERIC_MAPPING GenericMapping)
|
2005-08-07 18:38:37 +00:00
|
|
|
{
|
2008-03-31 20:07:02 +00:00
|
|
|
PAGED_CODE();
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-03-31 20:07:02 +00:00
|
|
|
/* Select the operation type */
|
|
|
|
switch (OperationType)
|
2008-04-23 20:38:37 +00:00
|
|
|
{
|
|
|
|
/* Setting a new descriptor */
|
2008-03-31 20:07:02 +00:00
|
|
|
case SetSecurityDescriptor:
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-03-31 20:07:02 +00:00
|
|
|
/* Sanity check */
|
|
|
|
ASSERT((PoolType == PagedPool) || (PoolType == NonPagedPool));
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-03-31 20:07:02 +00:00
|
|
|
/* Set the information */
|
|
|
|
return ObSetSecurityDescriptorInfo(Object,
|
|
|
|
SecurityInformation,
|
2005-08-07 18:38:37 +00:00
|
|
|
SecurityDescriptor,
|
2008-03-31 20:07:02 +00:00
|
|
|
OldSecurityDescriptor,
|
|
|
|
PoolType,
|
|
|
|
GenericMapping);
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-03-31 20:07:02 +00:00
|
|
|
case QuerySecurityDescriptor:
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-03-31 20:07:02 +00:00
|
|
|
/* Query the information */
|
|
|
|
return ObQuerySecurityDescriptorInfo(Object,
|
|
|
|
SecurityInformation,
|
|
|
|
SecurityDescriptor,
|
|
|
|
ReturnLength,
|
|
|
|
OldSecurityDescriptor);
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-03-31 20:07:02 +00:00
|
|
|
case DeleteSecurityDescriptor:
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-03-31 20:07:02 +00:00
|
|
|
/* De-assign it */
|
|
|
|
return ObDeassignSecurity(OldSecurityDescriptor);
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-03-31 20:07:02 +00:00
|
|
|
case AssignSecurityDescriptor:
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-03-31 20:07:02 +00:00
|
|
|
/* Assign it */
|
|
|
|
ObAssignObjectSecurityDescriptor(Object, SecurityDescriptor, PoolType);
|
|
|
|
return STATUS_SUCCESS;
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-03-31 20:07:02 +00:00
|
|
|
default:
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-03-31 20:07:02 +00:00
|
|
|
/* Bug check */
|
|
|
|
KeBugCheckEx(SECURITY_SYSTEM, 0, STATUS_INVALID_PARAMETER, 0, 0);
|
|
|
|
}
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-03-31 20:07:02 +00:00
|
|
|
/* Should never reach here */
|
|
|
|
ASSERT(FALSE);
|
2005-08-07 18:38:37 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
1998-10-05 04:01:30 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
static BOOLEAN
|
|
|
|
SepSidInToken(PACCESS_TOKEN _Token,
|
|
|
|
PSID Sid)
|
1998-08-25 04:27:26 +00:00
|
|
|
{
|
2008-04-23 20:38:37 +00:00
|
|
|
ULONG i;
|
|
|
|
PTOKEN Token = (PTOKEN)_Token;
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2006-07-23 08:20:57 +00:00
|
|
|
PAGED_CODE();
|
2009-06-25 13:29:58 +00:00
|
|
|
|
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail.
Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure.
Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set.
Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it.
Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued.
Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc.
The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set.
With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case).
Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE.
The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success).
Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication).
Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code.
svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
|
|
|
SidInTokenCalls++;
|
|
|
|
if (!(SidInTokenCalls % 10000)) DPRINT1("SidInToken Calls: %d\n", SidInTokenCalls);
|
2010-05-28 16:28:27 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
if (Token->UserAndGroupCount == 0)
|
2004-07-19 12:45:56 +00:00
|
|
|
{
|
2008-04-23 20:38:37 +00:00
|
|
|
return FALSE;
|
2004-07-19 12:45:56 +00:00
|
|
|
}
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
for (i=0; i<Token->UserAndGroupCount; i++)
|
2004-07-19 12:45:56 +00:00
|
|
|
{
|
2008-04-23 20:38:37 +00:00
|
|
|
if (RtlEqualSid(Sid, Token->UserAndGroups[i].Sid))
|
|
|
|
{
|
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail.
Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure.
Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set.
Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it.
Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued.
Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc.
The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set.
With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case).
Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE.
The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success).
Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication).
Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code.
svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
|
|
|
if ((i == 0)|| (Token->UserAndGroups[i].Attributes & SE_GROUP_ENABLED))
|
2008-04-23 20:38:37 +00:00
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2004-07-19 12:45:56 +00:00
|
|
|
}
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
return FALSE;
|
2004-09-14 11:04:48 +00:00
|
|
|
}
|
|
|
|
|
2010-04-02 15:13:24 +00:00
|
|
|
static BOOLEAN
|
|
|
|
SepTokenIsOwner(PACCESS_TOKEN Token,
|
|
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
PSID Sid = NULL;
|
|
|
|
BOOLEAN Defaulted;
|
|
|
|
|
|
|
|
Status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
|
|
|
|
&Sid,
|
|
|
|
&Defaulted);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("RtlGetOwnerSecurityDescriptor() failed (Status %lx)\n", Status);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Sid == NULL)
|
|
|
|
{
|
|
|
|
DPRINT1("Owner Sid is NULL\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SepSidInToken(Token, Sid);
|
|
|
|
}
|
2004-09-14 11:04:48 +00:00
|
|
|
|
2010-05-28 16:28:27 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
2008-04-23 20:38:37 +00:00
|
|
|
SeQuerySecurityAccessMask(IN SECURITY_INFORMATION SecurityInformation,
|
|
|
|
OUT PACCESS_MASK DesiredAccess)
|
2004-05-20 12:42:51 +00:00
|
|
|
{
|
2008-04-23 20:38:37 +00:00
|
|
|
*DesiredAccess = 0;
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
if (SecurityInformation & (OWNER_SECURITY_INFORMATION |
|
|
|
|
GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION))
|
2004-05-20 12:42:51 +00:00
|
|
|
{
|
2008-04-23 20:38:37 +00:00
|
|
|
*DesiredAccess |= READ_CONTROL;
|
2004-05-20 12:42:51 +00:00
|
|
|
}
|
2010-05-28 16:28:27 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
if (SecurityInformation & SACL_SECURITY_INFORMATION)
|
2002-02-20 20:16:49 +00:00
|
|
|
{
|
2008-04-23 20:38:37 +00:00
|
|
|
*DesiredAccess |= ACCESS_SYSTEM_SECURITY;
|
2002-02-20 20:16:49 +00:00
|
|
|
}
|
1998-08-25 04:27:26 +00:00
|
|
|
}
|
2000-01-26 10:07:30 +00:00
|
|
|
|
2010-05-28 16:28:27 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
2008-04-23 20:38:37 +00:00
|
|
|
SeSetSecurityAccessMask(IN SECURITY_INFORMATION SecurityInformation,
|
|
|
|
OUT PACCESS_MASK DesiredAccess)
|
1998-08-25 04:27:26 +00:00
|
|
|
{
|
2008-04-23 20:38:37 +00:00
|
|
|
*DesiredAccess = 0;
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
if (SecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
|
2004-07-20 12:08:04 +00:00
|
|
|
{
|
2008-04-23 20:38:37 +00:00
|
|
|
*DesiredAccess |= WRITE_OWNER;
|
2004-07-20 12:08:04 +00:00
|
|
|
}
|
2010-05-28 16:28:27 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
if (SecurityInformation & DACL_SECURITY_INFORMATION)
|
2004-07-20 12:08:04 +00:00
|
|
|
{
|
2008-04-23 20:38:37 +00:00
|
|
|
*DesiredAccess |= WRITE_DAC;
|
2004-07-20 12:08:04 +00:00
|
|
|
}
|
2010-05-28 16:28:27 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
if (SecurityInformation & SACL_SECURITY_INFORMATION)
|
2004-07-13 16:59:35 +00:00
|
|
|
{
|
2008-04-23 20:38:37 +00:00
|
|
|
*DesiredAccess |= ACCESS_SYSTEM_SECURITY;
|
2004-07-13 16:59:35 +00:00
|
|
|
}
|
2000-01-05 21:57:00 +00:00
|
|
|
}
|
|
|
|
|
2010-04-10 11:44:57 +00:00
|
|
|
|
|
|
|
#define OLD_ACCESS_CHECK
|
|
|
|
|
2008-11-29 20:47:48 +00:00
|
|
|
BOOLEAN NTAPI
|
2009-11-21 17:58:33 +00:00
|
|
|
SepAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
|
|
IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
|
|
|
|
IN ACCESS_MASK DesiredAccess,
|
|
|
|
IN ACCESS_MASK PreviouslyGrantedAccess,
|
|
|
|
OUT PPRIVILEGE_SET* Privileges,
|
|
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
|
|
IN KPROCESSOR_MODE AccessMode,
|
|
|
|
OUT PACCESS_MASK GrantedAccess,
|
2010-03-30 20:16:26 +00:00
|
|
|
OUT PNTSTATUS AccessStatus)
|
1998-08-25 04:27:26 +00:00
|
|
|
{
|
2007-03-19 19:05:39 +00:00
|
|
|
LUID_AND_ATTRIBUTES Privilege;
|
2010-04-10 11:44:57 +00:00
|
|
|
#ifdef OLD_ACCESS_CHECK
|
|
|
|
ACCESS_MASK CurrentAccess, AccessMask;
|
|
|
|
#endif
|
2010-04-02 17:46:24 +00:00
|
|
|
ACCESS_MASK RemainingAccess;
|
2010-04-03 10:52:17 +00:00
|
|
|
ACCESS_MASK TempAccess;
|
|
|
|
ACCESS_MASK TempGrantedAccess = 0;
|
|
|
|
ACCESS_MASK TempDeniedAccess = 0;
|
2007-03-19 19:05:39 +00:00
|
|
|
PACCESS_TOKEN Token;
|
|
|
|
ULONG i;
|
|
|
|
PACL Dacl;
|
|
|
|
BOOLEAN Present;
|
|
|
|
BOOLEAN Defaulted;
|
|
|
|
PACE CurrentAce;
|
|
|
|
PSID Sid;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2007-03-19 19:05:39 +00:00
|
|
|
/* Check for no access desired */
|
|
|
|
if (!DesiredAccess)
|
|
|
|
{
|
|
|
|
/* Check if we had no previous access */
|
|
|
|
if (!PreviouslyGrantedAccess)
|
|
|
|
{
|
|
|
|
/* Then there's nothing to give */
|
|
|
|
*AccessStatus = STATUS_ACCESS_DENIED;
|
|
|
|
return FALSE;
|
|
|
|
}
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2007-03-19 19:05:39 +00:00
|
|
|
/* Return the previous access only */
|
|
|
|
*GrantedAccess = PreviouslyGrantedAccess;
|
|
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
|
|
*Privileges = NULL;
|
|
|
|
return TRUE;
|
|
|
|
}
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* Map given accesses */
|
|
|
|
RtlMapGenericMask(&DesiredAccess, GenericMapping);
|
|
|
|
if (PreviouslyGrantedAccess)
|
|
|
|
RtlMapGenericMask(&PreviouslyGrantedAccess, GenericMapping);
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2010-04-10 11:44:57 +00:00
|
|
|
#ifdef OLD_ACCESS_CHECK
|
|
|
|
CurrentAccess = PreviouslyGrantedAccess;
|
|
|
|
#endif
|
2010-04-03 21:21:52 +00:00
|
|
|
/* Initialize remaining access rights */
|
2010-04-02 17:46:24 +00:00
|
|
|
RemainingAccess = DesiredAccess;
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
Token = SubjectSecurityContext->ClientToken ?
|
|
|
|
SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2010-04-02 17:46:24 +00:00
|
|
|
/* Check for system security access */
|
|
|
|
if (RemainingAccess & ACCESS_SYSTEM_SECURITY)
|
|
|
|
{
|
|
|
|
Privilege.Luid = SeSecurityPrivilege;
|
|
|
|
Privilege.Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
|
|
|
|
/* Fail if we do not the SeSecurityPrivilege */
|
|
|
|
if (!SepPrivilegeCheck(Token,
|
|
|
|
&Privilege,
|
|
|
|
1,
|
|
|
|
PRIVILEGE_SET_ALL_NECESSARY,
|
|
|
|
AccessMode))
|
|
|
|
{
|
|
|
|
*AccessStatus = STATUS_PRIVILEGE_NOT_HELD;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Adjust access rights */
|
|
|
|
RemainingAccess &= ~ACCESS_SYSTEM_SECURITY;
|
|
|
|
PreviouslyGrantedAccess |= ACCESS_SYSTEM_SECURITY;
|
|
|
|
|
|
|
|
/* Succeed if there are no more rights to grant */
|
|
|
|
if (RemainingAccess == 0)
|
|
|
|
{
|
|
|
|
*GrantedAccess = PreviouslyGrantedAccess;
|
|
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* Get the DACL */
|
|
|
|
Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
|
|
|
|
&Present,
|
|
|
|
&Dacl,
|
|
|
|
&Defaulted);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
*AccessStatus = Status;
|
|
|
|
return FALSE;
|
2004-07-14 14:25:31 +00:00
|
|
|
}
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* RULE 1: Grant desired access if the object is unprotected */
|
2010-03-30 17:01:23 +00:00
|
|
|
if (Present == FALSE || Dacl == NULL)
|
2004-07-13 16:59:35 +00:00
|
|
|
{
|
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail.
Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure.
Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set.
Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it.
Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued.
Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc.
The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set.
With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case).
Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE.
The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success).
Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication).
Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code.
svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
|
|
|
if (DesiredAccess & MAXIMUM_ALLOWED)
|
|
|
|
{
|
|
|
|
*GrantedAccess = GenericMapping->GenericAll;
|
|
|
|
*GrantedAccess |= (DesiredAccess & ~MAXIMUM_ALLOWED);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*GrantedAccess = DesiredAccess | PreviouslyGrantedAccess;
|
|
|
|
}
|
2010-05-28 16:28:27 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
|
|
return TRUE;
|
2004-07-13 16:59:35 +00:00
|
|
|
}
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2010-04-10 11:44:57 +00:00
|
|
|
#ifdef OLD_ACCESS_CHECK
|
|
|
|
CurrentAccess = PreviouslyGrantedAccess;
|
|
|
|
#endif
|
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* RULE 2: Check token for 'take ownership' privilege */
|
2010-04-02 15:13:24 +00:00
|
|
|
if (DesiredAccess & WRITE_OWNER)
|
|
|
|
{
|
|
|
|
Privilege.Luid = SeTakeOwnershipPrivilege;
|
|
|
|
Privilege.Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
|
|
|
|
if (SepPrivilegeCheck(Token,
|
|
|
|
&Privilege,
|
|
|
|
1,
|
|
|
|
PRIVILEGE_SET_ALL_NECESSARY,
|
|
|
|
AccessMode))
|
2007-07-02 22:39:11 +00:00
|
|
|
{
|
2010-04-02 17:46:24 +00:00
|
|
|
/* Adjust access rights */
|
|
|
|
RemainingAccess &= ~WRITE_OWNER;
|
|
|
|
PreviouslyGrantedAccess |= WRITE_OWNER;
|
2010-04-10 11:44:57 +00:00
|
|
|
#ifdef OLD_ACCESS_CHECK
|
|
|
|
CurrentAccess |= WRITE_OWNER;
|
|
|
|
#endif
|
2010-04-02 17:46:24 +00:00
|
|
|
|
|
|
|
/* Succeed if there are no more rights to grant */
|
|
|
|
if (RemainingAccess == 0)
|
2010-04-02 15:13:24 +00:00
|
|
|
{
|
2010-04-02 17:46:24 +00:00
|
|
|
*GrantedAccess = PreviouslyGrantedAccess;
|
2010-04-02 15:13:24 +00:00
|
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
|
|
return TRUE;
|
|
|
|
}
|
2007-07-02 22:39:11 +00:00
|
|
|
}
|
2004-07-14 14:25:31 +00:00
|
|
|
}
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2010-03-31 21:02:38 +00:00
|
|
|
/* Deny access if the DACL is empty */
|
|
|
|
if (Dacl->AceCount == 0)
|
|
|
|
{
|
2010-04-02 17:46:24 +00:00
|
|
|
if (RemainingAccess == MAXIMUM_ALLOWED && PreviouslyGrantedAccess != 0)
|
|
|
|
{
|
|
|
|
*GrantedAccess = PreviouslyGrantedAccess;
|
|
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*GrantedAccess = 0;
|
|
|
|
*AccessStatus = STATUS_ACCESS_DENIED;
|
|
|
|
return FALSE;
|
|
|
|
}
|
2010-03-31 21:02:38 +00:00
|
|
|
}
|
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* Fail if DACL is absent */
|
|
|
|
if (Present == FALSE)
|
2004-09-14 11:04:48 +00:00
|
|
|
{
|
2008-04-23 20:38:37 +00:00
|
|
|
*GrantedAccess = 0;
|
|
|
|
*AccessStatus = STATUS_ACCESS_DENIED;
|
|
|
|
return FALSE;
|
2004-09-14 11:04:48 +00:00
|
|
|
}
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2010-04-03 21:21:52 +00:00
|
|
|
/* Determine the MAXIMUM_ALLOWED access rights according to the DACL */
|
2010-04-03 10:52:17 +00:00
|
|
|
if (DesiredAccess & MAXIMUM_ALLOWED)
|
|
|
|
{
|
|
|
|
CurrentAce = (PACE)(Dacl + 1);
|
|
|
|
for (i = 0; i < Dacl->AceCount; i++)
|
|
|
|
{
|
2010-04-04 12:34:53 +00:00
|
|
|
if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE))
|
2010-04-03 10:52:17 +00:00
|
|
|
{
|
2010-04-04 12:34:53 +00:00
|
|
|
Sid = (PSID)(CurrentAce + 1);
|
|
|
|
if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
|
2010-04-03 10:52:17 +00:00
|
|
|
{
|
2010-04-04 12:34:53 +00:00
|
|
|
if (SepSidInToken(Token, Sid))
|
|
|
|
{
|
|
|
|
/* Map access rights from the ACE */
|
|
|
|
TempAccess = CurrentAce->AccessMask;
|
|
|
|
RtlMapGenericMask(&TempAccess, GenericMapping);
|
|
|
|
|
|
|
|
/* Deny access rights that have not been granted yet */
|
|
|
|
TempDeniedAccess |= (TempAccess & ~TempGrantedAccess);
|
|
|
|
}
|
2010-04-03 10:52:17 +00:00
|
|
|
}
|
2010-04-04 12:34:53 +00:00
|
|
|
else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
|
2010-04-03 10:52:17 +00:00
|
|
|
{
|
2010-04-04 12:34:53 +00:00
|
|
|
if (SepSidInToken(Token, Sid))
|
|
|
|
{
|
|
|
|
/* Map access rights from the ACE */
|
|
|
|
TempAccess = CurrentAce->AccessMask;
|
|
|
|
RtlMapGenericMask(&TempAccess, GenericMapping);
|
|
|
|
|
|
|
|
/* Grant access rights that have not been denied yet */
|
|
|
|
TempGrantedAccess |= (TempAccess & ~TempDeniedAccess);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
|
2010-04-03 10:52:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-03 21:21:52 +00:00
|
|
|
/* Get the next ACE */
|
2010-04-03 10:52:17 +00:00
|
|
|
CurrentAce = (PACE)((ULONG_PTR)CurrentAce + CurrentAce->Header.AceSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fail if some rights have not been granted */
|
|
|
|
RemainingAccess &= ~(MAXIMUM_ALLOWED | TempGrantedAccess);
|
|
|
|
if (RemainingAccess != 0)
|
|
|
|
{
|
|
|
|
*GrantedAccess = 0;
|
|
|
|
*AccessStatus = STATUS_ACCESS_DENIED;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set granted access right and access status */
|
|
|
|
*GrantedAccess = TempGrantedAccess | PreviouslyGrantedAccess;
|
|
|
|
if (*GrantedAccess != 0)
|
|
|
|
{
|
|
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*AccessStatus = STATUS_ACCESS_DENIED;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* RULE 4: Grant rights according to the DACL */
|
|
|
|
CurrentAce = (PACE)(Dacl + 1);
|
|
|
|
for (i = 0; i < Dacl->AceCount; i++)
|
2004-07-13 16:59:35 +00:00
|
|
|
{
|
2010-04-04 12:34:53 +00:00
|
|
|
if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE))
|
2007-03-18 12:47:27 +00:00
|
|
|
{
|
2010-04-04 12:34:53 +00:00
|
|
|
Sid = (PSID)(CurrentAce + 1);
|
|
|
|
if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
|
2007-03-18 12:47:27 +00:00
|
|
|
{
|
2010-04-04 12:34:53 +00:00
|
|
|
if (SepSidInToken(Token, Sid))
|
|
|
|
{
|
2010-04-10 11:44:57 +00:00
|
|
|
#ifdef OLD_ACCESS_CHECK
|
|
|
|
*GrantedAccess = 0;
|
|
|
|
*AccessStatus = STATUS_ACCESS_DENIED;
|
|
|
|
return FALSE;
|
|
|
|
#else
|
2010-04-04 12:34:53 +00:00
|
|
|
/* Map access rights from the ACE */
|
|
|
|
TempAccess = CurrentAce->AccessMask;
|
|
|
|
RtlMapGenericMask(&TempAccess, GenericMapping);
|
2010-04-03 21:21:52 +00:00
|
|
|
|
2010-04-04 12:34:53 +00:00
|
|
|
/* Leave if a remaining right must be denied */
|
|
|
|
if (RemainingAccess & TempAccess)
|
|
|
|
break;
|
2010-04-10 11:44:57 +00:00
|
|
|
#endif
|
2010-04-04 12:34:53 +00:00
|
|
|
}
|
2007-03-18 12:47:27 +00:00
|
|
|
}
|
2010-04-04 12:34:53 +00:00
|
|
|
else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
|
2007-03-18 12:47:27 +00:00
|
|
|
{
|
2010-04-04 12:34:53 +00:00
|
|
|
if (SepSidInToken(Token, Sid))
|
|
|
|
{
|
2010-04-10 11:44:57 +00:00
|
|
|
#ifdef OLD_ACCESS_CHECK
|
|
|
|
AccessMask = CurrentAce->AccessMask;
|
|
|
|
RtlMapGenericMask(&AccessMask, GenericMapping);
|
|
|
|
CurrentAccess |= AccessMask;
|
|
|
|
#else
|
2010-04-04 12:34:53 +00:00
|
|
|
/* Map access rights from the ACE */
|
|
|
|
TempAccess = CurrentAce->AccessMask;
|
|
|
|
RtlMapGenericMask(&TempAccess, GenericMapping);
|
2010-04-03 21:21:52 +00:00
|
|
|
|
2010-04-04 12:34:53 +00:00
|
|
|
/* Remove granted rights */
|
|
|
|
RemainingAccess &= ~TempAccess;
|
2010-04-10 11:44:57 +00:00
|
|
|
#endif
|
2010-04-04 12:34:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
|
2007-03-18 12:47:27 +00:00
|
|
|
}
|
2008-04-23 20:38:37 +00:00
|
|
|
}
|
2010-04-03 21:21:52 +00:00
|
|
|
|
|
|
|
/* Get the next ACE */
|
2007-03-18 12:47:27 +00:00
|
|
|
CurrentAce = (PACE)((ULONG_PTR)CurrentAce + CurrentAce->Header.AceSize);
|
2004-07-13 16:59:35 +00:00
|
|
|
}
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2010-04-10 11:44:57 +00:00
|
|
|
#ifdef OLD_ACCESS_CHECK
|
|
|
|
DPRINT("CurrentAccess %08lx\n DesiredAccess %08lx\n",
|
|
|
|
CurrentAccess, DesiredAccess);
|
|
|
|
|
|
|
|
*GrantedAccess = CurrentAccess & DesiredAccess;
|
|
|
|
|
|
|
|
if ((*GrantedAccess & ~VALID_INHERIT_FLAGS) ==
|
|
|
|
(DesiredAccess & ~VALID_INHERIT_FLAGS))
|
|
|
|
{
|
|
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DPRINT1("HACK: Should deny access for caller: granted 0x%lx, desired 0x%lx (generic mapping %p).\n",
|
|
|
|
*GrantedAccess, DesiredAccess, GenericMapping);
|
|
|
|
//*AccessStatus = STATUS_ACCESS_DENIED;
|
|
|
|
//return FALSE;
|
|
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
#else
|
2010-04-03 21:21:52 +00:00
|
|
|
DPRINT("DesiredAccess %08lx\nPreviouslyGrantedAccess %08lx\nRemainingAccess %08lx\n",
|
|
|
|
DesiredAccess, PreviouslyGrantedAccess, RemainingAccess);
|
2009-06-25 13:29:58 +00:00
|
|
|
|
2010-04-03 21:21:52 +00:00
|
|
|
/* Fail if some rights have not been granted */
|
|
|
|
if (RemainingAccess != 0)
|
2006-10-15 23:31:16 +00:00
|
|
|
{
|
2010-04-03 21:21:52 +00:00
|
|
|
*GrantedAccess = 0;
|
|
|
|
*AccessStatus = STATUS_ACCESS_DENIED;
|
|
|
|
return FALSE;
|
2006-10-15 23:31:16 +00:00
|
|
|
}
|
2010-04-03 21:21:52 +00:00
|
|
|
|
|
|
|
/* Set granted access rights */
|
|
|
|
*GrantedAccess = DesiredAccess | PreviouslyGrantedAccess;
|
|
|
|
|
|
|
|
DPRINT("GrantedAccess %08lx\n", *GrantedAccess);
|
|
|
|
|
|
|
|
/* Fail if no rights have been granted */
|
|
|
|
if (*GrantedAccess == 0)
|
2006-10-15 23:31:16 +00:00
|
|
|
{
|
2010-04-03 21:21:52 +00:00
|
|
|
*AccessStatus = STATUS_ACCESS_DENIED;
|
|
|
|
return FALSE;
|
2006-10-15 23:31:16 +00:00
|
|
|
}
|
2010-04-03 21:21:52 +00:00
|
|
|
|
|
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
|
|
return TRUE;
|
2010-04-10 11:44:57 +00:00
|
|
|
#endif
|
2004-07-14 14:25:31 +00:00
|
|
|
}
|
|
|
|
|
2010-03-27 16:54:02 +00:00
|
|
|
static PSID
|
|
|
|
SepGetSDOwner(IN PSECURITY_DESCRIPTOR _SecurityDescriptor)
|
|
|
|
{
|
|
|
|
PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
|
|
|
|
PSID Owner;
|
|
|
|
|
|
|
|
if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
|
|
|
|
Owner = (PSID)((ULONG_PTR)SecurityDescriptor->Owner +
|
|
|
|
(ULONG_PTR)SecurityDescriptor);
|
|
|
|
else
|
|
|
|
Owner = (PSID)SecurityDescriptor->Owner;
|
|
|
|
|
|
|
|
return Owner;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PSID
|
|
|
|
SepGetSDGroup(IN PSECURITY_DESCRIPTOR _SecurityDescriptor)
|
|
|
|
{
|
|
|
|
PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
|
|
|
|
PSID Group;
|
|
|
|
|
|
|
|
if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
|
|
|
|
Group = (PSID)((ULONG_PTR)SecurityDescriptor->Group +
|
|
|
|
(ULONG_PTR)SecurityDescriptor);
|
|
|
|
else
|
|
|
|
Group = (PSID)SecurityDescriptor->Group;
|
|
|
|
|
|
|
|
return Group;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-11-21 17:58:33 +00:00
|
|
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2010-05-28 16:28:27 +00:00
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
2009-11-21 17:58:33 +00:00
|
|
|
SeAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
|
|
IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
|
|
|
|
IN BOOLEAN SubjectContextLocked,
|
|
|
|
IN ACCESS_MASK DesiredAccess,
|
|
|
|
IN ACCESS_MASK PreviouslyGrantedAccess,
|
|
|
|
OUT PPRIVILEGE_SET* Privileges,
|
|
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
|
|
IN KPROCESSOR_MODE AccessMode,
|
|
|
|
OUT PACCESS_MASK GrantedAccess,
|
|
|
|
OUT PNTSTATUS AccessStatus)
|
|
|
|
{
|
2010-03-31 19:53:19 +00:00
|
|
|
BOOLEAN ret;
|
|
|
|
|
2010-03-30 17:01:23 +00:00
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
/* Check if this is kernel mode */
|
|
|
|
if (AccessMode == KernelMode)
|
|
|
|
{
|
|
|
|
/* Check if kernel wants everything */
|
|
|
|
if (DesiredAccess & MAXIMUM_ALLOWED)
|
|
|
|
{
|
|
|
|
/* Give it */
|
|
|
|
*GrantedAccess = GenericMapping->GenericAll;
|
|
|
|
*GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
|
|
|
|
*GrantedAccess |= PreviouslyGrantedAccess;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Give the desired and previous access */
|
|
|
|
*GrantedAccess = DesiredAccess | PreviouslyGrantedAccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Success */
|
|
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2010-03-30 20:16:26 +00:00
|
|
|
/* Check if we didn't get an SD */
|
|
|
|
if (!SecurityDescriptor)
|
|
|
|
{
|
|
|
|
/* Automatic failure */
|
|
|
|
*AccessStatus = STATUS_ACCESS_DENIED;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for invalid impersonation */
|
|
|
|
if ((SubjectSecurityContext->ClientToken) &&
|
|
|
|
(SubjectSecurityContext->ImpersonationLevel < SecurityImpersonation))
|
|
|
|
{
|
|
|
|
*AccessStatus = STATUS_BAD_IMPERSONATION_LEVEL;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2010-03-31 19:53:19 +00:00
|
|
|
/* Acquire the lock if needed */
|
|
|
|
if (!SubjectContextLocked)
|
|
|
|
SeLockSubjectContext(SubjectSecurityContext);
|
|
|
|
|
2010-04-02 15:13:24 +00:00
|
|
|
/* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
|
|
|
|
if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
|
|
|
|
{
|
|
|
|
PACCESS_TOKEN Token = SubjectSecurityContext->ClientToken ?
|
|
|
|
SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
|
|
|
|
|
|
|
|
if (SepTokenIsOwner(Token,
|
|
|
|
SecurityDescriptor))
|
|
|
|
{
|
|
|
|
if (DesiredAccess & MAXIMUM_ALLOWED)
|
|
|
|
PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
|
|
|
|
else
|
|
|
|
PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
|
|
|
|
|
|
|
|
DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DesiredAccess == 0)
|
|
|
|
{
|
|
|
|
*GrantedAccess = PreviouslyGrantedAccess;
|
|
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
|
|
ret = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Call the internal function */
|
|
|
|
ret = SepAccessCheck(SecurityDescriptor,
|
|
|
|
SubjectSecurityContext,
|
|
|
|
DesiredAccess,
|
|
|
|
PreviouslyGrantedAccess,
|
|
|
|
Privileges,
|
|
|
|
GenericMapping,
|
|
|
|
AccessMode,
|
|
|
|
GrantedAccess,
|
|
|
|
AccessStatus);
|
|
|
|
}
|
2010-03-31 19:53:19 +00:00
|
|
|
|
|
|
|
/* Release the lock if needed */
|
|
|
|
if (!SubjectContextLocked)
|
|
|
|
SeUnlockSubjectContext(SubjectSecurityContext);
|
|
|
|
|
|
|
|
return ret;
|
2009-11-21 17:58:33 +00:00
|
|
|
}
|
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* SYSTEM CALLS ***************************************************************/
|
2004-07-14 14:25:31 +00:00
|
|
|
|
2009-01-02 17:39:45 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
2004-07-14 14:25:31 +00:00
|
|
|
NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
2007-07-02 22:39:11 +00:00
|
|
|
IN HANDLE TokenHandle,
|
|
|
|
IN ACCESS_MASK DesiredAccess,
|
|
|
|
IN PGENERIC_MAPPING GenericMapping,
|
2009-01-02 17:39:45 +00:00
|
|
|
OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL,
|
|
|
|
IN OUT PULONG PrivilegeSetLength,
|
2007-07-02 22:39:11 +00:00
|
|
|
OUT PACCESS_MASK GrantedAccess,
|
|
|
|
OUT PNTSTATUS AccessStatus)
|
2004-07-14 14:25:31 +00:00
|
|
|
{
|
2010-03-30 20:16:26 +00:00
|
|
|
PSECURITY_DESCRIPTOR CapturedSecurityDescriptor = NULL;
|
2009-01-02 17:39:45 +00:00
|
|
|
SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
|
|
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
2010-04-02 15:13:24 +00:00
|
|
|
ACCESS_MASK PreviouslyGrantedAccess = 0;
|
2008-04-23 20:38:37 +00:00
|
|
|
PTOKEN Token;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
2009-06-24 22:23:29 +00:00
|
|
|
|
2009-01-02 17:39:45 +00:00
|
|
|
/* Check if this is kernel mode */
|
2008-04-23 20:38:37 +00:00
|
|
|
if (PreviousMode == KernelMode)
|
2004-07-14 14:25:31 +00:00
|
|
|
{
|
2009-01-02 17:39:45 +00:00
|
|
|
/* Check if kernel wants everything */
|
|
|
|
if (DesiredAccess & MAXIMUM_ALLOWED)
|
|
|
|
{
|
|
|
|
/* Give it */
|
|
|
|
*GrantedAccess = GenericMapping->GenericAll;
|
|
|
|
*GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Just give the desired access */
|
|
|
|
*GrantedAccess = DesiredAccess;
|
|
|
|
}
|
2009-06-24 22:23:29 +00:00
|
|
|
|
2009-01-02 17:39:45 +00:00
|
|
|
/* Success */
|
2008-04-23 20:38:37 +00:00
|
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
2009-01-02 17:39:45 +00:00
|
|
|
|
2010-03-21 14:10:50 +00:00
|
|
|
/* Protect probe in SEH */
|
|
|
|
_SEH2_TRY
|
|
|
|
{
|
|
|
|
/* Probe all pointers */
|
|
|
|
ProbeForRead(GenericMapping, sizeof(GENERIC_MAPPING), sizeof(ULONG));
|
|
|
|
ProbeForRead(PrivilegeSetLength, sizeof(ULONG), sizeof(ULONG));
|
|
|
|
ProbeForWrite(PrivilegeSet, *PrivilegeSetLength, sizeof(ULONG));
|
|
|
|
ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK), sizeof(ULONG));
|
|
|
|
ProbeForWrite(AccessStatus, sizeof(NTSTATUS), sizeof(ULONG));
|
|
|
|
}
|
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
/* Return the exception code */
|
|
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
|
|
}
|
|
|
|
_SEH2_END;
|
|
|
|
|
|
|
|
/* Check for unmapped access rights */
|
|
|
|
if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL))
|
|
|
|
return STATUS_GENERIC_NOT_MAPPED;
|
|
|
|
|
2009-01-02 17:39:45 +00:00
|
|
|
/* Reference the token */
|
2008-04-23 20:38:37 +00:00
|
|
|
Status = ObReferenceObjectByHandle(TokenHandle,
|
|
|
|
TOKEN_QUERY,
|
|
|
|
SepTokenObjectType,
|
|
|
|
PreviousMode,
|
|
|
|
(PVOID*)&Token,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2010-03-27 16:54:02 +00:00
|
|
|
DPRINT("Failed to reference token (Status %lx)\n", Status);
|
2008-04-23 20:38:37 +00:00
|
|
|
return Status;
|
|
|
|
}
|
2009-01-02 17:39:45 +00:00
|
|
|
|
2008-04-23 20:38:37 +00:00
|
|
|
/* Check token type */
|
|
|
|
if (Token->TokenType != TokenImpersonation)
|
|
|
|
{
|
2010-03-27 16:54:02 +00:00
|
|
|
DPRINT("No impersonation token\n");
|
2008-04-23 20:38:37 +00:00
|
|
|
ObDereferenceObject(Token);
|
2010-03-23 00:16:14 +00:00
|
|
|
return STATUS_NO_IMPERSONATION_TOKEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check the impersonation level */
|
|
|
|
if (Token->ImpersonationLevel < SecurityIdentification)
|
|
|
|
{
|
2010-03-27 16:54:02 +00:00
|
|
|
DPRINT("Impersonation level < SecurityIdentification\n");
|
2010-03-23 00:16:14 +00:00
|
|
|
ObDereferenceObject(Token);
|
|
|
|
return STATUS_BAD_IMPERSONATION_LEVEL;
|
2008-04-23 20:38:37 +00:00
|
|
|
}
|
2009-01-02 17:39:45 +00:00
|
|
|
|
2010-03-30 20:16:26 +00:00
|
|
|
/* Capture the security descriptor */
|
|
|
|
Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
|
|
|
|
PreviousMode,
|
|
|
|
PagedPool,
|
|
|
|
FALSE,
|
|
|
|
&CapturedSecurityDescriptor);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT("Failed to capture the Security Descriptor\n");
|
|
|
|
ObDereferenceObject(Token);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check the captured security descriptor */
|
|
|
|
if (CapturedSecurityDescriptor == NULL)
|
|
|
|
{
|
|
|
|
DPRINT("Security Descriptor is NULL\n");
|
|
|
|
ObDereferenceObject(Token);
|
|
|
|
return STATUS_INVALID_SECURITY_DESCR;
|
|
|
|
}
|
|
|
|
|
2010-03-27 16:54:02 +00:00
|
|
|
/* Check security descriptor for valid owner and group */
|
2010-03-31 19:53:19 +00:00
|
|
|
if (SepGetSDOwner(SecurityDescriptor) == NULL || // FIXME: use CapturedSecurityDescriptor
|
|
|
|
SepGetSDGroup(SecurityDescriptor) == NULL) // FIXME: use CapturedSecurityDescriptor
|
2010-03-27 16:54:02 +00:00
|
|
|
{
|
|
|
|
DPRINT("Security Descriptor does not have a valid group or owner\n");
|
2010-03-30 20:16:26 +00:00
|
|
|
SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
|
|
|
|
PreviousMode,
|
|
|
|
FALSE);
|
2010-03-27 16:54:02 +00:00
|
|
|
ObDereferenceObject(Token);
|
|
|
|
return STATUS_INVALID_SECURITY_DESCR;
|
|
|
|
}
|
|
|
|
|
2009-01-02 17:39:45 +00:00
|
|
|
/* Set up the subject context, and lock it */
|
2008-04-23 20:38:37 +00:00
|
|
|
SubjectSecurityContext.ClientToken = Token;
|
|
|
|
SubjectSecurityContext.ImpersonationLevel = Token->ImpersonationLevel;
|
2009-01-02 17:39:45 +00:00
|
|
|
SubjectSecurityContext.PrimaryToken = NULL;
|
|
|
|
SubjectSecurityContext.ProcessAuditId = NULL;
|
2008-04-23 20:38:37 +00:00
|
|
|
SeLockSubjectContext(&SubjectSecurityContext);
|
2009-01-02 17:39:45 +00:00
|
|
|
|
2010-04-02 15:13:24 +00:00
|
|
|
/* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
|
|
|
|
if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
|
|
|
|
{
|
|
|
|
if (SepTokenIsOwner(Token, SecurityDescriptor)) // FIXME: use CapturedSecurityDescriptor
|
|
|
|
{
|
|
|
|
if (DesiredAccess & MAXIMUM_ALLOWED)
|
|
|
|
PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
|
|
|
|
else
|
|
|
|
PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
|
|
|
|
|
|
|
|
DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DesiredAccess == 0)
|
|
|
|
{
|
|
|
|
*GrantedAccess = PreviouslyGrantedAccess;
|
|
|
|
*AccessStatus = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Now perform the access check */
|
|
|
|
SepAccessCheck(SecurityDescriptor, // FIXME: use CapturedSecurityDescriptor
|
|
|
|
&SubjectSecurityContext,
|
|
|
|
DesiredAccess,
|
|
|
|
PreviouslyGrantedAccess,
|
|
|
|
&PrivilegeSet, //FIXME
|
|
|
|
GenericMapping,
|
|
|
|
PreviousMode,
|
|
|
|
GrantedAccess,
|
|
|
|
AccessStatus);
|
|
|
|
}
|
2009-01-02 17:39:45 +00:00
|
|
|
|
2010-03-27 16:54:02 +00:00
|
|
|
/* Unlock subject context */
|
2008-04-23 20:38:37 +00:00
|
|
|
SeUnlockSubjectContext(&SubjectSecurityContext);
|
2010-03-27 16:54:02 +00:00
|
|
|
|
2010-03-30 20:16:26 +00:00
|
|
|
/* Release the captured security descriptor */
|
|
|
|
SeReleaseSecurityDescriptor(CapturedSecurityDescriptor,
|
|
|
|
PreviousMode,
|
|
|
|
FALSE);
|
|
|
|
|
2010-03-27 16:54:02 +00:00
|
|
|
/* Dereference the token */
|
2008-04-23 20:38:37 +00:00
|
|
|
ObDereferenceObject(Token);
|
2009-01-02 17:39:45 +00:00
|
|
|
|
2009-06-25 13:29:58 +00:00
|
|
|
/* Check succeeded */
|
|
|
|
return STATUS_SUCCESS;
|
1998-08-25 04:27:26 +00:00
|
|
|
}
|
|
|
|
|
2009-01-02 17:39:45 +00:00
|
|
|
|
2006-10-23 17:47:40 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NtAccessCheckByType(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
|
|
IN PSID PrincipalSelfSid,
|
2006-10-23 21:24:16 +00:00
|
|
|
IN HANDLE ClientToken,
|
2006-10-23 17:47:40 +00:00
|
|
|
IN ACCESS_MASK DesiredAccess,
|
|
|
|
IN POBJECT_TYPE_LIST ObjectTypeList,
|
|
|
|
IN ULONG ObjectTypeLength,
|
|
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
|
|
IN PPRIVILEGE_SET PrivilegeSet,
|
|
|
|
IN ULONG PrivilegeSetLength,
|
|
|
|
OUT PACCESS_MASK GrantedAccess,
|
|
|
|
OUT PNTSTATUS AccessStatus)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NtAccessCheckByTypeAndAuditAlarm(IN PUNICODE_STRING SubsystemName,
|
|
|
|
IN HANDLE HandleId,
|
|
|
|
IN PUNICODE_STRING ObjectTypeName,
|
|
|
|
IN PUNICODE_STRING ObjectName,
|
|
|
|
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
|
|
IN PSID PrincipalSelfSid,
|
|
|
|
IN ACCESS_MASK DesiredAccess,
|
|
|
|
IN AUDIT_EVENT_TYPE AuditType,
|
|
|
|
IN ULONG Flags,
|
|
|
|
IN POBJECT_TYPE_LIST ObjectTypeList,
|
|
|
|
IN ULONG ObjectTypeLength,
|
|
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
|
|
IN BOOLEAN ObjectCreation,
|
|
|
|
OUT PACCESS_MASK GrantedAccess,
|
|
|
|
OUT PNTSTATUS AccessStatus,
|
|
|
|
OUT PBOOLEAN GenerateOnClose)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NtAccessCheckByTypeResultList(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
|
|
IN PSID PrincipalSelfSid,
|
2006-10-23 21:24:16 +00:00
|
|
|
IN HANDLE ClientToken,
|
2006-10-23 17:47:40 +00:00
|
|
|
IN ACCESS_MASK DesiredAccess,
|
|
|
|
IN POBJECT_TYPE_LIST ObjectTypeList,
|
|
|
|
IN ULONG ObjectTypeLength,
|
|
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
|
|
IN PPRIVILEGE_SET PrivilegeSet,
|
|
|
|
IN ULONG PrivilegeSetLength,
|
|
|
|
OUT PACCESS_MASK GrantedAccess,
|
|
|
|
OUT PNTSTATUS AccessStatus)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NtAccessCheckByTypeResultListAndAuditAlarm(IN PUNICODE_STRING SubsystemName,
|
|
|
|
IN HANDLE HandleId,
|
|
|
|
IN PUNICODE_STRING ObjectTypeName,
|
|
|
|
IN PUNICODE_STRING ObjectName,
|
|
|
|
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
|
|
IN PSID PrincipalSelfSid,
|
|
|
|
IN ACCESS_MASK DesiredAccess,
|
|
|
|
IN AUDIT_EVENT_TYPE AuditType,
|
|
|
|
IN ULONG Flags,
|
|
|
|
IN POBJECT_TYPE_LIST ObjectTypeList,
|
|
|
|
IN ULONG ObjectTypeLength,
|
|
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
|
|
IN BOOLEAN ObjectCreation,
|
|
|
|
OUT PACCESS_MASK GrantedAccess,
|
|
|
|
OUT PNTSTATUS AccessStatus,
|
|
|
|
OUT PBOOLEAN GenerateOnClose)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NtAccessCheckByTypeResultListAndAuditAlarmByHandle(IN PUNICODE_STRING SubsystemName,
|
|
|
|
IN HANDLE HandleId,
|
2006-10-23 21:24:16 +00:00
|
|
|
IN HANDLE ClientToken,
|
2006-10-23 17:47:40 +00:00
|
|
|
IN PUNICODE_STRING ObjectTypeName,
|
|
|
|
IN PUNICODE_STRING ObjectName,
|
|
|
|
IN PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
|
|
IN PSID PrincipalSelfSid,
|
|
|
|
IN ACCESS_MASK DesiredAccess,
|
|
|
|
IN AUDIT_EVENT_TYPE AuditType,
|
|
|
|
IN ULONG Flags,
|
|
|
|
IN POBJECT_TYPE_LIST ObjectTypeList,
|
|
|
|
IN ULONG ObjectTypeLength,
|
|
|
|
IN PGENERIC_MAPPING GenericMapping,
|
|
|
|
IN BOOLEAN ObjectCreation,
|
|
|
|
OUT PACCESS_MASK GrantedAccess,
|
|
|
|
OUT PNTSTATUS AccessStatus,
|
|
|
|
OUT PBOOLEAN GenerateOnClose)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
1999-12-26 17:22:19 +00:00
|
|
|
/* EOF */
|