https://git.reactos.org/?p=reactos.git;a=commitdiff;h=9a2c62b544d6539f6c671…
commit 9a2c62b544d6539f6c6719190d841731d81816d2
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Sat May 28 21:14:04 2022 +0200
Commit: George Bișoc <george.bisoc(a)reactos.org>
CommitDate: Sun May 29 20:22:19 2022 +0200
[NTOS:SE] Reorganize the security manager component
The current state of Security manager's code is kind of a mess. Mainly,
there's code scattered around places where they shouldn't belong and token
implementation (token.c) is already of a bloat in itself as it is. The file has over 6k
lines and it's subject to grow exponentially with improvements, features, whatever
that is.
With that being said, the token implementation code in the kernel will be split
accordingly and rest of the code moved to appropriate places. The new layout will look as
follows (excluding the already existing files):
- client.c (Client security implementation code)
- objtype.c (Object type list implementation code -- more code related to object types
will be put here when I'm going to implement object type access checks in the future)
- subject.c (Subject security context support)
The token implementation in the kernel will be split in 4 distinct files as shown:
- token.c (Base token support routines)
- tokenlif.c (Life management of a token object -- that is Duplication, Creation and
Filtering)
- tokencls.c (Token Query/Set Information Classes support)
- tokenadj.c (Token privileges/groups adjusting support)
In addition to that, tidy up the internal header and reorganize it as well.
---
ntoskrnl/include/internal/se.h | 532 ++--
ntoskrnl/ntos.cmake | 6 +
ntoskrnl/se/access.c | 711 -----
ntoskrnl/se/audit.c | 103 +-
ntoskrnl/se/client.c | 331 +++
ntoskrnl/se/objtype.c | 115 +
ntoskrnl/se/sid.c | 140 +
ntoskrnl/se/subject.c | 185 ++
ntoskrnl/se/token.c | 5563 ++++------------------------------------
ntoskrnl/se/tokenadj.c | 910 +++++++
ntoskrnl/se/tokencls.c | 1588 ++++++++++++
ntoskrnl/se/tokenlif.c | 2201 ++++++++++++++++
12 files changed, 6325 insertions(+), 6060 deletions(-)
diff --git a/ntoskrnl/include/internal/se.h b/ntoskrnl/include/internal/se.h
index 034203d9313..db2dd0b58a3 100644
--- a/ntoskrnl/include/internal/se.h
+++ b/ntoskrnl/include/internal/se.h
@@ -1,5 +1,16 @@
+/*
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Internal header for the Security Manager
+ * COPYRIGHT: Copyright Eric Kohl
+ * Copyright 2022 George Bișoc <george.bisoc(a)reactos.org>
+ */
+
#pragma once
+//
+// Internal ACE type structures
+//
typedef struct _KNOWN_ACE
{
ACE_HEADER Header;
@@ -24,6 +35,9 @@ typedef struct _KNOWN_COMPOUND_ACE
ULONG SidStart;
} KNOWN_COMPOUND_ACE, *PKNOWN_COMPOUND_ACE;
+//
+// Access Check Rights
+//
typedef struct _ACCESS_CHECK_RIGHTS
{
ACCESS_MASK RemainingAccessRights;
@@ -37,6 +51,9 @@ typedef enum _ACCESS_CHECK_RIGHT_TYPE
AccessCheckRegular
} ACCESS_CHECK_RIGHT_TYPE;
+//
+// Token Audit Policy Information structure
+//
typedef struct _TOKEN_AUDIT_POLICY_INFORMATION
{
ULONG PolicyCount;
@@ -47,10 +64,16 @@ typedef struct _TOKEN_AUDIT_POLICY_INFORMATION
} Policies[1];
} TOKEN_AUDIT_POLICY_INFORMATION, *PTOKEN_AUDIT_POLICY_INFORMATION;
+//
+// Token creation method defines (for debugging purposes)
+//
#define TOKEN_CREATE_METHOD 0xCUL
#define TOKEN_DUPLICATE_METHOD 0xDUL
#define TOKEN_FILTER_METHOD 0xFUL
+//
+// Security descriptor internal helpers
+//
FORCEINLINE
PSID
SepGetGroupFromDescriptor(
@@ -137,14 +160,18 @@ SepGetSaclFromDescriptor(
#ifndef RTL_H
-/* SID Authorities */
+//
+// SID Authorities
+//
extern SID_IDENTIFIER_AUTHORITY SeNullSidAuthority;
extern SID_IDENTIFIER_AUTHORITY SeWorldSidAuthority;
extern SID_IDENTIFIER_AUTHORITY SeLocalSidAuthority;
extern SID_IDENTIFIER_AUTHORITY SeCreatorSidAuthority;
extern SID_IDENTIFIER_AUTHORITY SeNtSidAuthority;
-/* SIDs */
+//
+// SIDs
+//
extern PSID SeNullSid;
extern PSID SeWorldSid;
extern PSID SeLocalSid;
@@ -177,7 +204,9 @@ extern PSID SeAnonymousLogonSid;
extern PSID SeLocalServiceSid;
extern PSID SeNetworkServiceSid;
-/* Privileges */
+//
+// Privileges
+//
extern const LUID SeCreateTokenPrivilege;
extern const LUID SeAssignPrimaryTokenPrivilege;
extern const LUID SeLockMemoryPrivilege;
@@ -213,14 +242,18 @@ extern const LUID SeIncreaseWorkingSetPrivilege;
extern const LUID SeTimeZonePrivilege;
extern const LUID SeCreateSymbolicLinkPrivilege;
-/* DACLs */
+//
+// DACLs
+//
extern PACL SePublicDefaultUnrestrictedDacl;
extern PACL SePublicOpenDacl;
extern PACL SePublicOpenUnrestrictedDacl;
extern PACL SeUnrestrictedDacl;
extern PACL SeSystemAnonymousLogonDacl;
-/* SDs */
+//
+// SDs
+//
extern PSECURITY_DESCRIPTOR SePublicDefaultSd;
extern PSECURITY_DESCRIPTOR SePublicDefaultUnrestrictedSd;
extern PSECURITY_DESCRIPTOR SePublicOpenSd;
@@ -229,11 +262,16 @@ extern PSECURITY_DESCRIPTOR SeSystemDefaultSd;
extern PSECURITY_DESCRIPTOR SeUnrestrictedSd;
extern PSECURITY_DESCRIPTOR SeSystemAnonymousLogonSd;
-/* Anonymous Logon Tokens */
+//
+// Anonymous Logon Tokens
+//
extern PTOKEN SeAnonymousLogonToken;
extern PTOKEN SeAnonymousLogonTokenNoEveryone;
+//
+// Token lock management macros
+//
#define SepAcquireTokenLockExclusive(Token) \
{ \
KeEnterCriticalRegion(); \
@@ -254,68 +292,116 @@ extern PTOKEN SeAnonymousLogonTokenNoEveryone;
//
// Token Functions
//
-BOOLEAN
+CODE_SEG("INIT")
+VOID
NTAPI
-SepTokenIsOwner(
- _In_ PACCESS_TOKEN _Token,
- _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
- _In_ BOOLEAN TokenLocked);
+SepInitializeTokenImplementation(VOID);
-BOOLEAN
+CODE_SEG("INIT")
+PTOKEN
NTAPI
-SepSidInToken(
- _In_ PACCESS_TOKEN _Token,
- _In_ PSID Sid);
+SepCreateSystemProcessToken(VOID);
-BOOLEAN
+CODE_SEG("INIT")
+PTOKEN
+SepCreateSystemAnonymousLogonToken(VOID);
+
+CODE_SEG("INIT")
+PTOKEN
+SepCreateSystemAnonymousLogonTokenNoEveryone(VOID);
+
+NTSTATUS
NTAPI
-SepSidInTokenEx(
- _In_ PACCESS_TOKEN _Token,
- _In_ PSID PrincipalSelfSid,
- _In_ PSID _Sid,
- _In_ BOOLEAN Deny,
- _In_ BOOLEAN Restricted);
+SepDuplicateToken(
+ _In_ PTOKEN Token,
+ _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
+ _In_ BOOLEAN EffectiveOnly,
+ _In_ TOKEN_TYPE TokenType,
+ _In_ SECURITY_IMPERSONATION_LEVEL Level,
+ _In_ KPROCESSOR_MODE PreviousMode,
+ _Out_ PTOKEN* NewAccessToken);
-BOOLEAN
+NTSTATUS
NTAPI
-SeTokenCanImpersonate(
- _In_ PTOKEN ProcessToken,
- _In_ PTOKEN TokenToImpersonate,
- _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
+SepCreateToken(
+ _Out_ PHANDLE TokenHandle,
+ _In_ KPROCESSOR_MODE PreviousMode,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
+ _In_ TOKEN_TYPE TokenType,
+ _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
+ _In_ PLUID AuthenticationId,
+ _In_ PLARGE_INTEGER ExpirationTime,
+ _In_ PSID_AND_ATTRIBUTES User,
+ _In_ ULONG GroupCount,
+ _In_ PSID_AND_ATTRIBUTES Groups,
+ _In_ ULONG GroupsLength,
+ _In_ ULONG PrivilegeCount,
+ _In_ PLUID_AND_ATTRIBUTES Privileges,
+ _In_opt_ PSID Owner,
+ _In_ PSID PrimaryGroup,
+ _In_opt_ PACL DefaultDacl,
+ _In_ PTOKEN_SOURCE TokenSource,
+ _In_ BOOLEAN SystemToken);
-/* Functions */
-CODE_SEG("INIT")
BOOLEAN
NTAPI
-SeInitSystem(VOID);
+SepTokenIsOwner(
+ _In_ PACCESS_TOKEN _Token,
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_ BOOLEAN TokenLocked);
+
+NTSTATUS
+SepCreateTokenLock(
+ _Inout_ PTOKEN Token);
-CODE_SEG("INIT")
VOID
-NTAPI
-SepInitPrivileges(VOID);
+SepDeleteTokenLock(
+ _Inout_ PTOKEN Token);
-CODE_SEG("INIT")
-BOOLEAN
-NTAPI
-SepInitSecurityIDs(VOID);
+VOID
+SepUpdatePrivilegeFlagsToken(
+ _Inout_ PTOKEN Token);
-CODE_SEG("INIT")
-BOOLEAN
-NTAPI
-SepInitDACLs(VOID);
+NTSTATUS
+SepFindPrimaryGroupAndDefaultOwner(
+ _In_ PTOKEN Token,
+ _In_ PSID PrimaryGroup,
+ _In_opt_ PSID DefaultOwner,
+ _Out_opt_ PULONG PrimaryGroupIndex,
+ _Out_opt_ PULONG DefaultOwnerIndex);
-CODE_SEG("INIT")
-BOOLEAN
-NTAPI
-SepInitSDs(VOID);
+VOID
+SepUpdateSinglePrivilegeFlagToken(
+ _Inout_ PTOKEN Token,
+ _In_ ULONG Index);
+
+VOID
+SepUpdatePrivilegeFlagsToken(
+ _Inout_ PTOKEN Token);
+
+VOID
+SepRemovePrivilegeToken(
+ _Inout_ PTOKEN Token,
+ _In_ ULONG Index);
+
+VOID
+SepRemoveUserGroupToken(
+ _Inout_ PTOKEN Token,
+ _In_ ULONG Index);
BOOLEAN
NTAPI
-SeRmInitPhase0(VOID);
+SeTokenCanImpersonate(
+ _In_ PTOKEN ProcessToken,
+ _In_ PTOKEN TokenToImpersonate,
+ _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
-BOOLEAN
+VOID
NTAPI
-SeRmInitPhase1(VOID);
+SeGetTokenControlInformation(
+ _In_ PACCESS_TOKEN _Token,
+ _Out_ PTOKEN_CONTROL TokenControl);
VOID
NTAPI
@@ -330,23 +416,6 @@ SeSubProcessToken(
_In_ BOOLEAN InUse,
_In_ ULONG SessionId);
-NTSTATUS
-NTAPI
-SeInitializeProcessAuditName(
- _In_ PFILE_OBJECT FileObject,
- _In_ BOOLEAN DoAudit,
- _Out_ POBJECT_NAME_INFORMATION *AuditInfo);
-
-NTSTATUS
-NTAPI
-SeCreateAccessStateEx(
- _In_ PETHREAD Thread,
- _In_ PEPROCESS Process,
- _In_ OUT PACCESS_STATE AccessState,
- _In_ PAUX_ACCESS_DATA AuxData,
- _In_ ACCESS_MASK Access,
- _In_ PGENERIC_MAPPING GenericMapping);
-
NTSTATUS
NTAPI
SeIsTokenChild(
@@ -361,87 +430,63 @@ SeIsTokenSibling(
NTSTATUS
NTAPI
-SepCreateImpersonationTokenDacl(
- _In_ PTOKEN Token,
- _In_ PTOKEN PrimaryToken,
- _Out_ PACL* Dacl);
-
-NTSTATUS
-NTAPI
-SepRmInsertLogonSessionIntoToken(
- _Inout_ PTOKEN Token);
+SeExchangePrimaryToken(
+ _In_ PEPROCESS Process,
+ _In_ PACCESS_TOKEN NewAccessToken,
+ _Out_ PACCESS_TOKEN* OldAccessToken);
NTSTATUS
NTAPI
-SepRmRemoveLogonSessionFromToken(
- _Inout_ PTOKEN Token);
-
-CODE_SEG("INIT")
-VOID
-NTAPI
-SepInitializeTokenImplementation(VOID);
-
-CODE_SEG("INIT")
-PTOKEN
-NTAPI
-SepCreateSystemProcessToken(VOID);
+SeCopyClientToken(
+ _In_ PACCESS_TOKEN Token,
+ _In_ SECURITY_IMPERSONATION_LEVEL Level,
+ _In_ KPROCESSOR_MODE PreviousMode,
+ _Out_ PACCESS_TOKEN* NewToken);
-CODE_SEG("INIT")
-PTOKEN
-SepCreateSystemAnonymousLogonToken(VOID);
+ULONG
+RtlLengthSidAndAttributes(
+ _In_ ULONG Count,
+ _In_ PSID_AND_ATTRIBUTES Src);
+//
+// Security Manager (SeMgr) functions
+//
CODE_SEG("INIT")
-PTOKEN
-SepCreateSystemAnonymousLogonTokenNoEveryone(VOID);
-
BOOLEAN
NTAPI
-SeDetailedAuditingWithToken(
- _In_ PTOKEN Token);
-
-VOID
-NTAPI
-SeAuditProcessExit(
- _In_ PEPROCESS Process);
-
-VOID
-NTAPI
-SeAuditProcessCreate(
- _In_ PEPROCESS Process);
+SeInitSystem(VOID);
NTSTATUS
NTAPI
-SeExchangePrimaryToken(
- _In_ PEPROCESS Process,
- _In_ PACCESS_TOKEN NewAccessToken,
- _Out_ PACCESS_TOKEN* OldAccessToken);
+SeDefaultObjectMethod(
+ _In_ PVOID Object,
+ _In_ SECURITY_OPERATION_CODE OperationType,
+ _In_ PSECURITY_INFORMATION SecurityInformation,
+ _Inout_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _Inout_opt_ PULONG ReturnLength,
+ _Inout_opt_ PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
+ _In_ POOL_TYPE PoolType,
+ _In_ PGENERIC_MAPPING GenericMapping);
VOID
NTAPI
-SeCaptureSubjectContextEx(
- _In_ PETHREAD Thread,
- _In_ PEPROCESS Process,
- _Out_ PSECURITY_SUBJECT_CONTEXT SubjectContext);
+SeQuerySecurityAccessMask(
+ _In_ SECURITY_INFORMATION SecurityInformation,
+ _Out_ PACCESS_MASK DesiredAccess);
-NTSTATUS
+VOID
NTAPI
-SeCaptureLuidAndAttributesArray(
- _In_ PLUID_AND_ATTRIBUTES Src,
- _In_ ULONG PrivilegeCount,
- _In_ KPROCESSOR_MODE PreviousMode,
- _In_ PLUID_AND_ATTRIBUTES AllocatedMem,
- _In_ ULONG AllocatedLength,
- _In_ POOL_TYPE PoolType,
- _In_ BOOLEAN CaptureIfKernel,
- _Out_ PLUID_AND_ATTRIBUTES* Dest,
- _Inout_ PULONG Length);
+SeSetSecurityAccessMask(
+ _In_ SECURITY_INFORMATION SecurityInformation,
+ _Out_ PACCESS_MASK DesiredAccess);
+//
+// Privilege functions
+//
+CODE_SEG("INIT")
VOID
NTAPI
-SeReleaseLuidAndAttributesArray(
- _In_ PLUID_AND_ATTRIBUTES Privilege,
- _In_ KPROCESSOR_MODE PreviousMode,
- _In_ BOOLEAN CaptureIfKernel);
+SepInitPrivileges(VOID);
BOOLEAN
NTAPI
@@ -462,6 +507,12 @@ SePrivilegePolicyCheck(
_Out_opt_ PPRIVILEGE_SET *OutPrivilegeSet,
_In_ KPROCESSOR_MODE PreviousMode);
+BOOLEAN
+NTAPI
+SeCheckAuditPrivilege(
+ _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
+ _In_ KPROCESSOR_MODE PreviousMode);
+
BOOLEAN
NTAPI
SeCheckPrivilegedObject(
@@ -472,32 +523,32 @@ SeCheckPrivilegedObject(
NTSTATUS
NTAPI
-SepDuplicateToken(
- _In_ PTOKEN Token,
- _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
- _In_ BOOLEAN EffectiveOnly,
- _In_ TOKEN_TYPE TokenType,
- _In_ SECURITY_IMPERSONATION_LEVEL Level,
+SeCaptureLuidAndAttributesArray(
+ _In_ PLUID_AND_ATTRIBUTES Src,
+ _In_ ULONG PrivilegeCount,
_In_ KPROCESSOR_MODE PreviousMode,
- _Out_ PTOKEN* NewAccessToken);
-
-NTSTATUS
-NTAPI
-SepCaptureSecurityQualityOfService(
- _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
- _In_ KPROCESSOR_MODE AccessMode,
+ _In_ PLUID_AND_ATTRIBUTES AllocatedMem,
+ _In_ ULONG AllocatedLength,
_In_ POOL_TYPE PoolType,
_In_ BOOLEAN CaptureIfKernel,
- _Out_ PSECURITY_QUALITY_OF_SERVICE *CapturedSecurityQualityOfService,
- _Out_ PBOOLEAN Present);
+ _Out_ PLUID_AND_ATTRIBUTES* Dest,
+ _Inout_ PULONG Length);
VOID
NTAPI
-SepReleaseSecurityQualityOfService(
- _In_opt_ PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService,
- _In_ KPROCESSOR_MODE AccessMode,
+SeReleaseLuidAndAttributesArray(
+ _In_ PLUID_AND_ATTRIBUTES Privilege,
+ _In_ KPROCESSOR_MODE PreviousMode,
_In_ BOOLEAN CaptureIfKernel);
+//
+// SID functions
+//
+CODE_SEG("INIT")
+BOOLEAN
+NTAPI
+SepInitSecurityIDs(VOID);
+
NTSTATUS
NTAPI
SepCaptureSid(
@@ -514,6 +565,21 @@ SepReleaseSid(
_In_ KPROCESSOR_MODE AccessMode,
_In_ BOOLEAN CaptureIfKernel);
+BOOLEAN
+NTAPI
+SepSidInToken(
+ _In_ PACCESS_TOKEN _Token,
+ _In_ PSID Sid);
+
+BOOLEAN
+NTAPI
+SepSidInTokenEx(
+ _In_ PACCESS_TOKEN _Token,
+ _In_ PSID PrincipalSelfSid,
+ _In_ PSID _Sid,
+ _In_ BOOLEAN Deny,
+ _In_ BOOLEAN Restricted);
+
PSID
NTAPI
SepGetSidFromAce(
@@ -540,11 +606,20 @@ SeReleaseSidAndAttributesArray(
_In_ KPROCESSOR_MODE AccessMode,
_In_ BOOLEAN CaptureIfKernel);
+//
+// ACL functions
+//
+CODE_SEG("INIT")
+BOOLEAN
+NTAPI
+SepInitDACLs(VOID);
+
NTSTATUS
NTAPI
-SeComputeQuotaInformationSize(
- _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
- _Out_ PULONG QuotaInfoSize);
+SepCreateImpersonationTokenDacl(
+ _In_ PTOKEN Token,
+ _In_ PTOKEN PrimaryToken,
+ _Out_ PACL* Dacl);
NTSTATUS
NTAPI
@@ -588,17 +663,13 @@ SepSelectAcl(
_In_ BOOLEAN IsDirectoryObject,
_In_ PGENERIC_MAPPING GenericMapping);
-NTSTATUS
+//
+// SD functions
+//
+CODE_SEG("INIT")
+BOOLEAN
NTAPI
-SeDefaultObjectMethod(
- _In_ PVOID Object,
- _In_ SECURITY_OPERATION_CODE OperationType,
- _In_ PSECURITY_INFORMATION SecurityInformation,
- _Inout_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor,
- _Inout_opt_ PULONG ReturnLength,
- _Inout_opt_ PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
- _In_ POOL_TYPE PoolType,
- _In_ PGENERIC_MAPPING GenericMapping);
+SepInitSDs(VOID);
NTSTATUS
NTAPI
@@ -609,11 +680,38 @@ SeSetWorldSecurityDescriptor(
NTSTATUS
NTAPI
-SeCopyClientToken(
- _In_ PACCESS_TOKEN Token,
- _In_ SECURITY_IMPERSONATION_LEVEL Level,
- _In_ KPROCESSOR_MODE PreviousMode,
- _Out_ PACCESS_TOKEN* NewToken);
+SeComputeQuotaInformationSize(
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _Out_ PULONG QuotaInfoSize);
+
+//
+// Security Reference Monitor (SeRm) functions
+//
+BOOLEAN
+NTAPI
+SeRmInitPhase0(VOID);
+
+BOOLEAN
+NTAPI
+SeRmInitPhase1(VOID);
+
+NTSTATUS
+NTAPI
+SepRmInsertLogonSessionIntoToken(
+ _Inout_ PTOKEN Token);
+
+NTSTATUS
+NTAPI
+SepRmRemoveLogonSessionFromToken(
+ _Inout_ PTOKEN Token);
+
+NTSTATUS
+SepRmReferenceLogonSession(
+ _Inout_ PLUID LogonLuid);
+
+NTSTATUS
+SepRmDereferenceLogonSession(
+ _Inout_ PLUID LogonLuid);
NTSTATUS
NTAPI
@@ -624,31 +722,36 @@ SepRegQueryHelper(
_In_ ULONG DataLength,
_Out_ PVOID ValueData);
-VOID
+NTSTATUS
NTAPI
-SeQuerySecurityAccessMask(
- _In_ SECURITY_INFORMATION SecurityInformation,
- _Out_ PACCESS_MASK DesiredAccess);
+SeGetLogonIdDeviceMap(
+ _In_ PLUID LogonId,
+ _Out_ PDEVICE_MAP *DeviceMap);
-VOID
+//
+// Audit functions
+//
+NTSTATUS
NTAPI
-SeSetSecurityAccessMask(
- _In_ SECURITY_INFORMATION SecurityInformation,
- _Out_ PACCESS_MASK DesiredAccess);
+SeInitializeProcessAuditName(
+ _In_ PFILE_OBJECT FileObject,
+ _In_ BOOLEAN DoAudit,
+ _Out_ POBJECT_NAME_INFORMATION *AuditInfo);
BOOLEAN
NTAPI
-SeFastTraverseCheck(
- _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
- _In_ PACCESS_STATE AccessState,
- _In_ ACCESS_MASK DesiredAccess,
- _In_ KPROCESSOR_MODE AccessMode);
+SeDetailedAuditingWithToken(
+ _In_ PTOKEN Token);
-BOOLEAN
+VOID
NTAPI
-SeCheckAuditPrivilege(
- _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
- _In_ KPROCESSOR_MODE PreviousMode);
+SeAuditProcessExit(
+ _In_ PEPROCESS Process);
+
+VOID
+NTAPI
+SeAuditProcessCreate(
+ _In_ PEPROCESS Process);
VOID
NTAPI
@@ -658,19 +761,74 @@ SePrivilegedServiceAuditAlarm(
_In_ PPRIVILEGE_SET PrivilegeSet,
_In_ BOOLEAN AccessGranted);
+//
+// Subject functions
+//
+VOID
+NTAPI
+SeCaptureSubjectContextEx(
+ _In_ PETHREAD Thread,
+ _In_ PEPROCESS Process,
+ _Out_ PSECURITY_SUBJECT_CONTEXT SubjectContext);
+
+//
+// Security Quality of Service (SQoS) functions
+//
NTSTATUS
-SepRmReferenceLogonSession(
- _Inout_ PLUID LogonLuid);
+NTAPI
+SepCaptureSecurityQualityOfService(
+ _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
+ _In_ KPROCESSOR_MODE AccessMode,
+ _In_ POOL_TYPE PoolType,
+ _In_ BOOLEAN CaptureIfKernel,
+ _Out_ PSECURITY_QUALITY_OF_SERVICE *CapturedSecurityQualityOfService,
+ _Out_ PBOOLEAN Present);
+
+VOID
+NTAPI
+SepReleaseSecurityQualityOfService(
+ _In_opt_ PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService,
+ _In_ KPROCESSOR_MODE AccessMode,
+ _In_ BOOLEAN CaptureIfKernel);
+//
+// Object type list functions
+//
NTSTATUS
-SepRmDereferenceLogonSession(
- _Inout_ PLUID LogonLuid);
+SeCaptureObjectTypeList(
+ _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
+ _In_ ULONG ObjectTypeListLength,
+ _In_ KPROCESSOR_MODE PreviousMode,
+ _Out_ POBJECT_TYPE_LIST *CapturedObjectTypeList);
+VOID
+SeReleaseObjectTypeList(
+ _In_ _Post_invalid_ POBJECT_TYPE_LIST CapturedObjectTypeList,
+ _In_ KPROCESSOR_MODE PreviousMode);
+
+//
+// Access state functions
+//
NTSTATUS
NTAPI
-SeGetLogonIdDeviceMap(
- _In_ PLUID LogonId,
- _Out_ PDEVICE_MAP *DeviceMap);
+SeCreateAccessStateEx(
+ _In_ PETHREAD Thread,
+ _In_ PEPROCESS Process,
+ _In_ OUT PACCESS_STATE AccessState,
+ _In_ PAUX_ACCESS_DATA AuxData,
+ _In_ ACCESS_MASK Access,
+ _In_ PGENERIC_MAPPING GenericMapping);
+
+//
+// Access check functions
+//
+BOOLEAN
+NTAPI
+SeFastTraverseCheck(
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_ PACCESS_STATE AccessState,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ KPROCESSOR_MODE AccessMode);
#endif
diff --git a/ntoskrnl/ntos.cmake b/ntoskrnl/ntos.cmake
index 2284563e436..af8217bc480 100644
--- a/ntoskrnl/ntos.cmake
+++ b/ntoskrnl/ntos.cmake
@@ -275,13 +275,19 @@ list(APPEND SOURCE
${REACTOS_SOURCE_DIR}/ntoskrnl/se/accesschk.c
${REACTOS_SOURCE_DIR}/ntoskrnl/se/acl.c
${REACTOS_SOURCE_DIR}/ntoskrnl/se/audit.c
+ ${REACTOS_SOURCE_DIR}/ntoskrnl/se/client.c
+ ${REACTOS_SOURCE_DIR}/ntoskrnl/se/objtype.c
${REACTOS_SOURCE_DIR}/ntoskrnl/se/priv.c
${REACTOS_SOURCE_DIR}/ntoskrnl/se/sd.c
${REACTOS_SOURCE_DIR}/ntoskrnl/se/semgr.c
${REACTOS_SOURCE_DIR}/ntoskrnl/se/sid.c
${REACTOS_SOURCE_DIR}/ntoskrnl/se/sqos.c
${REACTOS_SOURCE_DIR}/ntoskrnl/se/srm.c
+ ${REACTOS_SOURCE_DIR}/ntoskrnl/se/subject.c
${REACTOS_SOURCE_DIR}/ntoskrnl/se/token.c
+ ${REACTOS_SOURCE_DIR}/ntoskrnl/se/tokenadj.c
+ ${REACTOS_SOURCE_DIR}/ntoskrnl/se/tokencls.c
+ ${REACTOS_SOURCE_DIR}/ntoskrnl/se/tokenlif.c
${REACTOS_SOURCE_DIR}/ntoskrnl/vf/driver.c
${REACTOS_SOURCE_DIR}/ntoskrnl/wmi/guidobj.c
${REACTOS_SOURCE_DIR}/ntoskrnl/wmi/smbios.c
diff --git a/ntoskrnl/se/access.c b/ntoskrnl/se/access.c
index 98b00a70d1e..77100336509 100644
--- a/ntoskrnl/se/access.c
+++ b/ntoskrnl/se/access.c
@@ -11,529 +11,8 @@
#define NDEBUG
#include <debug.h>
-/* GLOBALS ********************************************************************/
-
-ERESOURCE SepSubjectContextLock;
-
-/* PRIVATE FUNCTIONS **********************************************************/
-
-/**
- * @brief
- * Checks if a SID is present in a token.
- *
- * @param[in] _Token
- * A valid token object.
- *
- * @param[in] PrincipalSelfSid
- * A principal self SID.
- *
- * @param[in] _Sid
- * A regular SID.
- *
- * @param[in] Deny
- * If set to TRUE, the caller expected that a SID in a token
- * must be a deny-only SID, that is, access checks are performed
- * only for deny-only ACEs of the said SID.
- *
- * @param[in] Restricted
- * If set to TRUE, the caller expects that a SID in a token is
- * restricted (by the general definition, a token is restricted).
- *
- * @return
- * Returns TRUE if the specified SID in the call is present in the token,
- * FALSE otherwise.
- */
-BOOLEAN
-NTAPI
-SepSidInTokenEx(
- _In_ PACCESS_TOKEN _Token,
- _In_ PSID PrincipalSelfSid,
- _In_ PSID _Sid,
- _In_ BOOLEAN Deny,
- _In_ BOOLEAN Restricted)
-{
- ULONG SidIndex;
- PTOKEN Token = (PTOKEN)_Token;
- PISID TokenSid, Sid = (PISID)_Sid;
- PSID_AND_ATTRIBUTES SidAndAttributes;
- ULONG SidCount, SidLength;
- USHORT SidMetadata;
- PAGED_CODE();
-
- /* Check if a principal SID was given, and this is our current SID already */
- if ((PrincipalSelfSid) && (RtlEqualSid(SePrincipalSelfSid, Sid)))
- {
- /* Just use the principal SID in this case */
- Sid = PrincipalSelfSid;
- }
-
- /* Check if this is a restricted token or not */
- if (Restricted)
- {
- /* Use the restricted SIDs and count */
- SidAndAttributes = Token->RestrictedSids;
- SidCount = Token->RestrictedSidCount;
- }
- else
- {
- /* Use the normal SIDs and count */
- SidAndAttributes = Token->UserAndGroups;
- SidCount = Token->UserAndGroupCount;
- }
-
- /* Do checks here by hand instead of the usual 4 function calls */
- SidLength = FIELD_OFFSET(SID,
- SubAuthority[Sid->SubAuthorityCount]);
- SidMetadata = *(PUSHORT)&Sid->Revision;
-
- /* Loop every SID */
- for (SidIndex = 0; SidIndex < SidCount; SidIndex++)
- {
- TokenSid = (PISID)SidAndAttributes->Sid;
-#if SE_SID_DEBUG
- UNICODE_STRING sidString;
- RtlConvertSidToUnicodeString(&sidString, TokenSid, TRUE);
- DPRINT1("SID in Token: %wZ\n", &sidString);
- RtlFreeUnicodeString(&sidString);
-#endif
- /* Check if the SID metadata matches */
- if (*(PUSHORT)&TokenSid->Revision == SidMetadata)
- {
- /* Check if the SID data matches */
- if (RtlEqualMemory(Sid, TokenSid, SidLength))
- {
- /*
- * Check if the group is enabled, or used for deny only.
- * Otherwise we have to check if this is the first user.
- * We understand that by looking if this SID is not
- * restricted, this is the first element we are iterating
- * and that it doesn't have SE_GROUP_USE_FOR_DENY_ONLY
- * attribute.
- */
- if ((!Restricted && (SidIndex == 0) &&
!(SidAndAttributes->Attributes & SE_GROUP_USE_FOR_DENY_ONLY)) ||
- (SidAndAttributes->Attributes & SE_GROUP_ENABLED) ||
- ((Deny) && (SidAndAttributes->Attributes &
SE_GROUP_USE_FOR_DENY_ONLY)))
- {
- /* SID is present */
- return TRUE;
- }
- else
- {
- /* SID is not present */
- return FALSE;
- }
- }
- }
-
- /* Move to the next SID */
- SidAndAttributes++;
- }
-
- /* SID is not present */
- return FALSE;
-}
-
-/**
- * @brief
- * Checks if a SID is present in a token.
- *
- * @param[in] _Token
- * A valid token object.
- *
- * @param[in] _Sid
- * A regular SID.
- *
- * @return
- * Returns TRUE if the specified SID in the call is present in the token,
- * FALSE otherwise.
- */
-BOOLEAN
-NTAPI
-SepSidInToken(
- _In_ PACCESS_TOKEN _Token,
- _In_ PSID Sid)
-{
- /* Call extended API */
- return SepSidInTokenEx(_Token, NULL, Sid, FALSE, FALSE);
-}
-
-/**
- * @brief
- * Checks if a token belongs to the main user, being the owner.
- *
- * @param[in] _Token
- * A valid token object.
- *
- * @param[in] SecurityDescriptor
- * A security descriptor where the owner is to be found.
- *
- * @param[in] TokenLocked
- * If set to TRUE, the token has been already locked and there's
- * no need to lock it again. Otherwise the function will acquire
- * the lock.
- *
- * @return
- * Returns TRUE if the token belongs to a owner, FALSE otherwise.
- */
-BOOLEAN
-NTAPI
-SepTokenIsOwner(
- _In_ PACCESS_TOKEN _Token,
- _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
- _In_ BOOLEAN TokenLocked)
-{
- PSID Sid;
- BOOLEAN Result;
- PTOKEN Token = _Token;
-
- /* Get the owner SID */
- Sid = SepGetOwnerFromDescriptor(SecurityDescriptor);
- ASSERT(Sid != NULL);
-
- /* Lock the token if needed */
- if (!TokenLocked) SepAcquireTokenLockShared(Token);
-
- /* Check if the owner SID is found, handling restricted case as well */
- Result = SepSidInToken(Token, Sid);
- if ((Result) && (Token->TokenFlags & TOKEN_IS_RESTRICTED))
- {
- Result = SepSidInTokenEx(Token, NULL, Sid, FALSE, TRUE);
- }
-
- /* Release the lock if we had acquired it */
- if (!TokenLocked) SepReleaseTokenLock(Token);
-
- /* Return the result */
- return Result;
-}
-
-/**
- * @brief
- * Retrieves token control information.
- *
- * @param[in] _Token
- * A valid token object.
- *
- * @param[out] SecurityDescriptor
- * The returned token control information.
- *
- * @return
- * Nothing.
- */
-VOID
-NTAPI
-SeGetTokenControlInformation(
- _In_ PACCESS_TOKEN _Token,
- _Out_ PTOKEN_CONTROL TokenControl)
-{
- PTOKEN Token = _Token;
- PAGED_CODE();
-
- /* Capture the main fields */
- TokenControl->AuthenticationId = Token->AuthenticationId;
- TokenControl->TokenId = Token->TokenId;
- TokenControl->TokenSource = Token->TokenSource;
-
- /* Lock the token */
- SepAcquireTokenLockShared(Token);
-
- /* Capture the modified ID */
- TokenControl->ModifiedId = Token->ModifiedId;
-
- /* Unlock it */
- SepReleaseTokenLock(Token);
-}
-
-/**
- * @brief
- * Creates a client security context based upon an access token.
- *
- * @param[in] Token
- * A valid token object.
- *
- * @param[in] ClientSecurityQos
- * The Quality of Service (QoS) of a client security context.
- *
- * @param[in] ServerIsRemote
- * If the client is a remote server (TRUE), the function will retrieve the
- * control information of an access token, that is, we're doing delegation
- * and that the server isn't local.
- *
- * @param[in] TokenType
- * Type of token.
- *
- * @param[in] ThreadEffectiveOnly
- * If set to TRUE, the client wants that the current thread wants to modify
- * (enable or disable) privileges and groups.
- *
- * @param[in] ImpersonationLevel
- * Security impersonation level filled in the QoS context.
- *
- * @param[out] ClientContext
- * The returned security client context.
- *
- * @return
- * Returns STATUS_SUCCESS if client security creation has completed successfully.
- * STATUS_INVALID_PARAMETER is returned if one or more of the parameters are bogus.
- * STATUS_BAD_IMPERSONATION_LEVEL is returned if the current impersonation level
- * within QoS context doesn't meet with the conditions required. A failure
- * NTSTATUS code is returned otherwise.
- */
-NTSTATUS
-NTAPI
-SepCreateClientSecurity(
- _In_ PACCESS_TOKEN Token,
- _In_ PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos,
- _In_ BOOLEAN ServerIsRemote,
- _In_ TOKEN_TYPE TokenType,
- _In_ BOOLEAN ThreadEffectiveOnly,
- _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
- _Out_ PSECURITY_CLIENT_CONTEXT ClientContext)
-{
- NTSTATUS Status;
- PACCESS_TOKEN NewToken;
- PAGED_CODE();
-
- /* Check for bogus impersonation level */
- if (!VALID_IMPERSONATION_LEVEL(ClientSecurityQos->ImpersonationLevel))
- {
- /* Fail the call */
- return STATUS_INVALID_PARAMETER;
- }
-
- /* Check what kind of token this is */
- if (TokenType != TokenImpersonation)
- {
- /* On a primary token, if we do direct access, copy the flag from the QOS */
- ClientContext->DirectAccessEffectiveOnly =
ClientSecurityQos->EffectiveOnly;
- }
- else
- {
- /* This is an impersonation token, is the level ok? */
- if (ClientSecurityQos->ImpersonationLevel > ImpersonationLevel)
- {
- /* Nope, fail */
- return STATUS_BAD_IMPERSONATION_LEVEL;
- }
-
- /* Is the level too low, or are we doing something other than delegation remotely
*/
- if ((ImpersonationLevel == SecurityAnonymous) ||
- (ImpersonationLevel == SecurityIdentification) ||
- ((ServerIsRemote) && (ImpersonationLevel != SecurityDelegation)))
- {
- /* Fail the call */
- return STATUS_BAD_IMPERSONATION_LEVEL;
- }
-
- /* Pick either the thread setting or the QOS setting */
- ClientContext->DirectAccessEffectiveOnly =
- ((ThreadEffectiveOnly) || (ClientSecurityQos->EffectiveOnly)) ? TRUE :
FALSE;
- }
-
- /* Is this static tracking */
- if (ClientSecurityQos->ContextTrackingMode == SECURITY_STATIC_TRACKING)
- {
- /* Do not use direct access and make a copy */
- ClientContext->DirectlyAccessClientToken = FALSE;
- Status = SeCopyClientToken(Token,
- ClientSecurityQos->ImpersonationLevel,
- KernelMode,
- &NewToken);
- if (!NT_SUCCESS(Status))
- return Status;
- }
- else
- {
- /* Use direct access and check if this is local */
- ClientContext->DirectlyAccessClientToken = TRUE;
- if (ServerIsRemote)
- {
- /* We are doing delegation, so make a copy of the control data */
- SeGetTokenControlInformation(Token,
- &ClientContext->ClientTokenControl);
- }
-
- /* Keep the same token */
- NewToken = Token;
- }
-
- /* Fill out the context and return success */
- ClientContext->SecurityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
- ClientContext->SecurityQos.ImpersonationLevel =
ClientSecurityQos->ImpersonationLevel;
- ClientContext->SecurityQos.ContextTrackingMode =
ClientSecurityQos->ContextTrackingMode;
- ClientContext->SecurityQos.EffectiveOnly = ClientSecurityQos->EffectiveOnly;
- ClientContext->ServerIsRemote = ServerIsRemote;
- ClientContext->ClientToken = NewToken;
- return STATUS_SUCCESS;
-}
-
/* PUBLIC FUNCTIONS ***********************************************************/
-/**
- * @brief
- * An extended function that captures the security subject context based upon
- * the specified thread and process.
- *
- * @param[in] Thread
- * A thread where the calling thread's token is to be referenced for
- * the security context.
- *
- * @param[in] Process
- * A process where the main process' token is to be referenced for
- * the security context.
- *
- * @param[out] SubjectContext
- * The returned security subject context.
- *
- * @return
- * Nothing.
- */
-VOID
-NTAPI
-SeCaptureSubjectContextEx(
- _In_ PETHREAD Thread,
- _In_ PEPROCESS Process,
- _Out_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
-{
- BOOLEAN CopyOnOpen, EffectiveOnly;
-
- PAGED_CODE();
-
- /* Save the unique ID */
- SubjectContext->ProcessAuditId = Process->UniqueProcessId;
-
- /* Check if we have a thread */
- if (!Thread)
- {
- /* We don't, so no token */
- SubjectContext->ClientToken = NULL;
- }
- else
- {
- /* Get the impersonation token */
- SubjectContext->ClientToken = PsReferenceImpersonationToken(Thread,
- &CopyOnOpen,
- &EffectiveOnly,
-
&SubjectContext->ImpersonationLevel);
- }
-
- /* Get the primary token */
- SubjectContext->PrimaryToken = PsReferencePrimaryToken(Process);
-}
-
-/**
- * @brief
- * Captures the security subject context of the calling thread and calling
- * process.
- *
- * @param[out] SubjectContext
- * The returned security subject context.
- *
- * @return
- * Nothing.
- */
-VOID
-NTAPI
-SeCaptureSubjectContext(
- _Out_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
-{
- /* Call the extended API */
- SeCaptureSubjectContextEx(PsGetCurrentThread(),
- PsGetCurrentProcess(),
- SubjectContext);
-}
-
-/**
- * @brief
- * Locks both the referenced primary and client access tokens of a
- * security subject context.
- *
- * @param[in] SubjectContext
- * A valid security context with both referenced tokens.
- *
- * @return
- * Nothing.
- */
-VOID
-NTAPI
-SeLockSubjectContext(
- _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
-{
- PTOKEN PrimaryToken, ClientToken;
- PAGED_CODE();
-
- /* Read both tokens */
- PrimaryToken = SubjectContext->PrimaryToken;
- ClientToken = SubjectContext->ClientToken;
-
- /* Always lock the primary */
- SepAcquireTokenLockShared(PrimaryToken);
-
- /* Lock the impersonation one if it's there */
- if (!ClientToken) return;
- SepAcquireTokenLockShared(ClientToken);
-}
-
-/**
- * @brief
- * Unlocks both the referenced primary and client access tokens of a
- * security subject context.
- *
- * @param[in] SubjectContext
- * A valid security context with both referenced tokens.
- *
- * @return
- * Nothing.
- */
-VOID
-NTAPI
-SeUnlockSubjectContext(
- _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
-{
- PTOKEN PrimaryToken, ClientToken;
- PAGED_CODE();
-
- /* Read both tokens */
- PrimaryToken = SubjectContext->PrimaryToken;
- ClientToken = SubjectContext->ClientToken;
-
- /* Unlock the impersonation one if it's there */
- if (ClientToken)
- {
- SepReleaseTokenLock(ClientToken);
- }
-
- /* Always unlock the primary one */
- SepReleaseTokenLock(PrimaryToken);
-}
-
-/**
- * @brief
- * Releases both the primary and client tokens of a security
- * subject context.
- *
- * @param[in] SubjectContext
- * The captured security context.
- *
- * @return
- * Nothing.
- */
-VOID
-NTAPI
-SeReleaseSubjectContext(
- _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
-{
- PAGED_CODE();
-
- /* Drop reference on the primary */
- ObFastDereferenceObject(&PsGetCurrentProcess()->Token,
SubjectContext->PrimaryToken);
- SubjectContext->PrimaryToken = NULL;
-
- /* Drop reference on the impersonation, if there was one */
- PsDereferenceImpersonationToken(SubjectContext->ClientToken);
- SubjectContext->ClientToken = NULL;
-}
-
/**
* @brief
* An extended function that creates an access state.
@@ -721,194 +200,4 @@ SeSetAccessStateGenericMapping(
((PAUX_ACCESS_DATA)AccessState->AuxData)->GenericMapping = *GenericMapping;
}
-/**
- * @brief
- * Creates a client security context.
- *
- * @param[in] Thread
- * Thread object of the client where impersonation has to begin.
- *
- * @param[in] Qos
- * Quality of service to specify what kind of impersonation to be done.
- *
- * @param[in] RemoteClient
- * If set to TRUE, the client that we're going to impersonate is remote.
- *
- * @param[out] ClientContext
- * The returned security client context.
- *
- * @return
- * See SepCreateClientSecurity.
- */
-NTSTATUS
-NTAPI
-SeCreateClientSecurity(
- _In_ PETHREAD Thread,
- _In_ PSECURITY_QUALITY_OF_SERVICE Qos,
- _In_ BOOLEAN RemoteClient,
- _Out_ PSECURITY_CLIENT_CONTEXT ClientContext)
-{
- TOKEN_TYPE TokenType;
- BOOLEAN ThreadEffectiveOnly;
- SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
- PACCESS_TOKEN Token;
- NTSTATUS Status;
- PAGED_CODE();
-
- /* Reference the correct token */
- Token = PsReferenceEffectiveToken(Thread,
- &TokenType,
- &ThreadEffectiveOnly,
- &ImpersonationLevel);
-
- /* Create client security from it */
- Status = SepCreateClientSecurity(Token,
- Qos,
- RemoteClient,
- TokenType,
- ThreadEffectiveOnly,
- ImpersonationLevel,
- ClientContext);
-
- /* Check if we failed or static tracking was used */
- if (!(NT_SUCCESS(Status)) || (Qos->ContextTrackingMode ==
SECURITY_STATIC_TRACKING))
- {
- /* Dereference our copy since it's not being used */
- ObDereferenceObject(Token);
- }
-
- /* Return status */
- return Status;
-}
-
-/**
- * @brief
- * Creates a client security context based upon the captured security
- * subject context.
- *
- * @param[in] SubjectContext
- * The captured subject context where client security is to be created
- * from.
- *
- * @param[in] ClientSecurityQos
- * Quality of service to specify what kind of impersonation to be done.
- *
- * @param[in] ServerIsRemote
- * If set to TRUE, the client that we're going to impersonate is remote.
- *
- * @param[out] ClientContext
- * The returned security client context.
- *
- * @return
- * See SepCreateClientSecurity.
- */
-NTSTATUS
-NTAPI
-SeCreateClientSecurityFromSubjectContext(
- _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
- _In_ PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos,
- _In_ BOOLEAN ServerIsRemote,
- _Out_ PSECURITY_CLIENT_CONTEXT ClientContext)
-{
- PACCESS_TOKEN Token;
- NTSTATUS Status;
- PAGED_CODE();
-
- /* Get the right token and reference it */
- Token = SeQuerySubjectContextToken(SubjectContext);
- ObReferenceObject(Token);
-
- /* Create the context */
- Status = SepCreateClientSecurity(Token,
- ClientSecurityQos,
- ServerIsRemote,
- SubjectContext->ClientToken ?
- TokenImpersonation : TokenPrimary,
- FALSE,
- SubjectContext->ImpersonationLevel,
- ClientContext);
-
- /* Check if we failed or static tracking was used */
- if (!(NT_SUCCESS(Status)) ||
- (ClientSecurityQos->ContextTrackingMode == SECURITY_STATIC_TRACKING))
- {
- /* Dereference our copy since it's not being used */
- ObDereferenceObject(Token);
- }
-
- /* Return status */
- return Status;
-}
-
-/**
- * @brief
- * Extended function that impersonates a client.
- *
- * @param[in] ClientContext
- * A valid client context.
- *
- * @param[in] ServerThread
- * The thread where impersonation is to be done.
- *
- * @return
- * STATUS_SUCCESS is returned if the calling thread successfully impersonates
- * the client. A failure NTSTATUS code is returned otherwise.
- */
-NTSTATUS
-NTAPI
-SeImpersonateClientEx(
- _In_ PSECURITY_CLIENT_CONTEXT ClientContext,
- _In_opt_ PETHREAD ServerThread)
-{
- BOOLEAN EffectiveOnly;
- PAGED_CODE();
-
- /* Check if direct access is requested */
- if (!ClientContext->DirectlyAccessClientToken)
- {
- /* No, so get the flag from QOS */
- EffectiveOnly = ClientContext->SecurityQos.EffectiveOnly;
- }
- else
- {
- /* Yes, so see if direct access should be effective only */
- EffectiveOnly = ClientContext->DirectAccessEffectiveOnly;
- }
-
- /* Use the current thread if one was not passed */
- if (!ServerThread) ServerThread = PsGetCurrentThread();
-
- /* Call the lower layer routine */
- return PsImpersonateClient(ServerThread,
- ClientContext->ClientToken,
- TRUE,
- EffectiveOnly,
- ClientContext->SecurityQos.ImpersonationLevel);
-}
-
-/**
- * @brief
- * Impersonates a client user.
- *
- * @param[in] ClientContext
- * A valid client context.
- *
- * @param[in] ServerThread
- * The thread where impersonation is to be done.
- * *
- * @return
- * Nothing.
- */
-VOID
-NTAPI
-SeImpersonateClient(
- _In_ PSECURITY_CLIENT_CONTEXT ClientContext,
- _In_opt_ PETHREAD ServerThread)
-{
- PAGED_CODE();
-
- /* Call the new API */
- SeImpersonateClientEx(ClientContext, ServerThread);
-}
-
/* EOF */
diff --git a/ntoskrnl/se/audit.c b/ntoskrnl/se/audit.c
index 0d993a1761d..a201e214907 100644
--- a/ntoskrnl/se/audit.c
+++ b/ntoskrnl/se/audit.c
@@ -16,7 +16,7 @@
UNICODE_STRING SeSubsystemName = RTL_CONSTANT_STRING(L"Security");
-/* PRIVATE FUNCTIONS***********************************************************/
+/* PRIVATE FUNCTIONS ***********************************************************/
/**
* @unimplemented
@@ -411,107 +411,6 @@ SePrivilegedServiceAuditAlarm(
}
-/**
- * @brief
- * Captures a list of object types.
- *
- * @param[in] ObjectTypeList
- * An existing list of object types.
- *
- * @param[in] ObjectTypeListLength
- * The length size of the list.
- *
- * @param[in] PreviousMode
- * Processor access level mode.
- *
- * @param[out] CapturedObjectTypeList
- * The captured list of object types.
- *
- * @return
- * Returns STATUS_SUCCESS if the list of object types has been captured
- * successfully. STATUS_INVALID_PARAMETER is returned if the caller hasn't
- * supplied a buffer list of object types. STATUS_INSUFFICIENT_RESOURCES
- * is returned if pool memory allocation for the captured list has failed.
- */
-static
-NTSTATUS
-SeCaptureObjectTypeList(
- _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
- _In_ ULONG ObjectTypeListLength,
- _In_ KPROCESSOR_MODE PreviousMode,
- _Out_ POBJECT_TYPE_LIST *CapturedObjectTypeList)
-{
- SIZE_T Size;
-
- if (PreviousMode == KernelMode)
- {
- return STATUS_NOT_IMPLEMENTED;
- }
-
- if (ObjectTypeListLength == 0)
- {
- *CapturedObjectTypeList = NULL;
- return STATUS_SUCCESS;
- }
-
- if (ObjectTypeList == NULL)
- {
- return STATUS_INVALID_PARAMETER;
- }
-
- /* Calculate the list size and check for integer overflow */
- Size = ObjectTypeListLength * sizeof(OBJECT_TYPE_LIST);
- if (Size == 0)
- {
- return STATUS_INVALID_PARAMETER;
- }
-
- /* Allocate a new list */
- *CapturedObjectTypeList = ExAllocatePoolWithTag(PagedPool, Size, TAG_SEPA);
- if (*CapturedObjectTypeList == NULL)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- _SEH2_TRY
- {
- ProbeForRead(ObjectTypeList, Size, sizeof(ULONG));
- RtlCopyMemory(*CapturedObjectTypeList, ObjectTypeList, Size);
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- ExFreePoolWithTag(*CapturedObjectTypeList, TAG_SEPA);
- *CapturedObjectTypeList = NULL;
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
- }
- _SEH2_END;
-
- return STATUS_SUCCESS;
-}
-
-/**
- * @brief
- * Releases a buffer list of object types.
- *
- * @param[in] CapturedObjectTypeList
- * A list of object types to free.
- *
- * @param[in] PreviousMode
- * Processor access level mode.
- *
- * @return
- * Nothing.
- */
-static
-VOID
-SeReleaseObjectTypeList(
- _In_ _Post_invalid_ POBJECT_TYPE_LIST CapturedObjectTypeList,
- _In_ KPROCESSOR_MODE PreviousMode)
-{
- if ((PreviousMode != KernelMode) && (CapturedObjectTypeList != NULL))
- ExFreePoolWithTag(CapturedObjectTypeList, TAG_SEPA);
-}
-
/**
* @unimplemented
* @brief
diff --git a/ntoskrnl/se/client.c b/ntoskrnl/se/client.c
new file mode 100644
index 00000000000..773428009a9
--- /dev/null
+++ b/ntoskrnl/se/client.c
@@ -0,0 +1,331 @@
+/*
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Security client support routines
+ * COPYRIGHT: Copyright Alex Ionescu <alex(a)relsoft.net>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+/**
+ * @brief
+ * Creates a client security context based upon an access token.
+ *
+ * @param[in] Token
+ * A valid token object.
+ *
+ * @param[in] ClientSecurityQos
+ * The Quality of Service (QoS) of a client security context.
+ *
+ * @param[in] ServerIsRemote
+ * If the client is a remote server (TRUE), the function will retrieve the
+ * control information of an access token, that is, we're doing delegation
+ * and that the server isn't local.
+ *
+ * @param[in] TokenType
+ * Type of token.
+ *
+ * @param[in] ThreadEffectiveOnly
+ * If set to TRUE, the client wants that the current thread wants to modify
+ * (enable or disable) privileges and groups.
+ *
+ * @param[in] ImpersonationLevel
+ * Security impersonation level filled in the QoS context.
+ *
+ * @param[out] ClientContext
+ * The returned security client context.
+ *
+ * @return
+ * Returns STATUS_SUCCESS if client security creation has completed successfully.
+ * STATUS_INVALID_PARAMETER is returned if one or more of the parameters are bogus.
+ * STATUS_BAD_IMPERSONATION_LEVEL is returned if the current impersonation level
+ * within QoS context doesn't meet with the conditions required. A failure
+ * NTSTATUS code is returned otherwise.
+ */
+NTSTATUS
+NTAPI
+SepCreateClientSecurity(
+ _In_ PACCESS_TOKEN Token,
+ _In_ PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos,
+ _In_ BOOLEAN ServerIsRemote,
+ _In_ TOKEN_TYPE TokenType,
+ _In_ BOOLEAN ThreadEffectiveOnly,
+ _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
+ _Out_ PSECURITY_CLIENT_CONTEXT ClientContext)
+{
+ NTSTATUS Status;
+ PACCESS_TOKEN NewToken;
+ PAGED_CODE();
+
+ /* Check for bogus impersonation level */
+ if (!VALID_IMPERSONATION_LEVEL(ClientSecurityQos->ImpersonationLevel))
+ {
+ /* Fail the call */
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Check what kind of token this is */
+ if (TokenType != TokenImpersonation)
+ {
+ /* On a primary token, if we do direct access, copy the flag from the QOS */
+ ClientContext->DirectAccessEffectiveOnly =
ClientSecurityQos->EffectiveOnly;
+ }
+ else
+ {
+ /* This is an impersonation token, is the level ok? */
+ if (ClientSecurityQos->ImpersonationLevel > ImpersonationLevel)
+ {
+ /* Nope, fail */
+ return STATUS_BAD_IMPERSONATION_LEVEL;
+ }
+
+ /* Is the level too low, or are we doing something other than delegation remotely
*/
+ if ((ImpersonationLevel == SecurityAnonymous) ||
+ (ImpersonationLevel == SecurityIdentification) ||
+ ((ServerIsRemote) && (ImpersonationLevel != SecurityDelegation)))
+ {
+ /* Fail the call */
+ return STATUS_BAD_IMPERSONATION_LEVEL;
+ }
+
+ /* Pick either the thread setting or the QOS setting */
+ ClientContext->DirectAccessEffectiveOnly =
+ ((ThreadEffectiveOnly) || (ClientSecurityQos->EffectiveOnly)) ? TRUE :
FALSE;
+ }
+
+ /* Is this static tracking */
+ if (ClientSecurityQos->ContextTrackingMode == SECURITY_STATIC_TRACKING)
+ {
+ /* Do not use direct access and make a copy */
+ ClientContext->DirectlyAccessClientToken = FALSE;
+ Status = SeCopyClientToken(Token,
+ ClientSecurityQos->ImpersonationLevel,
+ KernelMode,
+ &NewToken);
+ if (!NT_SUCCESS(Status))
+ return Status;
+ }
+ else
+ {
+ /* Use direct access and check if this is local */
+ ClientContext->DirectlyAccessClientToken = TRUE;
+ if (ServerIsRemote)
+ {
+ /* We are doing delegation, so make a copy of the control data */
+ SeGetTokenControlInformation(Token,
+ &ClientContext->ClientTokenControl);
+ }
+
+ /* Keep the same token */
+ NewToken = Token;
+ }
+
+ /* Fill out the context and return success */
+ ClientContext->SecurityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
+ ClientContext->SecurityQos.ImpersonationLevel =
ClientSecurityQos->ImpersonationLevel;
+ ClientContext->SecurityQos.ContextTrackingMode =
ClientSecurityQos->ContextTrackingMode;
+ ClientContext->SecurityQos.EffectiveOnly = ClientSecurityQos->EffectiveOnly;
+ ClientContext->ServerIsRemote = ServerIsRemote;
+ ClientContext->ClientToken = NewToken;
+ return STATUS_SUCCESS;
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+/**
+ * @brief
+ * Creates a client security context.
+ *
+ * @param[in] Thread
+ * Thread object of the client where impersonation has to begin.
+ *
+ * @param[in] Qos
+ * Quality of service to specify what kind of impersonation to be done.
+ *
+ * @param[in] RemoteClient
+ * If set to TRUE, the client that we're going to impersonate is remote.
+ *
+ * @param[out] ClientContext
+ * The returned security client context.
+ *
+ * @return
+ * See SepCreateClientSecurity.
+ */
+NTSTATUS
+NTAPI
+SeCreateClientSecurity(
+ _In_ PETHREAD Thread,
+ _In_ PSECURITY_QUALITY_OF_SERVICE Qos,
+ _In_ BOOLEAN RemoteClient,
+ _Out_ PSECURITY_CLIENT_CONTEXT ClientContext)
+{
+ TOKEN_TYPE TokenType;
+ BOOLEAN ThreadEffectiveOnly;
+ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
+ PACCESS_TOKEN Token;
+ NTSTATUS Status;
+ PAGED_CODE();
+
+ /* Reference the correct token */
+ Token = PsReferenceEffectiveToken(Thread,
+ &TokenType,
+ &ThreadEffectiveOnly,
+ &ImpersonationLevel);
+
+ /* Create client security from it */
+ Status = SepCreateClientSecurity(Token,
+ Qos,
+ RemoteClient,
+ TokenType,
+ ThreadEffectiveOnly,
+ ImpersonationLevel,
+ ClientContext);
+
+ /* Check if we failed or static tracking was used */
+ if (!(NT_SUCCESS(Status)) || (Qos->ContextTrackingMode ==
SECURITY_STATIC_TRACKING))
+ {
+ /* Dereference our copy since it's not being used */
+ ObDereferenceObject(Token);
+ }
+
+ /* Return status */
+ return Status;
+}
+
+/**
+ * @brief
+ * Creates a client security context based upon the captured security
+ * subject context.
+ *
+ * @param[in] SubjectContext
+ * The captured subject context where client security is to be created
+ * from.
+ *
+ * @param[in] ClientSecurityQos
+ * Quality of service to specify what kind of impersonation to be done.
+ *
+ * @param[in] ServerIsRemote
+ * If set to TRUE, the client that we're going to impersonate is remote.
+ *
+ * @param[out] ClientContext
+ * The returned security client context.
+ *
+ * @return
+ * See SepCreateClientSecurity.
+ */
+NTSTATUS
+NTAPI
+SeCreateClientSecurityFromSubjectContext(
+ _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
+ _In_ PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos,
+ _In_ BOOLEAN ServerIsRemote,
+ _Out_ PSECURITY_CLIENT_CONTEXT ClientContext)
+{
+ PACCESS_TOKEN Token;
+ NTSTATUS Status;
+ PAGED_CODE();
+
+ /* Get the right token and reference it */
+ Token = SeQuerySubjectContextToken(SubjectContext);
+ ObReferenceObject(Token);
+
+ /* Create the context */
+ Status = SepCreateClientSecurity(Token,
+ ClientSecurityQos,
+ ServerIsRemote,
+ SubjectContext->ClientToken ?
+ TokenImpersonation : TokenPrimary,
+ FALSE,
+ SubjectContext->ImpersonationLevel,
+ ClientContext);
+
+ /* Check if we failed or static tracking was used */
+ if (!(NT_SUCCESS(Status)) ||
+ (ClientSecurityQos->ContextTrackingMode == SECURITY_STATIC_TRACKING))
+ {
+ /* Dereference our copy since it's not being used */
+ ObDereferenceObject(Token);
+ }
+
+ /* Return status */
+ return Status;
+}
+
+/**
+ * @brief
+ * Extended function that impersonates a client.
+ *
+ * @param[in] ClientContext
+ * A valid client context.
+ *
+ * @param[in] ServerThread
+ * The thread where impersonation is to be done.
+ *
+ * @return
+ * STATUS_SUCCESS is returned if the calling thread successfully impersonates
+ * the client. A failure NTSTATUS code is returned otherwise.
+ */
+NTSTATUS
+NTAPI
+SeImpersonateClientEx(
+ _In_ PSECURITY_CLIENT_CONTEXT ClientContext,
+ _In_opt_ PETHREAD ServerThread)
+{
+ BOOLEAN EffectiveOnly;
+ PAGED_CODE();
+
+ /* Check if direct access is requested */
+ if (!ClientContext->DirectlyAccessClientToken)
+ {
+ /* No, so get the flag from QOS */
+ EffectiveOnly = ClientContext->SecurityQos.EffectiveOnly;
+ }
+ else
+ {
+ /* Yes, so see if direct access should be effective only */
+ EffectiveOnly = ClientContext->DirectAccessEffectiveOnly;
+ }
+
+ /* Use the current thread if one was not passed */
+ if (!ServerThread) ServerThread = PsGetCurrentThread();
+
+ /* Call the lower layer routine */
+ return PsImpersonateClient(ServerThread,
+ ClientContext->ClientToken,
+ TRUE,
+ EffectiveOnly,
+ ClientContext->SecurityQos.ImpersonationLevel);
+}
+
+/**
+ * @brief
+ * Impersonates a client user.
+ *
+ * @param[in] ClientContext
+ * A valid client context.
+ *
+ * @param[in] ServerThread
+ * The thread where impersonation is to be done.
+ * *
+ * @return
+ * Nothing.
+ */
+VOID
+NTAPI
+SeImpersonateClient(
+ _In_ PSECURITY_CLIENT_CONTEXT ClientContext,
+ _In_opt_ PETHREAD ServerThread)
+{
+ PAGED_CODE();
+
+ /* Call the new API */
+ SeImpersonateClientEx(ClientContext, ServerThread);
+}
+
+/* EOF */
diff --git a/ntoskrnl/se/objtype.c b/ntoskrnl/se/objtype.c
new file mode 100644
index 00000000000..f4648d1a8ec
--- /dev/null
+++ b/ntoskrnl/se/objtype.c
@@ -0,0 +1,115 @@
+/*
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Security object type list support routines
+ * COPYRIGHT: Copyright Timo Kreuzer <timo.kreuzer(a)reactos.org>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* PRIVATE FUNCTIONS ***********************************************************/
+
+/**
+ * @brief
+ * Captures a list of object types.
+ *
+ * @param[in] ObjectTypeList
+ * An existing list of object types.
+ *
+ * @param[in] ObjectTypeListLength
+ * The length size of the list.
+ *
+ * @param[in] PreviousMode
+ * Processor access level mode.
+ *
+ * @param[out] CapturedObjectTypeList
+ * The captured list of object types.
+ *
+ * @return
+ * Returns STATUS_SUCCESS if the list of object types has been captured
+ * successfully. STATUS_INVALID_PARAMETER is returned if the caller hasn't
+ * supplied a buffer list of object types. STATUS_INSUFFICIENT_RESOURCES
+ * is returned if pool memory allocation for the captured list has failed.
+ */
+NTSTATUS
+SeCaptureObjectTypeList(
+ _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList,
+ _In_ ULONG ObjectTypeListLength,
+ _In_ KPROCESSOR_MODE PreviousMode,
+ _Out_ POBJECT_TYPE_LIST *CapturedObjectTypeList)
+{
+ SIZE_T Size;
+
+ if (PreviousMode == KernelMode)
+ {
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (ObjectTypeListLength == 0)
+ {
+ *CapturedObjectTypeList = NULL;
+ return STATUS_SUCCESS;
+ }
+
+ if (ObjectTypeList == NULL)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Calculate the list size and check for integer overflow */
+ Size = ObjectTypeListLength * sizeof(OBJECT_TYPE_LIST);
+ if (Size == 0)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Allocate a new list */
+ *CapturedObjectTypeList = ExAllocatePoolWithTag(PagedPool, Size, TAG_SEPA);
+ if (*CapturedObjectTypeList == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForRead(ObjectTypeList, Size, sizeof(ULONG));
+ RtlCopyMemory(*CapturedObjectTypeList, ObjectTypeList, Size);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ExFreePoolWithTag(*CapturedObjectTypeList, TAG_SEPA);
+ *CapturedObjectTypeList = NULL;
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ return STATUS_SUCCESS;
+}
+
+/**
+ * @brief
+ * Releases a buffer list of object types.
+ *
+ * @param[in] CapturedObjectTypeList
+ * A list of object types to free.
+ *
+ * @param[in] PreviousMode
+ * Processor access level mode.
+ *
+ * @return
+ * Nothing.
+ */
+VOID
+SeReleaseObjectTypeList(
+ _In_ _Post_invalid_ POBJECT_TYPE_LIST CapturedObjectTypeList,
+ _In_ KPROCESSOR_MODE PreviousMode)
+{
+ if ((PreviousMode != KernelMode) && (CapturedObjectTypeList != NULL))
+ ExFreePoolWithTag(CapturedObjectTypeList, TAG_SEPA);
+}
+
+/* EOF */
diff --git a/ntoskrnl/se/sid.c b/ntoskrnl/se/sid.c
index 13aeba2662b..3d4d8931a15 100644
--- a/ntoskrnl/se/sid.c
+++ b/ntoskrnl/se/sid.c
@@ -412,6 +412,146 @@ SepReleaseSid(
}
}
+/**
+ * @brief
+ * Checks if a SID is present in a token.
+ *
+ * @param[in] _Token
+ * A valid token object.
+ *
+ * @param[in] PrincipalSelfSid
+ * A principal self SID.
+ *
+ * @param[in] _Sid
+ * A regular SID.
+ *
+ * @param[in] Deny
+ * If set to TRUE, the caller expected that a SID in a token
+ * must be a deny-only SID, that is, access checks are performed
+ * only for deny-only ACEs of the said SID.
+ *
+ * @param[in] Restricted
+ * If set to TRUE, the caller expects that a SID in a token is
+ * restricted (by the general definition, a token is restricted).
+ *
+ * @return
+ * Returns TRUE if the specified SID in the call is present in the token,
+ * FALSE otherwise.
+ */
+BOOLEAN
+NTAPI
+SepSidInTokenEx(
+ _In_ PACCESS_TOKEN _Token,
+ _In_ PSID PrincipalSelfSid,
+ _In_ PSID _Sid,
+ _In_ BOOLEAN Deny,
+ _In_ BOOLEAN Restricted)
+{
+ ULONG SidIndex;
+ PTOKEN Token = (PTOKEN)_Token;
+ PISID TokenSid, Sid = (PISID)_Sid;
+ PSID_AND_ATTRIBUTES SidAndAttributes;
+ ULONG SidCount, SidLength;
+ USHORT SidMetadata;
+ PAGED_CODE();
+
+ /* Check if a principal SID was given, and this is our current SID already */
+ if ((PrincipalSelfSid) && (RtlEqualSid(SePrincipalSelfSid, Sid)))
+ {
+ /* Just use the principal SID in this case */
+ Sid = PrincipalSelfSid;
+ }
+
+ /* Check if this is a restricted token or not */
+ if (Restricted)
+ {
+ /* Use the restricted SIDs and count */
+ SidAndAttributes = Token->RestrictedSids;
+ SidCount = Token->RestrictedSidCount;
+ }
+ else
+ {
+ /* Use the normal SIDs and count */
+ SidAndAttributes = Token->UserAndGroups;
+ SidCount = Token->UserAndGroupCount;
+ }
+
+ /* Do checks here by hand instead of the usual 4 function calls */
+ SidLength = FIELD_OFFSET(SID,
+ SubAuthority[Sid->SubAuthorityCount]);
+ SidMetadata = *(PUSHORT)&Sid->Revision;
+
+ /* Loop every SID */
+ for (SidIndex = 0; SidIndex < SidCount; SidIndex++)
+ {
+ TokenSid = (PISID)SidAndAttributes->Sid;
+#if SE_SID_DEBUG
+ UNICODE_STRING sidString;
+ RtlConvertSidToUnicodeString(&sidString, TokenSid, TRUE);
+ DPRINT1("SID in Token: %wZ\n", &sidString);
+ RtlFreeUnicodeString(&sidString);
+#endif
+ /* Check if the SID metadata matches */
+ if (*(PUSHORT)&TokenSid->Revision == SidMetadata)
+ {
+ /* Check if the SID data matches */
+ if (RtlEqualMemory(Sid, TokenSid, SidLength))
+ {
+ /*
+ * Check if the group is enabled, or used for deny only.
+ * Otherwise we have to check if this is the first user.
+ * We understand that by looking if this SID is not
+ * restricted, this is the first element we are iterating
+ * and that it doesn't have SE_GROUP_USE_FOR_DENY_ONLY
+ * attribute.
+ */
+ if ((!Restricted && (SidIndex == 0) &&
!(SidAndAttributes->Attributes & SE_GROUP_USE_FOR_DENY_ONLY)) ||
+ (SidAndAttributes->Attributes & SE_GROUP_ENABLED) ||
+ ((Deny) && (SidAndAttributes->Attributes &
SE_GROUP_USE_FOR_DENY_ONLY)))
+ {
+ /* SID is present */
+ return TRUE;
+ }
+ else
+ {
+ /* SID is not present */
+ return FALSE;
+ }
+ }
+ }
+
+ /* Move to the next SID */
+ SidAndAttributes++;
+ }
+
+ /* SID is not present */
+ return FALSE;
+}
+
+/**
+ * @brief
+ * Checks if a SID is present in a token.
+ *
+ * @param[in] _Token
+ * A valid token object.
+ *
+ * @param[in] _Sid
+ * A regular SID.
+ *
+ * @return
+ * Returns TRUE if the specified SID in the call is present in the token,
+ * FALSE otherwise.
+ */
+BOOLEAN
+NTAPI
+SepSidInToken(
+ _In_ PACCESS_TOKEN _Token,
+ _In_ PSID Sid)
+{
+ /* Call extended API */
+ return SepSidInTokenEx(_Token, NULL, Sid, FALSE, FALSE);
+}
+
/**
* @brief
* Captures a security identifier from a
diff --git a/ntoskrnl/se/subject.c b/ntoskrnl/se/subject.c
new file mode 100644
index 00000000000..51a9e132028
--- /dev/null
+++ b/ntoskrnl/se/subject.c
@@ -0,0 +1,185 @@
+/*
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Security subject context support routines
+ * COPYRIGHT: Copyright Alex Ionescu <alex(a)relsoft.net>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS ********************************************************************/
+
+ERESOURCE SepSubjectContextLock;
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+/**
+ * @brief
+ * An extended function that captures the security subject context based upon
+ * the specified thread and process.
+ *
+ * @param[in] Thread
+ * A thread where the calling thread's token is to be referenced for
+ * the security context.
+ *
+ * @param[in] Process
+ * A process where the main process' token is to be referenced for
+ * the security context.
+ *
+ * @param[out] SubjectContext
+ * The returned security subject context.
+ *
+ * @return
+ * Nothing.
+ */
+VOID
+NTAPI
+SeCaptureSubjectContextEx(
+ _In_ PETHREAD Thread,
+ _In_ PEPROCESS Process,
+ _Out_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
+{
+ BOOLEAN CopyOnOpen, EffectiveOnly;
+
+ PAGED_CODE();
+
+ /* Save the unique ID */
+ SubjectContext->ProcessAuditId = Process->UniqueProcessId;
+
+ /* Check if we have a thread */
+ if (!Thread)
+ {
+ /* We don't, so no token */
+ SubjectContext->ClientToken = NULL;
+ }
+ else
+ {
+ /* Get the impersonation token */
+ SubjectContext->ClientToken = PsReferenceImpersonationToken(Thread,
+ &CopyOnOpen,
+ &EffectiveOnly,
+
&SubjectContext->ImpersonationLevel);
+ }
+
+ /* Get the primary token */
+ SubjectContext->PrimaryToken = PsReferencePrimaryToken(Process);
+}
+
+/**
+ * @brief
+ * Captures the security subject context of the calling thread and calling
+ * process.
+ *
+ * @param[out] SubjectContext
+ * The returned security subject context.
+ *
+ * @return
+ * Nothing.
+ */
+VOID
+NTAPI
+SeCaptureSubjectContext(
+ _Out_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
+{
+ /* Call the extended API */
+ SeCaptureSubjectContextEx(PsGetCurrentThread(),
+ PsGetCurrentProcess(),
+ SubjectContext);
+}
+
+/**
+ * @brief
+ * Locks both the referenced primary and client access tokens of a
+ * security subject context.
+ *
+ * @param[in] SubjectContext
+ * A valid security context with both referenced tokens.
+ *
+ * @return
+ * Nothing.
+ */
+VOID
+NTAPI
+SeLockSubjectContext(
+ _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
+{
+ PTOKEN PrimaryToken, ClientToken;
+ PAGED_CODE();
+
+ /* Read both tokens */
+ PrimaryToken = SubjectContext->PrimaryToken;
+ ClientToken = SubjectContext->ClientToken;
+
+ /* Always lock the primary */
+ SepAcquireTokenLockShared(PrimaryToken);
+
+ /* Lock the impersonation one if it's there */
+ if (!ClientToken) return;
+ SepAcquireTokenLockShared(ClientToken);
+}
+
+/**
+ * @brief
+ * Unlocks both the referenced primary and client access tokens of a
+ * security subject context.
+ *
+ * @param[in] SubjectContext
+ * A valid security context with both referenced tokens.
+ *
+ * @return
+ * Nothing.
+ */
+VOID
+NTAPI
+SeUnlockSubjectContext(
+ _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
+{
+ PTOKEN PrimaryToken, ClientToken;
+ PAGED_CODE();
+
+ /* Read both tokens */
+ PrimaryToken = SubjectContext->PrimaryToken;
+ ClientToken = SubjectContext->ClientToken;
+
+ /* Unlock the impersonation one if it's there */
+ if (ClientToken)
+ {
+ SepReleaseTokenLock(ClientToken);
+ }
+
+ /* Always unlock the primary one */
+ SepReleaseTokenLock(PrimaryToken);
+}
+
+/**
+ * @brief
+ * Releases both the primary and client tokens of a security
+ * subject context.
+ *
+ * @param[in] SubjectContext
+ * The captured security context.
+ *
+ * @return
+ * Nothing.
+ */
+VOID
+NTAPI
+SeReleaseSubjectContext(
+ _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
+{
+ PAGED_CODE();
+
+ /* Drop reference on the primary */
+ ObFastDereferenceObject(&PsGetCurrentProcess()->Token,
SubjectContext->PrimaryToken);
+ SubjectContext->PrimaryToken = NULL;
+
+ /* Drop reference on the impersonation, if there was one */
+ PsDereferenceImpersonationToken(SubjectContext->ClientToken);
+ SubjectContext->ClientToken = NULL;
+}
+
+/* EOF */
diff --git a/ntoskrnl/se/token.c b/ntoskrnl/se/token.c
index e773358b356..83b962f1ba9 100644
--- a/ntoskrnl/se/token.c
+++ b/ntoskrnl/se/token.c
@@ -1,7 +1,7 @@
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
- * PURPOSE: Security token implementation support
+ * PURPOSE: Security access token implementation base support routines
* COPYRIGHT: Copyright David Welch <welch(a)cwcom.net>
* Copyright 2021-2022 George Bișoc <george.bisoc(a)reactos.org>
*/
@@ -12,8 +12,6 @@
#define NDEBUG
#include <debug.h>
-#include <ntlsa.h>
-
/* GLOBALS ********************************************************************/
POBJECT_TYPE SeTokenObjectType = NULL;
@@ -29,48 +27,7 @@ static GENERIC_MAPPING SepTokenMapping = {
TOKEN_ALL_ACCESS
};
-static const INFORMATION_CLASS_INFO SeTokenInformationClass[] = {
-
- /* Class 0 not used, blame MS! */
- IQS_NONE,
-
- /* TokenUser */
- IQS_SAME(TOKEN_USER, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
- /* TokenGroups */
- IQS_SAME(TOKEN_GROUPS, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
- /* TokenPrivileges */
- IQS_SAME(TOKEN_PRIVILEGES, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
- /* TokenOwner */
- IQS_SAME(TOKEN_OWNER, ULONG, ICIF_QUERY | ICIF_SET | ICIF_SIZE_VARIABLE),
- /* TokenPrimaryGroup */
- IQS_SAME(TOKEN_PRIMARY_GROUP, ULONG, ICIF_QUERY | ICIF_SET | ICIF_SIZE_VARIABLE),
- /* TokenDefaultDacl */
- IQS_SAME(TOKEN_DEFAULT_DACL, ULONG, ICIF_QUERY | ICIF_SET | ICIF_SIZE_VARIABLE),
- /* TokenSource */
- IQS_SAME(TOKEN_SOURCE, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
- /* TokenType */
- IQS_SAME(TOKEN_TYPE, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
- /* TokenImpersonationLevel */
- IQS_SAME(SECURITY_IMPERSONATION_LEVEL, ULONG, ICIF_QUERY),
- /* TokenStatistics */
- IQS_SAME(TOKEN_STATISTICS, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
- /* TokenRestrictedSids */
- IQS_SAME(TOKEN_GROUPS, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
- /* TokenSessionId */
- IQS_SAME(ULONG, ULONG, ICIF_QUERY | ICIF_SET),
- /* TokenGroupsAndPrivileges */
- IQS_SAME(TOKEN_GROUPS_AND_PRIVILEGES, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
- /* TokenSessionReference */
- IQS_SAME(ULONG, ULONG, ICIF_SET),
- /* TokenSandBoxInert */
- IQS_SAME(ULONG, ULONG, ICIF_QUERY),
- /* TokenAuditPolicy */
- IQS_SAME(TOKEN_AUDIT_POLICY_INFORMATION, ULONG, ICIF_SET | ICIF_SET_SIZE_VARIABLE),
- /* TokenOrigin */
- IQS_SAME(TOKEN_ORIGIN, ULONG, ICIF_QUERY | ICIF_SET),
-};
-
-/* FUNCTIONS *****************************************************************/
+/* PRIVATE FUNCTIONS *****************************************************************/
/**
* @brief
@@ -84,7 +41,6 @@ static const INFORMATION_CLASS_INFO SeTokenInformationClass[] = {
* completed successfully, otherwise STATUS_INSUFFICIENT_RESOURCES on a
* pool allocation failure.
*/
-static
NTSTATUS
SepCreateTokenLock(
_Inout_ PTOKEN Token)
@@ -114,7 +70,6 @@ SepCreateTokenLock(
* @return
* Nothing.
*/
-static
VOID
SepDeleteTokenLock(
_Inout_ PTOKEN Token)
@@ -483,7 +438,6 @@ SepImpersonateAnonymousToken(
* @return
* Nothing.
*/
-static
VOID
SepUpdateSinglePrivilegeFlagToken(
_Inout_ PTOKEN Token,
@@ -534,6 +488,56 @@ SepUpdateSinglePrivilegeFlagToken(
}
}
+/**
+ * @brief
+ * Checks if a token belongs to the main user, being the owner.
+ *
+ * @param[in] _Token
+ * A valid token object.
+ *
+ * @param[in] SecurityDescriptor
+ * A security descriptor where the owner is to be found.
+ *
+ * @param[in] TokenLocked
+ * If set to TRUE, the token has been already locked and there's
+ * no need to lock it again. Otherwise the function will acquire
+ * the lock.
+ *
+ * @return
+ * Returns TRUE if the token belongs to a owner, FALSE otherwise.
+ */
+BOOLEAN
+NTAPI
+SepTokenIsOwner(
+ _In_ PACCESS_TOKEN _Token,
+ _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ _In_ BOOLEAN TokenLocked)
+{
+ PSID Sid;
+ BOOLEAN Result;
+ PTOKEN Token = _Token;
+
+ /* Get the owner SID */
+ Sid = SepGetOwnerFromDescriptor(SecurityDescriptor);
+ ASSERT(Sid != NULL);
+
+ /* Lock the token if needed */
+ if (!TokenLocked) SepAcquireTokenLockShared(Token);
+
+ /* Check if the owner SID is found, handling restricted case as well */
+ Result = SepSidInToken(Token, Sid);
+ if ((Result) && (Token->TokenFlags & TOKEN_IS_RESTRICTED))
+ {
+ Result = SepSidInTokenEx(Token, NULL, Sid, FALSE, TRUE);
+ }
+
+ /* Release the lock if we had acquired it */
+ if (!TokenLocked) SepReleaseTokenLock(Token);
+
+ /* Return the result */
+ return Result;
+}
+
/**
* @brief
* Updates the token's flags based upon the privilege that the token
@@ -546,7 +550,6 @@ SepUpdateSinglePrivilegeFlagToken(
* @return
* Nothing.
*/
-static
VOID
SepUpdatePrivilegeFlagsToken(
_Inout_ PTOKEN Token)
@@ -575,7 +578,6 @@ SepUpdatePrivilegeFlagsToken(
* @return
* Nothing.
*/
-static
VOID
SepRemovePrivilegeToken(
_Inout_ PTOKEN Token,
@@ -612,7 +614,6 @@ SepRemovePrivilegeToken(
* @return
* Nothing.
*/
-static
VOID
SepRemoveUserGroupToken(
_Inout_ PTOKEN Token,
@@ -819,7 +820,7 @@ SeDeassignPrimaryToken(
* @return
* Returns the total length of a SID size.
*/
-static ULONG
+ULONG
RtlLengthSidAndAttributes(
_In_ ULONG Count,
_In_ PSID_AND_ATTRIBUTES Src)
@@ -865,7 +866,7 @@ RtlLengthSidAndAttributes(
* user from the token. STATUS_INVALID_PRIMARY_GROUP is returned if the specified default
primary group does not match with the
* other group from the token.
*/
-static NTSTATUS
+NTSTATUS
SepFindPrimaryGroupAndDefaultOwner(
_In_ PTOKEN Token,
_In_ PSID PrimaryGroup,
@@ -959,349 +960,6 @@ SepFindPrimaryGroupAndDefaultOwner(
return STATUS_SUCCESS;
}
-/**
- * @brief
- * Duplicates an access token, from an existing valid token.
- *
- * @param[in] Token
- * Access token to duplicate.
- *
- * @param[in] ObjectAttributes
- * Object attributes for the new token.
- *
- * @param[in] EffectiveOnly
- * If set to TRUE, the function removes all the disabled privileges and groups of the
token
- * to duplicate.
- *
- * @param[in] TokenType
- * Type of token.
- *
- * @param[in] Level
- * Security impersonation level of a token.
- *
- * @param[in] PreviousMode
- * The processor request level mode.
- *
- * @param[out] NewAccessToken
- * The duplicated token.
- *
- * @return
- * Returns STATUS_SUCCESS if the token has been duplicated. STATUS_INSUFFICIENT_RESOURCES
is returned
- * if memory pool allocation of the dynamic part of the token for duplication has failed
due to the lack
- * of memory resources. A failure NTSTATUS code is returned otherwise.
- */
-NTSTATUS
-NTAPI
-SepDuplicateToken(
- _In_ PTOKEN Token,
- _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
- _In_ BOOLEAN EffectiveOnly,
- _In_ TOKEN_TYPE TokenType,
- _In_ SECURITY_IMPERSONATION_LEVEL Level,
- _In_ KPROCESSOR_MODE PreviousMode,
- _Out_ PTOKEN* NewAccessToken)
-{
- NTSTATUS Status;
- PTOKEN AccessToken;
- PVOID EndMem;
- ULONG PrimaryGroupIndex;
- ULONG VariableLength;
- ULONG TotalSize;
- ULONG PrivilegesIndex, GroupsIndex;
-
- PAGED_CODE();
-
- /* Compute how much size we need to allocate for the token */
- VariableLength = Token->VariableLength;
- TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
-
- Status = ObCreateObject(PreviousMode,
- SeTokenObjectType,
- ObjectAttributes,
- PreviousMode,
- NULL,
- TotalSize,
- 0,
- 0,
- (PVOID*)&AccessToken);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
- return Status;
- }
-
- /* Zero out the buffer and initialize the token */
- RtlZeroMemory(AccessToken, TotalSize);
-
- ExAllocateLocallyUniqueId(&AccessToken->TokenId);
-
- AccessToken->TokenType = TokenType;
- AccessToken->ImpersonationLevel = Level;
-
- /* Initialise the lock for the access token */
- Status = SepCreateTokenLock(AccessToken);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject(AccessToken);
- return Status;
- }
-
- /* Copy the immutable fields */
- AccessToken->TokenSource.SourceIdentifier =
Token->TokenSource.SourceIdentifier;
- RtlCopyMemory(AccessToken->TokenSource.SourceName,
- Token->TokenSource.SourceName,
- sizeof(Token->TokenSource.SourceName));
-
- AccessToken->AuthenticationId = Token->AuthenticationId;
- AccessToken->ParentTokenId = Token->ParentTokenId;
- AccessToken->ExpirationTime = Token->ExpirationTime;
- AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession;
-
- /* Lock the source token and copy the mutable fields */
- SepAcquireTokenLockShared(Token);
-
- AccessToken->SessionId = Token->SessionId;
- AccessToken->ModifiedId = Token->ModifiedId;
-
- AccessToken->TokenFlags = Token->TokenFlags &
~TOKEN_SESSION_NOT_REFERENCED;
-
- /* Reference the logon session */
- Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
- if (!NT_SUCCESS(Status))
- {
- /* No logon session could be found, bail out */
- DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n",
Status);
- /* Set the flag for proper cleanup by the delete procedure */
- AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
- goto Quit;
- }
-
- /* Insert the referenced logon session into the token */
- Status = SepRmInsertLogonSessionIntoToken(AccessToken);
- if (!NT_SUCCESS(Status))
- {
- /* Failed to insert the logon session into the token, bail out */
- DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n",
Status);
- goto Quit;
- }
-
- /* Fill in token debug information */
-#if DBG
- RtlCopyMemory(AccessToken->ImageFileName,
- PsGetCurrentProcess()->ImageFileName,
- min(sizeof(AccessToken->ImageFileName),
sizeof(PsGetCurrentProcess()->ImageFileName)));
-
- AccessToken->ProcessCid = PsGetCurrentProcessId();
- AccessToken->ThreadCid = PsGetCurrentThreadId();
- AccessToken->CreateMethod = TOKEN_DUPLICATE_METHOD;
-#endif
-
- /* Assign the data that reside in the token's variable information area */
- AccessToken->VariableLength = VariableLength;
- EndMem = (PVOID)&AccessToken->VariablePart;
-
- /* Copy the privileges */
- AccessToken->PrivilegeCount = 0;
- AccessToken->Privileges = NULL;
- if (Token->Privileges && (Token->PrivilegeCount > 0))
- {
- ULONG PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
- PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
-
- ASSERT(VariableLength >= PrivilegesLength);
-
- AccessToken->PrivilegeCount = Token->PrivilegeCount;
- AccessToken->Privileges = EndMem;
- EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
- VariableLength -= PrivilegesLength;
-
- RtlCopyMemory(AccessToken->Privileges,
- Token->Privileges,
- AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
- }
-
- /* Copy the user and groups */
- AccessToken->UserAndGroupCount = 0;
- AccessToken->UserAndGroups = NULL;
- if (Token->UserAndGroups && (Token->UserAndGroupCount > 0))
- {
- AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
- AccessToken->UserAndGroups = EndMem;
- EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
- VariableLength -= ((ULONG_PTR)EndMem -
(ULONG_PTR)AccessToken->UserAndGroups);
-
- Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount,
- Token->UserAndGroups,
- VariableLength,
- AccessToken->UserAndGroups,
- EndMem,
- &EndMem,
- &VariableLength);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("RtlCopySidAndAttributesArray(UserAndGroups) failed (Status
0x%lx)\n", Status);
- goto Quit;
- }
- }
-
- /* Find the token primary group */
- Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken,
- Token->PrimaryGroup,
- NULL,
- &PrimaryGroupIndex,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n",
Status);
- goto Quit;
- }
-
- AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid;
- AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
-
- /* Copy the restricted SIDs */
- AccessToken->RestrictedSidCount = 0;
- AccessToken->RestrictedSids = NULL;
- if (Token->RestrictedSids && (Token->RestrictedSidCount > 0))
- {
- AccessToken->RestrictedSidCount = Token->RestrictedSidCount;
- AccessToken->RestrictedSids = EndMem;
- EndMem =
&AccessToken->RestrictedSids[AccessToken->RestrictedSidCount];
- VariableLength -= ((ULONG_PTR)EndMem -
(ULONG_PTR)AccessToken->RestrictedSids);
-
- Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount,
- Token->RestrictedSids,
- VariableLength,
- AccessToken->RestrictedSids,
- EndMem,
- &EndMem,
- &VariableLength);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("RtlCopySidAndAttributesArray(RestrictedSids) failed (Status
0x%lx)\n", Status);
- goto Quit;
- }
- }
-
- /*
- * Filter the token by removing the disabled privileges
- * and groups if the caller wants to duplicate an access
- * token as effective only.
- */
- if (EffectiveOnly)
- {
- /* Begin querying the groups and search for disabled ones */
- for (GroupsIndex = 0; GroupsIndex < AccessToken->UserAndGroupCount;
GroupsIndex++)
- {
- /*
- * A group or user is considered disabled if its attributes is either
- * 0 or SE_GROUP_ENABLED is not included in the attributes flags list.
- * That is because a certain user and/or group can have several attributes
- * that bear no influence on whether a user/group is enabled or not
- * (SE_GROUP_ENABLED_BY_DEFAULT for example which is a mere indicator
- * that the group has just been enabled by default). A mandatory
- * group (that is, the group has SE_GROUP_MANDATORY attribute)
- * by standards it's always enabled and no one can disable it.
- */
- if (AccessToken->UserAndGroups[GroupsIndex].Attributes == 0 ||
- (AccessToken->UserAndGroups[GroupsIndex].Attributes &
SE_GROUP_ENABLED) == 0)
- {
- /*
- * If this group is an administrators group
- * and the token belongs to such group,
- * we've to take away TOKEN_HAS_ADMIN_GROUP
- * for the fact that's not enabled and as
- * such the token no longer belongs to
- * this group.
- */
- if (RtlEqualSid(SeAliasAdminsSid,
- &AccessToken->UserAndGroups[GroupsIndex].Sid))
- {
- AccessToken->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP;
- }
-
- /*
- * A group is not enabled, it's time to remove
- * from the token and update the groups index
- * accordingly and continue with the next group.
- */
- SepRemoveUserGroupToken(AccessToken, GroupsIndex);
- GroupsIndex--;
- }
- }
-
- /* Begin querying the privileges and search for disabled ones */
- for (PrivilegesIndex = 0; PrivilegesIndex < AccessToken->PrivilegeCount;
PrivilegesIndex++)
- {
- /*
- * A privilege is considered disabled if its attributes is either
- * 0 or SE_PRIVILEGE_ENABLED is not included in the attributes flags list.
- * That is because a certain privilege can have several attributes
- * that bear no influence on whether a privilege is enabled or not
- * (SE_PRIVILEGE_ENABLED_BY_DEFAULT for example which is a mere indicator
- * that the privilege has just been enabled by default).
- */
- if (AccessToken->Privileges[PrivilegesIndex].Attributes == 0 ||
- (AccessToken->Privileges[PrivilegesIndex].Attributes &
SE_PRIVILEGE_ENABLED) == 0)
- {
- /*
- * A privilege is not enabled, therefor it's time
- * to strip it from the token and continue with the next
- * privilege. Of course we must also want to update the
- * privileges index accordingly.
- */
- SepRemovePrivilegeToken(AccessToken, PrivilegesIndex);
- PrivilegesIndex--;
- }
- }
- }
-
- //
- // NOTE: So far our dynamic area only contains
- // the default dacl, so this makes the following
- // code pretty simple. The day where it stores
- // other data, the code will require adaptations.
- //
-
- /* Now allocate the token's dynamic information area and set the data */
- AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area.
- AccessToken->DynamicPart = NULL;
- if (Token->DynamicPart && Token->DefaultDacl)
- {
- AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
-
Token->DefaultDacl->AclSize,
- TAG_TOKEN_DYNAMIC);
- if (AccessToken->DynamicPart == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto Quit;
- }
-
- EndMem = (PVOID)AccessToken->DynamicPart;
- AccessToken->DefaultDacl = EndMem;
-
- RtlCopyMemory(AccessToken->DefaultDacl,
- Token->DefaultDacl,
- Token->DefaultDacl->AclSize);
- }
-
- /* Return the token to the caller */
- *NewAccessToken = AccessToken;
- Status = STATUS_SUCCESS;
-
-Quit:
- if (!NT_SUCCESS(Status))
- {
- /* Dereference the token, the delete procedure will clean it up */
- ObDereferenceObject(AccessToken);
- }
-
- /* Unlock the source token */
- SepReleaseTokenLock(Token);
-
- return Status;
-}
-
/**
* @brief
* Subtracts a token in exchange of duplicating a new one.
@@ -1638,1207 +1296,292 @@ SeAssignPrimaryToken(
/**
* @brief
- * Internal function responsible for access token object creation in the kernel.
- * A fully created token objected is inserted into the token handle, thus the handle
- * becoming a valid handle to an access token object and ready for use.
+ * Retrieves token control information.
*
- * @param[out] TokenHandle
- * Valid token handle that's ready for use after token creation and object
insertion.
- *
- * @param[in] PreviousMode
- * Processor request level mode.
- *
- * @param[in] DesiredAccess
- * Desired access right for the token object to be granted. This kind of access right
- * impacts how the token can be used and who.
- *
- * @param[in] ObjectAttributes
- * Object attributes for the token to be created.
- *
- * @param[in] TokenType
- * Type of token to assign upon creation.
- *
- * @param[in] ImpersonationLevel
- * Security impersonation level of token to assign upon creation.
- *
- * @param[in] AuthenticationId
- * Authentication ID that represents the authentication information of the token.
- *
- * @param[in] ExpirationTime
- * Expiration time of the token to assign. A value of -1 means that the token never
- * expires and its life depends upon the amount of references this token object has.
- *
- * @param[in] User
- * User entry to assign to the token.
- *
- * @param[in] GroupCount
- * The total number of groups count for the token.
- *
- * @param[in] Groups
- * The group entries for the token.
- *
- * @param[in] GroupsLength
- * The length size of the groups array, pointed by the Groups parameter.
+ * @param[in] _Token
+ * A valid token object.
*
- * @param[in] PrivilegeCount
- * The total number of priivleges that the newly created token has.
- *
- * @param[in] Privileges
- * The privileges for the token.
- *
- * @param[in] Owner
- * The main user (or also owner) that represents the token that we create.
- *
- * @param[in] PrimaryGroup
- * The main group that represents the token that we create.
- *
- * @param[in] DefaultDacl
- * A discretionary access control list for the token.
- *
- * @param[in] TokenSource
- * Source (or the origin) of the access token that creates it.
- *
- * @param[in] SystemToken
- * If set to TRUE, the newly created token is a system token and only in charge
- * by the internal system. The function directly returns a pointer to the
- * created token object for system kernel use. Otherwise if set to FALSE, the
- * function inserts the object to a handle making it a regular access token.
+ * @param[out] SecurityDescriptor
+ * The returned token control information.
*
* @return
- * Returns STATUS_SUCCESS if token creation has completed successfully.
- * STATUS_INSUFFICIENT_RESOURCES is returned if the dynamic area of memory of the
- * token hasn't been allocated because of lack of memory resources. A failure
- * NTSTATUS code is returned otherwise.
+ * Nothing.
*/
-NTSTATUS
+VOID
NTAPI
-SepCreateToken(
- _Out_ PHANDLE TokenHandle,
- _In_ KPROCESSOR_MODE PreviousMode,
- _In_ ACCESS_MASK DesiredAccess,
- _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
- _In_ TOKEN_TYPE TokenType,
- _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
- _In_ PLUID AuthenticationId,
- _In_ PLARGE_INTEGER ExpirationTime,
- _In_ PSID_AND_ATTRIBUTES User,
- _In_ ULONG GroupCount,
- _In_ PSID_AND_ATTRIBUTES Groups,
- _In_ ULONG GroupsLength,
- _In_ ULONG PrivilegeCount,
- _In_ PLUID_AND_ATTRIBUTES Privileges,
- _In_opt_ PSID Owner,
- _In_ PSID PrimaryGroup,
- _In_opt_ PACL DefaultDacl,
- _In_ PTOKEN_SOURCE TokenSource,
- _In_ BOOLEAN SystemToken)
+SeGetTokenControlInformation(
+ _In_ PACCESS_TOKEN _Token,
+ _Out_ PTOKEN_CONTROL TokenControl)
{
- NTSTATUS Status;
- PTOKEN AccessToken;
- ULONG TokenFlags = 0;
- ULONG PrimaryGroupIndex, DefaultOwnerIndex;
- LUID TokenId;
- LUID ModifiedId;
- PVOID EndMem;
- ULONG PrivilegesLength;
- ULONG UserGroupsLength;
- ULONG VariableLength;
- ULONG TotalSize;
- ULONG i;
-
+ PTOKEN Token = _Token;
PAGED_CODE();
- /* Loop all groups */
- for (i = 0; i < GroupCount; i++)
- {
- /* Check for mandatory groups */
- if (Groups[i].Attributes & SE_GROUP_MANDATORY)
- {
- /* Force them to be enabled */
- Groups[i].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
- }
-
- /* Check of the group is an admin group */
- if (RtlEqualSid(SeAliasAdminsSid, Groups[i].Sid))
- {
- /* Remember this so we can optimize queries later */
- TokenFlags |= TOKEN_HAS_ADMIN_GROUP;
- }
- }
-
- /* Allocate unique IDs for the token */
- ExAllocateLocallyUniqueId(&TokenId);
- ExAllocateLocallyUniqueId(&ModifiedId);
-
- /* Compute how much size we need to allocate for the token */
-
- /* Privileges size */
- PrivilegesLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
- PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
-
- /* User and groups size */
- UserGroupsLength = (1 + GroupCount) * sizeof(SID_AND_ATTRIBUTES);
- UserGroupsLength += RtlLengthSid(User->Sid);
- for (i = 0; i < GroupCount; i++)
- {
- UserGroupsLength += RtlLengthSid(Groups[i].Sid);
- }
- UserGroupsLength = ALIGN_UP_BY(UserGroupsLength, sizeof(PVOID));
+ /* Capture the main fields */
+ TokenControl->AuthenticationId = Token->AuthenticationId;
+ TokenControl->TokenId = Token->TokenId;
+ TokenControl->TokenSource = Token->TokenSource;
- /* Add the additional groups array length */
- UserGroupsLength += ALIGN_UP_BY(GroupsLength, sizeof(PVOID));
+ /* Lock the token */
+ SepAcquireTokenLockShared(Token);
- VariableLength = PrivilegesLength + UserGroupsLength;
- TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
+ /* Capture the modified ID */
+ TokenControl->ModifiedId = Token->ModifiedId;
- Status = ObCreateObject(PreviousMode,
- SeTokenObjectType,
- ObjectAttributes,
- PreviousMode,
- NULL,
- TotalSize,
- 0,
- 0,
- (PVOID*)&AccessToken);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
- return Status;
- }
+ /* Unlock it */
+ SepReleaseTokenLock(Token);
+}
- /* Zero out the buffer and initialize the token */
- RtlZeroMemory(AccessToken, TotalSize);
+/**
+ * @brief
+ * Creates the system process token.
+ *
+ * @return
+ * Returns the system process token if the operations have
+ * completed successfully.
+ */
+CODE_SEG("INIT")
+PTOKEN
+NTAPI
+SepCreateSystemProcessToken(VOID)
+{
+ LUID_AND_ATTRIBUTES Privileges[25];
+ ULONG GroupAttributes, OwnerAttributes;
+ SID_AND_ATTRIBUTES Groups[32];
+ LARGE_INTEGER Expiration;
+ SID_AND_ATTRIBUTES UserSid;
+ ULONG GroupsLength;
+ PSID PrimaryGroup;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PSID Owner;
+ ULONG i;
+ PTOKEN Token;
+ NTSTATUS Status;
- AccessToken->TokenId = TokenId;
- AccessToken->TokenType = TokenType;
- AccessToken->ImpersonationLevel = ImpersonationLevel;
+ /* Don't ever expire */
+ Expiration.QuadPart = -1;
- /* Initialise the lock for the access token */
- Status = SepCreateTokenLock(AccessToken);
- if (!NT_SUCCESS(Status))
- goto Quit;
+ /* All groups mandatory and enabled */
+ GroupAttributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY |
SE_GROUP_ENABLED_BY_DEFAULT;
+ OwnerAttributes = SE_GROUP_ENABLED | SE_GROUP_OWNER | SE_GROUP_ENABLED_BY_DEFAULT;
- AccessToken->TokenSource.SourceIdentifier = TokenSource->SourceIdentifier;
- RtlCopyMemory(AccessToken->TokenSource.SourceName,
- TokenSource->SourceName,
- sizeof(TokenSource->SourceName));
+ /* User is Local System */
+ UserSid.Sid = SeLocalSystemSid;
+ UserSid.Attributes = 0;
- AccessToken->ExpirationTime = *ExpirationTime;
- AccessToken->ModifiedId = ModifiedId;
+ /* Primary group is Local System */
+ PrimaryGroup = SeLocalSystemSid;
- AccessToken->TokenFlags = TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
+ /* Owner is Administrators */
+ Owner = SeAliasAdminsSid;
- /* Copy and reference the logon session */
- AccessToken->AuthenticationId = *AuthenticationId;
- Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
- if (!NT_SUCCESS(Status))
- {
- /* No logon session could be found, bail out */
- DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n",
Status);
- /* Set the flag for proper cleanup by the delete procedure */
- AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
- goto Quit;
- }
+ /* Groups are Administrators, World, and Authenticated Users */
+ Groups[0].Sid = SeAliasAdminsSid;
+ Groups[0].Attributes = OwnerAttributes;
+ Groups[1].Sid = SeWorldSid;
+ Groups[1].Attributes = GroupAttributes;
+ Groups[2].Sid = SeAuthenticatedUsersSid;
+ Groups[2].Attributes = GroupAttributes;
+ GroupsLength = sizeof(SID_AND_ATTRIBUTES) +
+ SeLengthSid(Groups[0].Sid) +
+ SeLengthSid(Groups[1].Sid) +
+ SeLengthSid(Groups[2].Sid);
+ ASSERT(GroupsLength <= sizeof(Groups));
- /* Insert the referenced logon session into the token */
- Status = SepRmInsertLogonSessionIntoToken(AccessToken);
- if (!NT_SUCCESS(Status))
- {
- /* Failed to insert the logon session into the token, bail out */
- DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n",
Status);
- goto Quit;
- }
+ /* Setup the privileges */
+ i = 0;
+ Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
+ Privileges[i++].Luid = SeTcbPrivilege;
- /* Fill in token debug information */
-#if DBG
- /*
- * We must determine ourselves that the current
- * process is not the initial CPU one. The initial
- * process is not a "real" process, that is, the
- * Process Manager has not yet been initialized and
- * as a matter of fact we are creating a token before
- * any process gets created by Ps. If it turns out
- * that the current process is the initial CPU process
- * where token creation execution takes place, don't
- * do anything.
- */
- if (PsGetCurrentProcess() != &KiInitialProcess)
- {
- RtlCopyMemory(AccessToken->ImageFileName,
- PsGetCurrentProcess()->ImageFileName,
- min(sizeof(AccessToken->ImageFileName),
sizeof(PsGetCurrentProcess()->ImageFileName)));
+ Privileges[i].Attributes = 0;
+ Privileges[i++].Luid = SeCreateTokenPrivilege;
- AccessToken->ProcessCid = PsGetCurrentProcessId();
- AccessToken->ThreadCid = PsGetCurrentThreadId();
- }
+ Privileges[i].Attributes = 0;
+ Privileges[i++].Luid = SeTakeOwnershipPrivilege;
- AccessToken->CreateMethod = TOKEN_CREATE_METHOD;
-#endif
+ Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
+ Privileges[i++].Luid = SeCreatePagefilePrivilege;
- /* Assign the data that reside in the token's variable information area */
- AccessToken->VariableLength = VariableLength;
- EndMem = (PVOID)&AccessToken->VariablePart;
+ Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
+ Privileges[i++].Luid = SeLockMemoryPrivilege;
- /* Copy the privileges */
- AccessToken->PrivilegeCount = PrivilegeCount;
- AccessToken->Privileges = NULL;
- if (PrivilegeCount > 0)
- {
- AccessToken->Privileges = EndMem;
- EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
- VariableLength -= PrivilegesLength;
+ Privileges[i].Attributes = 0;
+ Privileges[i++].Luid = SeAssignPrimaryTokenPrivilege;
- if (PreviousMode != KernelMode)
- {
- _SEH2_TRY
- {
- RtlCopyMemory(AccessToken->Privileges,
- Privileges,
- PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END;
- }
- else
- {
- RtlCopyMemory(AccessToken->Privileges,
- Privileges,
- PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
- }
+ Privileges[i].Attributes = 0;
+ Privileges[i++].Luid = SeIncreaseQuotaPrivilege;
- if (!NT_SUCCESS(Status))
- goto Quit;
- }
+ Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
+ Privileges[i++].Luid = SeIncreaseBasePriorityPrivilege;
- /* Update the privilege flags */
- SepUpdatePrivilegeFlagsToken(AccessToken);
-
- /* Copy the user and groups */
- AccessToken->UserAndGroupCount = 1 + GroupCount;
- AccessToken->UserAndGroups = EndMem;
- EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
- VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
-
- Status = RtlCopySidAndAttributesArray(1,
- User,
- VariableLength,
- &AccessToken->UserAndGroups[0],
- EndMem,
- &EndMem,
- &VariableLength);
- if (!NT_SUCCESS(Status))
- goto Quit;
+ Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
+ Privileges[i++].Luid = SeCreatePermanentPrivilege;
- Status = RtlCopySidAndAttributesArray(GroupCount,
- Groups,
- VariableLength,
- &AccessToken->UserAndGroups[1],
- EndMem,
- &EndMem,
- &VariableLength);
- if (!NT_SUCCESS(Status))
- goto Quit;
+ Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
+ Privileges[i++].Luid = SeDebugPrivilege;
- /* Find the token primary group and default owner */
- Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken,
- PrimaryGroup,
- Owner,
- &PrimaryGroupIndex,
- &DefaultOwnerIndex);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n",
Status);
- goto Quit;
- }
+ Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
+ Privileges[i++].Luid = SeAuditPrivilege;
- AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid;
- AccessToken->DefaultOwnerIndex = DefaultOwnerIndex;
+ Privileges[i].Attributes = 0;
+ Privileges[i++].Luid = SeSecurityPrivilege;
- /* Now allocate the token's dynamic information area and set the data */
- AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area.
- AccessToken->DynamicPart = NULL;
- if (DefaultDacl != NULL)
- {
- AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
- DefaultDacl->AclSize,
- TAG_TOKEN_DYNAMIC);
- if (AccessToken->DynamicPart == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto Quit;
- }
+ Privileges[i].Attributes = 0;
+ Privileges[i++].Luid = SeSystemEnvironmentPrivilege;
- EndMem = (PVOID)AccessToken->DynamicPart;
- AccessToken->DefaultDacl = EndMem;
+ Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
+ Privileges[i++].Luid = SeChangeNotifyPrivilege;
- RtlCopyMemory(AccessToken->DefaultDacl,
- DefaultDacl,
- DefaultDacl->AclSize);
- }
+ Privileges[i].Attributes = 0;
+ Privileges[i++].Luid = SeBackupPrivilege;
- /* Insert the token only if it's not the system token, otherwise return it
directly */
- if (!SystemToken)
- {
- Status = ObInsertObject(AccessToken,
- NULL,
- DesiredAccess,
- 0,
- NULL,
- TokenHandle);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ObInsertObject() failed (Status 0x%lx)\n", Status);
- }
- }
- else
- {
- /* Return pointer instead of handle */
- *TokenHandle = (HANDLE)AccessToken;
- }
+ Privileges[i].Attributes = 0;
+ Privileges[i++].Luid = SeRestorePrivilege;
-Quit:
- if (!NT_SUCCESS(Status))
- {
- /* Dereference the token, the delete procedure will clean it up */
- ObDereferenceObject(AccessToken);
- }
+ Privileges[i].Attributes = 0;
+ Privileges[i++].Luid = SeShutdownPrivilege;
- return Status;
+ Privileges[i].Attributes = 0;
+ Privileges[i++].Luid = SeLoadDriverPrivilege;
+
+ Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
+ Privileges[i++].Luid = SeProfileSingleProcessPrivilege;
+
+ Privileges[i].Attributes = 0;
+ Privileges[i++].Luid = SeSystemtimePrivilege;
+ ASSERT(i == 20);
+
+ /* Setup the object attributes */
+ InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
+ ASSERT(SeSystemDefaultDacl != NULL);
+
+ /* Create the token */
+ Status = SepCreateToken((PHANDLE)&Token,
+ KernelMode,
+ 0,
+ &ObjectAttributes,
+ TokenPrimary,
+ SecurityAnonymous,
+ &SeSystemAuthenticationId,
+ &Expiration,
+ &UserSid,
+ 3,
+ Groups,
+ GroupsLength,
+ 20,
+ Privileges,
+ Owner,
+ PrimaryGroup,
+ SeSystemDefaultDacl,
+ &SeSystemTokenSource,
+ TRUE);
+ ASSERT(Status == STATUS_SUCCESS);
+
+ /* Return the token */
+ return Token;
}
/**
* @brief
- * Private helper function responsible for creating a restricted access
- * token, that is, a filtered token from privileges and groups and with
- * restricted SIDs added into the token on demand by the caller.
- *
- * @param[in] Token
- * An existing and valid access token.
- *
- * @param[in] PrivilegesToBeDeleted
- * A list of privileges to be deleted within the token that's going
- * to be filtered. This parameter is ignored if the caller wants to disable
- * all the privileges by specifying DISABLE_MAX_PRIVILEGE in the flags
- * parameter.
- *
- * @param[in] SidsToBeDisabled
- * A list of group SIDs to be disabled within the token. This parameter
- * can be NULL.
- *
- * @param[in] RestrictedSidsIntoToken
- * A list of restricted SIDs to be added into the token. This parameter
- * can be NULL.
- *
- * @param[in] PrivilegesCount
- * The privilege count of the privileges list.
- *
- * @param[in] RegularGroupsSidCount
- * The SIDs count of the group SIDs list.
- *
- * @param[in] RestrictedSidsCount
- * The restricted SIDs count of restricted SIDs list.
- *
- * @param[in] PrivilegeFlags
- * Influences how the privileges should be filtered in an access
- * token. See NtFilterToken syscall for more information.
- *
- * @param[in] PreviousMode
- * Processor level access mode.
- *
- * @param[out] FilteredToken
- * The filtered token, returned to the caller.
+ * Creates the anonymous logon token for the system. The difference between this
+ * token and the other one is the inclusion of everyone SID group (being SeWorldSid).
+ * The other token lacks such group.
*
* @return
- * Returns STATUS_SUCCESS if token token filtering has completed successfully.
- * STATUS_INVALID_PARAMETER is returned if one or more of the parameters
- * do not meet the conditions imposed by the function. A failure NTSTATUS
- * code is returned otherwise.
- *
- * @remarks
- * The final outcome of privileges and/or SIDs filtering is not always
- * deterministic. That is, any privileges or SIDs that aren't present
- * in the access token are ignored and the function continues with the
- * next privilege or SID to find for filtering. For a fully deterministic
- * outcome the caller is responsible for querying the information details
- * of privileges and SIDs present in the token and then afterwards use
- * such obtained information to do any kind of filtering to the token.
+ * Returns the system's anonymous logon token if the operations have
+ * completed successfully.
*/
-static
-NTSTATUS
-SepPerformTokenFiltering(
- _In_ PTOKEN Token,
- _In_opt_ PLUID_AND_ATTRIBUTES PrivilegesToBeDeleted,
- _In_opt_ PSID_AND_ATTRIBUTES SidsToBeDisabled,
- _In_opt_ PSID_AND_ATTRIBUTES RestrictedSidsIntoToken,
- _When_(PrivilegesToBeDeleted != NULL, _In_) ULONG PrivilegesCount,
- _When_(SidsToBeDisabled != NULL, _In_) ULONG RegularGroupsSidCount,
- _When_(RestrictedSidsIntoToken != NULL, _In_) ULONG RestrictedSidsCount,
- _In_ ULONG PrivilegeFlags,
- _In_ KPROCESSOR_MODE PreviousMode,
- _Out_ PTOKEN *FilteredToken)
+CODE_SEG("INIT")
+PTOKEN
+SepCreateSystemAnonymousLogonToken(VOID)
{
+ SID_AND_ATTRIBUTES Groups[32], UserSid;
+ PSID PrimaryGroup;
+ PTOKEN Token;
+ ULONG GroupsLength;
+ LARGE_INTEGER Expiration;
+ OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
- PTOKEN AccessToken;
- PVOID EndMem;
- ULONG RestrictedSidsLength;
- ULONG PrivilegesLength;
- ULONG PrimaryGroupIndex;
- ULONG RestrictedSidsInList;
- ULONG RestrictedSidsInToken;
- ULONG VariableLength, TotalSize;
- ULONG PrivsInToken, PrivsInList;
- ULONG GroupsInToken, GroupsInList;
- BOOLEAN WantPrivilegesDisabled;
- BOOLEAN FoundPrivilege;
- BOOLEAN FoundGroup;
-
- PAGED_CODE();
-
- /* Ensure that the source token is valid, and lock it */
- ASSERT(Token);
- SepAcquireTokenLockShared(Token);
- /* Assume the caller doesn't want privileges disabled */
- WantPrivilegesDisabled = FALSE;
+ /* The token never expires */
+ Expiration.QuadPart = -1;
- /* Assume we haven't found anything */
- FoundPrivilege = FALSE;
- FoundGroup = FALSE;
+ /* The user is the anonymous logon */
+ UserSid.Sid = SeAnonymousLogonSid;
+ UserSid.Attributes = 0;
- /*
- * Take the size that we need for filtered token
- * allocation based upon the existing access token
- * we've been given.
- */
- VariableLength = Token->VariableLength;
+ /* The primary group is also the anonymous logon */
+ PrimaryGroup = SeAnonymousLogonSid;
- if (RestrictedSidsIntoToken != NULL)
- {
- /*
- * If the caller provided a list of restricted SIDs
- * to be added onto the filtered access token then
- * we must compute the size which is the total space
- * of the current token and the length of the restricted
- * SIDs for the filtered token.
- */
- RestrictedSidsLength = RestrictedSidsCount * sizeof(SID_AND_ATTRIBUTES);
- RestrictedSidsLength += RtlLengthSidAndAttributes(RestrictedSidsCount,
RestrictedSidsIntoToken);
- RestrictedSidsLength = ALIGN_UP_BY(RestrictedSidsLength, sizeof(PVOID));
+ /* The only group for the token is the World */
+ Groups[0].Sid = SeWorldSid;
+ Groups[0].Attributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY |
SE_GROUP_ENABLED_BY_DEFAULT;
+ GroupsLength = sizeof(SID_AND_ATTRIBUTES) +
+ SeLengthSid(Groups[0].Sid);
+ ASSERT(GroupsLength <= sizeof(Groups));
- /*
- * The variable length of the token is not just
- * the actual space length of the existing token
- * but also the sum of the restricted SIDs length.
- */
- VariableLength += RestrictedSidsLength;
- TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength +
RestrictedSidsLength;
- }
- else
- {
- /* Otherwise the size is of the actual current token */
- TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
- }
+ /* Initialise the object attributes for the token */
+ InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
+ ASSERT(SeSystemAnonymousLogonDacl != NULL);
- /* Set up a filtered token object */
- Status = ObCreateObject(PreviousMode,
- SeTokenObjectType,
- NULL,
- PreviousMode,
- NULL,
- TotalSize,
+ /* Create token */
+ Status = SepCreateToken((PHANDLE)&Token,
+ KernelMode,
0,
+ &ObjectAttributes,
+ TokenPrimary,
+ SecurityAnonymous,
+ &SeAnonymousAuthenticationId,
+ &Expiration,
+ &UserSid,
+ 1,
+ Groups,
+ GroupsLength,
0,
- (PVOID*)&AccessToken);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("SepPerformTokenFiltering(): Failed to create the filtered token
object (Status 0x%lx)\n", Status);
-
- /* Unlock the source token and bail out */
- SepReleaseTokenLock(Token);
- return Status;
- }
-
- /* Initialize the token and begin filling stuff to it */
- RtlZeroMemory(AccessToken, TotalSize);
+ NULL,
+ NULL,
+ PrimaryGroup,
+ SeSystemAnonymousLogonDacl,
+ &SeSystemTokenSource,
+ TRUE);
+ ASSERT(Status == STATUS_SUCCESS);
- /* Set up a lock for the new token */
- Status = SepCreateTokenLock(AccessToken);
- if (!NT_SUCCESS(Status))
- goto Quit;
+ /* Return the anonymous logon token */
+ return Token;
+}
- /* Allocate new IDs for the token */
- ExAllocateLocallyUniqueId(&AccessToken->TokenId);
- ExAllocateLocallyUniqueId(&AccessToken->ModifiedId);
+/**
+ * @brief
+ * Creates the anonymous logon token for the system. This kind of token
+ * doesn't include the everyone SID group (being SeWorldSid).
+ *
+ * @return
+ * Returns the system's anonymous logon token if the operations have
+ * completed successfully.
+ */
+CODE_SEG("INIT")
+PTOKEN
+SepCreateSystemAnonymousLogonTokenNoEveryone(VOID)
+{
+ SID_AND_ATTRIBUTES UserSid;
+ PSID PrimaryGroup;
+ PTOKEN Token;
+ LARGE_INTEGER Expiration;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ NTSTATUS Status;
- /* Copy the type and impersonation level from the token */
- AccessToken->TokenType = Token->TokenType;
- AccessToken->ImpersonationLevel = Token->ImpersonationLevel;
+ /* The token never expires */
+ Expiration.QuadPart = -1;
- /* Copy the immutable fields */
- AccessToken->TokenSource.SourceIdentifier =
Token->TokenSource.SourceIdentifier;
- RtlCopyMemory(AccessToken->TokenSource.SourceName,
- Token->TokenSource.SourceName,
- sizeof(Token->TokenSource.SourceName));
-
- AccessToken->AuthenticationId = Token->AuthenticationId;
- AccessToken->ParentTokenId = Token->TokenId;
- AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession;
-
- AccessToken->ExpirationTime = Token->ExpirationTime;
-
- /* Copy the mutable fields */
- AccessToken->SessionId = Token->SessionId;
- AccessToken->TokenFlags = Token->TokenFlags &
~TOKEN_SESSION_NOT_REFERENCED;
-
- /* Reference the logon session */
- Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
- if (!NT_SUCCESS(Status))
- {
- /* We failed, bail out*/
- DPRINT1("SepPerformTokenFiltering(): Failed to reference the logon session
(Status 0x%lx)\n", Status);
- AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
- goto Quit;
- }
-
- /* Insert the referenced logon session into the token */
- Status = SepRmInsertLogonSessionIntoToken(AccessToken);
- if (!NT_SUCCESS(Status))
- {
- /* Failed to insert the logon session into the token, bail out */
- DPRINT1("SepPerformTokenFiltering(): Failed to insert the logon session into
token (Status 0x%lx)\n", Status);
- goto Quit;
- }
-
- /* Fill in token debug information */
-#if DBG
- RtlCopyMemory(AccessToken->ImageFileName,
- PsGetCurrentProcess()->ImageFileName,
- min(sizeof(AccessToken->ImageFileName),
sizeof(PsGetCurrentProcess()->ImageFileName)));
-
- AccessToken->ProcessCid = PsGetCurrentProcessId();
- AccessToken->ThreadCid = PsGetCurrentThreadId();
- AccessToken->CreateMethod = TOKEN_FILTER_METHOD;
-#endif
-
- /* Assign the data that reside in the token's variable information area */
- AccessToken->VariableLength = VariableLength;
- EndMem = (PVOID)&AccessToken->VariablePart;
-
- /* Copy the privileges from the existing token */
- AccessToken->PrivilegeCount = 0;
- AccessToken->Privileges = NULL;
- if (Token->Privileges && (Token->PrivilegeCount > 0))
- {
- PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
- PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
-
- /*
- * Ensure that the token can actually hold all
- * the privileges from the existing token.
- * Otherwise something's seriously wrong and
- * we've to guard ourselves.
- */
- ASSERT(VariableLength >= PrivilegesLength);
-
- AccessToken->PrivilegeCount = Token->PrivilegeCount;
- AccessToken->Privileges = EndMem;
- EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
- VariableLength -= PrivilegesLength;
-
- RtlCopyMemory(AccessToken->Privileges,
- Token->Privileges,
- AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
- }
-
- /* Copy the user and groups */
- AccessToken->UserAndGroupCount = 0;
- AccessToken->UserAndGroups = NULL;
- if (Token->UserAndGroups && (Token->UserAndGroupCount > 0))
- {
- AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
- AccessToken->UserAndGroups = EndMem;
- EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
- VariableLength -= ((ULONG_PTR)EndMem -
(ULONG_PTR)AccessToken->UserAndGroups);
-
- Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount,
- Token->UserAndGroups,
- VariableLength,
- AccessToken->UserAndGroups,
- EndMem,
- &EndMem,
- &VariableLength);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("SepPerformTokenFiltering(): Failed to copy the groups into
token (Status 0x%lx)\n", Status);
- goto Quit;
- }
- }
-
- /* Copy the restricted SIDs */
- AccessToken->RestrictedSidCount = 0;
- AccessToken->RestrictedSids = NULL;
- if (Token->RestrictedSids && (Token->RestrictedSidCount > 0))
- {
- AccessToken->RestrictedSidCount = Token->RestrictedSidCount;
- AccessToken->RestrictedSids = EndMem;
- EndMem =
&AccessToken->RestrictedSids[AccessToken->RestrictedSidCount];
- VariableLength -= ((ULONG_PTR)EndMem -
(ULONG_PTR)AccessToken->RestrictedSids);
-
- Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount,
- Token->RestrictedSids,
- VariableLength,
- AccessToken->RestrictedSids,
- EndMem,
- &EndMem,
- &VariableLength);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("SepPerformTokenFiltering(): Failed to copy the restricted SIDs
into token (Status 0x%lx)\n", Status);
- goto Quit;
- }
- }
-
- /*
- * Insert the restricted SIDs into the token on
- * the request by the caller.
- */
- if (RestrictedSidsIntoToken != NULL)
- {
- for (RestrictedSidsInList = 0; RestrictedSidsInList < RestrictedSidsCount;
RestrictedSidsInList++)
- {
- /* Did the caller assign attributes to the restricted SIDs? */
- if (RestrictedSidsIntoToken[RestrictedSidsInList].Attributes != 0)
- {
- /* There mustn't be any attributes, bail out */
- DPRINT1("SepPerformTokenFiltering(): There mustn't be any
attributes to restricted SIDs!\n");
- Status = STATUS_INVALID_PARAMETER;
- goto Quit;
- }
- }
-
- /*
- * Ensure that the token can hold the restricted SIDs
- * (the variable length is calculated at the beginning
- * of the routine call).
- */
- ASSERT(VariableLength >= RestrictedSidsLength);
-
- /*
- * Now let's begin inserting the restricted SIDs into the filtered
- * access token from the list the caller gave us.
- */
- AccessToken->RestrictedSidCount = RestrictedSidsCount;
- AccessToken->RestrictedSids = EndMem;
- EndMem = (PVOID)((ULONG_PTR)EndMem + RestrictedSidsLength);
- VariableLength -= RestrictedSidsLength;
-
- RtlCopyMemory(AccessToken->RestrictedSids,
- RestrictedSidsIntoToken,
- AccessToken->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
-
- /*
- * As we've copied the restricted SIDs into
- * the token, we must assign them the following
- * combination of attributes SE_GROUP_ENABLED,
- * SE_GROUP_ENABLED_BY_DEFAULT and SE_GROUP_MANDATORY.
- * With such attributes we estabilish that restricting
- * SIDs into the token are enabled for access checks.
- */
- for (RestrictedSidsInToken = 0; RestrictedSidsInToken <
AccessToken->RestrictedSidCount; RestrictedSidsInToken++)
- {
- AccessToken->RestrictedSids[RestrictedSidsInToken].Attributes |=
(SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY);
- }
-
- /*
- * As we added restricted SIDs into the token, mark
- * it as restricted.
- */
- AccessToken->TokenFlags |= TOKEN_IS_RESTRICTED;
- }
-
- /* Search for the primary group */
- Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken,
- Token->PrimaryGroup,
- NULL,
- &PrimaryGroupIndex,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("SepPerformTokenFiltering(): Failed searching for the primary group
(Status 0x%lx)\n", Status);
- goto Quit;
- }
-
- /* Assign the primary group and default owner index now */
- AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid;
- AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
-
- /* Now allocate the token's dynamic information area and set the data */
- AccessToken->DynamicAvailable = 0;
- AccessToken->DynamicPart = NULL;
- if (Token->DynamicPart && Token->DefaultDacl)
- {
- AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
-
Token->DefaultDacl->AclSize,
- TAG_TOKEN_DYNAMIC);
- if (AccessToken->DynamicPart == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto Quit;
- }
-
- EndMem = (PVOID)AccessToken->DynamicPart;
- AccessToken->DefaultDacl = EndMem;
-
- RtlCopyMemory(AccessToken->DefaultDacl,
- Token->DefaultDacl,
- Token->DefaultDacl->AclSize);
- }
-
- /*
- * Now figure out what does the caller
- * want with the privileges.
- */
- if (PrivilegeFlags & DISABLE_MAX_PRIVILEGE)
- {
- /*
- * The caller wants them disabled, cache this request
- * for later operations.
- */
- WantPrivilegesDisabled = TRUE;
- }
-
- if (PrivilegeFlags & SANDBOX_INERT)
- {
- /* The caller wants an inert token, store the TOKEN_SANDBOX_INERT flag now */
- AccessToken->TokenFlags |= TOKEN_SANDBOX_INERT;
- }
-
- /*
- * Now it's time to filter the token's privileges.
- * Loop all the privileges in the token.
- */
- for (PrivsInToken = 0; PrivsInToken < AccessToken->PrivilegeCount;
PrivsInToken++)
- {
- if (WantPrivilegesDisabled)
- {
- /*
- * We got the acknowledgement that the caller wants
- * to disable all the privileges so let's just do it.
- * However, as per the general documentation is stated
- * that only SE_CHANGE_NOTIFY_PRIVILEGE must be kept
- * therefore in that case we must skip this privilege.
- */
- if (AccessToken->Privileges[PrivsInToken].Luid.LowPart ==
SE_CHANGE_NOTIFY_PRIVILEGE)
- {
- continue;
- }
- else
- {
- /*
- * The act of disabling privileges actually means
- * "deleting" them from the access token entirely.
- * First we must disable them so that we can update
- * token flags accordingly.
- */
- AccessToken->Privileges[PrivsInToken].Attributes &=
~SE_PRIVILEGE_ENABLED;
- SepUpdateSinglePrivilegeFlagToken(AccessToken, PrivsInToken);
-
- /* Remove the privileges now */
- SepRemovePrivilegeToken(AccessToken, PrivsInToken);
- PrivsInToken--;
- }
- }
- else
- {
- if (PrivilegesToBeDeleted != NULL)
- {
- /* Loop the privileges we've got to delete */
- for (PrivsInList = 0; PrivsInList < PrivilegesCount; PrivsInList++)
- {
- /* Does this privilege exist in the token? */
- if (RtlEqualLuid(&AccessToken->Privileges[PrivsInToken].Luid,
- &PrivilegesToBeDeleted[PrivsInList].Luid))
- {
- /* Mark that we found it */
- FoundPrivilege = TRUE;
- break;
- }
- }
-
- /* Did we find the privilege? */
- if (PrivsInList == PrivilegesCount)
- {
- /* We didn't, continue with next one */
- continue;
- }
- }
- }
-
- /*
- * If we have found the target privilege in the token
- * based on the privileges list given by the caller
- * then begin deleting it.
- */
- if (FoundPrivilege)
- {
- /* Disable the privilege and update the flags */
- AccessToken->Privileges[PrivsInToken].Attributes &=
~SE_PRIVILEGE_ENABLED;
- SepUpdateSinglePrivilegeFlagToken(AccessToken, PrivsInToken);
-
- /* Delete the privilege */
- SepRemovePrivilegeToken(AccessToken, PrivsInToken);
-
- /*
- * Adjust the index and reset the FoundPrivilege indicator
- * so that we can continue with the next privilege to delete.
- */
- PrivsInToken--;
- FoundPrivilege = FALSE;
- continue;
- }
- }
-
- /*
- * Loop the group SIDs that we want to disable as
- * per on the request by the caller.
- */
- if (SidsToBeDisabled != NULL)
- {
- for (GroupsInToken = 0; GroupsInToken < AccessToken->UserAndGroupCount;
GroupsInToken++)
- {
- for (GroupsInList = 0; GroupsInList < RegularGroupsSidCount;
GroupsInList++)
- {
- /* Does this group SID exist in the token? */
- if (RtlEqualSid(&AccessToken->UserAndGroups[GroupsInToken].Sid,
- &SidsToBeDisabled[GroupsInList].Sid))
- {
- /* Mark that we found it */
- FoundGroup = TRUE;
- break;
- }
- }
-
- /* Did we find the group? */
- if (GroupsInList == RegularGroupsSidCount)
- {
- /* We didn't, continue with next one */
- continue;
- }
-
- /* If we have found the group, disable it */
- if (FoundGroup)
- {
- /*
- * If the acess token belongs to the administrators
- * group and this is the target group, we must take
- * away TOKEN_HAS_ADMIN_GROUP flag from the token.
- */
- if (RtlEqualSid(SeAliasAdminsSid,
- &AccessToken->UserAndGroups[GroupsInToken].Sid))
- {
- AccessToken->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP;
- }
-
- /*
- * If the target group that we have found it is the
- * owner then from now on it no longer is but the user.
- * Therefore assign the default owner index as the user.
- */
- if (AccessToken->DefaultOwnerIndex == GroupsInToken)
- {
- AccessToken->DefaultOwnerIndex = 0;
- }
-
- /*
- * The principle of disabling a group SID is by
- * taking away SE_GROUP_ENABLED_BY_DEFAULT and
- * SE_GROUP_ENABLED attributes and assign
- * SE_GROUP_USE_FOR_DENY_ONLY. This renders
- * SID a "Deny only" SID.
- */
- AccessToken->UserAndGroups[GroupsInToken].Attributes &=
~(SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
- AccessToken->UserAndGroups[GroupsInToken].Attributes |=
SE_GROUP_USE_FOR_DENY_ONLY;
-
- /* Adjust the index and continue with the next group */
- GroupsInToken--;
- FoundGroup = FALSE;
- continue;
- }
- }
- }
-
- /* We've finally filtered the token, return it to the caller */
- *FilteredToken = AccessToken;
- Status = STATUS_SUCCESS;
- DPRINT("SepPerformTokenFiltering(): The token has been filtered!\n");
-
-Quit:
- if (!NT_SUCCESS(Status))
- {
- /* Dereference the created token */
- ObDereferenceObject(AccessToken);
- }
-
- /* Unlock the source token */
- SepReleaseTokenLock(Token);
-
- return Status;
-}
-
-/**
- * @brief
- * Creates the system process token.
- *
- * @return
- * Returns the system process token if the operations have
- * completed successfully.
- */
-CODE_SEG("INIT")
-PTOKEN
-NTAPI
-SepCreateSystemProcessToken(VOID)
-{
- LUID_AND_ATTRIBUTES Privileges[25];
- ULONG GroupAttributes, OwnerAttributes;
- SID_AND_ATTRIBUTES Groups[32];
- LARGE_INTEGER Expiration;
- SID_AND_ATTRIBUTES UserSid;
- ULONG GroupsLength;
- PSID PrimaryGroup;
- OBJECT_ATTRIBUTES ObjectAttributes;
- PSID Owner;
- ULONG i;
- PTOKEN Token;
- NTSTATUS Status;
-
- /* Don't ever expire */
- Expiration.QuadPart = -1;
-
- /* All groups mandatory and enabled */
- GroupAttributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY |
SE_GROUP_ENABLED_BY_DEFAULT;
- OwnerAttributes = SE_GROUP_ENABLED | SE_GROUP_OWNER | SE_GROUP_ENABLED_BY_DEFAULT;
-
- /* User is Local System */
- UserSid.Sid = SeLocalSystemSid;
+ /* The user is the anonymous logon */
+ UserSid.Sid = SeAnonymousLogonSid;
UserSid.Attributes = 0;
- /* Primary group is Local System */
- PrimaryGroup = SeLocalSystemSid;
-
- /* Owner is Administrators */
- Owner = SeAliasAdminsSid;
-
- /* Groups are Administrators, World, and Authenticated Users */
- Groups[0].Sid = SeAliasAdminsSid;
- Groups[0].Attributes = OwnerAttributes;
- Groups[1].Sid = SeWorldSid;
- Groups[1].Attributes = GroupAttributes;
- Groups[2].Sid = SeAuthenticatedUsersSid;
- Groups[2].Attributes = GroupAttributes;
- GroupsLength = sizeof(SID_AND_ATTRIBUTES) +
- SeLengthSid(Groups[0].Sid) +
- SeLengthSid(Groups[1].Sid) +
- SeLengthSid(Groups[2].Sid);
- ASSERT(GroupsLength <= sizeof(Groups));
-
- /* Setup the privileges */
- i = 0;
- Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
- Privileges[i++].Luid = SeTcbPrivilege;
-
- Privileges[i].Attributes = 0;
- Privileges[i++].Luid = SeCreateTokenPrivilege;
-
- Privileges[i].Attributes = 0;
- Privileges[i++].Luid = SeTakeOwnershipPrivilege;
-
- Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
- Privileges[i++].Luid = SeCreatePagefilePrivilege;
-
- Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
- Privileges[i++].Luid = SeLockMemoryPrivilege;
-
- Privileges[i].Attributes = 0;
- Privileges[i++].Luid = SeAssignPrimaryTokenPrivilege;
-
- Privileges[i].Attributes = 0;
- Privileges[i++].Luid = SeIncreaseQuotaPrivilege;
-
- Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
- Privileges[i++].Luid = SeIncreaseBasePriorityPrivilege;
-
- Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
- Privileges[i++].Luid = SeCreatePermanentPrivilege;
-
- Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
- Privileges[i++].Luid = SeDebugPrivilege;
+ /* The primary group is also the anonymous logon */
+ PrimaryGroup = SeAnonymousLogonSid;
- Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
- Privileges[i++].Luid = SeAuditPrivilege;
-
- Privileges[i].Attributes = 0;
- Privileges[i++].Luid = SeSecurityPrivilege;
-
- Privileges[i].Attributes = 0;
- Privileges[i++].Luid = SeSystemEnvironmentPrivilege;
-
- Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
- Privileges[i++].Luid = SeChangeNotifyPrivilege;
-
- Privileges[i].Attributes = 0;
- Privileges[i++].Luid = SeBackupPrivilege;
-
- Privileges[i].Attributes = 0;
- Privileges[i++].Luid = SeRestorePrivilege;
-
- Privileges[i].Attributes = 0;
- Privileges[i++].Luid = SeShutdownPrivilege;
-
- Privileges[i].Attributes = 0;
- Privileges[i++].Luid = SeLoadDriverPrivilege;
-
- Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
- Privileges[i++].Luid = SeProfileSingleProcessPrivilege;
-
- Privileges[i].Attributes = 0;
- Privileges[i++].Luid = SeSystemtimePrivilege;
- ASSERT(i == 20);
-
- /* Setup the object attributes */
- InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
- ASSERT(SeSystemDefaultDacl != NULL);
-
- /* Create the token */
- Status = SepCreateToken((PHANDLE)&Token,
- KernelMode,
- 0,
- &ObjectAttributes,
- TokenPrimary,
- SecurityAnonymous,
- &SeSystemAuthenticationId,
- &Expiration,
- &UserSid,
- 3,
- Groups,
- GroupsLength,
- 20,
- Privileges,
- Owner,
- PrimaryGroup,
- SeSystemDefaultDacl,
- &SeSystemTokenSource,
- TRUE);
- ASSERT(Status == STATUS_SUCCESS);
-
- /* Return the token */
- return Token;
-}
-
-/**
- * @brief
- * Creates the anonymous logon token for the system. The difference between this
- * token and the other one is the inclusion of everyone SID group (being SeWorldSid).
- * The other token lacks such group.
- *
- * @return
- * Returns the system's anonymous logon token if the operations have
- * completed successfully.
- */
-CODE_SEG("INIT")
-PTOKEN
-SepCreateSystemAnonymousLogonToken(VOID)
-{
- SID_AND_ATTRIBUTES Groups[32], UserSid;
- PSID PrimaryGroup;
- PTOKEN Token;
- ULONG GroupsLength;
- LARGE_INTEGER Expiration;
- OBJECT_ATTRIBUTES ObjectAttributes;
- NTSTATUS Status;
-
- /* The token never expires */
- Expiration.QuadPart = -1;
-
- /* The user is the anonymous logon */
- UserSid.Sid = SeAnonymousLogonSid;
- UserSid.Attributes = 0;
-
- /* The primary group is also the anonymous logon */
- PrimaryGroup = SeAnonymousLogonSid;
-
- /* The only group for the token is the World */
- Groups[0].Sid = SeWorldSid;
- Groups[0].Attributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY |
SE_GROUP_ENABLED_BY_DEFAULT;
- GroupsLength = sizeof(SID_AND_ATTRIBUTES) +
- SeLengthSid(Groups[0].Sid);
- ASSERT(GroupsLength <= sizeof(Groups));
-
- /* Initialise the object attributes for the token */
- InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
- ASSERT(SeSystemAnonymousLogonDacl != NULL);
-
- /* Create token */
- Status = SepCreateToken((PHANDLE)&Token,
- KernelMode,
- 0,
- &ObjectAttributes,
- TokenPrimary,
- SecurityAnonymous,
- &SeAnonymousAuthenticationId,
- &Expiration,
- &UserSid,
- 1,
- Groups,
- GroupsLength,
- 0,
- NULL,
- NULL,
- PrimaryGroup,
- SeSystemAnonymousLogonDacl,
- &SeSystemTokenSource,
- TRUE);
- ASSERT(Status == STATUS_SUCCESS);
-
- /* Return the anonymous logon token */
- return Token;
-}
-
-/**
- * @brief
- * Creates the anonymous logon token for the system. This kind of token
- * doesn't include the everyone SID group (being SeWorldSid).
- *
- * @return
- * Returns the system's anonymous logon token if the operations have
- * completed successfully.
- */
-CODE_SEG("INIT")
-PTOKEN
-SepCreateSystemAnonymousLogonTokenNoEveryone(VOID)
-{
- SID_AND_ATTRIBUTES UserSid;
- PSID PrimaryGroup;
- PTOKEN Token;
- LARGE_INTEGER Expiration;
- OBJECT_ATTRIBUTES ObjectAttributes;
- NTSTATUS Status;
-
- /* The token never expires */
- Expiration.QuadPart = -1;
-
- /* The user is the anonymous logon */
- UserSid.Sid = SeAnonymousLogonSid;
- UserSid.Attributes = 0;
-
- /* The primary group is also the anonymous logon */
- PrimaryGroup = SeAnonymousLogonSid;
-
- /* Initialise the object attributes for the token */
- InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
- ASSERT(SeSystemAnonymousLogonDacl != NULL);
+ /* Initialise the object attributes for the token */
+ InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
+ ASSERT(SeSystemAnonymousLogonDacl != NULL);
/* Create token */
Status = SepCreateToken((PHANDLE)&Token,
@@ -2852,3316 +1595,296 @@ SepCreateSystemAnonymousLogonTokenNoEveryone(VOID)
&UserSid,
0,
NULL,
- 0,
- 0,
- NULL,
- NULL,
- PrimaryGroup,
- SeSystemAnonymousLogonDacl,
- &SeSystemTokenSource,
- TRUE);
- ASSERT(Status == STATUS_SUCCESS);
-
- /* Return the anonymous (not including everyone) logon token */
- return Token;
-}
-
-/* PUBLIC FUNCTIONS ***********************************************************/
-
-/**
- * @brief
- * Filters an access token from an existing token, making it more restricted
- * than the previous one.
- *
- * @param[in] ExistingToken
- * An existing token for filtering.
- *
- * @param[in] Flags
- * Privilege flag options. This parameter argument influences how the token
- * is filtered. Such parameter can be 0. See NtFilterToken syscall for
- * more information.
- *
- * @param[in] SidsToDisable
- * Array of SIDs to disable. Such parameter can be NULL.
- *
- * @param[in] PrivilegesToDelete
- * Array of privileges to delete. If DISABLE_MAX_PRIVILEGE flag is specified
- * in the Flags parameter, PrivilegesToDelete is ignored.
- *
- * @param[in] RestrictedSids
- * An array of restricted SIDs for the new filtered token. Such parameter
- * can be NULL.
- *
- * @param[out] FilteredToken
- * The newly filtered token, returned to the caller.
- *
- * @return
- * Returns STATUS_SUCCESS if the function has successfully completed its
- * operations and that the access token has been filtered. STATUS_INVALID_PARAMETER
- * is returned if one or more of the parameter are not valid. A failure NTSTATUS code
- * is returned otherwise.
- */
-NTSTATUS
-NTAPI
-SeFilterToken(
- _In_ PACCESS_TOKEN ExistingToken,
- _In_ ULONG Flags,
- _In_opt_ PTOKEN_GROUPS SidsToDisable,
- _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,
- _In_opt_ PTOKEN_GROUPS RestrictedSids,
- _Out_ PACCESS_TOKEN *FilteredToken)
-{
- NTSTATUS Status;
- PTOKEN AccessToken;
- ULONG PrivilegesCount = 0;
- ULONG SidsCount = 0;
- ULONG RestrictedSidsCount = 0;
-
- PAGED_CODE();
-
- /* Begin copying the counters */
- if (SidsToDisable != NULL)
- {
- SidsCount = SidsToDisable->GroupCount;
- }
-
- if (PrivilegesToDelete != NULL)
- {
- PrivilegesCount = PrivilegesToDelete->PrivilegeCount;
- }
-
- if (RestrictedSids != NULL)
- {
- RestrictedSidsCount = RestrictedSids->GroupCount;
- }
-
- /* Call the internal API */
- Status = SepPerformTokenFiltering(ExistingToken,
- PrivilegesToDelete->Privileges,
- SidsToDisable->Groups,
- RestrictedSids->Groups,
- PrivilegesCount,
- SidsCount,
- RestrictedSidsCount,
- Flags,
- KernelMode,
- &AccessToken);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("SeFilterToken(): Failed to filter the token (Status 0x%lx)\n",
Status);
- return Status;
- }
-
- /* Insert the filtered token */
- Status = ObInsertObject(AccessToken,
- NULL,
- 0,
- 0,
- NULL,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("SeFilterToken(): Failed to insert the filtered token (Status
0x%lx)\n", Status);
- return Status;
- }
-
- /* Return it to the caller */
- *FilteredToken = AccessToken;
- return Status;
-}
-
-/**
- * @brief
- * Queries information details about the given token to the call. The difference
- * between NtQueryInformationToken and this routine is that the system call has
- * user mode buffer data probing and additional protection checks whereas this
- * routine doesn't have any of these. The routine is used exclusively in kernel
- * mode.
- *
- * @param[in] AccessToken
- * An access token to be given.
- *
- * @param[in] TokenInformationClass
- * Token information class.
- *
- * @param[out] TokenInformation
- * Buffer with retrieved information. Such information is arbitrary, depending
- * on the requested information class.
- *
- * @return
- * Returns STATUS_SUCCESS if the operation to query the desired information
- * has completed successfully. STATUS_INSUFFICIENT_RESOURCES is returned if
- * pool memory allocation has failed to satisfy an operation. Otherwise
- * STATUS_INVALID_INFO_CLASS is returned indicating that the information
- * class provided is not supported by the routine.
- *
- * @remarks
- * Only certain information classes are not implemented in this function and
- * these are TokenOrigin, TokenGroupsAndPrivileges, TokenRestrictedSids and
- * TokenSandBoxInert. The following classes are implemented in NtQueryInformationToken
- * only.
- */
-NTSTATUS
-NTAPI
-SeQueryInformationToken(
- _In_ PACCESS_TOKEN AccessToken,
- _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
- _Outptr_result_buffer_(_Inexpressible_(token-dependent)) PVOID *TokenInformation)
-{
- NTSTATUS Status;
- PTOKEN Token = (PTOKEN)AccessToken;
- ULONG RequiredLength;
- union
- {
- PSID PSid;
- ULONG Ulong;
- } Unused;
-
- PAGED_CODE();
-
- /* Lock the token */
- SepAcquireTokenLockShared(Token);
-
- switch (TokenInformationClass)
- {
- case TokenUser:
- {
- PTOKEN_USER tu;
-
- DPRINT("SeQueryInformationToken(TokenUser)\n");
- RequiredLength = sizeof(TOKEN_USER) +
- RtlLengthSid(Token->UserAndGroups[0].Sid);
-
- /* Allocate the output buffer */
- tu = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
- if (tu == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- break;
- }
-
- Status = RtlCopySidAndAttributesArray(1,
- &Token->UserAndGroups[0],
- RequiredLength - sizeof(TOKEN_USER),
- &tu->User,
- (PSID)(tu + 1),
- &Unused.PSid,
- &Unused.Ulong);
-
- /* Return the structure */
- *TokenInformation = tu;
- Status = STATUS_SUCCESS;
- break;
- }
-
- case TokenGroups:
- {
- PTOKEN_GROUPS tg;
- ULONG SidLen;
- PSID Sid;
-
- DPRINT("SeQueryInformationToken(TokenGroups)\n");
- RequiredLength = sizeof(tg->GroupCount) +
- RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1,
&Token->UserAndGroups[1]);
-
- SidLen = RequiredLength - sizeof(tg->GroupCount) -
- ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
-
- /* Allocate the output buffer */
- tg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
- if (tg == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- break;
- }
-
- Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
- ((Token->UserAndGroupCount - 1) *
sizeof(SID_AND_ATTRIBUTES)));
-
- tg->GroupCount = Token->UserAndGroupCount - 1;
- Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
- &Token->UserAndGroups[1],
- SidLen,
- &tg->Groups[0],
- Sid,
- &Unused.PSid,
- &Unused.Ulong);
-
- /* Return the structure */
- *TokenInformation = tg;
- Status = STATUS_SUCCESS;
- break;
- }
-
- case TokenPrivileges:
- {
- PTOKEN_PRIVILEGES tp;
-
- DPRINT("SeQueryInformationToken(TokenPrivileges)\n");
- RequiredLength = sizeof(tp->PrivilegeCount) +
- (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
-
- /* Allocate the output buffer */
- tp = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
- if (tp == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- break;
- }
-
- tp->PrivilegeCount = Token->PrivilegeCount;
- RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
- Token->Privileges,
- &tp->Privileges[0]);
-
- /* Return the structure */
- *TokenInformation = tp;
- Status = STATUS_SUCCESS;
- break;
- }
-
- case TokenOwner:
- {
- PTOKEN_OWNER to;
- ULONG SidLen;
-
- DPRINT("SeQueryInformationToken(TokenOwner)\n");
- SidLen =
RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
- RequiredLength = sizeof(TOKEN_OWNER) + SidLen;
-
- /* Allocate the output buffer */
- to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
- if (to == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- break;
- }
-
- to->Owner = (PSID)(to + 1);
- Status = RtlCopySid(SidLen,
- to->Owner,
-
Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
-
- /* Return the structure */
- *TokenInformation = to;
- Status = STATUS_SUCCESS;
- break;
- }
-
- case TokenPrimaryGroup:
- {
- PTOKEN_PRIMARY_GROUP tpg;
- ULONG SidLen;
-
- DPRINT("SeQueryInformationToken(TokenPrimaryGroup)\n");
- SidLen = RtlLengthSid(Token->PrimaryGroup);
- RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen;
-
- /* Allocate the output buffer */
- tpg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
- if (tpg == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- break;
- }
-
- tpg->PrimaryGroup = (PSID)(tpg + 1);
- Status = RtlCopySid(SidLen,
- tpg->PrimaryGroup,
- Token->PrimaryGroup);
-
- /* Return the structure */
- *TokenInformation = tpg;
- Status = STATUS_SUCCESS;
- break;
- }
-
- case TokenDefaultDacl:
- {
- PTOKEN_DEFAULT_DACL tdd;
-
- DPRINT("SeQueryInformationToken(TokenDefaultDacl)\n");
- RequiredLength = sizeof(TOKEN_DEFAULT_DACL);
-
- if (Token->DefaultDacl != NULL)
- RequiredLength += Token->DefaultDacl->AclSize;
-
- /* Allocate the output buffer */
- tdd = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
- if (tdd == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- break;
- }
-
- if (Token->DefaultDacl != NULL)
- {
- tdd->DefaultDacl = (PACL)(tdd + 1);
- RtlCopyMemory(tdd->DefaultDacl,
- Token->DefaultDacl,
- Token->DefaultDacl->AclSize);
- }
- else
- {
- tdd->DefaultDacl = NULL;
- }
-
- /* Return the structure */
- *TokenInformation = tdd;
- Status = STATUS_SUCCESS;
- break;
- }
-
- case TokenSource:
- {
- PTOKEN_SOURCE ts;
-
- DPRINT("SeQueryInformationToken(TokenSource)\n");
- RequiredLength = sizeof(TOKEN_SOURCE);
-
- /* Allocate the output buffer */
- ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
- if (ts == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- break;
- }
-
- *ts = Token->TokenSource;
-
- /* Return the structure */
- *TokenInformation = ts;
- Status = STATUS_SUCCESS;
- break;
- }
-
- case TokenType:
- {
- PTOKEN_TYPE tt;
-
- DPRINT("SeQueryInformationToken(TokenType)\n");
- RequiredLength = sizeof(TOKEN_TYPE);
-
- /* Allocate the output buffer */
- tt = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
- if (tt == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- break;
- }
-
- *tt = Token->TokenType;
-
- /* Return the structure */
- *TokenInformation = tt;
- Status = STATUS_SUCCESS;
- break;
- }
-
- case TokenImpersonationLevel:
- {
- PSECURITY_IMPERSONATION_LEVEL sil;
-
- DPRINT("SeQueryInformationToken(TokenImpersonationLevel)\n");
- RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL);
-
- /* Fail if the token is not an impersonation token */
- if (Token->TokenType != TokenImpersonation)
- {
- Status = STATUS_INVALID_INFO_CLASS;
- break;
- }
-
- /* Allocate the output buffer */
- sil = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
- if (sil == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- break;
- }
-
- *sil = Token->ImpersonationLevel;
-
- /* Return the structure */
- *TokenInformation = sil;
- Status = STATUS_SUCCESS;
- break;
- }
-
- case TokenStatistics:
- {
- PTOKEN_STATISTICS ts;
-
- DPRINT("SeQueryInformationToken(TokenStatistics)\n");
- RequiredLength = sizeof(TOKEN_STATISTICS);
-
- /* Allocate the output buffer */
- ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
- if (ts == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- break;
- }
-
- ts->TokenId = Token->TokenId;
- ts->AuthenticationId = Token->AuthenticationId;
- ts->ExpirationTime = Token->ExpirationTime;
- ts->TokenType = Token->TokenType;
- ts->ImpersonationLevel = Token->ImpersonationLevel;
- ts->DynamicCharged = Token->DynamicCharged;
- ts->DynamicAvailable = Token->DynamicAvailable;
- ts->GroupCount = Token->UserAndGroupCount - 1;
- ts->PrivilegeCount = Token->PrivilegeCount;
- ts->ModifiedId = Token->ModifiedId;
-
- /* Return the structure */
- *TokenInformation = ts;
- Status = STATUS_SUCCESS;
- break;
- }
-
- case TokenSessionId:
- {
- DPRINT("SeQueryInformationToken(TokenSessionId)\n");
- Status = SeQuerySessionIdToken(Token, (PULONG)TokenInformation);
- break;
- }
-
- default:
- DPRINT1("SeQueryInformationToken(%d) invalid information class\n",
TokenInformationClass);
- Status = STATUS_INVALID_INFO_CLASS;
- break;
- }
-
- /* Release the lock of the token */
- SepReleaseTokenLock(Token);
-
- return Status;
-}
-
-/**
- * @brief
- * Queries the session ID of an access token.
- *
- * @param[in] Token
- * A valid access token where the session ID has to be gathered.
- *
- * @param[out] pSessionId
- * The returned pointer to a session ID to the caller.
- *
- * @return
- * Returns STATUS_SUCCESS.
- */
-NTSTATUS
-NTAPI
-SeQuerySessionIdToken(
- _In_ PACCESS_TOKEN Token,
- _Out_ PULONG pSessionId)
-{
- PAGED_CODE();
-
- /* Lock the token */
- SepAcquireTokenLockShared(Token);
-
- *pSessionId = ((PTOKEN)Token)->SessionId;
-
- /* Unlock the token */
- SepReleaseTokenLock(Token);
-
- return STATUS_SUCCESS;
-}
-
-/**
- * @brief
- * Queries the authentication ID of an access token.
- *
- * @param[in] Token
- * A valid access token where the authentication ID has to be gathered.
- *
- * @param[out] pSessionId
- * The returned pointer to an authentication ID to the caller.
- *
- * @return
- * Returns STATUS_SUCCESS.
- */
-NTSTATUS
-NTAPI
-SeQueryAuthenticationIdToken(
- _In_ PACCESS_TOKEN Token,
- _Out_ PLUID LogonId)
-{
- PAGED_CODE();
-
- *LogonId = ((PTOKEN)Token)->AuthenticationId;
-
- return STATUS_SUCCESS;
-}
-
-/**
- * @brief
- * Gathers the security impersonation level of an access token.
- *
- * @param[in] Token
- * A valid access token where the impersonation level has to be gathered.
- *
- * @return
... 7988 lines suppressed ...