ReactOS 0.4.15-dev-7704-gc07eb9f
tokenlif.c File Reference
#include <ntoskrnl.h>
#include <debug.h>
Include dependency graph for tokenlif.c:

Go to the source code of this file.

Macros

#define NDEBUG
 
#define SE_TOKEN_DYNAMIC_SLIM   500
 

Functions

NTSTATUS 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)
 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.
 
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)
 Duplicates an access token, from an existing valid token.
 
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)
 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.
 
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)
 Filters an access token from an existing token, making it more restricted than the previous one.
 
__kernel_entry NTSTATUS NTAPI NtCreateToken (_Out_ PHANDLE TokenHandle, _In_ ACCESS_MASK DesiredAccess, _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, _In_ TOKEN_TYPE TokenType, _In_ PLUID AuthenticationId, _In_ PLARGE_INTEGER ExpirationTime, _In_ PTOKEN_USER TokenUser, _In_ PTOKEN_GROUPS TokenGroups, _In_ PTOKEN_PRIVILEGES TokenPrivileges, _In_opt_ PTOKEN_OWNER TokenOwner, _In_ PTOKEN_PRIMARY_GROUP TokenPrimaryGroup, _In_opt_ PTOKEN_DEFAULT_DACL TokenDefaultDacl, _In_ PTOKEN_SOURCE TokenSource)
 Creates an access token.
 
_Must_inspect_result_ __kernel_entry NTSTATUS NTAPI NtDuplicateToken (_In_ HANDLE ExistingTokenHandle, _In_ ACCESS_MASK DesiredAccess, _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, _In_ BOOLEAN EffectiveOnly, _In_ TOKEN_TYPE TokenType, _Out_ PHANDLE NewTokenHandle)
 Duplicates a token.
 
NTSTATUS NTAPI NtFilterToken (_In_ HANDLE ExistingTokenHandle, _In_ ULONG Flags, _In_opt_ PTOKEN_GROUPS SidsToDisable, _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete, _In_opt_ PTOKEN_GROUPS RestrictedSids, _Out_ PHANDLE NewTokenHandle)
 Creates an access token in a restricted form from the original existing token, that is, such action is called filtering.
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 12 of file tokenlif.c.

◆ SE_TOKEN_DYNAMIC_SLIM

#define SE_TOKEN_DYNAMIC_SLIM   500

Definition at line 17 of file tokenlif.c.

Function Documentation

◆ NtCreateToken()

__kernel_entry NTSTATUS NTAPI NtCreateToken ( _Out_ PHANDLE  TokenHandle,
_In_ ACCESS_MASK  DesiredAccess,
_In_opt_ POBJECT_ATTRIBUTES  ObjectAttributes,
_In_ TOKEN_TYPE  TokenType,
_In_ PLUID  AuthenticationId,
_In_ PLARGE_INTEGER  ExpirationTime,
_In_ PTOKEN_USER  TokenUser,
_In_ PTOKEN_GROUPS  TokenGroups,
_In_ PTOKEN_PRIVILEGES  TokenPrivileges,
_In_opt_ PTOKEN_OWNER  TokenOwner,
_In_ PTOKEN_PRIMARY_GROUP  TokenPrimaryGroup,
_In_opt_ PTOKEN_DEFAULT_DACL  TokenDefaultDacl,
_In_ PTOKEN_SOURCE  TokenSource 
)

Creates an access token.

Parameters
[out]TokenHandleThe returned created token handle to the caller.
[in]DesiredAccessThe desired access rights for the token that we're creating.
[in]ObjectAttributesThe object attributes for the token object that we're creating.
[in]TokenTypeThe type of token to assign for the newly created token.
[in]AuthenticationIdAuthentication ID that represents the token's identity.
[in]ExpirationTimeExpiration time for the token. If set to -1, the token never expires.
[in]TokenUserThe main user entity for the token to assign.
[in]TokenGroupsGroup list of SIDs for the token to assign.
[in]TokenPrivilegesPrivileges for the token.
[in]TokenOwnerThe main user that owns the newly created token.
[in]TokenPrimaryGroupThe primary group that represents as the main group of the token.
[in]TokenDefaultDaclDiscretionary access control list for the token. This limits on how the token can be used, accessed and used by whom.
[in]TokenSourceThe source origin of the token who creates it.
Returns
Returns STATUS_SUCCESS if the function has successfully created the token. A failure NTSTATUS code is returned otherwise.

Definition at line 1558 of file tokenlif.c.

1572{
1573 HANDLE hToken;
1575 ULONG PrivilegeCount, GroupCount;
1576 PSID OwnerSid, PrimaryGroupSid;
1577 PACL DefaultDacl;
1578 LARGE_INTEGER LocalExpirationTime = {{0, 0}};
1579 LUID LocalAuthenticationId;
1580 TOKEN_SOURCE LocalTokenSource;
1581 SECURITY_QUALITY_OF_SERVICE LocalSecurityQos;
1582 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
1583 PSID_AND_ATTRIBUTES CapturedUser = NULL;
1584 PSID_AND_ATTRIBUTES CapturedGroups = NULL;
1585 PSID CapturedOwnerSid = NULL;
1586 PSID CapturedPrimaryGroupSid = NULL;
1587 PACL CapturedDefaultDacl = NULL;
1588 ULONG PrivilegesLength, UserLength, GroupsLength;
1590
1591 PAGED_CODE();
1592
1594
1595 if (PreviousMode != KernelMode)
1596 {
1597 _SEH2_TRY
1598 {
1600
1601 if (ObjectAttributes != NULL)
1602 {
1604 sizeof(OBJECT_ATTRIBUTES),
1605 sizeof(ULONG));
1606 LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
1607 }
1608
1609 ProbeForRead(AuthenticationId,
1610 sizeof(LUID),
1611 sizeof(ULONG));
1612 LocalAuthenticationId = *AuthenticationId;
1613
1614 LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
1615
1617 sizeof(TOKEN_USER),
1618 sizeof(ULONG));
1619
1621 sizeof(TOKEN_GROUPS),
1622 sizeof(ULONG));
1623 GroupCount = TokenGroups->GroupCount;
1624
1626 sizeof(TOKEN_PRIVILEGES),
1627 sizeof(ULONG));
1628 PrivilegeCount = TokenPrivileges->PrivilegeCount;
1629
1630 if (TokenOwner != NULL)
1631 {
1633 sizeof(TOKEN_OWNER),
1634 sizeof(ULONG));
1635 OwnerSid = TokenOwner->Owner;
1636 }
1637 else
1638 {
1639 OwnerSid = NULL;
1640 }
1641
1643 sizeof(TOKEN_PRIMARY_GROUP),
1644 sizeof(ULONG));
1645 PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
1646
1647 if (TokenDefaultDacl != NULL)
1648 {
1650 sizeof(TOKEN_DEFAULT_DACL),
1651 sizeof(ULONG));
1652 DefaultDacl = TokenDefaultDacl->DefaultDacl;
1653 }
1654 else
1655 {
1656 DefaultDacl = NULL;
1657 }
1658
1660 sizeof(TOKEN_SOURCE),
1661 sizeof(ULONG));
1662 LocalTokenSource = *TokenSource;
1663 }
1665 {
1666 /* Return the exception code */
1668 }
1669 _SEH2_END;
1670 }
1671 else
1672 {
1673 if (ObjectAttributes != NULL)
1674 LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
1675 LocalAuthenticationId = *AuthenticationId;
1676 LocalExpirationTime = *ExpirationTime;
1677 GroupCount = TokenGroups->GroupCount;
1678 PrivilegeCount = TokenPrivileges->PrivilegeCount;
1679 OwnerSid = TokenOwner ? TokenOwner->Owner : NULL;
1680 PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
1681 DefaultDacl = TokenDefaultDacl ? TokenDefaultDacl->DefaultDacl : NULL;
1682 LocalTokenSource = *TokenSource;
1683 }
1684
1685 /* Check token type */
1686 if ((TokenType < TokenPrimary) ||
1688 {
1689 return STATUS_BAD_TOKEN_TYPE;
1690 }
1691
1692 /* Check for token creation privilege */
1694 {
1696 }
1697
1698 /* Capture the user SID and attributes */
1700 1,
1702 NULL,
1703 0,
1704 PagedPool,
1705 FALSE,
1706 &CapturedUser,
1707 &UserLength);
1708 if (!NT_SUCCESS(Status))
1709 {
1710 goto Cleanup;
1711 }
1712
1713 /* Capture the groups SID and attributes array */
1715 GroupCount,
1717 NULL,
1718 0,
1719 PagedPool,
1720 FALSE,
1721 &CapturedGroups,
1722 &GroupsLength);
1723 if (!NT_SUCCESS(Status))
1724 {
1725 goto Cleanup;
1726 }
1727
1728 /* Capture privileges */
1730 PrivilegeCount,
1732 NULL,
1733 0,
1734 PagedPool,
1735 FALSE,
1736 &CapturedPrivileges,
1737 &PrivilegesLength);
1738 if (!NT_SUCCESS(Status))
1739 {
1740 goto Cleanup;
1741 }
1742
1743 /* Capture the token owner SID */
1744 if (TokenOwner != NULL)
1745 {
1746 Status = SepCaptureSid(OwnerSid,
1748 PagedPool,
1749 FALSE,
1750 &CapturedOwnerSid);
1751 if (!NT_SUCCESS(Status))
1752 {
1753 goto Cleanup;
1754 }
1755 }
1756
1757 /* Capture the token primary group SID */
1758 Status = SepCaptureSid(PrimaryGroupSid,
1760 PagedPool,
1761 FALSE,
1762 &CapturedPrimaryGroupSid);
1763 if (!NT_SUCCESS(Status))
1764 {
1765 goto Cleanup;
1766 }
1767
1768 /* Capture DefaultDacl */
1769 if (DefaultDacl != NULL)
1770 {
1771 Status = SepCaptureAcl(DefaultDacl,
1774 FALSE,
1775 &CapturedDefaultDacl);
1776 if (!NT_SUCCESS(Status))
1777 {
1778 goto Cleanup;
1779 }
1780 }
1781
1782 /* Call the internal function */
1783 Status = SepCreateToken(&hToken,
1787 TokenType,
1788 LocalSecurityQos.ImpersonationLevel,
1789 &LocalAuthenticationId,
1790 &LocalExpirationTime,
1791 CapturedUser,
1792 GroupCount,
1793 CapturedGroups,
1794 GroupsLength,
1795 PrivilegeCount,
1796 CapturedPrivileges,
1797 CapturedOwnerSid,
1798 CapturedPrimaryGroupSid,
1799 CapturedDefaultDacl,
1800 &LocalTokenSource,
1801 FALSE);
1802 if (NT_SUCCESS(Status))
1803 {
1804 _SEH2_TRY
1805 {
1806 *TokenHandle = hToken;
1807 }
1809 {
1811 }
1812 _SEH2_END;
1813 }
1814
1815Cleanup:
1816
1817 /* Release what we captured */
1821 SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE);
1822 SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE);
1823 SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE);
1824
1825 return Status;
1826}
#define PAGED_CODE()
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
LONG NTSTATUS
Definition: precomp.h:26
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
static const WCHAR Cleanup[]
Definition: register.c:80
#define NonPagedPool
Definition: env_spec_w32.h:307
#define PagedPool
Definition: env_spec_w32.h:308
#define ExGetPreviousMode
Definition: ex.h:140
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
Status
Definition: gdiplustypes.h:25
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
@ TokenImpersonation
Definition: imports.h:274
@ TokenPrimary
Definition: imports.h:273
#define KernelMode
Definition: asm.h:34
_In_ ACCESS_MASK _In_ ULONG _Out_ PHANDLE TokenHandle
Definition: psfuncs.h:718
_In_ ACCESS_MASK _In_opt_ POBJECT_ATTRIBUTES _In_ BOOLEAN _In_ TOKEN_TYPE TokenType
Definition: sefuncs.h:411
VOID NTAPI SepReleaseSid(_In_ PSID CapturedSid, _In_ KPROCESSOR_MODE AccessMode, _In_ BOOLEAN CaptureIfKernel)
Releases a captured SID.
Definition: sid.c:400
NTSTATUS NTAPI SepCaptureSid(_In_ PSID InputSid, _In_ KPROCESSOR_MODE AccessMode, _In_ POOL_TYPE PoolType, _In_ BOOLEAN CaptureIfKernel, _Out_ PSID *CapturedSid)
Captures a SID.
Definition: sid.c:314
const LUID SeCreateTokenPrivilege
Definition: priv.c:21
VOID NTAPI SeReleaseSidAndAttributesArray(_In_ _Post_invalid_ PSID_AND_ATTRIBUTES CapturedSidAndAttributes, _In_ KPROCESSOR_MODE AccessMode, _In_ BOOLEAN CaptureIfKernel)
Releases a captured SID with attributes.
Definition: sid.c:976
VOID NTAPI SepReleaseAcl(_In_ PACL CapturedAcl, _In_ KPROCESSOR_MODE AccessMode, _In_ BOOLEAN CaptureIfKernel)
Releases (frees) a captured ACL from the memory pool.
Definition: acl.c:464
VOID NTAPI SeReleaseLuidAndAttributesArray(_In_ PLUID_AND_ATTRIBUTES Privilege, _In_ KPROCESSOR_MODE PreviousMode, _In_ BOOLEAN CaptureIfKernel)
Releases a LUID with attributes structure.
Definition: priv.c:554
NTSTATUS NTAPI SepCaptureAcl(_In_ PACL InputAcl, _In_ KPROCESSOR_MODE AccessMode, _In_ POOL_TYPE PoolType, _In_ BOOLEAN CaptureIfKernel, _Out_ PACL *CapturedAcl)
Captures an access control list from an already valid input ACL.
Definition: acl.c:352
NTSTATUS NTAPI SeCaptureSidAndAttributesArray(_In_ PSID_AND_ATTRIBUTES SrcSidAndAttributes, _In_ ULONG AttributeCount, _In_ KPROCESSOR_MODE PreviousMode, _In_opt_ PVOID AllocatedMem, _In_ ULONG AllocatedLength, _In_ POOL_TYPE PoolType, _In_ BOOLEAN CaptureIfKernel, _Out_ PSID_AND_ATTRIBUTES *CapturedSidAndAttributes, _Out_ PULONG ResultLength)
Captures a SID with attributes.
Definition: sid.c:693
NTSTATUS 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)
BOOLEAN NTAPI SeSinglePrivilegeCheck(_In_ LUID PrivilegeValue, _In_ KPROCESSOR_MODE PreviousMode)
Checks if a single privilege is present in the context of the calling thread.
Definition: priv.c:744
#define STATUS_BAD_TOKEN_TYPE
Definition: ntstatus.h:404
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:162
#define ProbeForWriteHandle(Ptr)
Definition: probe.h:43
#define ProbeForReadLargeInteger(Ptr)
Definition: probe.h:75
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
Definition: lsa.idl:65
NTSTATUS 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)
Internal function responsible for access token object creation in the kernel. A fully created token o...
Definition: tokenlif.c:97
uint32_t ULONG
Definition: typedefs.h:59
_Must_inspect_result_ _In_ WDFDEVICE _In_ ULONG _In_ ACCESS_MASK DesiredAccess
Definition: wdfdevice.h:2658
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
@ TokenDefaultDacl
Definition: setypes.h:971
@ TokenSource
Definition: setypes.h:972
@ TokenGroups
Definition: setypes.h:967
@ TokenPrivileges
Definition: setypes.h:968
@ TokenUser
Definition: setypes.h:966
@ TokenPrimaryGroup
Definition: setypes.h:970
@ TokenOwner
Definition: setypes.h:969

Referenced by LsapLogonUser().

◆ NtDuplicateToken()

_Must_inspect_result_ __kernel_entry NTSTATUS NTAPI NtDuplicateToken ( _In_ HANDLE  ExistingTokenHandle,
_In_ ACCESS_MASK  DesiredAccess,
_In_opt_ POBJECT_ATTRIBUTES  ObjectAttributes,
_In_ BOOLEAN  EffectiveOnly,
_In_ TOKEN_TYPE  TokenType,
_Out_ PHANDLE  NewTokenHandle 
)

Duplicates a token.

Parameters
[in]ExistingTokenHandleAn existing token to duplicate.
[in]DesiredAccessThe desired access rights for the new duplicated token.
[in]ObjectAttributesObject attributes for the new duplicated token.
[in]EffectiveOnlyIf set to TRUE, the function removes all the disabled privileges and groups of the token to duplicate.
[in]TokenTypeType of token to assign to the duplicated token.
[out]NewTokenHandleThe returned duplicated token handle.
Returns
STATUS_SUCCESS is returned if token duplication has completed successfully. STATUS_BAD_IMPERSONATION_LEVEL is returned if the caller erroneously wants to raise the impersonation level even though the conditions do not permit it. A failure NTSTATUS code is returned otherwise.
Remarks
Some sources claim 4th param is ImpersonationLevel, but on W2K this is certainly NOT true, although I can't say for sure that EffectiveOnly is correct either. -Gunnar This is true. EffectiveOnly overrides SQOS.EffectiveOnly. - IAI NOTE for readers: http://hex.pp.ua/nt/NtDuplicateToken.php is therefore wrong in that regard, while MSDN documentation is correct.

Definition at line 1869 of file tokenlif.c.

1876{
1878 HANDLE hToken;
1879 PTOKEN Token;
1880 PTOKEN NewToken;
1881 PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService;
1882 BOOLEAN QoSPresent;
1885
1886 PAGED_CODE();
1887
1890 {
1892 }
1893
1895
1896 if (PreviousMode != KernelMode)
1897 {
1898 _SEH2_TRY
1899 {
1901 }
1903 {
1904 /* Return the exception code */
1906 }
1907 _SEH2_END;
1908 }
1909
1912 PagedPool,
1913 FALSE,
1914 &CapturedSecurityQualityOfService,
1915 &QoSPresent);
1916 if (!NT_SUCCESS(Status))
1917 {
1918 DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status);
1919 return Status;
1920 }
1921
1922 Status = ObReferenceObjectByHandle(ExistingTokenHandle,
1926 (PVOID*)&Token,
1928 if (!NT_SUCCESS(Status))
1929 {
1930 DPRINT1("Failed to reference token (Status 0x%lx)\n", Status);
1931 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1933 FALSE);
1934 return Status;
1935 }
1936
1937 /*
1938 * Fail, if the original token is an impersonation token and the caller
1939 * tries to raise the impersonation level of the new token above the
1940 * impersonation level of the original token.
1941 */
1942 if (Token->TokenType == TokenImpersonation)
1943 {
1944 if (QoSPresent &&
1945 CapturedSecurityQualityOfService->ImpersonationLevel >Token->ImpersonationLevel)
1946 {
1948 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1950 FALSE);
1952 }
1953 }
1954
1955 /*
1956 * Fail, if a primary token is to be created from an impersonation token
1957 * and and the impersonation level of the impersonation token is below SecurityImpersonation.
1958 */
1959 if (Token->TokenType == TokenImpersonation &&
1961 Token->ImpersonationLevel < SecurityImpersonation)
1962 {
1964 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1966 FALSE);
1968 }
1969
1973 TokenType,
1974 (QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous),
1976 &NewToken);
1977
1979
1980 if (NT_SUCCESS(Status))
1981 {
1982 Status = ObInsertObject(NewToken,
1983 NULL,
1984 (DesiredAccess ? DesiredAccess : HandleInformation.GrantedAccess),
1985 0,
1986 NULL,
1987 &hToken);
1988 if (NT_SUCCESS(Status))
1989 {
1990 _SEH2_TRY
1991 {
1992 *NewTokenHandle = hToken;
1993 }
1995 {
1997 }
1998 _SEH2_END;
1999 }
2000 }
2001
2002 /* Free the captured structure */
2003 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
2005 FALSE);
2006
2007 return Status;
2008}
unsigned char BOOLEAN
#define DPRINT1
Definition: precomp.h:8
@ SecurityImpersonation
Definition: lsa.idl:57
@ SecurityAnonymous
Definition: lsa.idl:55
#define KeGetPreviousMode()
Definition: ketypes.h:1115
_In_ ACCESS_MASK _In_opt_ POBJECT_ATTRIBUTES _In_ BOOLEAN EffectiveOnly
Definition: sefuncs.h:410
_In_ ACCESS_MASK _In_opt_ POBJECT_ATTRIBUTES _In_ BOOLEAN _In_ TOKEN_TYPE _Out_ PHANDLE NewTokenHandle
Definition: sefuncs.h:412
NTSTATUS 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)
Captures the security quality of service data given the object attributes from an object.
Definition: sqos.c:52
VOID NTAPI SepReleaseSecurityQualityOfService(_In_opt_ PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService, _In_ KPROCESSOR_MODE AccessMode, _In_ BOOLEAN CaptureIfKernel)
Releases (frees) the captured SQOS data from an object in the memory pool.
Definition: sqos.c:225
POBJECT_TYPE SeTokenObjectType
Definition: token.c:17
#define STATUS_BAD_IMPERSONATION_LEVEL
Definition: ntstatus.h:401
NTSTATUS NTAPI ObInsertObject(IN PVOID Object, IN PACCESS_STATE AccessState OPTIONAL, IN ACCESS_MASK DesiredAccess, IN ULONG ObjectPointerBias, OUT PVOID *NewObject OPTIONAL, OUT PHANDLE Handle)
Definition: obhandle.c:2935
NTSTATUS NTAPI ObReferenceObjectByHandle(IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
Definition: obref.c:494
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)
Duplicates an access token, from an existing valid token.
Definition: tokenlif.c:471
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
_In_ ACCESS_MASK _In_opt_ POBJECT_TYPE _In_ KPROCESSOR_MODE _Out_ PVOID _Out_opt_ POBJECT_HANDLE_INFORMATION HandleInformation
Definition: obfuncs.h:44
#define ObDereferenceObject
Definition: obfuncs.h:203
#define TOKEN_DUPLICATE
Definition: setypes.h:926

Referenced by CreateProcessAsUserCommon(), DuplicateTokenAsEffective(), DuplicateTokenEx(), GetToken(), GetTokenProcess(), ImpersonateLoggedOnUser(), QueryTokenImpersonationTests(), and START_TEST().

◆ NtFilterToken()

NTSTATUS NTAPI NtFilterToken ( _In_ HANDLE  ExistingTokenHandle,
_In_ ULONG  Flags,
_In_opt_ PTOKEN_GROUPS  SidsToDisable,
_In_opt_ PTOKEN_PRIVILEGES  PrivilegesToDelete,
_In_opt_ PTOKEN_GROUPS  RestrictedSids,
_Out_ PHANDLE  NewTokenHandle 
)

Creates an access token in a restricted form from the original existing token, that is, such action is called filtering.

Parameters
[in]ExistingTokenHandleA handle to an access token which is to be filtered.
[in]FlagsPrivilege flag options. This parameter argument influences how the token's privileges are filtered. For further details see remarks.
[in]SidsToDisableArray of SIDs to disable. The action of doing so assigns the SE_GROUP_USE_FOR_DENY_ONLY attribute to the respective group SID and takes away SE_GROUP_ENABLED and SE_GROUP_ENABLED_BY_DEFAULT. This parameter can be NULL. This can be a UM pointer.
[in]PrivilegesToDeleteArray of privileges to delete. The function will walk within this array to determine if the specified privileges do exist in the access token. Any missing privileges gets ignored. This parameter can be NULL. This can be a UM pointer.
[in]RestrictedSidsAn array list of restricted groups SID to be added in the access token. A token that is already restricted the newly added restricted SIDs are redundant information in addition to the existing restricted SIDs in the token. This parameter can be NULL. This can be a UM pointer.
[out]NewTokenHandleA new handle to the restricted (filtered) access token. This can be a UM pointer.
Returns
Returns STATUS_SUCCESS if the routine has successfully filtered the access token. STATUS_INVALID_PARAMETER is returned if one or more parameters are not valid (see SepPerformTokenFiltering routine call for more information). A failure NTSTATUS code is returned otherwise.
Remarks
The Flags parameter determines the final outcome of how the privileges in an access token are filtered. This parameter can take these supported values (these can be combined):

0 – Filter the token's privileges in the usual way. The function expects that the caller MUST PROVIDE a valid array list of privileges to be deleted (that is, PrivilegesToDelete MUSTN'T BE NULL).

DISABLE_MAX_PRIVILEGE – Disables (deletes) all the privileges except SeChangeNotifyPrivilege in the new access token. Bear in mind if this flag is specified the routine ignores PrivilegesToDelete.

SANDBOX_INERT – Stores the TOKEN_SANDBOX_INERT token flag within the access token.

LUA_TOKEN – The newly filtered access token is a LUA token. This flag is not supported in Windows Server 2003.

WRITE_RESTRICTED – The newly filtered token has the restricted SIDs that are considered only when evaluating write access onto the token. This value is not supported in Windows Server 2003.

Definition at line 2075 of file tokenlif.c.

2082{
2083 PTOKEN Token, FilteredToken;
2084 HANDLE FilteredTokenHandle;
2087 OBJECT_HANDLE_INFORMATION HandleInfo;
2089 ULONG CapturedSidsCount = 0;
2090 ULONG CapturedPrivilegesCount = 0;
2091 ULONG CapturedRestrictedSidsCount = 0;
2092 ULONG ProbeSize = 0;
2093 PSID_AND_ATTRIBUTES CapturedSids = NULL;
2094 PSID_AND_ATTRIBUTES CapturedRestrictedSids = NULL;
2095 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
2096
2097 PAGED_CODE();
2098
2100
2101 _SEH2_TRY
2102 {
2103 /* Probe SidsToDisable */
2104 if (SidsToDisable != NULL)
2105 {
2106 /* Probe the header */
2107 ProbeForRead(SidsToDisable, sizeof(*SidsToDisable), sizeof(ULONG));
2108
2109 CapturedSidsCount = SidsToDisable->GroupCount;
2110 ProbeSize = FIELD_OFFSET(TOKEN_GROUPS, Groups[CapturedSidsCount]);
2111
2112 ProbeForRead(SidsToDisable, ProbeSize, sizeof(ULONG));
2113 }
2114
2115 /* Probe PrivilegesToDelete */
2116 if (PrivilegesToDelete != NULL)
2117 {
2118 /* Probe the header */
2119 ProbeForRead(PrivilegesToDelete, sizeof(*PrivilegesToDelete), sizeof(ULONG));
2120
2121 CapturedPrivilegesCount = PrivilegesToDelete->PrivilegeCount;
2122 ProbeSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedPrivilegesCount]);
2123
2124 ProbeForRead(PrivilegesToDelete, ProbeSize, sizeof(ULONG));
2125 }
2126
2127 /* Probe RestrictedSids */
2128 if (RestrictedSids != NULL)
2129 {
2130 /* Probe the header */
2131 ProbeForRead(RestrictedSids, sizeof(*RestrictedSids), sizeof(ULONG));
2132
2133 CapturedRestrictedSidsCount = RestrictedSids->GroupCount;
2134 ProbeSize = FIELD_OFFSET(TOKEN_GROUPS, Groups[CapturedRestrictedSidsCount]);
2135
2136 ProbeForRead(RestrictedSids, ProbeSize, sizeof(ULONG));
2137 }
2138
2139 /* Probe the handle */
2141 }
2143 {
2144 /* Return the exception code */
2146 }
2147 _SEH2_END;
2148
2149 /* Reference the token */
2150 Status = ObReferenceObjectByHandle(ExistingTokenHandle,
2154 (PVOID*)&Token,
2155 &HandleInfo);
2156 if (!NT_SUCCESS(Status))
2157 {
2158 DPRINT1("NtFilterToken(): Failed to reference the token (Status 0x%lx)\n", Status);
2159 return Status;
2160 }
2161
2162 /* Capture the group SIDs */
2163 if (SidsToDisable != NULL)
2164 {
2165 Status = SeCaptureSidAndAttributesArray(SidsToDisable->Groups,
2166 CapturedSidsCount,
2168 NULL,
2169 0,
2170 PagedPool,
2171 TRUE,
2172 &CapturedSids,
2173 &ResultLength);
2174 if (!NT_SUCCESS(Status))
2175 {
2176 DPRINT1("NtFilterToken(): Failed to capture the SIDs (Status 0x%lx)\n", Status);
2177 goto Quit;
2178 }
2179 }
2180
2181 /* Capture the privileges */
2182 if (PrivilegesToDelete != NULL)
2183 {
2184 Status = SeCaptureLuidAndAttributesArray(PrivilegesToDelete->Privileges,
2185 CapturedPrivilegesCount,
2187 NULL,
2188 0,
2189 PagedPool,
2190 TRUE,
2191 &CapturedPrivileges,
2192 &ResultLength);
2193 if (!NT_SUCCESS(Status))
2194 {
2195 DPRINT1("NtFilterToken(): Failed to capture the privileges (Status 0x%lx)\n", Status);
2196 goto Quit;
2197 }
2198 }
2199
2200 /* Capture the restricted SIDs */
2201 if (RestrictedSids != NULL)
2202 {
2203 Status = SeCaptureSidAndAttributesArray(RestrictedSids->Groups,
2204 CapturedRestrictedSidsCount,
2206 NULL,
2207 0,
2208 PagedPool,
2209 TRUE,
2210 &CapturedRestrictedSids,
2211 &ResultLength);
2212 if (!NT_SUCCESS(Status))
2213 {
2214 DPRINT1("NtFilterToken(): Failed to capture the restricted SIDs (Status 0x%lx)\n", Status);
2215 goto Quit;
2216 }
2217 }
2218
2219 /* Call the internal API */
2221 CapturedPrivileges,
2222 CapturedSids,
2223 CapturedRestrictedSids,
2224 CapturedPrivilegesCount,
2225 CapturedSidsCount,
2226 CapturedRestrictedSidsCount,
2227 Flags,
2229 &FilteredToken);
2230 if (!NT_SUCCESS(Status))
2231 {
2232 DPRINT1("NtFilterToken(): Failed to filter the token (Status 0x%lx)\n", Status);
2233 goto Quit;
2234 }
2235
2236 /* Insert the filtered token and retrieve a handle to it */
2237 Status = ObInsertObject(FilteredToken,
2238 NULL,
2239 HandleInfo.GrantedAccess,
2240 0,
2241 NULL,
2242 &FilteredTokenHandle);
2243 if (!NT_SUCCESS(Status))
2244 {
2245 DPRINT1("NtFilterToken(): Failed to insert the filtered token (Status 0x%lx)\n", Status);
2246 goto Quit;
2247 }
2248
2249 /* And return it to the caller once we're done */
2250 _SEH2_TRY
2251 {
2252 *NewTokenHandle = FilteredTokenHandle;
2253 }
2255 {
2257 _SEH2_YIELD(goto Quit);
2258 }
2259 _SEH2_END;
2260
2261Quit:
2262 /* Dereference the token */
2264
2265 /* Release all the captured data */
2266 if (CapturedSids != NULL)
2267 {
2268 SeReleaseSidAndAttributesArray(CapturedSids,
2270 TRUE);
2271 }
2272
2273 if (CapturedPrivileges != NULL)
2274 {
2275 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
2277 TRUE);
2278 }
2279
2280 if (CapturedRestrictedSids != NULL)
2281 {
2282 SeReleaseSidAndAttributesArray(CapturedRestrictedSids,
2284 TRUE);
2285 }
2286
2287 return Status;
2288}
#define TRUE
Definition: types.h:120
ACCESS_MASK GrantedAccess
Definition: iotypes.h:181
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)
Private helper function responsible for creating a restricted access token, that is,...
Definition: tokenlif.c:859
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG _Out_ PULONG ResultLength
Definition: wdfdevice.h:3776
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
_In_ PSECURITY_SUBJECT_CONTEXT _In_ BOOLEAN _In_ ACCESS_MASK _In_ ACCESS_MASK _Outptr_opt_ PPRIVILEGE_SET * Privileges
Definition: sefuncs.h:17

Referenced by CreateRestrictedToken(), QueryTokenIsSandboxInert(), QueryTokenPrivilegesAndGroupsTests(), QueryTokenRestrictedSidsTest(), and START_TEST().

◆ SeFilterToken()

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 
)

Filters an access token from an existing token, making it more restricted than the previous one.

Parameters
[in]ExistingTokenAn existing token for filtering.
[in]FlagsPrivilege flag options. This parameter argument influences how the token is filtered. Such parameter can be 0. See NtFilterToken syscall for more information.
[in]SidsToDisableArray of SIDs to disable. Such parameter can be NULL.
[in]PrivilegesToDeleteArray of privileges to delete. If DISABLE_MAX_PRIVILEGE flag is specified in the Flags parameter, PrivilegesToDelete is ignored.
[in]RestrictedSidsAn array of restricted SIDs for the new filtered token. Such parameter can be NULL.
[out]FilteredTokenThe newly filtered token, returned to the caller.
Returns
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.

Definition at line 1438 of file tokenlif.c.

1445{
1447 PTOKEN AccessToken;
1448 ULONG PrivilegesCount = 0;
1449 ULONG SidsCount = 0;
1450 ULONG RestrictedSidsCount = 0;
1451
1452 PAGED_CODE();
1453
1454 /* Begin copying the counters */
1455 if (SidsToDisable != NULL)
1456 {
1457 SidsCount = SidsToDisable->GroupCount;
1458 }
1459
1460 if (PrivilegesToDelete != NULL)
1461 {
1462 PrivilegesCount = PrivilegesToDelete->PrivilegeCount;
1463 }
1464
1465 if (RestrictedSids != NULL)
1466 {
1467 RestrictedSidsCount = RestrictedSids->GroupCount;
1468 }
1469
1470 /* Call the internal API */
1471 Status = SepPerformTokenFiltering(ExistingToken,
1472 PrivilegesToDelete->Privileges,
1473 SidsToDisable->Groups,
1474 RestrictedSids->Groups,
1475 PrivilegesCount,
1476 SidsCount,
1477 RestrictedSidsCount,
1478 Flags,
1479 KernelMode,
1480 &AccessToken);
1481 if (!NT_SUCCESS(Status))
1482 {
1483 DPRINT1("SeFilterToken(): Failed to filter the token (Status 0x%lx)\n", Status);
1484 return Status;
1485 }
1486
1487 /* Insert the filtered token */
1488 Status = ObInsertObject(AccessToken,
1489 NULL,
1490 0,
1491 0,
1492 NULL,
1493 NULL);
1494 if (!NT_SUCCESS(Status))
1495 {
1496 DPRINT1("SeFilterToken(): Failed to insert the filtered token (Status 0x%lx)\n", Status);
1497 return Status;
1498 }
1499
1500 /* Return it to the caller */
1501 *FilteredToken = AccessToken;
1502 return Status;
1503}

Referenced by FatCreateRestrictEveryoneToken(), and FilterToken().

◆ SepCreateToken()

NTSTATUS 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 
)

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.

Parameters
[out]TokenHandleValid token handle that's ready for use after token creation and object insertion.
[in]PreviousModeProcessor request level mode.
[in]DesiredAccessDesired access right for the token object to be granted. This kind of access right impacts how the token can be used and who.
[in]ObjectAttributesObject attributes for the token to be created.
[in]TokenTypeType of token to assign upon creation.
[in]ImpersonationLevelSecurity impersonation level of token to assign upon creation.
[in]AuthenticationIdAuthentication ID that represents the authentication information of the token.
[in]ExpirationTimeExpiration 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.
[in]UserUser entry to assign to the token.
[in]GroupCountThe total number of groups count for the token.
[in]GroupsThe group entries for the token.
[in]GroupsLengthThe length size of the groups array, pointed by the Groups parameter.
[in]PrivilegeCountThe total number of priivleges that the newly created token has.
[in]PrivilegesThe privileges for the token.
[in]OwnerThe main user (or also owner) that represents the token that we create.
[in]PrimaryGroupThe main group that represents the token that we create.
[in]DefaultDaclA discretionary access control list for the token.
[in]TokenSourceSource (or the origin) of the access token that creates it.
[in]SystemTokenIf 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.
Returns
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.

Definition at line 97 of file tokenlif.c.

117{
119 PTOKEN AccessToken;
120 ULONG TokenFlags = 0;
121 ULONG PrimaryGroupIndex, DefaultOwnerIndex;
122 LUID TokenId;
123 LUID ModifiedId;
124 PVOID EndMem;
125 ULONG PrivilegesLength;
126 ULONG UserGroupsLength;
127 ULONG VariableLength;
128 ULONG DynamicPartSize, TotalSize;
129 ULONG TokenPagedCharges;
130 ULONG i;
131
132 PAGED_CODE();
133
134 /* Loop all groups */
135 for (i = 0; i < GroupCount; i++)
136 {
137 /* Check for mandatory groups */
138 if (Groups[i].Attributes & SE_GROUP_MANDATORY)
139 {
140 /* Force them to be enabled */
141 Groups[i].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
142 }
143
144 /* Check of the group is an admin group */
145 if (RtlEqualSid(SeAliasAdminsSid, Groups[i].Sid))
146 {
147 /* Remember this so we can optimize queries later */
148 TokenFlags |= TOKEN_HAS_ADMIN_GROUP;
149 }
150 }
151
152 /* Allocate unique IDs for the token */
154 ExAllocateLocallyUniqueId(&ModifiedId);
155
156 /* Compute how much size we need to allocate for the token */
157
158 /* Privileges size */
159 PrivilegesLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
160 PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
161
162 /* User and groups size */
163 UserGroupsLength = (1 + GroupCount) * sizeof(SID_AND_ATTRIBUTES);
164 UserGroupsLength += RtlLengthSid(User->Sid);
165 for (i = 0; i < GroupCount; i++)
166 {
167 UserGroupsLength += RtlLengthSid(Groups[i].Sid);
168 }
169 UserGroupsLength = ALIGN_UP_BY(UserGroupsLength, sizeof(PVOID));
170
171 /* Add the additional groups array length */
172 UserGroupsLength += ALIGN_UP_BY(GroupsLength, sizeof(PVOID));
173
174 VariableLength = PrivilegesLength + UserGroupsLength;
175 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
176
177 /*
178 * A token is considered slim if it has the default dynamic
179 * contents, or in other words, the primary group and ACL.
180 * We judge if such contents are default by checking their
181 * total size if it's over the range. On Windows this range
182 * is 0x1F4 (aka 500). If the size of the whole dynamic contents
183 * is over that range then the token is considered fat and
184 * the token will be charged the whole of its token body length
185 * plus the dynamic size.
186 */
187 DynamicPartSize = DefaultDacl ? DefaultDacl->AclSize : 0;
188 DynamicPartSize += RtlLengthSid(PrimaryGroup);
189 if (DynamicPartSize > SE_TOKEN_DYNAMIC_SLIM)
190 {
191 TokenPagedCharges = DynamicPartSize + TotalSize;
192 }
193 else
194 {
195 TokenPagedCharges = SE_TOKEN_DYNAMIC_SLIM + TotalSize;
196 }
197
202 NULL,
203 TotalSize,
204 TokenPagedCharges,
205 0,
206 (PVOID*)&AccessToken);
207 if (!NT_SUCCESS(Status))
208 {
209 DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
210 return Status;
211 }
212
213 /* Zero out the buffer and initialize the token */
214 RtlZeroMemory(AccessToken, TotalSize);
215
216 AccessToken->TokenId = TokenId;
217 AccessToken->TokenType = TokenType;
219
220 /* Initialise the lock for the access token */
221 Status = SepCreateTokenLock(AccessToken);
222 if (!NT_SUCCESS(Status))
223 goto Quit;
224
225 AccessToken->TokenSource.SourceIdentifier = TokenSource->SourceIdentifier;
227 TokenSource->SourceName,
228 sizeof(TokenSource->SourceName));
229
230 AccessToken->ExpirationTime = *ExpirationTime;
231 AccessToken->ModifiedId = ModifiedId;
232 AccessToken->DynamicCharged = TokenPagedCharges - TotalSize;
233
234 AccessToken->TokenFlags = TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
235
236 /* Copy and reference the logon session */
237 AccessToken->AuthenticationId = *AuthenticationId;
239 if (!NT_SUCCESS(Status))
240 {
241 /* No logon session could be found, bail out */
242 DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status);
243 /* Set the flag for proper cleanup by the delete procedure */
245 goto Quit;
246 }
247
248 /* Insert the referenced logon session into the token */
250 if (!NT_SUCCESS(Status))
251 {
252 /* Failed to insert the logon session into the token, bail out */
253 DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n", Status);
254 goto Quit;
255 }
256
257 /* Fill in token debug information */
258#if DBG
259 /*
260 * We must determine ourselves that the current
261 * process is not the initial CPU one. The initial
262 * process is not a "real" process, that is, the
263 * Process Manager has not yet been initialized and
264 * as a matter of fact we are creating a token before
265 * any process gets created by Ps. If it turns out
266 * that the current process is the initial CPU process
267 * where token creation execution takes place, don't
268 * do anything.
269 */
271 {
272 RtlCopyMemory(AccessToken->ImageFileName,
273 PsGetCurrentProcess()->ImageFileName,
274 min(sizeof(AccessToken->ImageFileName), sizeof(PsGetCurrentProcess()->ImageFileName)));
275
276 AccessToken->ProcessCid = PsGetCurrentProcessId();
277 AccessToken->ThreadCid = PsGetCurrentThreadId();
278 }
279
280 AccessToken->CreateMethod = TOKEN_CREATE_METHOD;
281#endif
282
283 /* Assign the data that reside in the token's variable information area */
284 AccessToken->VariableLength = VariableLength;
285 EndMem = (PVOID)&AccessToken->VariablePart;
286
287 /* Copy the privileges */
288 AccessToken->PrivilegeCount = PrivilegeCount;
289 AccessToken->Privileges = NULL;
290 if (PrivilegeCount > 0)
291 {
292 AccessToken->Privileges = EndMem;
293 EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
294 VariableLength -= PrivilegesLength;
295
297 {
299 {
300 RtlCopyMemory(AccessToken->Privileges,
302 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
303 }
305 {
307 }
308 _SEH2_END;
309 }
310 else
311 {
312 RtlCopyMemory(AccessToken->Privileges,
314 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
315 }
316
317 if (!NT_SUCCESS(Status))
318 goto Quit;
319 }
320
321 /* Update the privilege flags */
322 SepUpdatePrivilegeFlagsToken(AccessToken);
323
324 /* Copy the user and groups */
325 AccessToken->UserAndGroupCount = 1 + GroupCount;
326 AccessToken->UserAndGroups = EndMem;
327 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
328 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
329
331 User,
332 VariableLength,
333 &AccessToken->UserAndGroups[0],
334 EndMem,
335 &EndMem,
336 &VariableLength);
337 if (!NT_SUCCESS(Status))
338 goto Quit;
339
341 Groups,
342 VariableLength,
343 &AccessToken->UserAndGroups[1],
344 EndMem,
345 &EndMem,
346 &VariableLength);
347 if (!NT_SUCCESS(Status))
348 goto Quit;
349
350 /* Find the token primary group and default owner */
353 Owner,
354 &PrimaryGroupIndex,
355 &DefaultOwnerIndex);
356 if (!NT_SUCCESS(Status))
357 {
358 DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status);
359 goto Quit;
360 }
361
362 /*
363 * Now allocate the token's dynamic information area
364 * and set the data. The dynamic part consists of two
365 * contents, the primary group SID and the default DACL
366 * of the token, in this strict order.
367 */
369 DynamicPartSize,
371 if (AccessToken->DynamicPart == NULL)
372 {
374 goto Quit;
375 }
376
377 /* Unused memory in the dynamic area */
378 AccessToken->DynamicAvailable = 0;
379
380 /*
381 * Assign the primary group to the token
382 * and put it in the dynamic part as well.
383 */
384 EndMem = (PVOID)AccessToken->DynamicPart;
385 AccessToken->PrimaryGroup = EndMem;
386 RtlCopySid(RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid),
387 EndMem,
388 AccessToken->UserAndGroups[PrimaryGroupIndex].Sid);
389 AccessToken->DefaultOwnerIndex = DefaultOwnerIndex;
390 EndMem = (PVOID)((ULONG_PTR)EndMem + RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid));
391
392 /*
393 * We have assigned a primary group and put it in the
394 * dynamic part, now it's time to copy the provided
395 * default DACL (if it's provided to begin with) into
396 * the DACL field of the token and put it at the end
397 * tail of the dynamic part too.
398 */
399 if (DefaultDacl != NULL)
400 {
401 AccessToken->DefaultDacl = EndMem;
402
403 RtlCopyMemory(EndMem,
404 DefaultDacl,
405 DefaultDacl->AclSize);
406 }
407
408 /* Insert the token only if it's not the system token, otherwise return it directly */
409 if (!SystemToken)
410 {
411 Status = ObInsertObject(AccessToken,
412 NULL,
414 0,
415 NULL,
417 if (!NT_SUCCESS(Status))
418 {
419 DPRINT1("ObInsertObject() failed (Status 0x%lx)\n", Status);
420 }
421 }
422 else
423 {
424 /* Return pointer instead of handle */
425 *TokenHandle = (HANDLE)AccessToken;
426 }
427
428Quit:
429 if (!NT_SUCCESS(Status))
430 {
431 /* Dereference the token, the delete procedure will clean it up */
432 ObDereferenceObject(AccessToken);
433 }
434
435 return Status;
436}
#define ALIGN_UP_BY(size, align)
#define ULONG_PTR
Definition: config.h:101
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
PsGetCurrentThreadId
Definition: CrNtStubs.h:8
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
NTSYSAPI BOOLEAN WINAPI RtlCopySid(DWORD, PSID, PSID)
if(dx< 0)
Definition: linetemp.h:194
#define min(a, b)
Definition: monoChain.cc:55
NTSYSAPI NTSTATUS NTAPI RtlCopySidAndAttributesArray(_In_ ULONG Count, _In_ PSID_AND_ATTRIBUTES Src, _In_ ULONG SidAreaSize, _In_ PSID_AND_ATTRIBUTES Dest, _In_ PSID SidArea, _Out_ PSID *RemainingSidArea, _Out_ PULONG RemainingSidAreaSize)
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ SaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ OwnerSize PSID Owner
Definition: rtlfuncs.h:1597
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ SaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ OwnerSize PSID _Inout_ PULONG _Out_writes_bytes_to_opt_ PrimaryGroupSize PSID PrimaryGroup
Definition: rtlfuncs.h:1599
NTSYSAPI ULONG NTAPI RtlLengthSid(IN PSID Sid)
Definition: sid.c:150
_In_ ULONG _In_ ACCESS_MASK _In_ PSID Sid
Definition: rtlfuncs.h:1133
NTSYSAPI BOOLEAN NTAPI RtlEqualSid(_In_ PSID Sid1, _In_ PSID Sid2)
#define SE_GROUP_MANDATORY
Definition: setypes.h:90
#define SE_GROUP_ENABLED_BY_DEFAULT
Definition: setypes.h:91
#define SE_GROUP_ENABLED
Definition: setypes.h:92
VOID NTAPI ExAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
Definition: uuid.c:335
EPROCESS KiInitialProcess
Definition: krnlinit.c:45
NTSTATUS NTAPI SepRmInsertLogonSessionIntoToken(_Inout_ PTOKEN Token)
Inserts a logon session into an access token specified by the caller.
Definition: srm.c:368
NTSTATUS SepFindPrimaryGroupAndDefaultOwner(_In_ PTOKEN Token, _In_ PSID PrimaryGroup, _In_opt_ PSID DefaultOwner, _Out_opt_ PULONG PrimaryGroupIndex, _Out_opt_ PULONG DefaultOwnerIndex)
Finds the primary group and default owner entity based on the submitted primary group instance and an...
Definition: token.c:1011
NTSTATUS SepCreateTokenLock(_Inout_ PTOKEN Token)
Creates a lock for the token.
Definition: token.c:45
#define TOKEN_CREATE_METHOD
Definition: se.h:80
PSID SeAliasAdminsSid
Definition: sid.c:41
VOID SepUpdatePrivilegeFlagsToken(_Inout_ PTOKEN Token)
Updates the token's flags based upon the privilege that the token has been granted....
Definition: token.c:554
NTSTATUS SepRmReferenceLogonSession(_Inout_ PLUID LogonLuid)
HANDLE NTAPI PsGetCurrentProcessId(VOID)
Definition: process.c:1123
NTSTATUS NTAPI ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL, IN POBJECT_TYPE Type, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN KPROCESSOR_MODE AccessMode, IN OUT PVOID ParseContext OPTIONAL, IN ULONG ObjectSize, IN ULONG PagedPoolCharge OPTIONAL, IN ULONG NonPagedPoolCharge OPTIONAL, OUT PVOID *Object)
Definition: oblife.c:1039
CCHAR SourceName[TOKEN_SOURCE_LENGTH]
Definition: imports.h:278
LUID SourceIdentifier
Definition: imports.h:279
LUID AuthenticationId
Definition: setypes.h:219
ULONG DynamicCharged
Definition: setypes.h:230
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
Definition: setypes.h:240
LUID ModifiedId
Definition: setypes.h:224
ULONG DefaultOwnerIndex
Definition: setypes.h:232
LARGE_INTEGER ExpirationTime
Definition: setypes.h:221
ULONG VariablePart
Definition: setypes.h:253
ULONG PrivilegeCount
Definition: setypes.h:228
PLUID_AND_ATTRIBUTES Privileges
Definition: setypes.h:236
PSID_AND_ATTRIBUTES UserAndGroups
Definition: setypes.h:233
TOKEN_TYPE TokenType
Definition: setypes.h:239
ULONG TokenFlags
Definition: setypes.h:241
ULONG DynamicAvailable
Definition: setypes.h:231
ULONG VariableLength
Definition: setypes.h:229
PACL DefaultDacl
Definition: setypes.h:238
PSID PrimaryGroup
Definition: setypes.h:235
LUID TokenId
Definition: setypes.h:218
PULONG DynamicPart
Definition: setypes.h:237
ULONG UserAndGroupCount
Definition: setypes.h:226
TOKEN_SOURCE TokenSource
Definition: setypes.h:217
#define TAG_TOKEN_DYNAMIC
Definition: tag.h:158
#define SE_TOKEN_DYNAMIC_SLIM
Definition: tokenlif.c:17
void * PVOID
Definition: typedefs.h:50
PVOID HANDLE
Definition: typedefs.h:73
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_Must_inspect_result_ _In_ WDFDMAENABLER _In_ _In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes
#define PsGetCurrentProcess
Definition: psfuncs.h:17
_Out_ PBOOLEAN _Out_ PBOOLEAN _Out_ PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel
Definition: psfuncs.h:156
#define TOKEN_SESSION_NOT_REFERENCED
Definition: setypes.h:1184
struct _LUID_AND_ATTRIBUTES LUID_AND_ATTRIBUTES
#define TOKEN_HAS_ADMIN_GROUP
Definition: setypes.h:1182

Referenced by NtCreateToken(), SepCreateSystemAnonymousLogonToken(), SepCreateSystemAnonymousLogonTokenNoEveryone(), and SepCreateSystemProcessToken().

◆ SepDuplicateToken()

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 
)

Duplicates an access token, from an existing valid token.

Parameters
[in]TokenAccess token to duplicate.
[in]ObjectAttributesObject attributes for the new token.
[in]EffectiveOnlyIf set to TRUE, the function removes all the disabled privileges and groups of the token to duplicate.
[in]TokenTypeType of token.
[in]LevelSecurity impersonation level of a token.
[in]PreviousModeThe processor request level mode.
[out]NewAccessTokenThe duplicated token.
Returns
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.

Definition at line 471 of file tokenlif.c.

479{
481 PTOKEN AccessToken;
482 PVOID EndMem;
483 ULONG PrimaryGroupIndex;
484 ULONG VariableLength;
485 ULONG DynamicPartSize, TotalSize;
486 ULONG PrivilegesIndex, GroupsIndex;
487
488 PAGED_CODE();
489
490 /* Compute how much size we need to allocate for the token */
491 VariableLength = Token->VariableLength;
492 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
493
494 /*
495 * Compute how much size we need to allocate
496 * the dynamic part of the newly duplicated
497 * token.
498 */
499 DynamicPartSize = Token->DefaultDacl ? Token->DefaultDacl->AclSize : 0;
500 DynamicPartSize += RtlLengthSid(Token->PrimaryGroup);
501
506 NULL,
507 TotalSize,
508 Token->DynamicCharged,
509 TotalSize,
510 (PVOID*)&AccessToken);
511 if (!NT_SUCCESS(Status))
512 {
513 DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
514 return Status;
515 }
516
517 /* Zero out the buffer and initialize the token */
518 RtlZeroMemory(AccessToken, TotalSize);
519
520 ExAllocateLocallyUniqueId(&AccessToken->TokenId);
521
522 AccessToken->TokenType = TokenType;
523 AccessToken->ImpersonationLevel = Level;
524
525 /* Initialise the lock for the access token */
526 Status = SepCreateTokenLock(AccessToken);
527 if (!NT_SUCCESS(Status))
528 {
529 ObDereferenceObject(AccessToken);
530 return Status;
531 }
532
533 /* Copy the immutable fields */
534 AccessToken->TokenSource.SourceIdentifier = Token->TokenSource.SourceIdentifier;
536 Token->TokenSource.SourceName,
537 sizeof(Token->TokenSource.SourceName));
538
539 AccessToken->AuthenticationId = Token->AuthenticationId;
540 AccessToken->ParentTokenId = Token->ParentTokenId;
541 AccessToken->ExpirationTime = Token->ExpirationTime;
542 AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession;
543 AccessToken->DynamicCharged = Token->DynamicCharged;
544
545 /* Lock the source token and copy the mutable fields */
547
548 AccessToken->SessionId = Token->SessionId;
549 AccessToken->ModifiedId = Token->ModifiedId;
550
551 AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
552
553 /* Reference the logon session */
555 if (!NT_SUCCESS(Status))
556 {
557 /* No logon session could be found, bail out */
558 DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status);
559 /* Set the flag for proper cleanup by the delete procedure */
561 goto Quit;
562 }
563
564 /* Insert the referenced logon session into the token */
566 if (!NT_SUCCESS(Status))
567 {
568 /* Failed to insert the logon session into the token, bail out */
569 DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n", Status);
570 goto Quit;
571 }
572
573 /* Fill in token debug information */
574#if DBG
575 RtlCopyMemory(AccessToken->ImageFileName,
576 PsGetCurrentProcess()->ImageFileName,
577 min(sizeof(AccessToken->ImageFileName), sizeof(PsGetCurrentProcess()->ImageFileName)));
578
579 AccessToken->ProcessCid = PsGetCurrentProcessId();
580 AccessToken->ThreadCid = PsGetCurrentThreadId();
581 AccessToken->CreateMethod = TOKEN_DUPLICATE_METHOD;
582#endif
583
584 /* Assign the data that reside in the token's variable information area */
585 AccessToken->VariableLength = VariableLength;
586 EndMem = (PVOID)&AccessToken->VariablePart;
587
588 /* Copy the privileges */
589 AccessToken->PrivilegeCount = 0;
590 AccessToken->Privileges = NULL;
591 if (Token->Privileges && (Token->PrivilegeCount > 0))
592 {
593 ULONG PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
594 PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
595
596 ASSERT(VariableLength >= PrivilegesLength);
597
598 AccessToken->PrivilegeCount = Token->PrivilegeCount;
599 AccessToken->Privileges = EndMem;
600 EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
601 VariableLength -= PrivilegesLength;
602
603 RtlCopyMemory(AccessToken->Privileges,
604 Token->Privileges,
605 AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
606 }
607
608 /* Copy the user and groups */
609 AccessToken->UserAndGroupCount = 0;
610 AccessToken->UserAndGroups = NULL;
611 if (Token->UserAndGroups && (Token->UserAndGroupCount > 0))
612 {
613 AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
614 AccessToken->UserAndGroups = EndMem;
615 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
616 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
617
619 Token->UserAndGroups,
620 VariableLength,
621 AccessToken->UserAndGroups,
622 EndMem,
623 &EndMem,
624 &VariableLength);
625 if (!NT_SUCCESS(Status))
626 {
627 DPRINT1("RtlCopySidAndAttributesArray(UserAndGroups) failed (Status 0x%lx)\n", Status);
628 goto Quit;
629 }
630 }
631
632 /* Find the token primary group */
634 Token->PrimaryGroup,
635 NULL,
636 &PrimaryGroupIndex,
637 NULL);
638 if (!NT_SUCCESS(Status))
639 {
640 DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status);
641 goto Quit;
642 }
643
644 /* Copy the restricted SIDs */
645 AccessToken->RestrictedSidCount = 0;
646 AccessToken->RestrictedSids = NULL;
647 if (Token->RestrictedSids && (Token->RestrictedSidCount > 0))
648 {
649 AccessToken->RestrictedSidCount = Token->RestrictedSidCount;
650 AccessToken->RestrictedSids = EndMem;
651 EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount];
652 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids);
653
655 Token->RestrictedSids,
656 VariableLength,
657 AccessToken->RestrictedSids,
658 EndMem,
659 &EndMem,
660 &VariableLength);
661 if (!NT_SUCCESS(Status))
662 {
663 DPRINT1("RtlCopySidAndAttributesArray(RestrictedSids) failed (Status 0x%lx)\n", Status);
664 goto Quit;
665 }
666 }
667
668 /* Now allocate the token's dynamic information area and set the data */
670 DynamicPartSize,
672 if (AccessToken->DynamicPart == NULL)
673 {
675 goto Quit;
676 }
677
678 /* Unused memory in the dynamic area */
679 AccessToken->DynamicAvailable = 0;
680
681 /*
682 * Assign the primary group to the token
683 * and put it in the dynamic part as well.
684 */
685 EndMem = (PVOID)AccessToken->DynamicPart;
686 AccessToken->PrimaryGroup = EndMem;
687 RtlCopySid(RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid),
688 EndMem,
689 AccessToken->UserAndGroups[PrimaryGroupIndex].Sid);
690 AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
691 EndMem = (PVOID)((ULONG_PTR)EndMem + RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid));
692
693 /*
694 * The existing token has a default DACL only
695 * if it has an allocated dynamic part.
696 */
697 if (Token->DynamicPart && Token->DefaultDacl)
698 {
699 AccessToken->DefaultDacl = EndMem;
700
701 RtlCopyMemory(EndMem,
702 Token->DefaultDacl,
703 Token->DefaultDacl->AclSize);
704 }
705
706 /*
707 * Filter the token by removing the disabled privileges
708 * and groups if the caller wants to duplicate an access
709 * token as effective only.
710 */
711 if (EffectiveOnly)
712 {
713 /*
714 * Begin querying the groups and search for disabled ones. Do not touch the
715 * user which is at the first position because it cannot be disabled, no
716 * matter what attributes it has.
717 */
718 for (GroupsIndex = 1; GroupsIndex < AccessToken->UserAndGroupCount; GroupsIndex++)
719 {
720 /*
721 * A group is considered disabled if its attributes is either
722 * 0 or SE_GROUP_ENABLED is not included in the attributes flags list.
723 * That is because a certain user and/or group can have several attributes
724 * that bear no influence on whether a user/group is enabled or not
725 * (SE_GROUP_ENABLED_BY_DEFAULT for example which is a mere indicator
726 * that the group has just been enabled by default). A mandatory
727 * group (that is, the group has SE_GROUP_MANDATORY attribute)
728 * by standards it's always enabled and no one can disable it.
729 */
730 if (AccessToken->UserAndGroups[GroupsIndex].Attributes == 0 ||
731 (AccessToken->UserAndGroups[GroupsIndex].Attributes & SE_GROUP_ENABLED) == 0)
732 {
733 /*
734 * If this group is an administrators group
735 * and the token belongs to such group,
736 * we've to take away TOKEN_HAS_ADMIN_GROUP
737 * for the fact that's not enabled and as
738 * such the token no longer belongs to
739 * this group.
740 */
742 &AccessToken->UserAndGroups[GroupsIndex].Sid))
743 {
744 AccessToken->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP;
745 }
746
747 /*
748 * A group is not enabled, it's time to remove
749 * from the token and update the groups index
750 * accordingly and continue with the next group.
751 */
752 SepRemoveUserGroupToken(AccessToken, GroupsIndex);
753 GroupsIndex--;
754 }
755 }
756
757 /* Begin querying the privileges and search for disabled ones */
758 for (PrivilegesIndex = 0; PrivilegesIndex < AccessToken->PrivilegeCount; PrivilegesIndex++)
759 {
760 /*
761 * A privilege is considered disabled if its attributes is either
762 * 0 or SE_PRIVILEGE_ENABLED is not included in the attributes flags list.
763 * That is because a certain privilege can have several attributes
764 * that bear no influence on whether a privilege is enabled or not
765 * (SE_PRIVILEGE_ENABLED_BY_DEFAULT for example which is a mere indicator
766 * that the privilege has just been enabled by default).
767 */
768 if (AccessToken->Privileges[PrivilegesIndex].Attributes == 0 ||
769 (AccessToken->Privileges[PrivilegesIndex].Attributes & SE_PRIVILEGE_ENABLED) == 0)
770 {
771 /*
772 * A privilege is not enabled, therefor it's time
773 * to strip it from the token and continue with the next
774 * privilege. Of course we must also want to update the
775 * privileges index accordingly.
776 */
777 SepRemovePrivilegeToken(AccessToken, PrivilegesIndex);
778 PrivilegesIndex--;
779 }
780 }
781 }
782
783 /* Return the token to the caller */
784 *NewAccessToken = AccessToken;
786
787Quit:
788 if (!NT_SUCCESS(Status))
789 {
790 /* Dereference the token, the delete procedure will clean it up */
791 ObDereferenceObject(AccessToken);
792 }
793
794 /* Unlock the source token */
796
797 return Status;
798}
#define ASSERT(a)
Definition: mode.c:44
VOID SepRemovePrivilegeToken(_Inout_ PTOKEN Token, _In_ ULONG Index)
Removes a privilege from the token.
Definition: token.c:582
#define SepAcquireTokenLockShared(Token)
Definition: se.h:290
VOID SepRemoveUserGroupToken(_Inout_ PTOKEN Token, _In_ ULONG Index)
Removes a group from the token.
Definition: token.c:618
#define SepReleaseTokenLock(Token)
Definition: se.h:296
#define TOKEN_DUPLICATE_METHOD
Definition: se.h:81
#define STATUS_SUCCESS
Definition: shellext.h:65
PSID_AND_ATTRIBUTES RestrictedSids
Definition: setypes.h:234
ULONG SessionId
Definition: setypes.h:225
LUID ParentTokenId
Definition: setypes.h:220
LUID OriginatingLogonSession
Definition: setypes.h:246
ULONG RestrictedSidCount
Definition: setypes.h:227
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:56
#define SE_PRIVILEGE_ENABLED
Definition: setypes.h:63

Referenced by NtDuplicateToken(), SeCopyClientToken(), SepOpenThreadToken(), and SeSubProcessToken().

◆ SepPerformTokenFiltering()

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 
)
static

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.

Parameters
[in]TokenAn existing and valid access token.
[in]PrivilegesToBeDeletedA 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.
[in]SidsToBeDisabledA list of group SIDs to be disabled within the token. This parameter can be NULL.
[in]RestrictedSidsIntoTokenA list of restricted SIDs to be added into the token. This parameter can be NULL.
[in]PrivilegesCountThe privilege count of the privileges list.
[in]RegularGroupsSidCountThe SIDs count of the group SIDs list.
[in]RestrictedSidsCountThe restricted SIDs count of restricted SIDs list.
[in]PrivilegeFlagsInfluences how the privileges should be filtered in an access token. See NtFilterToken syscall for more information.
[in]PreviousModeProcessor level access mode.
[out]FilteredTokenThe filtered token, returned to the caller.
Returns
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.

Definition at line 859 of file tokenlif.c.

870{
872 PTOKEN AccessToken;
873 PVOID EndMem;
874 ULONG DynamicPartSize;
875 ULONG RestrictedSidsLength;
876 ULONG PrivilegesLength;
877 ULONG PrimaryGroupIndex;
878 ULONG RestrictedSidsInList;
879 ULONG RestrictedSidsInToken;
880 ULONG VariableLength, TotalSize;
881 ULONG PrivsInToken, PrivsInList;
882 ULONG GroupsInToken, GroupsInList;
883 BOOLEAN WantPrivilegesDisabled;
884 BOOLEAN FoundPrivilege;
885 BOOLEAN FoundGroup;
886
887 PAGED_CODE();
888
889 /* Ensure that the source token is valid, and lock it */
890 ASSERT(Token);
892
893 /* Assume the caller doesn't want privileges disabled */
894 WantPrivilegesDisabled = FALSE;
895
896 /* Assume we haven't found anything */
897 FoundPrivilege = FALSE;
898 FoundGroup = FALSE;
899
900 /*
901 * Take the size that we need for filtered token
902 * allocation based upon the existing access token
903 * we've been given.
904 */
905 VariableLength = Token->VariableLength;
906
907 if (RestrictedSidsIntoToken != NULL)
908 {
909 /*
910 * If the caller provided a list of restricted SIDs
911 * to be added onto the filtered access token then
912 * we must compute the size which is the total space
913 * of the current token and the length of the restricted
914 * SIDs for the filtered token.
915 */
916 RestrictedSidsLength = RestrictedSidsCount * sizeof(SID_AND_ATTRIBUTES);
917 RestrictedSidsLength += RtlLengthSidAndAttributes(RestrictedSidsCount, RestrictedSidsIntoToken);
918 RestrictedSidsLength = ALIGN_UP_BY(RestrictedSidsLength, sizeof(PVOID));
919
920 /*
921 * The variable length of the token is not just
922 * the actual space length of the existing token
923 * but also the sum of the restricted SIDs length.
924 */
925 VariableLength += RestrictedSidsLength;
926 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength + RestrictedSidsLength;
927 }
928 else
929 {
930 /* Otherwise the size is of the actual current token */
931 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
932 }
933
934 /*
935 * Compute how much size we need to allocate
936 * the dynamic part of the newly duplicated
937 * token.
938 */
939 DynamicPartSize = Token->DefaultDacl ? Token->DefaultDacl->AclSize : 0;
940 DynamicPartSize += RtlLengthSid(Token->PrimaryGroup);
941
942 /* Set up a filtered token object */
945 NULL,
947 NULL,
948 TotalSize,
949 Token->DynamicCharged,
950 TotalSize,
951 (PVOID*)&AccessToken);
952 if (!NT_SUCCESS(Status))
953 {
954 DPRINT1("SepPerformTokenFiltering(): Failed to create the filtered token object (Status 0x%lx)\n", Status);
955
956 /* Unlock the source token and bail out */
958 return Status;
959 }
960
961 /* Initialize the token and begin filling stuff to it */
962 RtlZeroMemory(AccessToken, TotalSize);
963
964 /* Set up a lock for the new token */
965 Status = SepCreateTokenLock(AccessToken);
966 if (!NT_SUCCESS(Status))
967 goto Quit;
968
969 /* Allocate new IDs for the token */
970 ExAllocateLocallyUniqueId(&AccessToken->TokenId);
972
973 /* Copy the type and impersonation level from the token */
974 AccessToken->TokenType = Token->TokenType;
975 AccessToken->ImpersonationLevel = Token->ImpersonationLevel;
976
977 /* Copy the immutable fields */
978 AccessToken->TokenSource.SourceIdentifier = Token->TokenSource.SourceIdentifier;
980 Token->TokenSource.SourceName,
981 sizeof(Token->TokenSource.SourceName));
982
983 AccessToken->AuthenticationId = Token->AuthenticationId;
984 AccessToken->ParentTokenId = Token->TokenId;
985 AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession;
986 AccessToken->DynamicCharged = Token->DynamicCharged;
987
988 AccessToken->ExpirationTime = Token->ExpirationTime;
989
990 /* Copy the mutable fields */
991 AccessToken->SessionId = Token->SessionId;
992 AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
993
994 /* Reference the logon session */
996 if (!NT_SUCCESS(Status))
997 {
998 /* We failed, bail out*/
999 DPRINT1("SepPerformTokenFiltering(): Failed to reference the logon session (Status 0x%lx)\n", Status);
1001 goto Quit;
1002 }
1003
1004 /* Insert the referenced logon session into the token */
1006 if (!NT_SUCCESS(Status))
1007 {
1008 /* Failed to insert the logon session into the token, bail out */
1009 DPRINT1("SepPerformTokenFiltering(): Failed to insert the logon session into token (Status 0x%lx)\n", Status);
1010 goto Quit;
1011 }
1012
1013 /* Fill in token debug information */
1014#if DBG
1015 RtlCopyMemory(AccessToken->ImageFileName,
1016 PsGetCurrentProcess()->ImageFileName,
1017 min(sizeof(AccessToken->ImageFileName), sizeof(PsGetCurrentProcess()->ImageFileName)));
1018
1019 AccessToken->ProcessCid = PsGetCurrentProcessId();
1020 AccessToken->ThreadCid = PsGetCurrentThreadId();
1021 AccessToken->CreateMethod = TOKEN_FILTER_METHOD;
1022#endif
1023
1024 /* Assign the data that reside in the token's variable information area */
1025 AccessToken->VariableLength = VariableLength;
1026 EndMem = (PVOID)&AccessToken->VariablePart;
1027
1028 /* Copy the privileges from the existing token */
1029 AccessToken->PrivilegeCount = 0;
1030 AccessToken->Privileges = NULL;
1031 if (Token->Privileges && (Token->PrivilegeCount > 0))
1032 {
1033 PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
1034 PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
1035
1036 /*
1037 * Ensure that the token can actually hold all
1038 * the privileges from the existing token.
1039 * Otherwise something's seriously wrong and
1040 * we've to guard ourselves.
1041 */
1042 ASSERT(VariableLength >= PrivilegesLength);
1043
1044 AccessToken->PrivilegeCount = Token->PrivilegeCount;
1045 AccessToken->Privileges = EndMem;
1046 EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
1047 VariableLength -= PrivilegesLength;
1048
1049 RtlCopyMemory(AccessToken->Privileges,
1050 Token->Privileges,
1051 AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1052 }
1053
1054 /* Copy the user and groups */
1055 AccessToken->UserAndGroupCount = 0;
1056 AccessToken->UserAndGroups = NULL;
1057 if (Token->UserAndGroups && (Token->UserAndGroupCount > 0))
1058 {
1059 AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
1060 AccessToken->UserAndGroups = EndMem;
1061 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
1062 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
1063
1065 Token->UserAndGroups,
1066 VariableLength,
1067 AccessToken->UserAndGroups,
1068 EndMem,
1069 &EndMem,
1070 &VariableLength);
1071 if (!NT_SUCCESS(Status))
1072 {
1073 DPRINT1("SepPerformTokenFiltering(): Failed to copy the groups into token (Status 0x%lx)\n", Status);
1074 goto Quit;
1075 }
1076 }
1077
1078 /* Copy the restricted SIDs */
1079 AccessToken->RestrictedSidCount = 0;
1080 AccessToken->RestrictedSids = NULL;
1081 if (Token->RestrictedSids && (Token->RestrictedSidCount > 0))
1082 {
1083 AccessToken->RestrictedSidCount = Token->RestrictedSidCount;
1084 AccessToken->RestrictedSids = EndMem;
1085 EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount];
1086 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids);
1087
1089 Token->RestrictedSids,
1090 VariableLength,
1091 AccessToken->RestrictedSids,
1092 EndMem,
1093 &EndMem,
1094 &VariableLength);
1095 if (!NT_SUCCESS(Status))
1096 {
1097 DPRINT1("SepPerformTokenFiltering(): Failed to copy the restricted SIDs into token (Status 0x%lx)\n", Status);
1098 goto Quit;
1099 }
1100 }
1101
1102 /*
1103 * Insert the restricted SIDs into the token on
1104 * the request by the caller.
1105 */
1106 if (RestrictedSidsIntoToken != NULL)
1107 {
1108 for (RestrictedSidsInList = 0; RestrictedSidsInList < RestrictedSidsCount; RestrictedSidsInList++)
1109 {
1110 /* Did the caller assign attributes to the restricted SIDs? */
1111 if (RestrictedSidsIntoToken[RestrictedSidsInList].Attributes != 0)
1112 {
1113 /* There mustn't be any attributes, bail out */
1114 DPRINT1("SepPerformTokenFiltering(): There mustn't be any attributes to restricted SIDs!\n");
1116 goto Quit;
1117 }
1118 }
1119
1120 /*
1121 * Ensure that the token can hold the restricted SIDs
1122 * (the variable length is calculated at the beginning
1123 * of the routine call).
1124 */
1125 ASSERT(VariableLength >= RestrictedSidsLength);
1126
1127 /*
1128 * Now let's begin inserting the restricted SIDs into the filtered
1129 * access token from the list the caller gave us.
1130 */
1131 AccessToken->RestrictedSidCount = RestrictedSidsCount;
1132 AccessToken->RestrictedSids = EndMem;
1133 EndMem = (PVOID)((ULONG_PTR)EndMem + RestrictedSidsLength);
1134 VariableLength -= RestrictedSidsLength;
1135
1136 RtlCopyMemory(AccessToken->RestrictedSids,
1137 RestrictedSidsIntoToken,
1138 AccessToken->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
1139
1140 /*
1141 * As we've copied the restricted SIDs into
1142 * the token, we must assign them the following
1143 * combination of attributes SE_GROUP_ENABLED,
1144 * SE_GROUP_ENABLED_BY_DEFAULT and SE_GROUP_MANDATORY.
1145 * With such attributes we estabilish that restricting
1146 * SIDs into the token are enabled for access checks.
1147 */
1148 for (RestrictedSidsInToken = 0; RestrictedSidsInToken < AccessToken->RestrictedSidCount; RestrictedSidsInToken++)
1149 {
1151 }
1152
1153 /*
1154 * As we added restricted SIDs into the token, mark
1155 * it as restricted.
1156 */
1157 AccessToken->TokenFlags |= TOKEN_IS_RESTRICTED;
1158 }
1159
1160 /* Search for the primary group */
1162 Token->PrimaryGroup,
1163 NULL,
1164 &PrimaryGroupIndex,
1165 NULL);
1166 if (!NT_SUCCESS(Status))
1167 {
1168 DPRINT1("SepPerformTokenFiltering(): Failed searching for the primary group (Status 0x%lx)\n", Status);
1169 goto Quit;
1170 }
1171
1172 /* Now allocate the token's dynamic information area and set the data */
1174 DynamicPartSize,
1176 if (AccessToken->DynamicPart == NULL)
1177 {
1179 goto Quit;
1180 }
1181
1182 /* Unused memory in the dynamic area */
1183 AccessToken->DynamicAvailable = 0;
1184
1185 /*
1186 * Assign the primary group to the token
1187 * and put it in the dynamic part as well.
1188 */
1189 EndMem = (PVOID)AccessToken->DynamicPart;
1190 AccessToken->PrimaryGroup = EndMem;
1191 RtlCopySid(RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid),
1192 EndMem,
1193 AccessToken->UserAndGroups[PrimaryGroupIndex].Sid);
1194 AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
1195 EndMem = (PVOID)((ULONG_PTR)EndMem + RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid));
1196
1197 /*
1198 * The existing token has a default DACL only
1199 * if it has an allocated dynamic part.
1200 */
1201 if (Token->DynamicPart && Token->DefaultDacl)
1202 {
1203 AccessToken->DefaultDacl = EndMem;
1204
1205 RtlCopyMemory(EndMem,
1206 Token->DefaultDacl,
1207 Token->DefaultDacl->AclSize);
1208 }
1209
1210 /*
1211 * Now figure out what does the caller
1212 * want with the privileges.
1213 */
1214 if (PrivilegeFlags & DISABLE_MAX_PRIVILEGE)
1215 {
1216 /*
1217 * The caller wants them disabled, cache this request
1218 * for later operations.
1219 */
1220 WantPrivilegesDisabled = TRUE;
1221 }
1222
1223 if (PrivilegeFlags & SANDBOX_INERT)
1224 {
1225 /* The caller wants an inert token, store the TOKEN_SANDBOX_INERT flag now */
1226 AccessToken->TokenFlags |= TOKEN_SANDBOX_INERT;
1227 }
1228
1229 /*
1230 * Now it's time to filter the token's privileges.
1231 * Loop all the privileges in the token.
1232 */
1233 for (PrivsInToken = 0; PrivsInToken < AccessToken->PrivilegeCount; PrivsInToken++)
1234 {
1235 if (WantPrivilegesDisabled)
1236 {
1237 /*
1238 * We got the acknowledgement that the caller wants
1239 * to disable all the privileges so let's just do it.
1240 * However, as per the general documentation is stated
1241 * that only SE_CHANGE_NOTIFY_PRIVILEGE must be kept
1242 * therefore in that case we must skip this privilege.
1243 */
1244 if (AccessToken->Privileges[PrivsInToken].Luid.LowPart == SE_CHANGE_NOTIFY_PRIVILEGE)
1245 {
1246 continue;
1247 }
1248 else
1249 {
1250 /*
1251 * The act of disabling privileges actually means
1252 * "deleting" them from the access token entirely.
1253 * First we must disable them so that we can update
1254 * token flags accordingly.
1255 */
1256 AccessToken->Privileges[PrivsInToken].Attributes &= ~SE_PRIVILEGE_ENABLED;
1257 SepUpdateSinglePrivilegeFlagToken(AccessToken, PrivsInToken);
1258
1259 /* Remove the privileges now */
1260 SepRemovePrivilegeToken(AccessToken, PrivsInToken);
1261 PrivsInToken--;
1262 }
1263 }
1264 else
1265 {
1266 if (PrivilegesToBeDeleted != NULL)
1267 {
1268 /* Loop the privileges we've got to delete */
1269 for (PrivsInList = 0; PrivsInList < PrivilegesCount; PrivsInList++)
1270 {
1271 /* Does this privilege exist in the token? */
1272 if (RtlEqualLuid(&AccessToken->Privileges[PrivsInToken].Luid,
1273 &PrivilegesToBeDeleted[PrivsInList].Luid))
1274 {
1275 /* Mark that we found it */
1276 FoundPrivilege = TRUE;
1277 break;
1278 }
1279 }
1280
1281 /* Did we find the privilege? */
1282 if (PrivsInList == PrivilegesCount)
1283 {
1284 /* We didn't, continue with next one */
1285 continue;
1286 }
1287 }
1288 }
1289
1290 /*
1291 * If we have found the target privilege in the token
1292 * based on the privileges list given by the caller
1293 * then begin deleting it.
1294 */
1295 if (FoundPrivilege)
1296 {
1297 /* Disable the privilege and update the flags */
1298 AccessToken->Privileges[PrivsInToken].Attributes &= ~SE_PRIVILEGE_ENABLED;
1299 SepUpdateSinglePrivilegeFlagToken(AccessToken, PrivsInToken);
1300
1301 /* Delete the privilege */
1302 SepRemovePrivilegeToken(AccessToken, PrivsInToken);
1303
1304 /*
1305 * Adjust the index and reset the FoundPrivilege indicator
1306 * so that we can continue with the next privilege to delete.
1307 */
1308 PrivsInToken--;
1309 FoundPrivilege = FALSE;
1310 continue;
1311 }
1312 }
1313
1314 /*
1315 * Loop the group SIDs that we want to disable as
1316 * per on the request by the caller.
1317 */
1318 if (SidsToBeDisabled != NULL)
1319 {
1320 for (GroupsInToken = 0; GroupsInToken < AccessToken->UserAndGroupCount; GroupsInToken++)
1321 {
1322 for (GroupsInList = 0; GroupsInList < RegularGroupsSidCount; GroupsInList++)
1323 {
1324 /* Does this group SID exist in the token? */
1325 if (RtlEqualSid(&AccessToken->UserAndGroups[GroupsInToken].Sid,
1326 &SidsToBeDisabled[GroupsInList].Sid))
1327 {
1328 /* Mark that we found it */
1329 FoundGroup = TRUE;
1330 break;
1331 }
1332 }
1333
1334 /* Did we find the group? */
1335 if (GroupsInList == RegularGroupsSidCount)
1336 {
1337 /* We didn't, continue with next one */
1338 continue;
1339 }
1340
1341 /* If we have found the group, disable it */
1342 if (FoundGroup)
1343 {
1344 /*
1345 * If the acess token belongs to the administrators
1346 * group and this is the target group, we must take
1347 * away TOKEN_HAS_ADMIN_GROUP flag from the token.
1348 */
1350 &AccessToken->UserAndGroups[GroupsInToken].Sid))
1351 {
1352 AccessToken->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP;
1353 }
1354
1355 /*
1356 * If the target group that we have found it is the
1357 * owner then from now on it no longer is but the user.
1358 * Therefore assign the default owner index as the user.
1359 */
1360 if (AccessToken->DefaultOwnerIndex == GroupsInToken)
1361 {
1362 AccessToken->DefaultOwnerIndex = 0;
1363 }
1364
1365 /*
1366 * The principle of disabling a group SID is by
1367 * taking away SE_GROUP_ENABLED_BY_DEFAULT and
1368 * SE_GROUP_ENABLED attributes and assign
1369 * SE_GROUP_USE_FOR_DENY_ONLY. This renders
1370 * SID a "Deny only" SID.
1371 */
1372 AccessToken->UserAndGroups[GroupsInToken].Attributes &= ~(SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
1373 AccessToken->UserAndGroups[GroupsInToken].Attributes |= SE_GROUP_USE_FOR_DENY_ONLY;
1374
1375 /* Adjust the index and continue with the next group */
1376 GroupsInToken--;
1377 FoundGroup = FALSE;
1378 continue;
1379 }
1380 }
1381 }
1382
1383 /* We've finally filtered the token, return it to the caller */
1384 *FilteredToken = AccessToken;
1386 DPRINT("SepPerformTokenFiltering(): The token has been filtered!\n");
1387
1388Quit:
1389 if (!NT_SUCCESS(Status))
1390 {
1391 /* Dereference the created token */
1392 ObDereferenceObject(AccessToken);
1393 }
1394
1395 /* Unlock the source token */
1397
1398 return Status;
1399}
#define SE_CHANGE_NOTIFY_PRIVILEGE
Definition: security.c:677
#define SE_GROUP_USE_FOR_DENY_ONLY
Definition: setypes.h:94
#define DISABLE_MAX_PRIVILEGE
Definition: setypes.h:114
#define SANDBOX_INERT
Definition: setypes.h:115
ULONG RtlLengthSidAndAttributes(_In_ ULONG Count, _In_ PSID_AND_ATTRIBUTES Src)
Computes the length size of a SID.
Definition: token.c:965
VOID SepUpdateSinglePrivilegeFlagToken(_Inout_ PTOKEN Token, _In_ ULONG Index)
Updates the token's flags based upon the privilege that the token has been granted....
Definition: token.c:442
#define TOKEN_FILTER_METHOD
Definition: se.h:82
#define DPRINT
Definition: sndvol32.h:71
DWORD LowPart
#define RtlEqualLuid(Luid1, Luid2)
Definition: rtlfuncs.h:301
struct _SID_AND_ATTRIBUTES SID_AND_ATTRIBUTES
#define TOKEN_SANDBOX_INERT
Definition: setypes.h:1185
#define TOKEN_IS_RESTRICTED
Definition: setypes.h:1183

Referenced by NtFilterToken(), and SeFilterToken().