xref: /reactos/ntoskrnl/se/tokenlif.c (revision a389f8aa)
19a2c62b5SGeorge Bișoc /*
29a2c62b5SGeorge Bișoc  * PROJECT:     ReactOS Kernel
39a2c62b5SGeorge Bișoc  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
49a2c62b5SGeorge Bișoc  * PURPOSE:     Access token lifetime management implementation (Creation/Duplication/Filtering)
59a2c62b5SGeorge Bișoc  * COPYRIGHT:   Copyright David Welch <welch@cwcom.net>
69a2c62b5SGeorge Bișoc  *              Copyright 2021-2022 George Bișoc <george.bisoc@reactos.org>
79a2c62b5SGeorge Bișoc  */
89a2c62b5SGeorge Bișoc 
99a2c62b5SGeorge Bișoc /* INCLUDES *******************************************************************/
109a2c62b5SGeorge Bișoc 
119a2c62b5SGeorge Bișoc #include <ntoskrnl.h>
129a2c62b5SGeorge Bișoc #define NDEBUG
139a2c62b5SGeorge Bișoc #include <debug.h>
149a2c62b5SGeorge Bișoc 
154471ee4dSGeorge Bișoc /* DEFINES ********************************************************************/
164471ee4dSGeorge Bișoc 
174471ee4dSGeorge Bișoc #define SE_TOKEN_DYNAMIC_SLIM 500
184471ee4dSGeorge Bișoc 
199a2c62b5SGeorge Bișoc /* PRIVATE FUNCTIONS *********************************************************/
209a2c62b5SGeorge Bișoc 
219a2c62b5SGeorge Bișoc /**
229a2c62b5SGeorge Bișoc  * @brief
239a2c62b5SGeorge Bișoc  * Internal function responsible for access token object creation in the kernel.
249a2c62b5SGeorge Bișoc  * A fully created token objected is inserted into the token handle, thus the handle
259a2c62b5SGeorge Bișoc  * becoming a valid handle to an access token object and ready for use.
269a2c62b5SGeorge Bișoc  *
279a2c62b5SGeorge Bișoc  * @param[out] TokenHandle
289a2c62b5SGeorge Bișoc  * Valid token handle that's ready for use after token creation and object insertion.
299a2c62b5SGeorge Bișoc  *
309a2c62b5SGeorge Bișoc  * @param[in] PreviousMode
319a2c62b5SGeorge Bișoc  * Processor request level mode.
329a2c62b5SGeorge Bișoc  *
339a2c62b5SGeorge Bișoc  * @param[in] DesiredAccess
349a2c62b5SGeorge Bișoc  * Desired access right for the token object to be granted. This kind of access right
359a2c62b5SGeorge Bișoc  * impacts how the token can be used and who.
369a2c62b5SGeorge Bișoc  *
379a2c62b5SGeorge Bișoc  * @param[in] ObjectAttributes
389a2c62b5SGeorge Bișoc  * Object attributes for the token to be created.
399a2c62b5SGeorge Bișoc  *
409a2c62b5SGeorge Bișoc  * @param[in] TokenType
419a2c62b5SGeorge Bișoc  * Type of token to assign upon creation.
429a2c62b5SGeorge Bișoc  *
439a2c62b5SGeorge Bișoc  * @param[in] ImpersonationLevel
449a2c62b5SGeorge Bișoc  * Security impersonation level of token to assign upon creation.
459a2c62b5SGeorge Bișoc  *
469a2c62b5SGeorge Bișoc  * @param[in] AuthenticationId
479a2c62b5SGeorge Bișoc  * Authentication ID that represents the authentication information of the token.
489a2c62b5SGeorge Bișoc  *
499a2c62b5SGeorge Bișoc  * @param[in] ExpirationTime
509a2c62b5SGeorge Bișoc  * Expiration time of the token to assign. A value of -1 means that the token never
519a2c62b5SGeorge Bișoc  * expires and its life depends upon the amount of references this token object has.
529a2c62b5SGeorge Bișoc  *
539a2c62b5SGeorge Bișoc  * @param[in] User
549a2c62b5SGeorge Bișoc  * User entry to assign to the token.
559a2c62b5SGeorge Bișoc  *
569a2c62b5SGeorge Bișoc  * @param[in] GroupCount
579a2c62b5SGeorge Bișoc  * The total number of groups count for the token.
589a2c62b5SGeorge Bișoc  *
599a2c62b5SGeorge Bișoc  * @param[in] Groups
609a2c62b5SGeorge Bișoc  * The group entries for the token.
619a2c62b5SGeorge Bișoc  *
629a2c62b5SGeorge Bișoc  * @param[in] GroupsLength
639a2c62b5SGeorge Bișoc  * The length size of the groups array, pointed by the Groups parameter.
649a2c62b5SGeorge Bișoc  *
659a2c62b5SGeorge Bișoc  * @param[in] PrivilegeCount
669a2c62b5SGeorge Bișoc  * The total number of priivleges that the newly created token has.
679a2c62b5SGeorge Bișoc  *
689a2c62b5SGeorge Bișoc  * @param[in] Privileges
699a2c62b5SGeorge Bișoc  * The privileges for the token.
709a2c62b5SGeorge Bișoc  *
719a2c62b5SGeorge Bișoc  * @param[in] Owner
729a2c62b5SGeorge Bișoc  * The main user (or also owner) that represents the token that we create.
739a2c62b5SGeorge Bișoc  *
749a2c62b5SGeorge Bișoc  * @param[in] PrimaryGroup
759a2c62b5SGeorge Bișoc  * The main group that represents the token that we create.
769a2c62b5SGeorge Bișoc  *
779a2c62b5SGeorge Bișoc  * @param[in] DefaultDacl
789a2c62b5SGeorge Bișoc  * A discretionary access control list for the token.
799a2c62b5SGeorge Bișoc  *
809a2c62b5SGeorge Bișoc  * @param[in] TokenSource
819a2c62b5SGeorge Bișoc  * Source (or the origin) of the access token that creates it.
829a2c62b5SGeorge Bișoc  *
839a2c62b5SGeorge Bișoc  * @param[in] SystemToken
849a2c62b5SGeorge Bișoc  * If set to TRUE, the newly created token is a system token and only in charge
859a2c62b5SGeorge Bișoc  * by the internal system. The function directly returns a pointer to the
869a2c62b5SGeorge Bișoc  * created token object for system kernel use. Otherwise if set to FALSE, the
879a2c62b5SGeorge Bișoc  * function inserts the object to a handle making it a regular access token.
889a2c62b5SGeorge Bișoc  *
899a2c62b5SGeorge Bișoc  * @return
909a2c62b5SGeorge Bișoc  * Returns STATUS_SUCCESS if token creation has completed successfully.
919a2c62b5SGeorge Bișoc  * STATUS_INSUFFICIENT_RESOURCES is returned if the dynamic area of memory of the
929a2c62b5SGeorge Bișoc  * token hasn't been allocated because of lack of memory resources. A failure
939a2c62b5SGeorge Bișoc  * NTSTATUS code is returned otherwise.
949a2c62b5SGeorge Bișoc  */
959a2c62b5SGeorge Bișoc NTSTATUS
969a2c62b5SGeorge Bișoc 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)979a2c62b5SGeorge Bișoc SepCreateToken(
989a2c62b5SGeorge Bișoc     _Out_ PHANDLE TokenHandle,
999a2c62b5SGeorge Bișoc     _In_ KPROCESSOR_MODE PreviousMode,
1009a2c62b5SGeorge Bișoc     _In_ ACCESS_MASK DesiredAccess,
1019a2c62b5SGeorge Bișoc     _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
1029a2c62b5SGeorge Bișoc     _In_ TOKEN_TYPE TokenType,
1039a2c62b5SGeorge Bișoc     _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
1049a2c62b5SGeorge Bișoc     _In_ PLUID AuthenticationId,
1059a2c62b5SGeorge Bișoc     _In_ PLARGE_INTEGER ExpirationTime,
1069a2c62b5SGeorge Bișoc     _In_ PSID_AND_ATTRIBUTES User,
1079a2c62b5SGeorge Bișoc     _In_ ULONG GroupCount,
1089a2c62b5SGeorge Bișoc     _In_ PSID_AND_ATTRIBUTES Groups,
1099a2c62b5SGeorge Bișoc     _In_ ULONG GroupsLength,
1109a2c62b5SGeorge Bișoc     _In_ ULONG PrivilegeCount,
1119a2c62b5SGeorge Bișoc     _In_ PLUID_AND_ATTRIBUTES Privileges,
1129a2c62b5SGeorge Bișoc     _In_opt_ PSID Owner,
1139a2c62b5SGeorge Bișoc     _In_ PSID PrimaryGroup,
1149a2c62b5SGeorge Bișoc     _In_opt_ PACL DefaultDacl,
1159a2c62b5SGeorge Bișoc     _In_ PTOKEN_SOURCE TokenSource,
1169a2c62b5SGeorge Bișoc     _In_ BOOLEAN SystemToken)
1179a2c62b5SGeorge Bișoc {
1189a2c62b5SGeorge Bișoc     NTSTATUS Status;
1199a2c62b5SGeorge Bișoc     PTOKEN AccessToken;
1209a2c62b5SGeorge Bișoc     ULONG TokenFlags = 0;
1219a2c62b5SGeorge Bișoc     ULONG PrimaryGroupIndex, DefaultOwnerIndex;
1229a2c62b5SGeorge Bișoc     LUID TokenId;
1239a2c62b5SGeorge Bișoc     LUID ModifiedId;
1249a2c62b5SGeorge Bișoc     PVOID EndMem;
1259a2c62b5SGeorge Bișoc     ULONG PrivilegesLength;
1269a2c62b5SGeorge Bișoc     ULONG UserGroupsLength;
1279a2c62b5SGeorge Bișoc     ULONG VariableLength;
1284471ee4dSGeorge Bișoc     ULONG DynamicPartSize, TotalSize;
1294471ee4dSGeorge Bișoc     ULONG TokenPagedCharges;
1309a2c62b5SGeorge Bișoc     ULONG i;
1319a2c62b5SGeorge Bișoc 
1329a2c62b5SGeorge Bișoc     PAGED_CODE();
1339a2c62b5SGeorge Bișoc 
1349a2c62b5SGeorge Bișoc     /* Loop all groups */
1359a2c62b5SGeorge Bișoc     for (i = 0; i < GroupCount; i++)
1369a2c62b5SGeorge Bișoc     {
1379a2c62b5SGeorge Bișoc         /* Check for mandatory groups */
1389a2c62b5SGeorge Bișoc         if (Groups[i].Attributes & SE_GROUP_MANDATORY)
1399a2c62b5SGeorge Bișoc         {
1409a2c62b5SGeorge Bișoc             /* Force them to be enabled */
1419a2c62b5SGeorge Bișoc             Groups[i].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
1429a2c62b5SGeorge Bișoc         }
1439a2c62b5SGeorge Bișoc 
1449a2c62b5SGeorge Bișoc         /* Check of the group is an admin group */
1459a2c62b5SGeorge Bișoc         if (RtlEqualSid(SeAliasAdminsSid, Groups[i].Sid))
1469a2c62b5SGeorge Bișoc         {
1479a2c62b5SGeorge Bișoc             /* Remember this so we can optimize queries later */
1489a2c62b5SGeorge Bișoc             TokenFlags |= TOKEN_HAS_ADMIN_GROUP;
1499a2c62b5SGeorge Bișoc         }
1509a2c62b5SGeorge Bișoc     }
1519a2c62b5SGeorge Bișoc 
1529a2c62b5SGeorge Bișoc     /* Allocate unique IDs for the token */
1539a2c62b5SGeorge Bișoc     ExAllocateLocallyUniqueId(&TokenId);
1549a2c62b5SGeorge Bișoc     ExAllocateLocallyUniqueId(&ModifiedId);
1559a2c62b5SGeorge Bișoc 
1569a2c62b5SGeorge Bișoc     /* Compute how much size we need to allocate for the token */
1579a2c62b5SGeorge Bișoc 
1589a2c62b5SGeorge Bișoc     /* Privileges size */
1599a2c62b5SGeorge Bișoc     PrivilegesLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
1609a2c62b5SGeorge Bișoc     PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
1619a2c62b5SGeorge Bișoc 
1629a2c62b5SGeorge Bișoc     /* User and groups size */
1639a2c62b5SGeorge Bișoc     UserGroupsLength = (1 + GroupCount) * sizeof(SID_AND_ATTRIBUTES);
1649a2c62b5SGeorge Bișoc     UserGroupsLength += RtlLengthSid(User->Sid);
1659a2c62b5SGeorge Bișoc     for (i = 0; i < GroupCount; i++)
1669a2c62b5SGeorge Bișoc     {
1679a2c62b5SGeorge Bișoc         UserGroupsLength += RtlLengthSid(Groups[i].Sid);
1689a2c62b5SGeorge Bișoc     }
1699a2c62b5SGeorge Bișoc     UserGroupsLength = ALIGN_UP_BY(UserGroupsLength, sizeof(PVOID));
1709a2c62b5SGeorge Bișoc 
1719a2c62b5SGeorge Bișoc     /* Add the additional groups array length */
1729a2c62b5SGeorge Bișoc     UserGroupsLength += ALIGN_UP_BY(GroupsLength, sizeof(PVOID));
1739a2c62b5SGeorge Bișoc 
1749a2c62b5SGeorge Bișoc     VariableLength = PrivilegesLength + UserGroupsLength;
1759a2c62b5SGeorge Bișoc     TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
1769a2c62b5SGeorge Bișoc 
1774471ee4dSGeorge Bișoc     /*
1784471ee4dSGeorge Bișoc      * A token is considered slim if it has the default dynamic
1794471ee4dSGeorge Bișoc      * contents, or in other words, the primary group and ACL.
1804471ee4dSGeorge Bișoc      * We judge if such contents are default by checking their
1814471ee4dSGeorge Bișoc      * total size if it's over the range. On Windows this range
1824471ee4dSGeorge Bișoc      * is 0x1F4 (aka 500). If the size of the whole dynamic contents
1834471ee4dSGeorge Bișoc      * is over that range then the token is considered fat and
1844471ee4dSGeorge Bișoc      * the token will be charged the whole of its token body length
1854471ee4dSGeorge Bișoc      * plus the dynamic size.
1864471ee4dSGeorge Bișoc      */
1874471ee4dSGeorge Bișoc     DynamicPartSize = DefaultDacl ? DefaultDacl->AclSize : 0;
1884471ee4dSGeorge Bișoc     DynamicPartSize += RtlLengthSid(PrimaryGroup);
1894471ee4dSGeorge Bișoc     if (DynamicPartSize > SE_TOKEN_DYNAMIC_SLIM)
1904471ee4dSGeorge Bișoc     {
1914471ee4dSGeorge Bișoc         TokenPagedCharges = DynamicPartSize + TotalSize;
1924471ee4dSGeorge Bișoc     }
1934471ee4dSGeorge Bișoc     else
1944471ee4dSGeorge Bișoc     {
1954471ee4dSGeorge Bișoc         TokenPagedCharges = SE_TOKEN_DYNAMIC_SLIM + TotalSize;
1964471ee4dSGeorge Bișoc     }
1974471ee4dSGeorge Bișoc 
1989a2c62b5SGeorge Bișoc     Status = ObCreateObject(PreviousMode,
1999a2c62b5SGeorge Bișoc                             SeTokenObjectType,
2009a2c62b5SGeorge Bișoc                             ObjectAttributes,
2019a2c62b5SGeorge Bișoc                             PreviousMode,
2029a2c62b5SGeorge Bișoc                             NULL,
2039a2c62b5SGeorge Bișoc                             TotalSize,
2044471ee4dSGeorge Bișoc                             TokenPagedCharges,
2059a2c62b5SGeorge Bișoc                             0,
2069a2c62b5SGeorge Bișoc                             (PVOID*)&AccessToken);
2079a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
2089a2c62b5SGeorge Bișoc     {
2099a2c62b5SGeorge Bișoc         DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
2109a2c62b5SGeorge Bișoc         return Status;
2119a2c62b5SGeorge Bișoc     }
2129a2c62b5SGeorge Bișoc 
2139a2c62b5SGeorge Bișoc     /* Zero out the buffer and initialize the token */
2149a2c62b5SGeorge Bișoc     RtlZeroMemory(AccessToken, TotalSize);
2159a2c62b5SGeorge Bișoc 
2169a2c62b5SGeorge Bișoc     AccessToken->TokenId = TokenId;
2179a2c62b5SGeorge Bișoc     AccessToken->TokenType = TokenType;
2189a2c62b5SGeorge Bișoc     AccessToken->ImpersonationLevel = ImpersonationLevel;
2199a2c62b5SGeorge Bișoc 
2209a2c62b5SGeorge Bișoc     /* Initialise the lock for the access token */
2219a2c62b5SGeorge Bișoc     Status = SepCreateTokenLock(AccessToken);
2229a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
2239a2c62b5SGeorge Bișoc         goto Quit;
2249a2c62b5SGeorge Bișoc 
2259a2c62b5SGeorge Bișoc     AccessToken->TokenSource.SourceIdentifier = TokenSource->SourceIdentifier;
2269a2c62b5SGeorge Bișoc     RtlCopyMemory(AccessToken->TokenSource.SourceName,
2279a2c62b5SGeorge Bișoc                   TokenSource->SourceName,
2289a2c62b5SGeorge Bișoc                   sizeof(TokenSource->SourceName));
2299a2c62b5SGeorge Bișoc 
2309a2c62b5SGeorge Bișoc     AccessToken->ExpirationTime = *ExpirationTime;
2319a2c62b5SGeorge Bișoc     AccessToken->ModifiedId = ModifiedId;
2324471ee4dSGeorge Bișoc     AccessToken->DynamicCharged = TokenPagedCharges - TotalSize;
2339a2c62b5SGeorge Bișoc 
2349a2c62b5SGeorge Bișoc     AccessToken->TokenFlags = TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
2359a2c62b5SGeorge Bișoc 
2369a2c62b5SGeorge Bișoc     /* Copy and reference the logon session */
2379a2c62b5SGeorge Bișoc     AccessToken->AuthenticationId = *AuthenticationId;
2389a2c62b5SGeorge Bișoc     Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
2399a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
2409a2c62b5SGeorge Bișoc     {
2419a2c62b5SGeorge Bișoc         /* No logon session could be found, bail out */
2429a2c62b5SGeorge Bișoc         DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status);
2439a2c62b5SGeorge Bișoc         /* Set the flag for proper cleanup by the delete procedure */
2449a2c62b5SGeorge Bișoc         AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
2459a2c62b5SGeorge Bișoc         goto Quit;
2469a2c62b5SGeorge Bișoc     }
2479a2c62b5SGeorge Bișoc 
2489a2c62b5SGeorge Bișoc     /* Insert the referenced logon session into the token */
2499a2c62b5SGeorge Bișoc     Status = SepRmInsertLogonSessionIntoToken(AccessToken);
2509a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
2519a2c62b5SGeorge Bișoc     {
2529a2c62b5SGeorge Bișoc         /* Failed to insert the logon session into the token, bail out */
2539a2c62b5SGeorge Bișoc         DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n", Status);
2549a2c62b5SGeorge Bișoc         goto Quit;
2559a2c62b5SGeorge Bișoc     }
2569a2c62b5SGeorge Bișoc 
2579a2c62b5SGeorge Bișoc     /* Fill in token debug information */
2589a2c62b5SGeorge Bișoc #if DBG
2599a2c62b5SGeorge Bișoc     /*
2609a2c62b5SGeorge Bișoc      * We must determine ourselves that the current
2619a2c62b5SGeorge Bișoc      * process is not the initial CPU one. The initial
2629a2c62b5SGeorge Bișoc      * process is not a "real" process, that is, the
2639a2c62b5SGeorge Bișoc      * Process Manager has not yet been initialized and
2649a2c62b5SGeorge Bișoc      * as a matter of fact we are creating a token before
2659a2c62b5SGeorge Bișoc      * any process gets created by Ps. If it turns out
2669a2c62b5SGeorge Bișoc      * that the current process is the initial CPU process
2679a2c62b5SGeorge Bișoc      * where token creation execution takes place, don't
2689a2c62b5SGeorge Bișoc      * do anything.
2699a2c62b5SGeorge Bișoc      */
2709a2c62b5SGeorge Bișoc     if (PsGetCurrentProcess() != &KiInitialProcess)
2719a2c62b5SGeorge Bișoc     {
2729a2c62b5SGeorge Bișoc         RtlCopyMemory(AccessToken->ImageFileName,
2739a2c62b5SGeorge Bișoc                       PsGetCurrentProcess()->ImageFileName,
2749a2c62b5SGeorge Bișoc                       min(sizeof(AccessToken->ImageFileName), sizeof(PsGetCurrentProcess()->ImageFileName)));
2759a2c62b5SGeorge Bișoc 
2769a2c62b5SGeorge Bișoc         AccessToken->ProcessCid = PsGetCurrentProcessId();
2779a2c62b5SGeorge Bișoc         AccessToken->ThreadCid = PsGetCurrentThreadId();
2789a2c62b5SGeorge Bișoc     }
2799a2c62b5SGeorge Bișoc 
2809a2c62b5SGeorge Bișoc     AccessToken->CreateMethod = TOKEN_CREATE_METHOD;
2819a2c62b5SGeorge Bișoc #endif
2829a2c62b5SGeorge Bișoc 
2839a2c62b5SGeorge Bișoc     /* Assign the data that reside in the token's variable information area */
2849a2c62b5SGeorge Bișoc     AccessToken->VariableLength = VariableLength;
2859a2c62b5SGeorge Bișoc     EndMem = (PVOID)&AccessToken->VariablePart;
2869a2c62b5SGeorge Bișoc 
2879a2c62b5SGeorge Bișoc     /* Copy the privileges */
2889a2c62b5SGeorge Bișoc     AccessToken->PrivilegeCount = PrivilegeCount;
2899a2c62b5SGeorge Bișoc     AccessToken->Privileges = NULL;
2909a2c62b5SGeorge Bișoc     if (PrivilegeCount > 0)
2919a2c62b5SGeorge Bișoc     {
2929a2c62b5SGeorge Bișoc         AccessToken->Privileges = EndMem;
2939a2c62b5SGeorge Bișoc         EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
2949a2c62b5SGeorge Bișoc         VariableLength -= PrivilegesLength;
2959a2c62b5SGeorge Bișoc 
2969a2c62b5SGeorge Bișoc         if (PreviousMode != KernelMode)
2979a2c62b5SGeorge Bișoc         {
2989a2c62b5SGeorge Bișoc             _SEH2_TRY
2999a2c62b5SGeorge Bișoc             {
3009a2c62b5SGeorge Bișoc                 RtlCopyMemory(AccessToken->Privileges,
3019a2c62b5SGeorge Bișoc                               Privileges,
3029a2c62b5SGeorge Bișoc                               PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
3039a2c62b5SGeorge Bișoc             }
3049a2c62b5SGeorge Bișoc             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3059a2c62b5SGeorge Bișoc             {
3069a2c62b5SGeorge Bișoc                 Status = _SEH2_GetExceptionCode();
3079a2c62b5SGeorge Bișoc             }
3089a2c62b5SGeorge Bișoc             _SEH2_END;
3099a2c62b5SGeorge Bișoc         }
3109a2c62b5SGeorge Bișoc         else
3119a2c62b5SGeorge Bișoc         {
3129a2c62b5SGeorge Bișoc             RtlCopyMemory(AccessToken->Privileges,
3139a2c62b5SGeorge Bișoc                           Privileges,
3149a2c62b5SGeorge Bișoc                           PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
3159a2c62b5SGeorge Bișoc         }
3169a2c62b5SGeorge Bișoc 
3179a2c62b5SGeorge Bișoc         if (!NT_SUCCESS(Status))
3189a2c62b5SGeorge Bișoc             goto Quit;
3199a2c62b5SGeorge Bișoc     }
3209a2c62b5SGeorge Bișoc 
3219a2c62b5SGeorge Bișoc     /* Update the privilege flags */
3229a2c62b5SGeorge Bișoc     SepUpdatePrivilegeFlagsToken(AccessToken);
3239a2c62b5SGeorge Bișoc 
3249a2c62b5SGeorge Bișoc     /* Copy the user and groups */
3259a2c62b5SGeorge Bișoc     AccessToken->UserAndGroupCount = 1 + GroupCount;
3269a2c62b5SGeorge Bișoc     AccessToken->UserAndGroups = EndMem;
3279a2c62b5SGeorge Bișoc     EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
3289a2c62b5SGeorge Bișoc     VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
3299a2c62b5SGeorge Bișoc 
3309a2c62b5SGeorge Bișoc     Status = RtlCopySidAndAttributesArray(1,
3319a2c62b5SGeorge Bișoc                                           User,
3329a2c62b5SGeorge Bișoc                                           VariableLength,
3339a2c62b5SGeorge Bișoc                                           &AccessToken->UserAndGroups[0],
3349a2c62b5SGeorge Bișoc                                           EndMem,
3359a2c62b5SGeorge Bișoc                                           &EndMem,
3369a2c62b5SGeorge Bișoc                                           &VariableLength);
3379a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
3389a2c62b5SGeorge Bișoc         goto Quit;
3399a2c62b5SGeorge Bișoc 
3409a2c62b5SGeorge Bișoc     Status = RtlCopySidAndAttributesArray(GroupCount,
3419a2c62b5SGeorge Bișoc                                           Groups,
3429a2c62b5SGeorge Bișoc                                           VariableLength,
3439a2c62b5SGeorge Bișoc                                           &AccessToken->UserAndGroups[1],
3449a2c62b5SGeorge Bișoc                                           EndMem,
3459a2c62b5SGeorge Bișoc                                           &EndMem,
3469a2c62b5SGeorge Bișoc                                           &VariableLength);
3479a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
3489a2c62b5SGeorge Bișoc         goto Quit;
3499a2c62b5SGeorge Bișoc 
3509a2c62b5SGeorge Bișoc     /* Find the token primary group and default owner */
3519a2c62b5SGeorge Bișoc     Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken,
3529a2c62b5SGeorge Bișoc                                                 PrimaryGroup,
3539a2c62b5SGeorge Bișoc                                                 Owner,
3549a2c62b5SGeorge Bișoc                                                 &PrimaryGroupIndex,
3559a2c62b5SGeorge Bișoc                                                 &DefaultOwnerIndex);
3569a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
3579a2c62b5SGeorge Bișoc     {
3589a2c62b5SGeorge Bișoc         DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status);
3599a2c62b5SGeorge Bișoc         goto Quit;
3609a2c62b5SGeorge Bișoc     }
3619a2c62b5SGeorge Bișoc 
3624471ee4dSGeorge Bișoc     /*
3634471ee4dSGeorge Bișoc      * Now allocate the token's dynamic information area
3644471ee4dSGeorge Bișoc      * and set the data. The dynamic part consists of two
3654471ee4dSGeorge Bișoc      * contents, the primary group SID and the default DACL
3664471ee4dSGeorge Bișoc      * of the token, in this strict order.
3674471ee4dSGeorge Bișoc      */
3689a2c62b5SGeorge Bișoc     AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
3694471ee4dSGeorge Bișoc                                                      DynamicPartSize,
3709a2c62b5SGeorge Bișoc                                                      TAG_TOKEN_DYNAMIC);
3719a2c62b5SGeorge Bișoc     if (AccessToken->DynamicPart == NULL)
3729a2c62b5SGeorge Bișoc     {
3739a2c62b5SGeorge Bișoc         Status = STATUS_INSUFFICIENT_RESOURCES;
3749a2c62b5SGeorge Bișoc         goto Quit;
3759a2c62b5SGeorge Bișoc     }
3769a2c62b5SGeorge Bișoc 
3774471ee4dSGeorge Bișoc     /* Unused memory in the dynamic area */
3784471ee4dSGeorge Bișoc     AccessToken->DynamicAvailable = 0;
3794471ee4dSGeorge Bișoc 
3804471ee4dSGeorge Bișoc     /*
3814471ee4dSGeorge Bișoc      * Assign the primary group to the token
3824471ee4dSGeorge Bișoc      * and put it in the dynamic part as well.
3834471ee4dSGeorge Bișoc      */
3849a2c62b5SGeorge Bișoc     EndMem = (PVOID)AccessToken->DynamicPart;
3854471ee4dSGeorge Bișoc     AccessToken->PrimaryGroup = EndMem;
3864471ee4dSGeorge Bișoc     RtlCopySid(RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid),
3874471ee4dSGeorge Bișoc                             EndMem,
3884471ee4dSGeorge Bișoc                             AccessToken->UserAndGroups[PrimaryGroupIndex].Sid);
3894471ee4dSGeorge Bișoc     AccessToken->DefaultOwnerIndex = DefaultOwnerIndex;
3904471ee4dSGeorge Bișoc     EndMem = (PVOID)((ULONG_PTR)EndMem + RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid));
3914471ee4dSGeorge Bișoc 
3924471ee4dSGeorge Bișoc     /*
3934471ee4dSGeorge Bișoc      * We have assigned a primary group and put it in the
3944471ee4dSGeorge Bișoc      * dynamic part, now it's time to copy the provided
3954471ee4dSGeorge Bișoc      * default DACL (if it's provided to begin with) into
3964471ee4dSGeorge Bișoc      * the DACL field of the token and put it at the end
3974471ee4dSGeorge Bișoc      * tail of the dynamic part too.
3984471ee4dSGeorge Bișoc      */
3994471ee4dSGeorge Bișoc     if (DefaultDacl != NULL)
4004471ee4dSGeorge Bișoc     {
4019a2c62b5SGeorge Bișoc         AccessToken->DefaultDacl = EndMem;
4029a2c62b5SGeorge Bișoc 
4034471ee4dSGeorge Bișoc         RtlCopyMemory(EndMem,
4049a2c62b5SGeorge Bișoc                       DefaultDacl,
4059a2c62b5SGeorge Bișoc                       DefaultDacl->AclSize);
4069a2c62b5SGeorge Bișoc     }
4079a2c62b5SGeorge Bișoc 
4089a2c62b5SGeorge Bișoc     /* Insert the token only if it's not the system token, otherwise return it directly */
4099a2c62b5SGeorge Bișoc     if (!SystemToken)
4109a2c62b5SGeorge Bișoc     {
4119a2c62b5SGeorge Bișoc         Status = ObInsertObject(AccessToken,
4129a2c62b5SGeorge Bișoc                                 NULL,
4139a2c62b5SGeorge Bișoc                                 DesiredAccess,
4149a2c62b5SGeorge Bișoc                                 0,
4159a2c62b5SGeorge Bișoc                                 NULL,
4169a2c62b5SGeorge Bișoc                                 TokenHandle);
4179a2c62b5SGeorge Bișoc         if (!NT_SUCCESS(Status))
4189a2c62b5SGeorge Bișoc         {
4199a2c62b5SGeorge Bișoc             DPRINT1("ObInsertObject() failed (Status 0x%lx)\n", Status);
4209a2c62b5SGeorge Bișoc         }
4219a2c62b5SGeorge Bișoc     }
4229a2c62b5SGeorge Bișoc     else
4239a2c62b5SGeorge Bișoc     {
4249a2c62b5SGeorge Bișoc         /* Return pointer instead of handle */
4259a2c62b5SGeorge Bișoc         *TokenHandle = (HANDLE)AccessToken;
4269a2c62b5SGeorge Bișoc     }
4279a2c62b5SGeorge Bișoc 
4289a2c62b5SGeorge Bișoc Quit:
4299a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
4309a2c62b5SGeorge Bișoc     {
4319a2c62b5SGeorge Bișoc         /* Dereference the token, the delete procedure will clean it up */
4329a2c62b5SGeorge Bișoc         ObDereferenceObject(AccessToken);
4339a2c62b5SGeorge Bișoc     }
4349a2c62b5SGeorge Bișoc 
4359a2c62b5SGeorge Bișoc     return Status;
4369a2c62b5SGeorge Bișoc }
4379a2c62b5SGeorge Bișoc 
4389a2c62b5SGeorge Bișoc /**
4399a2c62b5SGeorge Bișoc  * @brief
4409a2c62b5SGeorge Bișoc  * Duplicates an access token, from an existing valid token.
4419a2c62b5SGeorge Bișoc  *
4429a2c62b5SGeorge Bișoc  * @param[in] Token
4439a2c62b5SGeorge Bișoc  * Access token to duplicate.
4449a2c62b5SGeorge Bișoc  *
4459a2c62b5SGeorge Bișoc  * @param[in] ObjectAttributes
4469a2c62b5SGeorge Bișoc  * Object attributes for the new token.
4479a2c62b5SGeorge Bișoc  *
4489a2c62b5SGeorge Bișoc  * @param[in] EffectiveOnly
4499a2c62b5SGeorge Bișoc  * If set to TRUE, the function removes all the disabled privileges and groups of the token
4509a2c62b5SGeorge Bișoc  * to duplicate.
4519a2c62b5SGeorge Bișoc  *
4529a2c62b5SGeorge Bișoc  * @param[in] TokenType
4539a2c62b5SGeorge Bișoc  * Type of token.
4549a2c62b5SGeorge Bișoc  *
4559a2c62b5SGeorge Bișoc  * @param[in] Level
4569a2c62b5SGeorge Bișoc  * Security impersonation level of a token.
4579a2c62b5SGeorge Bișoc  *
4589a2c62b5SGeorge Bișoc  * @param[in] PreviousMode
4599a2c62b5SGeorge Bișoc  * The processor request level mode.
4609a2c62b5SGeorge Bișoc  *
4619a2c62b5SGeorge Bișoc  * @param[out] NewAccessToken
4629a2c62b5SGeorge Bișoc  * The duplicated token.
4639a2c62b5SGeorge Bișoc  *
4649a2c62b5SGeorge Bișoc  * @return
4659a2c62b5SGeorge Bișoc  * Returns STATUS_SUCCESS if the token has been duplicated. STATUS_INSUFFICIENT_RESOURCES is returned
4669a2c62b5SGeorge Bișoc  * if memory pool allocation of the dynamic part of the token for duplication has failed due to the lack
4679a2c62b5SGeorge Bișoc  * of memory resources. A failure NTSTATUS code is returned otherwise.
4689a2c62b5SGeorge Bișoc  */
4699a2c62b5SGeorge Bișoc NTSTATUS
4709a2c62b5SGeorge Bișoc 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)4719a2c62b5SGeorge Bișoc SepDuplicateToken(
4729a2c62b5SGeorge Bișoc     _In_ PTOKEN Token,
4739a2c62b5SGeorge Bișoc     _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
4749a2c62b5SGeorge Bișoc     _In_ BOOLEAN EffectiveOnly,
4759a2c62b5SGeorge Bișoc     _In_ TOKEN_TYPE TokenType,
4769a2c62b5SGeorge Bișoc     _In_ SECURITY_IMPERSONATION_LEVEL Level,
4779a2c62b5SGeorge Bișoc     _In_ KPROCESSOR_MODE PreviousMode,
4789a2c62b5SGeorge Bișoc     _Out_ PTOKEN* NewAccessToken)
4799a2c62b5SGeorge Bișoc {
4809a2c62b5SGeorge Bișoc     NTSTATUS Status;
4819a2c62b5SGeorge Bișoc     PTOKEN AccessToken;
4829a2c62b5SGeorge Bișoc     PVOID EndMem;
4839a2c62b5SGeorge Bișoc     ULONG PrimaryGroupIndex;
4849a2c62b5SGeorge Bișoc     ULONG VariableLength;
4854471ee4dSGeorge Bișoc     ULONG DynamicPartSize, TotalSize;
4869a2c62b5SGeorge Bișoc     ULONG PrivilegesIndex, GroupsIndex;
4879a2c62b5SGeorge Bișoc 
4889a2c62b5SGeorge Bișoc     PAGED_CODE();
4899a2c62b5SGeorge Bișoc 
4909a2c62b5SGeorge Bișoc     /* Compute how much size we need to allocate for the token */
4919a2c62b5SGeorge Bișoc     VariableLength = Token->VariableLength;
4929a2c62b5SGeorge Bișoc     TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
4939a2c62b5SGeorge Bișoc 
4944471ee4dSGeorge Bișoc     /*
4954471ee4dSGeorge Bișoc      * Compute how much size we need to allocate
4964471ee4dSGeorge Bișoc      * the dynamic part of the newly duplicated
4974471ee4dSGeorge Bișoc      * token.
4984471ee4dSGeorge Bișoc      */
4994471ee4dSGeorge Bișoc     DynamicPartSize = Token->DefaultDacl ? Token->DefaultDacl->AclSize : 0;
5004471ee4dSGeorge Bișoc     DynamicPartSize += RtlLengthSid(Token->PrimaryGroup);
5014471ee4dSGeorge Bișoc 
5029a2c62b5SGeorge Bișoc     Status = ObCreateObject(PreviousMode,
5039a2c62b5SGeorge Bișoc                             SeTokenObjectType,
5049a2c62b5SGeorge Bișoc                             ObjectAttributes,
5059a2c62b5SGeorge Bișoc                             PreviousMode,
5069a2c62b5SGeorge Bișoc                             NULL,
5079a2c62b5SGeorge Bișoc                             TotalSize,
5084471ee4dSGeorge Bișoc                             Token->DynamicCharged,
5094471ee4dSGeorge Bișoc                             TotalSize,
5109a2c62b5SGeorge Bișoc                             (PVOID*)&AccessToken);
5119a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
5129a2c62b5SGeorge Bișoc     {
5139a2c62b5SGeorge Bișoc         DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
5149a2c62b5SGeorge Bișoc         return Status;
5159a2c62b5SGeorge Bișoc     }
5169a2c62b5SGeorge Bișoc 
5179a2c62b5SGeorge Bișoc     /* Zero out the buffer and initialize the token */
5189a2c62b5SGeorge Bișoc     RtlZeroMemory(AccessToken, TotalSize);
5199a2c62b5SGeorge Bișoc 
5209a2c62b5SGeorge Bișoc     ExAllocateLocallyUniqueId(&AccessToken->TokenId);
5219a2c62b5SGeorge Bișoc 
5229a2c62b5SGeorge Bișoc     AccessToken->TokenType = TokenType;
5239a2c62b5SGeorge Bișoc     AccessToken->ImpersonationLevel = Level;
5249a2c62b5SGeorge Bișoc 
5259a2c62b5SGeorge Bișoc     /* Initialise the lock for the access token */
5269a2c62b5SGeorge Bișoc     Status = SepCreateTokenLock(AccessToken);
5279a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
5289a2c62b5SGeorge Bișoc     {
5299a2c62b5SGeorge Bișoc         ObDereferenceObject(AccessToken);
5309a2c62b5SGeorge Bișoc         return Status;
5319a2c62b5SGeorge Bișoc     }
5329a2c62b5SGeorge Bișoc 
5339a2c62b5SGeorge Bișoc     /* Copy the immutable fields */
5349a2c62b5SGeorge Bișoc     AccessToken->TokenSource.SourceIdentifier = Token->TokenSource.SourceIdentifier;
5359a2c62b5SGeorge Bișoc     RtlCopyMemory(AccessToken->TokenSource.SourceName,
5369a2c62b5SGeorge Bișoc                   Token->TokenSource.SourceName,
5379a2c62b5SGeorge Bișoc                   sizeof(Token->TokenSource.SourceName));
5389a2c62b5SGeorge Bișoc 
5399a2c62b5SGeorge Bișoc     AccessToken->AuthenticationId = Token->AuthenticationId;
5409a2c62b5SGeorge Bișoc     AccessToken->ParentTokenId = Token->ParentTokenId;
5419a2c62b5SGeorge Bișoc     AccessToken->ExpirationTime = Token->ExpirationTime;
5429a2c62b5SGeorge Bișoc     AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession;
5434471ee4dSGeorge Bișoc     AccessToken->DynamicCharged = Token->DynamicCharged;
5449a2c62b5SGeorge Bișoc 
5459a2c62b5SGeorge Bișoc     /* Lock the source token and copy the mutable fields */
5469a2c62b5SGeorge Bișoc     SepAcquireTokenLockShared(Token);
5479a2c62b5SGeorge Bișoc 
5489a2c62b5SGeorge Bișoc     AccessToken->SessionId = Token->SessionId;
5499a2c62b5SGeorge Bișoc     AccessToken->ModifiedId = Token->ModifiedId;
5509a2c62b5SGeorge Bișoc 
5519a2c62b5SGeorge Bișoc     AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
5529a2c62b5SGeorge Bișoc 
5539a2c62b5SGeorge Bișoc     /* Reference the logon session */
5549a2c62b5SGeorge Bișoc     Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
5559a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
5569a2c62b5SGeorge Bișoc     {
5579a2c62b5SGeorge Bișoc         /* No logon session could be found, bail out */
5589a2c62b5SGeorge Bișoc         DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status);
5599a2c62b5SGeorge Bișoc         /* Set the flag for proper cleanup by the delete procedure */
5609a2c62b5SGeorge Bișoc         AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
5619a2c62b5SGeorge Bișoc         goto Quit;
5629a2c62b5SGeorge Bișoc     }
5639a2c62b5SGeorge Bișoc 
5649a2c62b5SGeorge Bișoc     /* Insert the referenced logon session into the token */
5659a2c62b5SGeorge Bișoc     Status = SepRmInsertLogonSessionIntoToken(AccessToken);
5669a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
5679a2c62b5SGeorge Bișoc     {
5689a2c62b5SGeorge Bișoc         /* Failed to insert the logon session into the token, bail out */
5699a2c62b5SGeorge Bișoc         DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n", Status);
5709a2c62b5SGeorge Bișoc         goto Quit;
5719a2c62b5SGeorge Bișoc     }
5729a2c62b5SGeorge Bișoc 
5739a2c62b5SGeorge Bișoc     /* Fill in token debug information */
5749a2c62b5SGeorge Bișoc #if DBG
5759a2c62b5SGeorge Bișoc     RtlCopyMemory(AccessToken->ImageFileName,
5769a2c62b5SGeorge Bișoc                   PsGetCurrentProcess()->ImageFileName,
5779a2c62b5SGeorge Bișoc                   min(sizeof(AccessToken->ImageFileName), sizeof(PsGetCurrentProcess()->ImageFileName)));
5789a2c62b5SGeorge Bișoc 
5799a2c62b5SGeorge Bișoc     AccessToken->ProcessCid = PsGetCurrentProcessId();
5809a2c62b5SGeorge Bișoc     AccessToken->ThreadCid = PsGetCurrentThreadId();
5819a2c62b5SGeorge Bișoc     AccessToken->CreateMethod = TOKEN_DUPLICATE_METHOD;
5829a2c62b5SGeorge Bișoc #endif
5839a2c62b5SGeorge Bișoc 
5849a2c62b5SGeorge Bișoc     /* Assign the data that reside in the token's variable information area */
5859a2c62b5SGeorge Bișoc     AccessToken->VariableLength = VariableLength;
5869a2c62b5SGeorge Bișoc     EndMem = (PVOID)&AccessToken->VariablePart;
5879a2c62b5SGeorge Bișoc 
5889a2c62b5SGeorge Bișoc     /* Copy the privileges */
5899a2c62b5SGeorge Bișoc     AccessToken->PrivilegeCount = 0;
5909a2c62b5SGeorge Bișoc     AccessToken->Privileges = NULL;
5919a2c62b5SGeorge Bișoc     if (Token->Privileges && (Token->PrivilegeCount > 0))
5929a2c62b5SGeorge Bișoc     {
5939a2c62b5SGeorge Bișoc         ULONG PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
5949a2c62b5SGeorge Bișoc         PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
5959a2c62b5SGeorge Bișoc 
5969a2c62b5SGeorge Bișoc         ASSERT(VariableLength >= PrivilegesLength);
5979a2c62b5SGeorge Bișoc 
5989a2c62b5SGeorge Bișoc         AccessToken->PrivilegeCount = Token->PrivilegeCount;
5999a2c62b5SGeorge Bișoc         AccessToken->Privileges = EndMem;
6009a2c62b5SGeorge Bișoc         EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
6019a2c62b5SGeorge Bișoc         VariableLength -= PrivilegesLength;
6029a2c62b5SGeorge Bișoc 
6039a2c62b5SGeorge Bișoc         RtlCopyMemory(AccessToken->Privileges,
6049a2c62b5SGeorge Bișoc                       Token->Privileges,
6059a2c62b5SGeorge Bișoc                       AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
6069a2c62b5SGeorge Bișoc     }
6079a2c62b5SGeorge Bișoc 
6089a2c62b5SGeorge Bișoc     /* Copy the user and groups */
6099a2c62b5SGeorge Bișoc     AccessToken->UserAndGroupCount = 0;
6109a2c62b5SGeorge Bișoc     AccessToken->UserAndGroups = NULL;
6119a2c62b5SGeorge Bișoc     if (Token->UserAndGroups && (Token->UserAndGroupCount > 0))
6129a2c62b5SGeorge Bișoc     {
6139a2c62b5SGeorge Bișoc         AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
6149a2c62b5SGeorge Bișoc         AccessToken->UserAndGroups = EndMem;
6159a2c62b5SGeorge Bișoc         EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
6169a2c62b5SGeorge Bișoc         VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
6179a2c62b5SGeorge Bișoc 
6189a2c62b5SGeorge Bișoc         Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount,
6199a2c62b5SGeorge Bișoc                                               Token->UserAndGroups,
6209a2c62b5SGeorge Bișoc                                               VariableLength,
6219a2c62b5SGeorge Bișoc                                               AccessToken->UserAndGroups,
6229a2c62b5SGeorge Bișoc                                               EndMem,
6239a2c62b5SGeorge Bișoc                                               &EndMem,
6249a2c62b5SGeorge Bișoc                                               &VariableLength);
6259a2c62b5SGeorge Bișoc         if (!NT_SUCCESS(Status))
6269a2c62b5SGeorge Bișoc         {
6279a2c62b5SGeorge Bișoc             DPRINT1("RtlCopySidAndAttributesArray(UserAndGroups) failed (Status 0x%lx)\n", Status);
6289a2c62b5SGeorge Bișoc             goto Quit;
6299a2c62b5SGeorge Bișoc         }
6309a2c62b5SGeorge Bișoc     }
6319a2c62b5SGeorge Bișoc 
6329a2c62b5SGeorge Bișoc     /* Find the token primary group */
6339a2c62b5SGeorge Bișoc     Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken,
6349a2c62b5SGeorge Bișoc                                                 Token->PrimaryGroup,
6359a2c62b5SGeorge Bișoc                                                 NULL,
6369a2c62b5SGeorge Bișoc                                                 &PrimaryGroupIndex,
6379a2c62b5SGeorge Bișoc                                                 NULL);
6389a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
6399a2c62b5SGeorge Bișoc     {
6409a2c62b5SGeorge Bișoc         DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status);
6419a2c62b5SGeorge Bișoc         goto Quit;
6429a2c62b5SGeorge Bișoc     }
6439a2c62b5SGeorge Bișoc 
6449a2c62b5SGeorge Bișoc     /* Copy the restricted SIDs */
6459a2c62b5SGeorge Bișoc     AccessToken->RestrictedSidCount = 0;
6469a2c62b5SGeorge Bișoc     AccessToken->RestrictedSids = NULL;
6479a2c62b5SGeorge Bișoc     if (Token->RestrictedSids && (Token->RestrictedSidCount > 0))
6489a2c62b5SGeorge Bișoc     {
6499a2c62b5SGeorge Bișoc         AccessToken->RestrictedSidCount = Token->RestrictedSidCount;
6509a2c62b5SGeorge Bișoc         AccessToken->RestrictedSids = EndMem;
6519a2c62b5SGeorge Bișoc         EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount];
6529a2c62b5SGeorge Bișoc         VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids);
6539a2c62b5SGeorge Bișoc 
6549a2c62b5SGeorge Bișoc         Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount,
6559a2c62b5SGeorge Bișoc                                               Token->RestrictedSids,
6569a2c62b5SGeorge Bișoc                                               VariableLength,
6579a2c62b5SGeorge Bișoc                                               AccessToken->RestrictedSids,
6589a2c62b5SGeorge Bișoc                                               EndMem,
6599a2c62b5SGeorge Bișoc                                               &EndMem,
6609a2c62b5SGeorge Bișoc                                               &VariableLength);
6619a2c62b5SGeorge Bișoc         if (!NT_SUCCESS(Status))
6629a2c62b5SGeorge Bișoc         {
6639a2c62b5SGeorge Bișoc             DPRINT1("RtlCopySidAndAttributesArray(RestrictedSids) failed (Status 0x%lx)\n", Status);
6649a2c62b5SGeorge Bișoc             goto Quit;
6659a2c62b5SGeorge Bișoc         }
6669a2c62b5SGeorge Bișoc     }
6679a2c62b5SGeorge Bișoc 
668*a389f8aaSGeorge Bișoc     /* Now allocate the token's dynamic information area and set the data */
669*a389f8aaSGeorge Bișoc     AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
670*a389f8aaSGeorge Bișoc                                                      DynamicPartSize,
671*a389f8aaSGeorge Bișoc                                                      TAG_TOKEN_DYNAMIC);
672*a389f8aaSGeorge Bișoc     if (AccessToken->DynamicPart == NULL)
673*a389f8aaSGeorge Bișoc     {
674*a389f8aaSGeorge Bișoc         Status = STATUS_INSUFFICIENT_RESOURCES;
675*a389f8aaSGeorge Bișoc         goto Quit;
676*a389f8aaSGeorge Bișoc     }
677*a389f8aaSGeorge Bișoc 
678*a389f8aaSGeorge Bișoc     /* Unused memory in the dynamic area */
679*a389f8aaSGeorge Bișoc     AccessToken->DynamicAvailable = 0;
680*a389f8aaSGeorge Bișoc 
681*a389f8aaSGeorge Bișoc     /*
682*a389f8aaSGeorge Bișoc      * Assign the primary group to the token
683*a389f8aaSGeorge Bișoc      * and put it in the dynamic part as well.
684*a389f8aaSGeorge Bișoc      */
685*a389f8aaSGeorge Bișoc     EndMem = (PVOID)AccessToken->DynamicPart;
686*a389f8aaSGeorge Bișoc     AccessToken->PrimaryGroup = EndMem;
687*a389f8aaSGeorge Bișoc     RtlCopySid(RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid),
688*a389f8aaSGeorge Bișoc                             EndMem,
689*a389f8aaSGeorge Bișoc                             AccessToken->UserAndGroups[PrimaryGroupIndex].Sid);
690*a389f8aaSGeorge Bișoc     AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
691*a389f8aaSGeorge Bișoc     EndMem = (PVOID)((ULONG_PTR)EndMem + RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid));
692*a389f8aaSGeorge Bișoc 
693*a389f8aaSGeorge Bișoc     /*
694*a389f8aaSGeorge Bișoc      * The existing token has a default DACL only
695*a389f8aaSGeorge Bișoc      * if it has an allocated dynamic part.
696*a389f8aaSGeorge Bișoc      */
697*a389f8aaSGeorge Bișoc     if (Token->DynamicPart && Token->DefaultDacl)
698*a389f8aaSGeorge Bișoc     {
699*a389f8aaSGeorge Bișoc         AccessToken->DefaultDacl = EndMem;
700*a389f8aaSGeorge Bișoc 
701*a389f8aaSGeorge Bișoc         RtlCopyMemory(EndMem,
702*a389f8aaSGeorge Bișoc                       Token->DefaultDacl,
703*a389f8aaSGeorge Bișoc                       Token->DefaultDacl->AclSize);
704*a389f8aaSGeorge Bișoc     }
705*a389f8aaSGeorge Bișoc 
7069a2c62b5SGeorge Bișoc     /*
7079a2c62b5SGeorge Bișoc      * Filter the token by removing the disabled privileges
7089a2c62b5SGeorge Bișoc      * and groups if the caller wants to duplicate an access
7099a2c62b5SGeorge Bișoc      * token as effective only.
7109a2c62b5SGeorge Bișoc      */
7119a2c62b5SGeorge Bișoc     if (EffectiveOnly)
7129a2c62b5SGeorge Bișoc     {
713*a389f8aaSGeorge Bișoc         /*
714*a389f8aaSGeorge Bișoc          * Begin querying the groups and search for disabled ones. Do not touch the
715*a389f8aaSGeorge Bișoc          * user which is at the first position because it cannot be disabled, no
716*a389f8aaSGeorge Bișoc          * matter what attributes it has.
717*a389f8aaSGeorge Bișoc          */
718*a389f8aaSGeorge Bișoc         for (GroupsIndex = 1; GroupsIndex < AccessToken->UserAndGroupCount; GroupsIndex++)
7199a2c62b5SGeorge Bișoc         {
7209a2c62b5SGeorge Bișoc             /*
721*a389f8aaSGeorge Bișoc              * A group is considered disabled if its attributes is either
7229a2c62b5SGeorge Bișoc              * 0 or SE_GROUP_ENABLED is not included in the attributes flags list.
7239a2c62b5SGeorge Bișoc              * That is because a certain user and/or group can have several attributes
7249a2c62b5SGeorge Bișoc              * that bear no influence on whether a user/group is enabled or not
7259a2c62b5SGeorge Bișoc              * (SE_GROUP_ENABLED_BY_DEFAULT for example which is a mere indicator
7269a2c62b5SGeorge Bișoc              * that the group has just been enabled by default). A mandatory
7279a2c62b5SGeorge Bișoc              * group (that is, the group has SE_GROUP_MANDATORY attribute)
7289a2c62b5SGeorge Bișoc              * by standards it's always enabled and no one can disable it.
7299a2c62b5SGeorge Bișoc              */
7309a2c62b5SGeorge Bișoc             if (AccessToken->UserAndGroups[GroupsIndex].Attributes == 0 ||
7319a2c62b5SGeorge Bișoc                 (AccessToken->UserAndGroups[GroupsIndex].Attributes & SE_GROUP_ENABLED) == 0)
7329a2c62b5SGeorge Bișoc             {
7339a2c62b5SGeorge Bișoc                 /*
7349a2c62b5SGeorge Bișoc                  * If this group is an administrators group
7359a2c62b5SGeorge Bișoc                  * and the token belongs to such group,
7369a2c62b5SGeorge Bișoc                  * we've to take away TOKEN_HAS_ADMIN_GROUP
7379a2c62b5SGeorge Bișoc                  * for the fact that's not enabled and as
7389a2c62b5SGeorge Bișoc                  * such the token no longer belongs to
7399a2c62b5SGeorge Bișoc                  * this group.
7409a2c62b5SGeorge Bișoc                  */
7419a2c62b5SGeorge Bișoc                 if (RtlEqualSid(SeAliasAdminsSid,
7429a2c62b5SGeorge Bișoc                                 &AccessToken->UserAndGroups[GroupsIndex].Sid))
7439a2c62b5SGeorge Bișoc                 {
7449a2c62b5SGeorge Bișoc                     AccessToken->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP;
7459a2c62b5SGeorge Bișoc                 }
7469a2c62b5SGeorge Bișoc 
7479a2c62b5SGeorge Bișoc                 /*
7489a2c62b5SGeorge Bișoc                  * A group is not enabled, it's time to remove
7499a2c62b5SGeorge Bișoc                  * from the token and update the groups index
7509a2c62b5SGeorge Bișoc                  * accordingly and continue with the next group.
7519a2c62b5SGeorge Bișoc                  */
7529a2c62b5SGeorge Bișoc                 SepRemoveUserGroupToken(AccessToken, GroupsIndex);
7539a2c62b5SGeorge Bișoc                 GroupsIndex--;
7549a2c62b5SGeorge Bișoc             }
7559a2c62b5SGeorge Bișoc         }
7569a2c62b5SGeorge Bișoc 
7579a2c62b5SGeorge Bișoc         /* Begin querying the privileges and search for disabled ones */
7589a2c62b5SGeorge Bișoc         for (PrivilegesIndex = 0; PrivilegesIndex < AccessToken->PrivilegeCount; PrivilegesIndex++)
7599a2c62b5SGeorge Bișoc         {
7609a2c62b5SGeorge Bișoc             /*
7619a2c62b5SGeorge Bișoc              * A privilege is considered disabled if its attributes is either
7629a2c62b5SGeorge Bișoc              * 0 or SE_PRIVILEGE_ENABLED is not included in the attributes flags list.
7639a2c62b5SGeorge Bișoc              * That is because a certain privilege can have several attributes
7649a2c62b5SGeorge Bișoc              * that bear no influence on whether a privilege is enabled or not
7659a2c62b5SGeorge Bișoc              * (SE_PRIVILEGE_ENABLED_BY_DEFAULT for example which is a mere indicator
7669a2c62b5SGeorge Bișoc              * that the privilege has just been enabled by default).
7679a2c62b5SGeorge Bișoc              */
7689a2c62b5SGeorge Bișoc             if (AccessToken->Privileges[PrivilegesIndex].Attributes == 0 ||
7699a2c62b5SGeorge Bișoc                 (AccessToken->Privileges[PrivilegesIndex].Attributes & SE_PRIVILEGE_ENABLED) == 0)
7709a2c62b5SGeorge Bișoc             {
7719a2c62b5SGeorge Bișoc                 /*
7729a2c62b5SGeorge Bișoc                  * A privilege is not enabled, therefor it's time
7739a2c62b5SGeorge Bișoc                  * to strip it from the token and continue with the next
7749a2c62b5SGeorge Bișoc                  * privilege. Of course we must also want to update the
7759a2c62b5SGeorge Bișoc                  * privileges index accordingly.
7769a2c62b5SGeorge Bișoc                  */
7779a2c62b5SGeorge Bișoc                 SepRemovePrivilegeToken(AccessToken, PrivilegesIndex);
7789a2c62b5SGeorge Bișoc                 PrivilegesIndex--;
7799a2c62b5SGeorge Bișoc             }
7809a2c62b5SGeorge Bișoc         }
7819a2c62b5SGeorge Bișoc     }
7829a2c62b5SGeorge Bișoc 
7839a2c62b5SGeorge Bișoc     /* Return the token to the caller */
7849a2c62b5SGeorge Bișoc     *NewAccessToken = AccessToken;
7859a2c62b5SGeorge Bișoc     Status = STATUS_SUCCESS;
7869a2c62b5SGeorge Bișoc 
7879a2c62b5SGeorge Bișoc Quit:
7889a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
7899a2c62b5SGeorge Bișoc     {
7909a2c62b5SGeorge Bișoc         /* Dereference the token, the delete procedure will clean it up */
7919a2c62b5SGeorge Bișoc         ObDereferenceObject(AccessToken);
7929a2c62b5SGeorge Bișoc     }
7939a2c62b5SGeorge Bișoc 
7949a2c62b5SGeorge Bișoc     /* Unlock the source token */
7959a2c62b5SGeorge Bișoc     SepReleaseTokenLock(Token);
7969a2c62b5SGeorge Bișoc 
7979a2c62b5SGeorge Bișoc     return Status;
7989a2c62b5SGeorge Bișoc }
7999a2c62b5SGeorge Bișoc 
8009a2c62b5SGeorge Bișoc /**
8019a2c62b5SGeorge Bișoc  * @brief
8029a2c62b5SGeorge Bișoc  * Private helper function responsible for creating a restricted access
8039a2c62b5SGeorge Bișoc  * token, that is, a filtered token from privileges and groups and with
8049a2c62b5SGeorge Bișoc  * restricted SIDs added into the token on demand by the caller.
8059a2c62b5SGeorge Bișoc  *
8069a2c62b5SGeorge Bișoc  * @param[in] Token
8079a2c62b5SGeorge Bișoc  * An existing and valid access token.
8089a2c62b5SGeorge Bișoc  *
8099a2c62b5SGeorge Bișoc  * @param[in] PrivilegesToBeDeleted
8109a2c62b5SGeorge Bișoc  * A list of privileges to be deleted within the token that's going
8119a2c62b5SGeorge Bișoc  * to be filtered. This parameter is ignored if the caller wants to disable
8129a2c62b5SGeorge Bișoc  * all the privileges by specifying DISABLE_MAX_PRIVILEGE in the flags
8139a2c62b5SGeorge Bișoc  * parameter.
8149a2c62b5SGeorge Bișoc  *
8159a2c62b5SGeorge Bișoc  * @param[in] SidsToBeDisabled
8169a2c62b5SGeorge Bișoc  * A list of group SIDs to be disabled within the token. This parameter
8179a2c62b5SGeorge Bișoc  * can be NULL.
8189a2c62b5SGeorge Bișoc  *
8199a2c62b5SGeorge Bișoc  * @param[in] RestrictedSidsIntoToken
8209a2c62b5SGeorge Bișoc  * A list of restricted SIDs to be added into the token. This parameter
8219a2c62b5SGeorge Bișoc  * can be NULL.
8229a2c62b5SGeorge Bișoc  *
8239a2c62b5SGeorge Bișoc  * @param[in] PrivilegesCount
8249a2c62b5SGeorge Bișoc  * The privilege count of the privileges list.
8259a2c62b5SGeorge Bișoc  *
8269a2c62b5SGeorge Bișoc  * @param[in] RegularGroupsSidCount
8279a2c62b5SGeorge Bișoc  * The SIDs count of the group SIDs list.
8289a2c62b5SGeorge Bișoc  *
8299a2c62b5SGeorge Bișoc  * @param[in] RestrictedSidsCount
8309a2c62b5SGeorge Bișoc  * The restricted SIDs count of restricted SIDs list.
8319a2c62b5SGeorge Bișoc  *
8329a2c62b5SGeorge Bișoc  * @param[in] PrivilegeFlags
8339a2c62b5SGeorge Bișoc  * Influences how the privileges should be filtered in an access
8349a2c62b5SGeorge Bișoc  * token. See NtFilterToken syscall for more information.
8359a2c62b5SGeorge Bișoc  *
8369a2c62b5SGeorge Bișoc  * @param[in] PreviousMode
8379a2c62b5SGeorge Bișoc  * Processor level access mode.
8389a2c62b5SGeorge Bișoc  *
8399a2c62b5SGeorge Bișoc  * @param[out] FilteredToken
8409a2c62b5SGeorge Bișoc  * The filtered token, returned to the caller.
8419a2c62b5SGeorge Bișoc  *
8429a2c62b5SGeorge Bișoc  * @return
8439a2c62b5SGeorge Bișoc  * Returns STATUS_SUCCESS if token token filtering has completed successfully.
8449a2c62b5SGeorge Bișoc  * STATUS_INVALID_PARAMETER is returned if one or more of the parameters
8459a2c62b5SGeorge Bișoc  * do not meet the conditions imposed by the function. A failure NTSTATUS
8469a2c62b5SGeorge Bișoc  * code is returned otherwise.
8479a2c62b5SGeorge Bișoc  *
8489a2c62b5SGeorge Bișoc  * @remarks
8499a2c62b5SGeorge Bișoc  * The final outcome of privileges and/or SIDs filtering is not always
8509a2c62b5SGeorge Bișoc  * deterministic. That is, any privileges or SIDs that aren't present
8519a2c62b5SGeorge Bișoc  * in the access token are ignored and the function continues with the
8529a2c62b5SGeorge Bișoc  * next privilege or SID to find for filtering. For a fully deterministic
8539a2c62b5SGeorge Bișoc  * outcome the caller is responsible for querying the information details
8549a2c62b5SGeorge Bișoc  * of privileges and SIDs present in the token and then afterwards use
8559a2c62b5SGeorge Bișoc  * such obtained information to do any kind of filtering to the token.
8569a2c62b5SGeorge Bișoc  */
8579a2c62b5SGeorge Bișoc static
8589a2c62b5SGeorge Bișoc NTSTATUS
8599a2c62b5SGeorge Bișoc SepPerformTokenFiltering(
8609a2c62b5SGeorge Bișoc     _In_ PTOKEN Token,
8619a2c62b5SGeorge Bișoc     _In_opt_ PLUID_AND_ATTRIBUTES PrivilegesToBeDeleted,
8629a2c62b5SGeorge Bișoc     _In_opt_ PSID_AND_ATTRIBUTES SidsToBeDisabled,
8639a2c62b5SGeorge Bișoc     _In_opt_ PSID_AND_ATTRIBUTES RestrictedSidsIntoToken,
8649a2c62b5SGeorge Bișoc     _When_(PrivilegesToBeDeleted != NULL, _In_) ULONG PrivilegesCount,
8659a2c62b5SGeorge Bișoc     _When_(SidsToBeDisabled != NULL, _In_) ULONG RegularGroupsSidCount,
8669a2c62b5SGeorge Bișoc     _When_(RestrictedSidsIntoToken != NULL, _In_) ULONG RestrictedSidsCount,
8679a2c62b5SGeorge Bișoc     _In_ ULONG PrivilegeFlags,
8689a2c62b5SGeorge Bișoc     _In_ KPROCESSOR_MODE PreviousMode,
8699a2c62b5SGeorge Bișoc     _Out_ PTOKEN *FilteredToken)
8709a2c62b5SGeorge Bișoc {
8719a2c62b5SGeorge Bișoc     NTSTATUS Status;
8729a2c62b5SGeorge Bișoc     PTOKEN AccessToken;
8739a2c62b5SGeorge Bișoc     PVOID EndMem;
8744471ee4dSGeorge Bișoc     ULONG DynamicPartSize;
8759a2c62b5SGeorge Bișoc     ULONG RestrictedSidsLength;
8769a2c62b5SGeorge Bișoc     ULONG PrivilegesLength;
8779a2c62b5SGeorge Bișoc     ULONG PrimaryGroupIndex;
8789a2c62b5SGeorge Bișoc     ULONG RestrictedSidsInList;
8799a2c62b5SGeorge Bișoc     ULONG RestrictedSidsInToken;
8809a2c62b5SGeorge Bișoc     ULONG VariableLength, TotalSize;
8819a2c62b5SGeorge Bișoc     ULONG PrivsInToken, PrivsInList;
8829a2c62b5SGeorge Bișoc     ULONG GroupsInToken, GroupsInList;
8839a2c62b5SGeorge Bișoc     BOOLEAN WantPrivilegesDisabled;
8849a2c62b5SGeorge Bișoc     BOOLEAN FoundPrivilege;
8859a2c62b5SGeorge Bișoc     BOOLEAN FoundGroup;
8869a2c62b5SGeorge Bișoc 
8879a2c62b5SGeorge Bișoc     PAGED_CODE();
8889a2c62b5SGeorge Bișoc 
8899a2c62b5SGeorge Bișoc     /* Ensure that the source token is valid, and lock it */
8909a2c62b5SGeorge Bișoc     ASSERT(Token);
8919a2c62b5SGeorge Bișoc     SepAcquireTokenLockShared(Token);
8929a2c62b5SGeorge Bișoc 
8939a2c62b5SGeorge Bișoc     /* Assume the caller doesn't want privileges disabled */
8949a2c62b5SGeorge Bișoc     WantPrivilegesDisabled = FALSE;
8959a2c62b5SGeorge Bișoc 
8969a2c62b5SGeorge Bișoc     /* Assume we haven't found anything */
8979a2c62b5SGeorge Bișoc     FoundPrivilege = FALSE;
8989a2c62b5SGeorge Bișoc     FoundGroup = FALSE;
8999a2c62b5SGeorge Bișoc 
9009a2c62b5SGeorge Bișoc     /*
9019a2c62b5SGeorge Bișoc      * Take the size that we need for filtered token
9029a2c62b5SGeorge Bișoc      * allocation based upon the existing access token
9039a2c62b5SGeorge Bișoc      * we've been given.
9049a2c62b5SGeorge Bișoc      */
9059a2c62b5SGeorge Bișoc     VariableLength = Token->VariableLength;
9069a2c62b5SGeorge Bișoc 
9079a2c62b5SGeorge Bișoc     if (RestrictedSidsIntoToken != NULL)
9089a2c62b5SGeorge Bișoc     {
9099a2c62b5SGeorge Bișoc         /*
9109a2c62b5SGeorge Bișoc          * If the caller provided a list of restricted SIDs
9119a2c62b5SGeorge Bișoc          * to be added onto the filtered access token then
9129a2c62b5SGeorge Bișoc          * we must compute the size which is the total space
9139a2c62b5SGeorge Bișoc          * of the current token and the length of the restricted
9149a2c62b5SGeorge Bișoc          * SIDs for the filtered token.
9159a2c62b5SGeorge Bișoc          */
9169a2c62b5SGeorge Bișoc         RestrictedSidsLength = RestrictedSidsCount * sizeof(SID_AND_ATTRIBUTES);
9179a2c62b5SGeorge Bișoc         RestrictedSidsLength += RtlLengthSidAndAttributes(RestrictedSidsCount, RestrictedSidsIntoToken);
9189a2c62b5SGeorge Bișoc         RestrictedSidsLength = ALIGN_UP_BY(RestrictedSidsLength, sizeof(PVOID));
9199a2c62b5SGeorge Bișoc 
9209a2c62b5SGeorge Bișoc         /*
9219a2c62b5SGeorge Bișoc          * The variable length of the token is not just
9229a2c62b5SGeorge Bișoc          * the actual space length of the existing token
9239a2c62b5SGeorge Bișoc          * but also the sum of the restricted SIDs length.
9249a2c62b5SGeorge Bișoc          */
9259a2c62b5SGeorge Bișoc         VariableLength += RestrictedSidsLength;
9269a2c62b5SGeorge Bișoc         TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength + RestrictedSidsLength;
9279a2c62b5SGeorge Bișoc     }
9289a2c62b5SGeorge Bișoc     else
9299a2c62b5SGeorge Bișoc     {
9309a2c62b5SGeorge Bișoc         /* Otherwise the size is of the actual current token */
9319a2c62b5SGeorge Bișoc         TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
9329a2c62b5SGeorge Bișoc     }
9339a2c62b5SGeorge Bișoc 
9344471ee4dSGeorge Bișoc     /*
9354471ee4dSGeorge Bișoc      * Compute how much size we need to allocate
9364471ee4dSGeorge Bișoc      * the dynamic part of the newly duplicated
9374471ee4dSGeorge Bișoc      * token.
9384471ee4dSGeorge Bișoc      */
9394471ee4dSGeorge Bișoc     DynamicPartSize = Token->DefaultDacl ? Token->DefaultDacl->AclSize : 0;
9404471ee4dSGeorge Bișoc     DynamicPartSize += RtlLengthSid(Token->PrimaryGroup);
9414471ee4dSGeorge Bișoc 
9429a2c62b5SGeorge Bișoc     /* Set up a filtered token object */
9439a2c62b5SGeorge Bișoc     Status = ObCreateObject(PreviousMode,
9449a2c62b5SGeorge Bișoc                             SeTokenObjectType,
9459a2c62b5SGeorge Bișoc                             NULL,
9469a2c62b5SGeorge Bișoc                             PreviousMode,
9479a2c62b5SGeorge Bișoc                             NULL,
9489a2c62b5SGeorge Bișoc                             TotalSize,
9494471ee4dSGeorge Bișoc                             Token->DynamicCharged,
9504471ee4dSGeorge Bișoc                             TotalSize,
9519a2c62b5SGeorge Bișoc                             (PVOID*)&AccessToken);
9529a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
9539a2c62b5SGeorge Bișoc     {
9549a2c62b5SGeorge Bișoc         DPRINT1("SepPerformTokenFiltering(): Failed to create the filtered token object (Status 0x%lx)\n", Status);
9559a2c62b5SGeorge Bișoc 
9569a2c62b5SGeorge Bișoc         /* Unlock the source token and bail out */
9579a2c62b5SGeorge Bișoc         SepReleaseTokenLock(Token);
9589a2c62b5SGeorge Bișoc         return Status;
9599a2c62b5SGeorge Bișoc     }
9609a2c62b5SGeorge Bișoc 
9619a2c62b5SGeorge Bișoc     /* Initialize the token and begin filling stuff to it */
9629a2c62b5SGeorge Bișoc     RtlZeroMemory(AccessToken, TotalSize);
9639a2c62b5SGeorge Bișoc 
9649a2c62b5SGeorge Bișoc     /* Set up a lock for the new token */
9659a2c62b5SGeorge Bișoc     Status = SepCreateTokenLock(AccessToken);
9669a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
9679a2c62b5SGeorge Bișoc         goto Quit;
9689a2c62b5SGeorge Bișoc 
9699a2c62b5SGeorge Bișoc     /* Allocate new IDs for the token */
9709a2c62b5SGeorge Bișoc     ExAllocateLocallyUniqueId(&AccessToken->TokenId);
9719a2c62b5SGeorge Bișoc     ExAllocateLocallyUniqueId(&AccessToken->ModifiedId);
9729a2c62b5SGeorge Bișoc 
9739a2c62b5SGeorge Bișoc     /* Copy the type and impersonation level from the token */
9749a2c62b5SGeorge Bișoc     AccessToken->TokenType = Token->TokenType;
9759a2c62b5SGeorge Bișoc     AccessToken->ImpersonationLevel = Token->ImpersonationLevel;
9769a2c62b5SGeorge Bișoc 
9779a2c62b5SGeorge Bișoc     /* Copy the immutable fields */
9789a2c62b5SGeorge Bișoc     AccessToken->TokenSource.SourceIdentifier = Token->TokenSource.SourceIdentifier;
9799a2c62b5SGeorge Bișoc     RtlCopyMemory(AccessToken->TokenSource.SourceName,
9809a2c62b5SGeorge Bișoc                   Token->TokenSource.SourceName,
9819a2c62b5SGeorge Bișoc                   sizeof(Token->TokenSource.SourceName));
9829a2c62b5SGeorge Bișoc 
9839a2c62b5SGeorge Bișoc     AccessToken->AuthenticationId = Token->AuthenticationId;
9849a2c62b5SGeorge Bișoc     AccessToken->ParentTokenId = Token->TokenId;
9859a2c62b5SGeorge Bișoc     AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession;
9864471ee4dSGeorge Bișoc     AccessToken->DynamicCharged = Token->DynamicCharged;
9879a2c62b5SGeorge Bișoc 
9889a2c62b5SGeorge Bișoc     AccessToken->ExpirationTime = Token->ExpirationTime;
9899a2c62b5SGeorge Bișoc 
9909a2c62b5SGeorge Bișoc     /* Copy the mutable fields */
9919a2c62b5SGeorge Bișoc     AccessToken->SessionId = Token->SessionId;
9929a2c62b5SGeorge Bișoc     AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
9939a2c62b5SGeorge Bișoc 
9949a2c62b5SGeorge Bișoc     /* Reference the logon session */
9959a2c62b5SGeorge Bișoc     Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
9969a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
9979a2c62b5SGeorge Bișoc     {
9989a2c62b5SGeorge Bișoc         /* We failed, bail out*/
9999a2c62b5SGeorge Bișoc         DPRINT1("SepPerformTokenFiltering(): Failed to reference the logon session (Status 0x%lx)\n", Status);
10009a2c62b5SGeorge Bișoc         AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
10019a2c62b5SGeorge Bișoc         goto Quit;
10029a2c62b5SGeorge Bișoc     }
10039a2c62b5SGeorge Bișoc 
10049a2c62b5SGeorge Bișoc     /* Insert the referenced logon session into the token */
10059a2c62b5SGeorge Bișoc     Status = SepRmInsertLogonSessionIntoToken(AccessToken);
10069a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
10079a2c62b5SGeorge Bișoc     {
10089a2c62b5SGeorge Bișoc         /* Failed to insert the logon session into the token, bail out */
10099a2c62b5SGeorge Bișoc         DPRINT1("SepPerformTokenFiltering(): Failed to insert the logon session into token (Status 0x%lx)\n", Status);
10109a2c62b5SGeorge Bișoc         goto Quit;
10119a2c62b5SGeorge Bișoc     }
10129a2c62b5SGeorge Bișoc 
10139a2c62b5SGeorge Bișoc     /* Fill in token debug information */
10149a2c62b5SGeorge Bișoc #if DBG
10159a2c62b5SGeorge Bișoc     RtlCopyMemory(AccessToken->ImageFileName,
10169a2c62b5SGeorge Bișoc                   PsGetCurrentProcess()->ImageFileName,
10179a2c62b5SGeorge Bișoc                   min(sizeof(AccessToken->ImageFileName), sizeof(PsGetCurrentProcess()->ImageFileName)));
10189a2c62b5SGeorge Bișoc 
10199a2c62b5SGeorge Bișoc     AccessToken->ProcessCid = PsGetCurrentProcessId();
10209a2c62b5SGeorge Bișoc     AccessToken->ThreadCid = PsGetCurrentThreadId();
10219a2c62b5SGeorge Bișoc     AccessToken->CreateMethod = TOKEN_FILTER_METHOD;
10229a2c62b5SGeorge Bișoc #endif
10239a2c62b5SGeorge Bișoc 
10249a2c62b5SGeorge Bișoc     /* Assign the data that reside in the token's variable information area */
10259a2c62b5SGeorge Bișoc     AccessToken->VariableLength = VariableLength;
10269a2c62b5SGeorge Bișoc     EndMem = (PVOID)&AccessToken->VariablePart;
10279a2c62b5SGeorge Bișoc 
10289a2c62b5SGeorge Bișoc     /* Copy the privileges from the existing token */
10299a2c62b5SGeorge Bișoc     AccessToken->PrivilegeCount = 0;
10309a2c62b5SGeorge Bișoc     AccessToken->Privileges = NULL;
10319a2c62b5SGeorge Bișoc     if (Token->Privileges && (Token->PrivilegeCount > 0))
10329a2c62b5SGeorge Bișoc     {
10339a2c62b5SGeorge Bișoc         PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
10349a2c62b5SGeorge Bișoc         PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
10359a2c62b5SGeorge Bișoc 
10369a2c62b5SGeorge Bișoc         /*
10379a2c62b5SGeorge Bișoc          * Ensure that the token can actually hold all
10389a2c62b5SGeorge Bișoc          * the privileges from the existing token.
10399a2c62b5SGeorge Bișoc          * Otherwise something's seriously wrong and
10409a2c62b5SGeorge Bișoc          * we've to guard ourselves.
10419a2c62b5SGeorge Bișoc          */
10429a2c62b5SGeorge Bișoc         ASSERT(VariableLength >= PrivilegesLength);
10439a2c62b5SGeorge Bișoc 
10449a2c62b5SGeorge Bișoc         AccessToken->PrivilegeCount = Token->PrivilegeCount;
10459a2c62b5SGeorge Bișoc         AccessToken->Privileges = EndMem;
10469a2c62b5SGeorge Bișoc         EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
10479a2c62b5SGeorge Bișoc         VariableLength -= PrivilegesLength;
10489a2c62b5SGeorge Bișoc 
10499a2c62b5SGeorge Bișoc         RtlCopyMemory(AccessToken->Privileges,
10509a2c62b5SGeorge Bișoc                       Token->Privileges,
10519a2c62b5SGeorge Bișoc                       AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
10529a2c62b5SGeorge Bișoc     }
10539a2c62b5SGeorge Bișoc 
10549a2c62b5SGeorge Bișoc     /* Copy the user and groups */
10559a2c62b5SGeorge Bișoc     AccessToken->UserAndGroupCount = 0;
10569a2c62b5SGeorge Bișoc     AccessToken->UserAndGroups = NULL;
10579a2c62b5SGeorge Bișoc     if (Token->UserAndGroups && (Token->UserAndGroupCount > 0))
10589a2c62b5SGeorge Bișoc     {
10599a2c62b5SGeorge Bișoc         AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
10609a2c62b5SGeorge Bișoc         AccessToken->UserAndGroups = EndMem;
10619a2c62b5SGeorge Bișoc         EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
10629a2c62b5SGeorge Bișoc         VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
10639a2c62b5SGeorge Bișoc 
10649a2c62b5SGeorge Bișoc         Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount,
10659a2c62b5SGeorge Bișoc                                               Token->UserAndGroups,
10669a2c62b5SGeorge Bișoc                                               VariableLength,
10679a2c62b5SGeorge Bișoc                                               AccessToken->UserAndGroups,
10689a2c62b5SGeorge Bișoc                                               EndMem,
10699a2c62b5SGeorge Bișoc                                               &EndMem,
10709a2c62b5SGeorge Bișoc                                               &VariableLength);
10719a2c62b5SGeorge Bișoc         if (!NT_SUCCESS(Status))
10729a2c62b5SGeorge Bișoc         {
10739a2c62b5SGeorge Bișoc             DPRINT1("SepPerformTokenFiltering(): Failed to copy the groups into token (Status 0x%lx)\n", Status);
10749a2c62b5SGeorge Bișoc             goto Quit;
10759a2c62b5SGeorge Bișoc         }
10769a2c62b5SGeorge Bișoc     }
10779a2c62b5SGeorge Bișoc 
10789a2c62b5SGeorge Bișoc     /* Copy the restricted SIDs */
10799a2c62b5SGeorge Bișoc     AccessToken->RestrictedSidCount = 0;
10809a2c62b5SGeorge Bișoc     AccessToken->RestrictedSids = NULL;
10819a2c62b5SGeorge Bișoc     if (Token->RestrictedSids && (Token->RestrictedSidCount > 0))
10829a2c62b5SGeorge Bișoc     {
10839a2c62b5SGeorge Bișoc         AccessToken->RestrictedSidCount = Token->RestrictedSidCount;
10849a2c62b5SGeorge Bișoc         AccessToken->RestrictedSids = EndMem;
10859a2c62b5SGeorge Bișoc         EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount];
10869a2c62b5SGeorge Bișoc         VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids);
10879a2c62b5SGeorge Bișoc 
10889a2c62b5SGeorge Bișoc         Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount,
10899a2c62b5SGeorge Bișoc                                               Token->RestrictedSids,
10909a2c62b5SGeorge Bișoc                                               VariableLength,
10919a2c62b5SGeorge Bișoc                                               AccessToken->RestrictedSids,
10929a2c62b5SGeorge Bișoc                                               EndMem,
10939a2c62b5SGeorge Bișoc                                               &EndMem,
10949a2c62b5SGeorge Bișoc                                               &VariableLength);
10959a2c62b5SGeorge Bișoc         if (!NT_SUCCESS(Status))
10969a2c62b5SGeorge Bișoc         {
10979a2c62b5SGeorge Bișoc             DPRINT1("SepPerformTokenFiltering(): Failed to copy the restricted SIDs into token (Status 0x%lx)\n", Status);
10989a2c62b5SGeorge Bișoc             goto Quit;
10999a2c62b5SGeorge Bișoc         }
11009a2c62b5SGeorge Bișoc     }
11019a2c62b5SGeorge Bișoc 
11029a2c62b5SGeorge Bișoc     /*
11039a2c62b5SGeorge Bișoc      * Insert the restricted SIDs into the token on
11049a2c62b5SGeorge Bișoc      * the request by the caller.
11059a2c62b5SGeorge Bișoc      */
11069a2c62b5SGeorge Bișoc     if (RestrictedSidsIntoToken != NULL)
11079a2c62b5SGeorge Bișoc     {
11089a2c62b5SGeorge Bișoc         for (RestrictedSidsInList = 0; RestrictedSidsInList < RestrictedSidsCount; RestrictedSidsInList++)
11099a2c62b5SGeorge Bișoc         {
11109a2c62b5SGeorge Bișoc             /* Did the caller assign attributes to the restricted SIDs? */
11119a2c62b5SGeorge Bișoc             if (RestrictedSidsIntoToken[RestrictedSidsInList].Attributes != 0)
11129a2c62b5SGeorge Bișoc             {
11139a2c62b5SGeorge Bișoc                 /* There mustn't be any attributes, bail out */
11149a2c62b5SGeorge Bișoc                 DPRINT1("SepPerformTokenFiltering(): There mustn't be any attributes to restricted SIDs!\n");
11159a2c62b5SGeorge Bișoc                 Status = STATUS_INVALID_PARAMETER;
11169a2c62b5SGeorge Bișoc                 goto Quit;
11179a2c62b5SGeorge Bișoc             }
11189a2c62b5SGeorge Bișoc         }
11199a2c62b5SGeorge Bișoc 
11209a2c62b5SGeorge Bișoc         /*
11219a2c62b5SGeorge Bișoc          * Ensure that the token can hold the restricted SIDs
11229a2c62b5SGeorge Bișoc          * (the variable length is calculated at the beginning
11239a2c62b5SGeorge Bișoc          * of the routine call).
11249a2c62b5SGeorge Bișoc          */
11259a2c62b5SGeorge Bișoc         ASSERT(VariableLength >= RestrictedSidsLength);
11269a2c62b5SGeorge Bișoc 
11279a2c62b5SGeorge Bișoc         /*
11289a2c62b5SGeorge Bișoc          * Now let's begin inserting the restricted SIDs into the filtered
11299a2c62b5SGeorge Bișoc          * access token from the list the caller gave us.
11309a2c62b5SGeorge Bișoc          */
11319a2c62b5SGeorge Bișoc         AccessToken->RestrictedSidCount = RestrictedSidsCount;
11329a2c62b5SGeorge Bișoc         AccessToken->RestrictedSids = EndMem;
11339a2c62b5SGeorge Bișoc         EndMem = (PVOID)((ULONG_PTR)EndMem + RestrictedSidsLength);
11349a2c62b5SGeorge Bișoc         VariableLength -= RestrictedSidsLength;
11359a2c62b5SGeorge Bișoc 
11369a2c62b5SGeorge Bișoc         RtlCopyMemory(AccessToken->RestrictedSids,
11379a2c62b5SGeorge Bișoc                       RestrictedSidsIntoToken,
11389a2c62b5SGeorge Bișoc                       AccessToken->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
11399a2c62b5SGeorge Bișoc 
11409a2c62b5SGeorge Bișoc         /*
11419a2c62b5SGeorge Bișoc          * As we've copied the restricted SIDs into
11429a2c62b5SGeorge Bișoc          * the token, we must assign them the following
11439a2c62b5SGeorge Bișoc          * combination of attributes SE_GROUP_ENABLED,
11449a2c62b5SGeorge Bișoc          * SE_GROUP_ENABLED_BY_DEFAULT and SE_GROUP_MANDATORY.
11459a2c62b5SGeorge Bișoc          * With such attributes we estabilish that restricting
11469a2c62b5SGeorge Bișoc          * SIDs into the token are enabled for access checks.
11479a2c62b5SGeorge Bișoc          */
11489a2c62b5SGeorge Bișoc         for (RestrictedSidsInToken = 0; RestrictedSidsInToken < AccessToken->RestrictedSidCount; RestrictedSidsInToken++)
11499a2c62b5SGeorge Bișoc         {
11509a2c62b5SGeorge Bișoc             AccessToken->RestrictedSids[RestrictedSidsInToken].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY);
11519a2c62b5SGeorge Bișoc         }
11529a2c62b5SGeorge Bișoc 
11539a2c62b5SGeorge Bișoc         /*
11549a2c62b5SGeorge Bișoc          * As we added restricted SIDs into the token, mark
11559a2c62b5SGeorge Bișoc          * it as restricted.
11569a2c62b5SGeorge Bișoc          */
11579a2c62b5SGeorge Bișoc         AccessToken->TokenFlags |= TOKEN_IS_RESTRICTED;
11589a2c62b5SGeorge Bișoc     }
11599a2c62b5SGeorge Bișoc 
11609a2c62b5SGeorge Bișoc     /* Search for the primary group */
11619a2c62b5SGeorge Bișoc     Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken,
11629a2c62b5SGeorge Bișoc                                                 Token->PrimaryGroup,
11639a2c62b5SGeorge Bișoc                                                 NULL,
11649a2c62b5SGeorge Bișoc                                                 &PrimaryGroupIndex,
11659a2c62b5SGeorge Bișoc                                                 NULL);
11669a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
11679a2c62b5SGeorge Bișoc     {
11689a2c62b5SGeorge Bișoc         DPRINT1("SepPerformTokenFiltering(): Failed searching for the primary group (Status 0x%lx)\n", Status);
11699a2c62b5SGeorge Bișoc         goto Quit;
11709a2c62b5SGeorge Bișoc     }
11719a2c62b5SGeorge Bișoc 
11729a2c62b5SGeorge Bișoc     /* Now allocate the token's dynamic information area and set the data */
11739a2c62b5SGeorge Bișoc     AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
11744471ee4dSGeorge Bișoc                                                      DynamicPartSize,
11759a2c62b5SGeorge Bișoc                                                      TAG_TOKEN_DYNAMIC);
11769a2c62b5SGeorge Bișoc     if (AccessToken->DynamicPart == NULL)
11779a2c62b5SGeorge Bișoc     {
11789a2c62b5SGeorge Bișoc         Status = STATUS_INSUFFICIENT_RESOURCES;
11799a2c62b5SGeorge Bișoc         goto Quit;
11809a2c62b5SGeorge Bișoc     }
11819a2c62b5SGeorge Bișoc 
11824471ee4dSGeorge Bișoc     /* Unused memory in the dynamic area */
11834471ee4dSGeorge Bișoc     AccessToken->DynamicAvailable = 0;
11844471ee4dSGeorge Bișoc 
11854471ee4dSGeorge Bișoc     /*
11864471ee4dSGeorge Bișoc      * Assign the primary group to the token
11874471ee4dSGeorge Bișoc      * and put it in the dynamic part as well.
11884471ee4dSGeorge Bișoc      */
11899a2c62b5SGeorge Bișoc     EndMem = (PVOID)AccessToken->DynamicPart;
11904471ee4dSGeorge Bișoc     AccessToken->PrimaryGroup = EndMem;
11914471ee4dSGeorge Bișoc     RtlCopySid(RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid),
11924471ee4dSGeorge Bișoc                             EndMem,
11934471ee4dSGeorge Bișoc                             AccessToken->UserAndGroups[PrimaryGroupIndex].Sid);
11944471ee4dSGeorge Bișoc     AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
11954471ee4dSGeorge Bișoc     EndMem = (PVOID)((ULONG_PTR)EndMem + RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid));
11964471ee4dSGeorge Bișoc 
11974471ee4dSGeorge Bișoc     /*
11984471ee4dSGeorge Bișoc      * The existing token has a default DACL only
11994471ee4dSGeorge Bișoc      * if it has an allocated dynamic part.
12004471ee4dSGeorge Bișoc      */
12014471ee4dSGeorge Bișoc     if (Token->DynamicPart && Token->DefaultDacl)
12024471ee4dSGeorge Bișoc     {
12039a2c62b5SGeorge Bișoc         AccessToken->DefaultDacl = EndMem;
12049a2c62b5SGeorge Bișoc 
12054471ee4dSGeorge Bișoc         RtlCopyMemory(EndMem,
12069a2c62b5SGeorge Bișoc                       Token->DefaultDacl,
12079a2c62b5SGeorge Bișoc                       Token->DefaultDacl->AclSize);
12089a2c62b5SGeorge Bișoc     }
12099a2c62b5SGeorge Bișoc 
12109a2c62b5SGeorge Bișoc     /*
12119a2c62b5SGeorge Bișoc      * Now figure out what does the caller
12129a2c62b5SGeorge Bișoc      * want with the privileges.
12139a2c62b5SGeorge Bișoc      */
12149a2c62b5SGeorge Bișoc     if (PrivilegeFlags & DISABLE_MAX_PRIVILEGE)
12159a2c62b5SGeorge Bișoc     {
12169a2c62b5SGeorge Bișoc         /*
12179a2c62b5SGeorge Bișoc          * The caller wants them disabled, cache this request
12189a2c62b5SGeorge Bișoc          * for later operations.
12199a2c62b5SGeorge Bișoc          */
12209a2c62b5SGeorge Bișoc         WantPrivilegesDisabled = TRUE;
12219a2c62b5SGeorge Bișoc     }
12229a2c62b5SGeorge Bișoc 
12239a2c62b5SGeorge Bișoc     if (PrivilegeFlags & SANDBOX_INERT)
12249a2c62b5SGeorge Bișoc     {
12259a2c62b5SGeorge Bișoc         /* The caller wants an inert token, store the TOKEN_SANDBOX_INERT flag now */
12269a2c62b5SGeorge Bișoc         AccessToken->TokenFlags |= TOKEN_SANDBOX_INERT;
12279a2c62b5SGeorge Bișoc     }
12289a2c62b5SGeorge Bișoc 
12299a2c62b5SGeorge Bișoc     /*
12309a2c62b5SGeorge Bișoc      * Now it's time to filter the token's privileges.
12319a2c62b5SGeorge Bișoc      * Loop all the privileges in the token.
12329a2c62b5SGeorge Bișoc      */
12339a2c62b5SGeorge Bișoc     for (PrivsInToken = 0; PrivsInToken < AccessToken->PrivilegeCount; PrivsInToken++)
12349a2c62b5SGeorge Bișoc     {
12359a2c62b5SGeorge Bișoc         if (WantPrivilegesDisabled)
12369a2c62b5SGeorge Bișoc         {
12379a2c62b5SGeorge Bișoc             /*
12389a2c62b5SGeorge Bișoc              * We got the acknowledgement that the caller wants
12399a2c62b5SGeorge Bișoc              * to disable all the privileges so let's just do it.
12409a2c62b5SGeorge Bișoc              * However, as per the general documentation is stated
12419a2c62b5SGeorge Bișoc              * that only SE_CHANGE_NOTIFY_PRIVILEGE must be kept
12429a2c62b5SGeorge Bișoc              * therefore in that case we must skip this privilege.
12439a2c62b5SGeorge Bișoc              */
12449a2c62b5SGeorge Bișoc             if (AccessToken->Privileges[PrivsInToken].Luid.LowPart == SE_CHANGE_NOTIFY_PRIVILEGE)
12459a2c62b5SGeorge Bișoc             {
12469a2c62b5SGeorge Bișoc                 continue;
12479a2c62b5SGeorge Bișoc             }
12489a2c62b5SGeorge Bișoc             else
12499a2c62b5SGeorge Bișoc             {
12509a2c62b5SGeorge Bișoc                 /*
12519a2c62b5SGeorge Bișoc                  * The act of disabling privileges actually means
12529a2c62b5SGeorge Bișoc                  * "deleting" them from the access token entirely.
12539a2c62b5SGeorge Bișoc                  * First we must disable them so that we can update
12549a2c62b5SGeorge Bișoc                  * token flags accordingly.
12559a2c62b5SGeorge Bișoc                  */
12569a2c62b5SGeorge Bișoc                 AccessToken->Privileges[PrivsInToken].Attributes &= ~SE_PRIVILEGE_ENABLED;
12579a2c62b5SGeorge Bișoc                 SepUpdateSinglePrivilegeFlagToken(AccessToken, PrivsInToken);
12589a2c62b5SGeorge Bișoc 
12599a2c62b5SGeorge Bișoc                 /* Remove the privileges now */
12609a2c62b5SGeorge Bișoc                 SepRemovePrivilegeToken(AccessToken, PrivsInToken);
12619a2c62b5SGeorge Bișoc                 PrivsInToken--;
12629a2c62b5SGeorge Bișoc             }
12639a2c62b5SGeorge Bișoc         }
12649a2c62b5SGeorge Bișoc         else
12659a2c62b5SGeorge Bișoc         {
12669a2c62b5SGeorge Bișoc             if (PrivilegesToBeDeleted != NULL)
12679a2c62b5SGeorge Bișoc             {
12689a2c62b5SGeorge Bișoc                 /* Loop the privileges we've got to delete */
12699a2c62b5SGeorge Bișoc                 for (PrivsInList = 0; PrivsInList < PrivilegesCount; PrivsInList++)
12709a2c62b5SGeorge Bișoc                 {
12719a2c62b5SGeorge Bișoc                     /* Does this privilege exist in the token? */
12729a2c62b5SGeorge Bișoc                     if (RtlEqualLuid(&AccessToken->Privileges[PrivsInToken].Luid,
12739a2c62b5SGeorge Bișoc                                      &PrivilegesToBeDeleted[PrivsInList].Luid))
12749a2c62b5SGeorge Bișoc                     {
12759a2c62b5SGeorge Bișoc                         /* Mark that we found it */
12769a2c62b5SGeorge Bișoc                         FoundPrivilege = TRUE;
12779a2c62b5SGeorge Bișoc                         break;
12789a2c62b5SGeorge Bișoc                     }
12799a2c62b5SGeorge Bișoc                 }
12809a2c62b5SGeorge Bișoc 
12819a2c62b5SGeorge Bișoc                 /* Did we find the privilege? */
12829a2c62b5SGeorge Bișoc                 if (PrivsInList == PrivilegesCount)
12839a2c62b5SGeorge Bișoc                 {
12849a2c62b5SGeorge Bișoc                     /* We didn't, continue with next one */
12859a2c62b5SGeorge Bișoc                     continue;
12869a2c62b5SGeorge Bișoc                 }
12879a2c62b5SGeorge Bișoc             }
12889a2c62b5SGeorge Bișoc         }
12899a2c62b5SGeorge Bișoc 
12909a2c62b5SGeorge Bișoc         /*
12919a2c62b5SGeorge Bișoc          * If we have found the target privilege in the token
12929a2c62b5SGeorge Bișoc          * based on the privileges list given by the caller
12939a2c62b5SGeorge Bișoc          * then begin deleting it.
12949a2c62b5SGeorge Bișoc          */
12959a2c62b5SGeorge Bișoc         if (FoundPrivilege)
12969a2c62b5SGeorge Bișoc         {
12979a2c62b5SGeorge Bișoc             /* Disable the privilege and update the flags */
12989a2c62b5SGeorge Bișoc             AccessToken->Privileges[PrivsInToken].Attributes &= ~SE_PRIVILEGE_ENABLED;
12999a2c62b5SGeorge Bișoc             SepUpdateSinglePrivilegeFlagToken(AccessToken, PrivsInToken);
13009a2c62b5SGeorge Bișoc 
13019a2c62b5SGeorge Bișoc             /* Delete the privilege */
13029a2c62b5SGeorge Bișoc             SepRemovePrivilegeToken(AccessToken, PrivsInToken);
13039a2c62b5SGeorge Bișoc 
13049a2c62b5SGeorge Bișoc             /*
13059a2c62b5SGeorge Bișoc              * Adjust the index and reset the FoundPrivilege indicator
13069a2c62b5SGeorge Bișoc              * so that we can continue with the next privilege to delete.
13079a2c62b5SGeorge Bișoc              */
13089a2c62b5SGeorge Bișoc             PrivsInToken--;
13099a2c62b5SGeorge Bișoc             FoundPrivilege = FALSE;
13109a2c62b5SGeorge Bișoc             continue;
13119a2c62b5SGeorge Bișoc         }
13129a2c62b5SGeorge Bișoc     }
13139a2c62b5SGeorge Bișoc 
13149a2c62b5SGeorge Bișoc     /*
13159a2c62b5SGeorge Bișoc      * Loop the group SIDs that we want to disable as
13169a2c62b5SGeorge Bișoc      * per on the request by the caller.
13179a2c62b5SGeorge Bișoc      */
13189a2c62b5SGeorge Bișoc     if (SidsToBeDisabled != NULL)
13199a2c62b5SGeorge Bișoc     {
13209a2c62b5SGeorge Bișoc         for (GroupsInToken = 0; GroupsInToken < AccessToken->UserAndGroupCount; GroupsInToken++)
13219a2c62b5SGeorge Bișoc         {
13229a2c62b5SGeorge Bișoc             for (GroupsInList = 0; GroupsInList < RegularGroupsSidCount; GroupsInList++)
13239a2c62b5SGeorge Bișoc             {
13249a2c62b5SGeorge Bișoc                 /* Does this group SID exist in the token? */
13259a2c62b5SGeorge Bișoc                 if (RtlEqualSid(&AccessToken->UserAndGroups[GroupsInToken].Sid,
13269a2c62b5SGeorge Bișoc                                 &SidsToBeDisabled[GroupsInList].Sid))
13279a2c62b5SGeorge Bișoc                 {
13289a2c62b5SGeorge Bișoc                     /* Mark that we found it */
13299a2c62b5SGeorge Bișoc                     FoundGroup = TRUE;
13309a2c62b5SGeorge Bișoc                     break;
13319a2c62b5SGeorge Bișoc                 }
13329a2c62b5SGeorge Bișoc             }
13339a2c62b5SGeorge Bișoc 
13349a2c62b5SGeorge Bișoc             /* Did we find the group? */
13359a2c62b5SGeorge Bișoc             if (GroupsInList == RegularGroupsSidCount)
13369a2c62b5SGeorge Bișoc             {
13379a2c62b5SGeorge Bișoc                 /* We didn't, continue with next one */
13389a2c62b5SGeorge Bișoc                 continue;
13399a2c62b5SGeorge Bișoc             }
13409a2c62b5SGeorge Bișoc 
13419a2c62b5SGeorge Bișoc             /* If we have found the group, disable it */
13429a2c62b5SGeorge Bișoc             if (FoundGroup)
13439a2c62b5SGeorge Bișoc             {
13449a2c62b5SGeorge Bișoc                 /*
13459a2c62b5SGeorge Bișoc                  * If the acess token belongs to the administrators
13469a2c62b5SGeorge Bișoc                  * group and this is the target group, we must take
13479a2c62b5SGeorge Bișoc                  * away TOKEN_HAS_ADMIN_GROUP flag from the token.
13489a2c62b5SGeorge Bișoc                  */
13499a2c62b5SGeorge Bișoc                 if (RtlEqualSid(SeAliasAdminsSid,
13509a2c62b5SGeorge Bișoc                                 &AccessToken->UserAndGroups[GroupsInToken].Sid))
13519a2c62b5SGeorge Bișoc                 {
13529a2c62b5SGeorge Bișoc                     AccessToken->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP;
13539a2c62b5SGeorge Bișoc                 }
13549a2c62b5SGeorge Bișoc 
13559a2c62b5SGeorge Bișoc                 /*
13569a2c62b5SGeorge Bișoc                  * If the target group that we have found it is the
13579a2c62b5SGeorge Bișoc                  * owner then from now on it no longer is but the user.
13589a2c62b5SGeorge Bișoc                  * Therefore assign the default owner index as the user.
13599a2c62b5SGeorge Bișoc                  */
13609a2c62b5SGeorge Bișoc                 if (AccessToken->DefaultOwnerIndex == GroupsInToken)
13619a2c62b5SGeorge Bișoc                 {
13629a2c62b5SGeorge Bișoc                     AccessToken->DefaultOwnerIndex = 0;
13639a2c62b5SGeorge Bișoc                 }
13649a2c62b5SGeorge Bișoc 
13659a2c62b5SGeorge Bișoc                 /*
13669a2c62b5SGeorge Bișoc                  * The principle of disabling a group SID is by
13679a2c62b5SGeorge Bișoc                  * taking away SE_GROUP_ENABLED_BY_DEFAULT and
13689a2c62b5SGeorge Bișoc                  * SE_GROUP_ENABLED attributes and assign
13699a2c62b5SGeorge Bișoc                  * SE_GROUP_USE_FOR_DENY_ONLY. This renders
13709a2c62b5SGeorge Bișoc                  * SID a "Deny only" SID.
13719a2c62b5SGeorge Bișoc                  */
13729a2c62b5SGeorge Bișoc                 AccessToken->UserAndGroups[GroupsInToken].Attributes &= ~(SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
13739a2c62b5SGeorge Bișoc                 AccessToken->UserAndGroups[GroupsInToken].Attributes |= SE_GROUP_USE_FOR_DENY_ONLY;
13749a2c62b5SGeorge Bișoc 
13759a2c62b5SGeorge Bișoc                 /* Adjust the index and continue with the next group */
13769a2c62b5SGeorge Bișoc                 GroupsInToken--;
13779a2c62b5SGeorge Bișoc                 FoundGroup = FALSE;
13789a2c62b5SGeorge Bișoc                 continue;
13799a2c62b5SGeorge Bișoc             }
13809a2c62b5SGeorge Bișoc         }
13819a2c62b5SGeorge Bișoc     }
13829a2c62b5SGeorge Bișoc 
13839a2c62b5SGeorge Bișoc     /* We've finally filtered the token, return it to the caller */
13849a2c62b5SGeorge Bișoc     *FilteredToken = AccessToken;
13859a2c62b5SGeorge Bișoc     Status = STATUS_SUCCESS;
13869a2c62b5SGeorge Bișoc     DPRINT("SepPerformTokenFiltering(): The token has been filtered!\n");
13879a2c62b5SGeorge Bișoc 
13889a2c62b5SGeorge Bișoc Quit:
13899a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
13909a2c62b5SGeorge Bișoc     {
13919a2c62b5SGeorge Bișoc         /* Dereference the created token */
13929a2c62b5SGeorge Bișoc         ObDereferenceObject(AccessToken);
13939a2c62b5SGeorge Bișoc     }
13949a2c62b5SGeorge Bișoc 
13959a2c62b5SGeorge Bișoc     /* Unlock the source token */
13969a2c62b5SGeorge Bișoc     SepReleaseTokenLock(Token);
13979a2c62b5SGeorge Bișoc 
13989a2c62b5SGeorge Bișoc     return Status;
13999a2c62b5SGeorge Bișoc }
14009a2c62b5SGeorge Bișoc 
14019a2c62b5SGeorge Bișoc /* PUBLIC FUNCTIONS ***********************************************************/
14029a2c62b5SGeorge Bișoc 
14039a2c62b5SGeorge Bișoc /**
14049a2c62b5SGeorge Bișoc  * @brief
14059a2c62b5SGeorge Bișoc  * Filters an access token from an existing token, making it more restricted
14069a2c62b5SGeorge Bișoc  * than the previous one.
14079a2c62b5SGeorge Bișoc  *
14089a2c62b5SGeorge Bișoc  * @param[in] ExistingToken
14099a2c62b5SGeorge Bișoc  * An existing token for filtering.
14109a2c62b5SGeorge Bișoc  *
14119a2c62b5SGeorge Bișoc  * @param[in] Flags
14129a2c62b5SGeorge Bișoc  * Privilege flag options. This parameter argument influences how the token
14139a2c62b5SGeorge Bișoc  * is filtered. Such parameter can be 0. See NtFilterToken syscall for
14149a2c62b5SGeorge Bișoc  * more information.
14159a2c62b5SGeorge Bișoc  *
14169a2c62b5SGeorge Bișoc  * @param[in] SidsToDisable
14179a2c62b5SGeorge Bișoc  * Array of SIDs to disable. Such parameter can be NULL.
14189a2c62b5SGeorge Bișoc  *
14199a2c62b5SGeorge Bișoc  * @param[in] PrivilegesToDelete
14209a2c62b5SGeorge Bișoc  * Array of privileges to delete. If DISABLE_MAX_PRIVILEGE flag is specified
14219a2c62b5SGeorge Bișoc  * in the Flags parameter, PrivilegesToDelete is ignored.
14229a2c62b5SGeorge Bișoc  *
14239a2c62b5SGeorge Bișoc  * @param[in] RestrictedSids
14249a2c62b5SGeorge Bișoc  * An array of restricted SIDs for the new filtered token. Such parameter
14259a2c62b5SGeorge Bișoc  * can be NULL.
14269a2c62b5SGeorge Bișoc  *
14279a2c62b5SGeorge Bișoc  * @param[out] FilteredToken
14289a2c62b5SGeorge Bișoc  * The newly filtered token, returned to the caller.
14299a2c62b5SGeorge Bișoc  *
14309a2c62b5SGeorge Bișoc  * @return
14319a2c62b5SGeorge Bișoc  * Returns STATUS_SUCCESS if the function has successfully completed its
14329a2c62b5SGeorge Bișoc  * operations and that the access token has been filtered. STATUS_INVALID_PARAMETER
14339a2c62b5SGeorge Bișoc  * is returned if one or more of the parameter are not valid. A failure NTSTATUS code
14349a2c62b5SGeorge Bișoc  * is returned otherwise.
14359a2c62b5SGeorge Bișoc  */
14369a2c62b5SGeorge Bișoc NTSTATUS
14379a2c62b5SGeorge Bișoc 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)14389a2c62b5SGeorge Bișoc SeFilterToken(
14399a2c62b5SGeorge Bișoc     _In_ PACCESS_TOKEN ExistingToken,
14409a2c62b5SGeorge Bișoc     _In_ ULONG Flags,
14419a2c62b5SGeorge Bișoc     _In_opt_ PTOKEN_GROUPS SidsToDisable,
14429a2c62b5SGeorge Bișoc     _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,
14439a2c62b5SGeorge Bișoc     _In_opt_ PTOKEN_GROUPS RestrictedSids,
14449a2c62b5SGeorge Bișoc     _Out_ PACCESS_TOKEN *FilteredToken)
14459a2c62b5SGeorge Bișoc {
14469a2c62b5SGeorge Bișoc     NTSTATUS Status;
14479a2c62b5SGeorge Bișoc     PTOKEN AccessToken;
14489a2c62b5SGeorge Bișoc     ULONG PrivilegesCount = 0;
14499a2c62b5SGeorge Bișoc     ULONG SidsCount = 0;
14509a2c62b5SGeorge Bișoc     ULONG RestrictedSidsCount = 0;
14519a2c62b5SGeorge Bișoc 
14529a2c62b5SGeorge Bișoc     PAGED_CODE();
14539a2c62b5SGeorge Bișoc 
14549a2c62b5SGeorge Bișoc     /* Begin copying the counters */
14559a2c62b5SGeorge Bișoc     if (SidsToDisable != NULL)
14569a2c62b5SGeorge Bișoc     {
14579a2c62b5SGeorge Bișoc         SidsCount = SidsToDisable->GroupCount;
14589a2c62b5SGeorge Bișoc     }
14599a2c62b5SGeorge Bișoc 
14609a2c62b5SGeorge Bișoc     if (PrivilegesToDelete != NULL)
14619a2c62b5SGeorge Bișoc     {
14629a2c62b5SGeorge Bișoc         PrivilegesCount = PrivilegesToDelete->PrivilegeCount;
14639a2c62b5SGeorge Bișoc     }
14649a2c62b5SGeorge Bișoc 
14659a2c62b5SGeorge Bișoc     if (RestrictedSids != NULL)
14669a2c62b5SGeorge Bișoc     {
14679a2c62b5SGeorge Bișoc         RestrictedSidsCount = RestrictedSids->GroupCount;
14689a2c62b5SGeorge Bișoc     }
14699a2c62b5SGeorge Bișoc 
14709a2c62b5SGeorge Bișoc     /* Call the internal API */
14719a2c62b5SGeorge Bișoc     Status = SepPerformTokenFiltering(ExistingToken,
14729a2c62b5SGeorge Bișoc                                       PrivilegesToDelete->Privileges,
14739a2c62b5SGeorge Bișoc                                       SidsToDisable->Groups,
14749a2c62b5SGeorge Bișoc                                       RestrictedSids->Groups,
14759a2c62b5SGeorge Bișoc                                       PrivilegesCount,
14769a2c62b5SGeorge Bișoc                                       SidsCount,
14779a2c62b5SGeorge Bișoc                                       RestrictedSidsCount,
14789a2c62b5SGeorge Bișoc                                       Flags,
14799a2c62b5SGeorge Bișoc                                       KernelMode,
14809a2c62b5SGeorge Bișoc                                       &AccessToken);
14819a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
14829a2c62b5SGeorge Bișoc     {
14839a2c62b5SGeorge Bișoc         DPRINT1("SeFilterToken(): Failed to filter the token (Status 0x%lx)\n", Status);
14849a2c62b5SGeorge Bișoc         return Status;
14859a2c62b5SGeorge Bișoc     }
14869a2c62b5SGeorge Bișoc 
14879a2c62b5SGeorge Bișoc     /* Insert the filtered token */
14889a2c62b5SGeorge Bișoc     Status = ObInsertObject(AccessToken,
14899a2c62b5SGeorge Bișoc                             NULL,
14909a2c62b5SGeorge Bișoc                             0,
14919a2c62b5SGeorge Bișoc                             0,
14929a2c62b5SGeorge Bișoc                             NULL,
14939a2c62b5SGeorge Bișoc                             NULL);
14949a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
14959a2c62b5SGeorge Bișoc     {
14969a2c62b5SGeorge Bișoc         DPRINT1("SeFilterToken(): Failed to insert the filtered token (Status 0x%lx)\n", Status);
14979a2c62b5SGeorge Bișoc         return Status;
14989a2c62b5SGeorge Bișoc     }
14999a2c62b5SGeorge Bișoc 
15009a2c62b5SGeorge Bișoc     /* Return it to the caller */
15019a2c62b5SGeorge Bișoc     *FilteredToken = AccessToken;
15029a2c62b5SGeorge Bișoc     return Status;
15039a2c62b5SGeorge Bișoc }
15049a2c62b5SGeorge Bișoc 
15059a2c62b5SGeorge Bișoc /* SYSTEM CALLS ***************************************************************/
15069a2c62b5SGeorge Bișoc 
15079a2c62b5SGeorge Bișoc /**
15089a2c62b5SGeorge Bișoc  * @brief
15099a2c62b5SGeorge Bișoc  * Creates an access token.
15109a2c62b5SGeorge Bișoc  *
15119a2c62b5SGeorge Bișoc  * @param[out] TokenHandle
15129a2c62b5SGeorge Bișoc  * The returned created token handle to the caller.
15139a2c62b5SGeorge Bișoc  *
15149a2c62b5SGeorge Bișoc  * @param[in] DesiredAccess
15159a2c62b5SGeorge Bișoc  * The desired access rights for the token that we're creating.
15169a2c62b5SGeorge Bișoc  *
15179a2c62b5SGeorge Bișoc  * @param[in] ObjectAttributes
15189a2c62b5SGeorge Bișoc  * The object attributes for the token object that we're creating.
15199a2c62b5SGeorge Bișoc  *
15209a2c62b5SGeorge Bișoc  * @param[in] TokenType
15219a2c62b5SGeorge Bișoc  * The type of token to assign for the newly created token.
15229a2c62b5SGeorge Bișoc  *
15239a2c62b5SGeorge Bișoc  * @param[in] AuthenticationId
15249a2c62b5SGeorge Bișoc  * Authentication ID that represents the token's identity.
15259a2c62b5SGeorge Bișoc  *
15269a2c62b5SGeorge Bișoc  * @param[in] ExpirationTime
15279a2c62b5SGeorge Bișoc  * Expiration time for the token. If set to -1, the token never expires.
15289a2c62b5SGeorge Bișoc  *
15299a2c62b5SGeorge Bișoc  * @param[in] TokenUser
15309a2c62b5SGeorge Bișoc  * The main user entity for the token to assign.
15319a2c62b5SGeorge Bișoc  *
15329a2c62b5SGeorge Bișoc  * @param[in] TokenGroups
15339a2c62b5SGeorge Bișoc  * Group list of SIDs for the token to assign.
15349a2c62b5SGeorge Bișoc  *
15359a2c62b5SGeorge Bișoc  * @param[in] TokenPrivileges
15369a2c62b5SGeorge Bișoc  * Privileges for the token.
15379a2c62b5SGeorge Bișoc  *
15389a2c62b5SGeorge Bișoc  * @param[in] TokenOwner
15399a2c62b5SGeorge Bișoc  * The main user that owns the newly created token.
15409a2c62b5SGeorge Bișoc  *
15419a2c62b5SGeorge Bișoc  * @param[in] TokenPrimaryGroup
15429a2c62b5SGeorge Bișoc  * The primary group that represents as the main group of the token.
15439a2c62b5SGeorge Bișoc  *
15449a2c62b5SGeorge Bișoc  * @param[in] TokenDefaultDacl
15459a2c62b5SGeorge Bișoc  * Discretionary access control list for the token. This limits on how
15469a2c62b5SGeorge Bișoc  * the token can be used, accessed and used by whom.
15479a2c62b5SGeorge Bișoc  *
15489a2c62b5SGeorge Bișoc  * @param[in] TokenSource
15499a2c62b5SGeorge Bișoc  * The source origin of the token who creates it.
15509a2c62b5SGeorge Bișoc  *
15519a2c62b5SGeorge Bișoc  * @return
15529a2c62b5SGeorge Bișoc  * Returns STATUS_SUCCESS if the function has successfully created the token.
15539a2c62b5SGeorge Bișoc  * A failure NTSTATUS code is returned otherwise.
15549a2c62b5SGeorge Bișoc  */
15559a2c62b5SGeorge Bișoc __kernel_entry
15569a2c62b5SGeorge Bișoc NTSTATUS
15579a2c62b5SGeorge Bișoc 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)15589a2c62b5SGeorge Bișoc NtCreateToken(
15599a2c62b5SGeorge Bișoc     _Out_ PHANDLE TokenHandle,
15609a2c62b5SGeorge Bișoc     _In_ ACCESS_MASK DesiredAccess,
15619a2c62b5SGeorge Bișoc     _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
15629a2c62b5SGeorge Bișoc     _In_ TOKEN_TYPE TokenType,
15639a2c62b5SGeorge Bișoc     _In_ PLUID AuthenticationId,
15649a2c62b5SGeorge Bișoc     _In_ PLARGE_INTEGER ExpirationTime,
15659a2c62b5SGeorge Bișoc     _In_ PTOKEN_USER TokenUser,
15669a2c62b5SGeorge Bișoc     _In_ PTOKEN_GROUPS TokenGroups,
15679a2c62b5SGeorge Bișoc     _In_ PTOKEN_PRIVILEGES TokenPrivileges,
15689a2c62b5SGeorge Bișoc     _In_opt_ PTOKEN_OWNER TokenOwner,
15699a2c62b5SGeorge Bișoc     _In_ PTOKEN_PRIMARY_GROUP TokenPrimaryGroup,
15709a2c62b5SGeorge Bișoc     _In_opt_ PTOKEN_DEFAULT_DACL TokenDefaultDacl,
15719a2c62b5SGeorge Bișoc     _In_ PTOKEN_SOURCE TokenSource)
15729a2c62b5SGeorge Bișoc {
15739a2c62b5SGeorge Bișoc     HANDLE hToken;
15749a2c62b5SGeorge Bișoc     KPROCESSOR_MODE PreviousMode;
15759a2c62b5SGeorge Bișoc     ULONG PrivilegeCount, GroupCount;
15769a2c62b5SGeorge Bișoc     PSID OwnerSid, PrimaryGroupSid;
15779a2c62b5SGeorge Bișoc     PACL DefaultDacl;
15789a2c62b5SGeorge Bișoc     LARGE_INTEGER LocalExpirationTime = {{0, 0}};
15799a2c62b5SGeorge Bișoc     LUID LocalAuthenticationId;
15809a2c62b5SGeorge Bișoc     TOKEN_SOURCE LocalTokenSource;
15819a2c62b5SGeorge Bișoc     SECURITY_QUALITY_OF_SERVICE LocalSecurityQos;
15829a2c62b5SGeorge Bișoc     PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
15839a2c62b5SGeorge Bișoc     PSID_AND_ATTRIBUTES CapturedUser = NULL;
15849a2c62b5SGeorge Bișoc     PSID_AND_ATTRIBUTES CapturedGroups = NULL;
15859a2c62b5SGeorge Bișoc     PSID CapturedOwnerSid = NULL;
15869a2c62b5SGeorge Bișoc     PSID CapturedPrimaryGroupSid = NULL;
15879a2c62b5SGeorge Bișoc     PACL CapturedDefaultDacl = NULL;
15889a2c62b5SGeorge Bișoc     ULONG PrivilegesLength, UserLength, GroupsLength;
15899a2c62b5SGeorge Bișoc     NTSTATUS Status;
15909a2c62b5SGeorge Bișoc 
15919a2c62b5SGeorge Bișoc     PAGED_CODE();
15929a2c62b5SGeorge Bișoc 
15939a2c62b5SGeorge Bișoc     PreviousMode = ExGetPreviousMode();
15949a2c62b5SGeorge Bișoc 
15959a2c62b5SGeorge Bișoc     if (PreviousMode != KernelMode)
15969a2c62b5SGeorge Bișoc     {
15979a2c62b5SGeorge Bișoc         _SEH2_TRY
15989a2c62b5SGeorge Bișoc         {
15999a2c62b5SGeorge Bișoc             ProbeForWriteHandle(TokenHandle);
16009a2c62b5SGeorge Bișoc 
16019a2c62b5SGeorge Bișoc             if (ObjectAttributes != NULL)
16029a2c62b5SGeorge Bișoc             {
16039a2c62b5SGeorge Bișoc                 ProbeForRead(ObjectAttributes,
16049a2c62b5SGeorge Bișoc                              sizeof(OBJECT_ATTRIBUTES),
16059a2c62b5SGeorge Bișoc                              sizeof(ULONG));
16069a2c62b5SGeorge Bișoc                 LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
16079a2c62b5SGeorge Bișoc             }
16089a2c62b5SGeorge Bișoc 
16099a2c62b5SGeorge Bișoc             ProbeForRead(AuthenticationId,
16109a2c62b5SGeorge Bișoc                          sizeof(LUID),
16119a2c62b5SGeorge Bișoc                          sizeof(ULONG));
16129a2c62b5SGeorge Bișoc             LocalAuthenticationId = *AuthenticationId;
16139a2c62b5SGeorge Bișoc 
16149a2c62b5SGeorge Bișoc             LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
16159a2c62b5SGeorge Bișoc 
16169a2c62b5SGeorge Bișoc             ProbeForRead(TokenUser,
16179a2c62b5SGeorge Bișoc                          sizeof(TOKEN_USER),
16189a2c62b5SGeorge Bișoc                          sizeof(ULONG));
16199a2c62b5SGeorge Bișoc 
16209a2c62b5SGeorge Bișoc             ProbeForRead(TokenGroups,
16219a2c62b5SGeorge Bișoc                          sizeof(TOKEN_GROUPS),
16229a2c62b5SGeorge Bișoc                          sizeof(ULONG));
16239a2c62b5SGeorge Bișoc             GroupCount = TokenGroups->GroupCount;
16249a2c62b5SGeorge Bișoc 
16259a2c62b5SGeorge Bișoc             ProbeForRead(TokenPrivileges,
16269a2c62b5SGeorge Bișoc                          sizeof(TOKEN_PRIVILEGES),
16279a2c62b5SGeorge Bișoc                          sizeof(ULONG));
16289a2c62b5SGeorge Bișoc             PrivilegeCount = TokenPrivileges->PrivilegeCount;
16299a2c62b5SGeorge Bișoc 
16309a2c62b5SGeorge Bișoc             if (TokenOwner != NULL)
16319a2c62b5SGeorge Bișoc             {
16329a2c62b5SGeorge Bișoc                 ProbeForRead(TokenOwner,
16339a2c62b5SGeorge Bișoc                              sizeof(TOKEN_OWNER),
16349a2c62b5SGeorge Bișoc                              sizeof(ULONG));
16359a2c62b5SGeorge Bișoc                 OwnerSid = TokenOwner->Owner;
16369a2c62b5SGeorge Bișoc             }
16379a2c62b5SGeorge Bișoc             else
16389a2c62b5SGeorge Bișoc             {
16399a2c62b5SGeorge Bișoc                 OwnerSid = NULL;
16409a2c62b5SGeorge Bișoc             }
16419a2c62b5SGeorge Bișoc 
16429a2c62b5SGeorge Bișoc             ProbeForRead(TokenPrimaryGroup,
16439a2c62b5SGeorge Bișoc                          sizeof(TOKEN_PRIMARY_GROUP),
16449a2c62b5SGeorge Bișoc                          sizeof(ULONG));
16459a2c62b5SGeorge Bișoc             PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
16469a2c62b5SGeorge Bișoc 
16479a2c62b5SGeorge Bișoc             if (TokenDefaultDacl != NULL)
16489a2c62b5SGeorge Bișoc             {
16499a2c62b5SGeorge Bișoc                 ProbeForRead(TokenDefaultDacl,
16509a2c62b5SGeorge Bișoc                              sizeof(TOKEN_DEFAULT_DACL),
16519a2c62b5SGeorge Bișoc                              sizeof(ULONG));
16529a2c62b5SGeorge Bișoc                 DefaultDacl = TokenDefaultDacl->DefaultDacl;
16539a2c62b5SGeorge Bișoc             }
16549a2c62b5SGeorge Bișoc             else
16559a2c62b5SGeorge Bișoc             {
16569a2c62b5SGeorge Bișoc                 DefaultDacl = NULL;
16579a2c62b5SGeorge Bișoc             }
16589a2c62b5SGeorge Bișoc 
16599a2c62b5SGeorge Bișoc             ProbeForRead(TokenSource,
16609a2c62b5SGeorge Bișoc                          sizeof(TOKEN_SOURCE),
16619a2c62b5SGeorge Bișoc                          sizeof(ULONG));
16629a2c62b5SGeorge Bișoc             LocalTokenSource = *TokenSource;
16639a2c62b5SGeorge Bișoc         }
16649a2c62b5SGeorge Bișoc         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
16659a2c62b5SGeorge Bișoc         {
16669a2c62b5SGeorge Bișoc             /* Return the exception code */
16679a2c62b5SGeorge Bișoc             _SEH2_YIELD(return _SEH2_GetExceptionCode());
16689a2c62b5SGeorge Bișoc         }
16699a2c62b5SGeorge Bișoc         _SEH2_END;
16709a2c62b5SGeorge Bișoc     }
16719a2c62b5SGeorge Bișoc     else
16729a2c62b5SGeorge Bișoc     {
16739a2c62b5SGeorge Bișoc         if (ObjectAttributes != NULL)
16749a2c62b5SGeorge Bișoc             LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
16759a2c62b5SGeorge Bișoc         LocalAuthenticationId = *AuthenticationId;
16769a2c62b5SGeorge Bișoc         LocalExpirationTime = *ExpirationTime;
16779a2c62b5SGeorge Bișoc         GroupCount = TokenGroups->GroupCount;
16789a2c62b5SGeorge Bișoc         PrivilegeCount = TokenPrivileges->PrivilegeCount;
16799a2c62b5SGeorge Bișoc         OwnerSid = TokenOwner ? TokenOwner->Owner : NULL;
16809a2c62b5SGeorge Bișoc         PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
16819a2c62b5SGeorge Bișoc         DefaultDacl = TokenDefaultDacl ? TokenDefaultDacl->DefaultDacl : NULL;
16829a2c62b5SGeorge Bișoc         LocalTokenSource = *TokenSource;
16839a2c62b5SGeorge Bișoc     }
16849a2c62b5SGeorge Bișoc 
16859a2c62b5SGeorge Bișoc     /* Check token type */
16869a2c62b5SGeorge Bișoc     if ((TokenType < TokenPrimary) ||
16879a2c62b5SGeorge Bișoc         (TokenType > TokenImpersonation))
16889a2c62b5SGeorge Bișoc     {
16899a2c62b5SGeorge Bișoc         return STATUS_BAD_TOKEN_TYPE;
16909a2c62b5SGeorge Bișoc     }
16919a2c62b5SGeorge Bișoc 
16929a2c62b5SGeorge Bișoc     /* Check for token creation privilege */
16939a2c62b5SGeorge Bișoc     if (!SeSinglePrivilegeCheck(SeCreateTokenPrivilege, PreviousMode))
16949a2c62b5SGeorge Bișoc     {
16959a2c62b5SGeorge Bișoc         return STATUS_PRIVILEGE_NOT_HELD;
16969a2c62b5SGeorge Bișoc     }
16979a2c62b5SGeorge Bișoc 
16989a2c62b5SGeorge Bișoc     /* Capture the user SID and attributes */
16999a2c62b5SGeorge Bișoc     Status = SeCaptureSidAndAttributesArray(&TokenUser->User,
17009a2c62b5SGeorge Bișoc                                             1,
17019a2c62b5SGeorge Bișoc                                             PreviousMode,
17029a2c62b5SGeorge Bișoc                                             NULL,
17039a2c62b5SGeorge Bișoc                                             0,
17049a2c62b5SGeorge Bișoc                                             PagedPool,
17059a2c62b5SGeorge Bișoc                                             FALSE,
17069a2c62b5SGeorge Bișoc                                             &CapturedUser,
17079a2c62b5SGeorge Bișoc                                             &UserLength);
17089a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
17099a2c62b5SGeorge Bișoc     {
17109a2c62b5SGeorge Bișoc         goto Cleanup;
17119a2c62b5SGeorge Bișoc     }
17129a2c62b5SGeorge Bișoc 
17139a2c62b5SGeorge Bișoc     /* Capture the groups SID and attributes array */
17149a2c62b5SGeorge Bișoc     Status = SeCaptureSidAndAttributesArray(&TokenGroups->Groups[0],
17159a2c62b5SGeorge Bișoc                                             GroupCount,
17169a2c62b5SGeorge Bișoc                                             PreviousMode,
17179a2c62b5SGeorge Bișoc                                             NULL,
17189a2c62b5SGeorge Bișoc                                             0,
17199a2c62b5SGeorge Bișoc                                             PagedPool,
17209a2c62b5SGeorge Bișoc                                             FALSE,
17219a2c62b5SGeorge Bișoc                                             &CapturedGroups,
17229a2c62b5SGeorge Bișoc                                             &GroupsLength);
17239a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
17249a2c62b5SGeorge Bișoc     {
17259a2c62b5SGeorge Bișoc         goto Cleanup;
17269a2c62b5SGeorge Bișoc     }
17279a2c62b5SGeorge Bișoc 
17289a2c62b5SGeorge Bișoc     /* Capture privileges */
17299a2c62b5SGeorge Bișoc     Status = SeCaptureLuidAndAttributesArray(&TokenPrivileges->Privileges[0],
17309a2c62b5SGeorge Bișoc                                              PrivilegeCount,
17319a2c62b5SGeorge Bișoc                                              PreviousMode,
17329a2c62b5SGeorge Bișoc                                              NULL,
17339a2c62b5SGeorge Bișoc                                              0,
17349a2c62b5SGeorge Bișoc                                              PagedPool,
17359a2c62b5SGeorge Bișoc                                              FALSE,
17369a2c62b5SGeorge Bișoc                                              &CapturedPrivileges,
17379a2c62b5SGeorge Bișoc                                              &PrivilegesLength);
17389a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
17399a2c62b5SGeorge Bișoc     {
17409a2c62b5SGeorge Bișoc         goto Cleanup;
17419a2c62b5SGeorge Bișoc     }
17429a2c62b5SGeorge Bișoc 
17439a2c62b5SGeorge Bișoc     /* Capture the token owner SID */
17449a2c62b5SGeorge Bișoc     if (TokenOwner != NULL)
17459a2c62b5SGeorge Bișoc     {
17469a2c62b5SGeorge Bișoc         Status = SepCaptureSid(OwnerSid,
17479a2c62b5SGeorge Bișoc                                PreviousMode,
17489a2c62b5SGeorge Bișoc                                PagedPool,
17499a2c62b5SGeorge Bișoc                                FALSE,
17509a2c62b5SGeorge Bișoc                                &CapturedOwnerSid);
17519a2c62b5SGeorge Bișoc         if (!NT_SUCCESS(Status))
17529a2c62b5SGeorge Bișoc         {
17539a2c62b5SGeorge Bișoc             goto Cleanup;
17549a2c62b5SGeorge Bișoc         }
17559a2c62b5SGeorge Bișoc     }
17569a2c62b5SGeorge Bișoc 
17579a2c62b5SGeorge Bișoc     /* Capture the token primary group SID */
17589a2c62b5SGeorge Bișoc     Status = SepCaptureSid(PrimaryGroupSid,
17599a2c62b5SGeorge Bișoc                            PreviousMode,
17609a2c62b5SGeorge Bișoc                            PagedPool,
17619a2c62b5SGeorge Bișoc                            FALSE,
17629a2c62b5SGeorge Bișoc                            &CapturedPrimaryGroupSid);
17639a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
17649a2c62b5SGeorge Bișoc     {
17659a2c62b5SGeorge Bișoc         goto Cleanup;
17669a2c62b5SGeorge Bișoc     }
17679a2c62b5SGeorge Bișoc 
17689a2c62b5SGeorge Bișoc     /* Capture DefaultDacl */
17699a2c62b5SGeorge Bișoc     if (DefaultDacl != NULL)
17709a2c62b5SGeorge Bișoc     {
17719a2c62b5SGeorge Bișoc         Status = SepCaptureAcl(DefaultDacl,
17729a2c62b5SGeorge Bișoc                                PreviousMode,
17739a2c62b5SGeorge Bișoc                                NonPagedPool,
17749a2c62b5SGeorge Bișoc                                FALSE,
17759a2c62b5SGeorge Bișoc                                &CapturedDefaultDacl);
17769a2c62b5SGeorge Bișoc         if (!NT_SUCCESS(Status))
17779a2c62b5SGeorge Bișoc         {
17789a2c62b5SGeorge Bișoc             goto Cleanup;
17799a2c62b5SGeorge Bișoc         }
17809a2c62b5SGeorge Bișoc     }
17819a2c62b5SGeorge Bișoc 
17829a2c62b5SGeorge Bișoc     /* Call the internal function */
17839a2c62b5SGeorge Bișoc     Status = SepCreateToken(&hToken,
17849a2c62b5SGeorge Bișoc                             PreviousMode,
17859a2c62b5SGeorge Bișoc                             DesiredAccess,
17869a2c62b5SGeorge Bișoc                             ObjectAttributes,
17879a2c62b5SGeorge Bișoc                             TokenType,
17889a2c62b5SGeorge Bișoc                             LocalSecurityQos.ImpersonationLevel,
17899a2c62b5SGeorge Bișoc                             &LocalAuthenticationId,
17909a2c62b5SGeorge Bișoc                             &LocalExpirationTime,
17919a2c62b5SGeorge Bișoc                             CapturedUser,
17929a2c62b5SGeorge Bișoc                             GroupCount,
17939a2c62b5SGeorge Bișoc                             CapturedGroups,
17949a2c62b5SGeorge Bișoc                             GroupsLength,
17959a2c62b5SGeorge Bișoc                             PrivilegeCount,
17969a2c62b5SGeorge Bișoc                             CapturedPrivileges,
17979a2c62b5SGeorge Bișoc                             CapturedOwnerSid,
17989a2c62b5SGeorge Bișoc                             CapturedPrimaryGroupSid,
17999a2c62b5SGeorge Bișoc                             CapturedDefaultDacl,
18009a2c62b5SGeorge Bișoc                             &LocalTokenSource,
18019a2c62b5SGeorge Bișoc                             FALSE);
18029a2c62b5SGeorge Bișoc     if (NT_SUCCESS(Status))
18039a2c62b5SGeorge Bișoc     {
18049a2c62b5SGeorge Bișoc         _SEH2_TRY
18059a2c62b5SGeorge Bișoc         {
18069a2c62b5SGeorge Bișoc             *TokenHandle = hToken;
18079a2c62b5SGeorge Bișoc         }
18089a2c62b5SGeorge Bișoc         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
18099a2c62b5SGeorge Bișoc         {
18109a2c62b5SGeorge Bișoc             Status = _SEH2_GetExceptionCode();
18119a2c62b5SGeorge Bișoc         }
18129a2c62b5SGeorge Bișoc         _SEH2_END;
18139a2c62b5SGeorge Bișoc     }
18149a2c62b5SGeorge Bișoc 
18159a2c62b5SGeorge Bișoc Cleanup:
18169a2c62b5SGeorge Bișoc 
18179a2c62b5SGeorge Bișoc     /* Release what we captured */
18189a2c62b5SGeorge Bișoc     SeReleaseSidAndAttributesArray(CapturedUser, PreviousMode, FALSE);
18199a2c62b5SGeorge Bișoc     SeReleaseSidAndAttributesArray(CapturedGroups, PreviousMode, FALSE);
18209a2c62b5SGeorge Bișoc     SeReleaseLuidAndAttributesArray(CapturedPrivileges, PreviousMode, FALSE);
18219a2c62b5SGeorge Bișoc     SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE);
18229a2c62b5SGeorge Bișoc     SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE);
18239a2c62b5SGeorge Bișoc     SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE);
18249a2c62b5SGeorge Bișoc 
18259a2c62b5SGeorge Bișoc     return Status;
18269a2c62b5SGeorge Bișoc }
18279a2c62b5SGeorge Bișoc 
18289a2c62b5SGeorge Bișoc /**
18299a2c62b5SGeorge Bișoc  * @brief
18309a2c62b5SGeorge Bișoc  * Duplicates a token.
18319a2c62b5SGeorge Bișoc  *
18329a2c62b5SGeorge Bișoc  * @param[in] ExistingTokenHandle
18339a2c62b5SGeorge Bișoc  * An existing token to duplicate.
18349a2c62b5SGeorge Bișoc  *
18359a2c62b5SGeorge Bișoc  * @param[in] DesiredAccess
18369a2c62b5SGeorge Bișoc  * The desired access rights for the new duplicated token.
18379a2c62b5SGeorge Bișoc  *
18389a2c62b5SGeorge Bișoc  * @param[in] ObjectAttributes
18399a2c62b5SGeorge Bișoc  * Object attributes for the new duplicated token.
18409a2c62b5SGeorge Bișoc  *
18419a2c62b5SGeorge Bișoc  * @param[in] EffectiveOnly
18429a2c62b5SGeorge Bișoc  * If set to TRUE, the function removes all the disabled privileges and groups
18439a2c62b5SGeorge Bișoc  * of the token to duplicate.
18449a2c62b5SGeorge Bișoc  *
18459a2c62b5SGeorge Bișoc  * @param[in] TokenType
18469a2c62b5SGeorge Bișoc  * Type of token to assign to the duplicated token.
18479a2c62b5SGeorge Bișoc  *
18489a2c62b5SGeorge Bișoc  * @param[out] NewTokenHandle
18499a2c62b5SGeorge Bișoc  * The returned duplicated token handle.
18509a2c62b5SGeorge Bișoc  *
18519a2c62b5SGeorge Bișoc  * @return
18529a2c62b5SGeorge Bișoc  * STATUS_SUCCESS is returned if token duplication has completed successfully.
18539a2c62b5SGeorge Bișoc  * STATUS_BAD_IMPERSONATION_LEVEL is returned if the caller erroneously wants
18549a2c62b5SGeorge Bișoc  * to raise the impersonation level even though the conditions do not permit
18559a2c62b5SGeorge Bișoc  * it. A failure NTSTATUS code is returned otherwise.
18569a2c62b5SGeorge Bișoc  *
18579a2c62b5SGeorge Bișoc  * @remarks
18589a2c62b5SGeorge Bișoc  * Some sources claim 4th param is ImpersonationLevel, but on W2K
18599a2c62b5SGeorge Bișoc  * this is certainly NOT true, although I can't say for sure that EffectiveOnly
18609a2c62b5SGeorge Bișoc  * is correct either. -Gunnar
18619a2c62b5SGeorge Bișoc  * This is true. EffectiveOnly overrides SQOS.EffectiveOnly. - IAI
18629a2c62b5SGeorge Bișoc  * NOTE for readers: http://hex.pp.ua/nt/NtDuplicateToken.php is therefore
18639a2c62b5SGeorge Bișoc  * wrong in that regard, while MSDN documentation is correct.
18649a2c62b5SGeorge Bișoc  */
18659a2c62b5SGeorge Bișoc _Must_inspect_result_
18669a2c62b5SGeorge Bișoc __kernel_entry
18679a2c62b5SGeorge Bișoc NTSTATUS
18689a2c62b5SGeorge Bișoc NTAPI
NtDuplicateToken(_In_ HANDLE ExistingTokenHandle,_In_ ACCESS_MASK DesiredAccess,_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,_In_ BOOLEAN EffectiveOnly,_In_ TOKEN_TYPE TokenType,_Out_ PHANDLE NewTokenHandle)18699a2c62b5SGeorge Bișoc NtDuplicateToken(
18709a2c62b5SGeorge Bișoc     _In_ HANDLE ExistingTokenHandle,
18719a2c62b5SGeorge Bișoc     _In_ ACCESS_MASK DesiredAccess,
18729a2c62b5SGeorge Bișoc     _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
18739a2c62b5SGeorge Bișoc     _In_ BOOLEAN EffectiveOnly,
18749a2c62b5SGeorge Bișoc     _In_ TOKEN_TYPE TokenType,
18759a2c62b5SGeorge Bișoc     _Out_ PHANDLE NewTokenHandle)
18769a2c62b5SGeorge Bișoc {
18779a2c62b5SGeorge Bișoc     KPROCESSOR_MODE PreviousMode;
18789a2c62b5SGeorge Bișoc     HANDLE hToken;
18799a2c62b5SGeorge Bișoc     PTOKEN Token;
18809a2c62b5SGeorge Bișoc     PTOKEN NewToken;
18819a2c62b5SGeorge Bișoc     PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService;
18829a2c62b5SGeorge Bișoc     BOOLEAN QoSPresent;
18839a2c62b5SGeorge Bișoc     OBJECT_HANDLE_INFORMATION HandleInformation;
18849a2c62b5SGeorge Bișoc     NTSTATUS Status;
18859a2c62b5SGeorge Bișoc 
18869a2c62b5SGeorge Bișoc     PAGED_CODE();
18879a2c62b5SGeorge Bișoc 
18889a2c62b5SGeorge Bișoc     if (TokenType != TokenImpersonation &&
18899a2c62b5SGeorge Bișoc         TokenType != TokenPrimary)
18909a2c62b5SGeorge Bișoc     {
18919a2c62b5SGeorge Bișoc         return STATUS_INVALID_PARAMETER;
18929a2c62b5SGeorge Bișoc     }
18939a2c62b5SGeorge Bișoc 
18949a2c62b5SGeorge Bișoc     PreviousMode = KeGetPreviousMode();
18959a2c62b5SGeorge Bișoc 
18969a2c62b5SGeorge Bișoc     if (PreviousMode != KernelMode)
18979a2c62b5SGeorge Bișoc     {
18989a2c62b5SGeorge Bișoc         _SEH2_TRY
18999a2c62b5SGeorge Bișoc         {
19009a2c62b5SGeorge Bișoc             ProbeForWriteHandle(NewTokenHandle);
19019a2c62b5SGeorge Bișoc         }
19029a2c62b5SGeorge Bișoc         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
19039a2c62b5SGeorge Bișoc         {
19049a2c62b5SGeorge Bișoc             /* Return the exception code */
19059a2c62b5SGeorge Bișoc             _SEH2_YIELD(return _SEH2_GetExceptionCode());
19069a2c62b5SGeorge Bișoc         }
19079a2c62b5SGeorge Bișoc         _SEH2_END;
19089a2c62b5SGeorge Bișoc     }
19099a2c62b5SGeorge Bișoc 
19109a2c62b5SGeorge Bișoc     Status = SepCaptureSecurityQualityOfService(ObjectAttributes,
19119a2c62b5SGeorge Bișoc                                                 PreviousMode,
19129a2c62b5SGeorge Bișoc                                                 PagedPool,
19139a2c62b5SGeorge Bișoc                                                 FALSE,
19149a2c62b5SGeorge Bișoc                                                 &CapturedSecurityQualityOfService,
19159a2c62b5SGeorge Bișoc                                                 &QoSPresent);
19169a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
19179a2c62b5SGeorge Bișoc     {
19189a2c62b5SGeorge Bișoc         DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status);
19199a2c62b5SGeorge Bișoc         return Status;
19209a2c62b5SGeorge Bișoc     }
19219a2c62b5SGeorge Bișoc 
19229a2c62b5SGeorge Bișoc     Status = ObReferenceObjectByHandle(ExistingTokenHandle,
19239a2c62b5SGeorge Bișoc                                        TOKEN_DUPLICATE,
19249a2c62b5SGeorge Bișoc                                        SeTokenObjectType,
19259a2c62b5SGeorge Bișoc                                        PreviousMode,
19269a2c62b5SGeorge Bișoc                                        (PVOID*)&Token,
19279a2c62b5SGeorge Bișoc                                        &HandleInformation);
19289a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
19299a2c62b5SGeorge Bișoc     {
19309a2c62b5SGeorge Bișoc         DPRINT1("Failed to reference token (Status 0x%lx)\n", Status);
19319a2c62b5SGeorge Bișoc         SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
19329a2c62b5SGeorge Bișoc                                            PreviousMode,
19339a2c62b5SGeorge Bișoc                                            FALSE);
19349a2c62b5SGeorge Bișoc         return Status;
19359a2c62b5SGeorge Bișoc     }
19369a2c62b5SGeorge Bișoc 
19379a2c62b5SGeorge Bișoc     /*
19389a2c62b5SGeorge Bișoc      * Fail, if the original token is an impersonation token and the caller
19399a2c62b5SGeorge Bișoc      * tries to raise the impersonation level of the new token above the
19409a2c62b5SGeorge Bișoc      * impersonation level of the original token.
19419a2c62b5SGeorge Bișoc      */
19429a2c62b5SGeorge Bișoc     if (Token->TokenType == TokenImpersonation)
19439a2c62b5SGeorge Bișoc     {
19449a2c62b5SGeorge Bișoc         if (QoSPresent &&
19459a2c62b5SGeorge Bișoc             CapturedSecurityQualityOfService->ImpersonationLevel >Token->ImpersonationLevel)
19469a2c62b5SGeorge Bișoc         {
19479a2c62b5SGeorge Bișoc             ObDereferenceObject(Token);
19489a2c62b5SGeorge Bișoc             SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
19499a2c62b5SGeorge Bișoc                                                PreviousMode,
19509a2c62b5SGeorge Bișoc                                                FALSE);
19519a2c62b5SGeorge Bișoc             return STATUS_BAD_IMPERSONATION_LEVEL;
19529a2c62b5SGeorge Bișoc         }
19539a2c62b5SGeorge Bișoc     }
19549a2c62b5SGeorge Bișoc 
19559a2c62b5SGeorge Bișoc     /*
19569a2c62b5SGeorge Bișoc      * Fail, if a primary token is to be created from an impersonation token
19579a2c62b5SGeorge Bișoc      * and and the impersonation level of the impersonation token is below SecurityImpersonation.
19589a2c62b5SGeorge Bișoc      */
19599a2c62b5SGeorge Bișoc     if (Token->TokenType == TokenImpersonation &&
19609a2c62b5SGeorge Bișoc         TokenType == TokenPrimary &&
19619a2c62b5SGeorge Bișoc         Token->ImpersonationLevel < SecurityImpersonation)
19629a2c62b5SGeorge Bișoc     {
19639a2c62b5SGeorge Bișoc         ObDereferenceObject(Token);
19649a2c62b5SGeorge Bișoc         SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
19659a2c62b5SGeorge Bișoc                                            PreviousMode,
19669a2c62b5SGeorge Bișoc                                            FALSE);
19679a2c62b5SGeorge Bișoc         return STATUS_BAD_IMPERSONATION_LEVEL;
19689a2c62b5SGeorge Bișoc     }
19699a2c62b5SGeorge Bișoc 
19709a2c62b5SGeorge Bișoc     Status = SepDuplicateToken(Token,
19719a2c62b5SGeorge Bișoc                                ObjectAttributes,
19729a2c62b5SGeorge Bișoc                                EffectiveOnly,
19739a2c62b5SGeorge Bișoc                                TokenType,
19749a2c62b5SGeorge Bișoc                                (QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous),
19759a2c62b5SGeorge Bișoc                                PreviousMode,
19769a2c62b5SGeorge Bișoc                                &NewToken);
19779a2c62b5SGeorge Bișoc 
19789a2c62b5SGeorge Bișoc     ObDereferenceObject(Token);
19799a2c62b5SGeorge Bișoc 
19809a2c62b5SGeorge Bișoc     if (NT_SUCCESS(Status))
19819a2c62b5SGeorge Bișoc     {
19829a2c62b5SGeorge Bișoc         Status = ObInsertObject(NewToken,
19839a2c62b5SGeorge Bișoc                                 NULL,
19849a2c62b5SGeorge Bișoc                                 (DesiredAccess ? DesiredAccess : HandleInformation.GrantedAccess),
19859a2c62b5SGeorge Bișoc                                 0,
19869a2c62b5SGeorge Bișoc                                 NULL,
19879a2c62b5SGeorge Bișoc                                 &hToken);
19889a2c62b5SGeorge Bișoc         if (NT_SUCCESS(Status))
19899a2c62b5SGeorge Bișoc         {
19909a2c62b5SGeorge Bișoc             _SEH2_TRY
19919a2c62b5SGeorge Bișoc             {
19929a2c62b5SGeorge Bișoc                 *NewTokenHandle = hToken;
19939a2c62b5SGeorge Bișoc             }
19949a2c62b5SGeorge Bișoc             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
19959a2c62b5SGeorge Bișoc             {
19969a2c62b5SGeorge Bișoc                 Status = _SEH2_GetExceptionCode();
19979a2c62b5SGeorge Bișoc             }
19989a2c62b5SGeorge Bișoc             _SEH2_END;
19999a2c62b5SGeorge Bișoc         }
20009a2c62b5SGeorge Bișoc     }
20019a2c62b5SGeorge Bișoc 
20029a2c62b5SGeorge Bișoc     /* Free the captured structure */
20039a2c62b5SGeorge Bișoc     SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
20049a2c62b5SGeorge Bișoc                                        PreviousMode,
20059a2c62b5SGeorge Bișoc                                        FALSE);
20069a2c62b5SGeorge Bișoc 
20079a2c62b5SGeorge Bișoc     return Status;
20089a2c62b5SGeorge Bișoc }
20099a2c62b5SGeorge Bișoc 
20109a2c62b5SGeorge Bișoc /**
20119a2c62b5SGeorge Bișoc  * @brief
20129a2c62b5SGeorge Bișoc  * Creates an access token in a restricted form
20139a2c62b5SGeorge Bișoc  * from the original existing token, that is, such
20149a2c62b5SGeorge Bișoc  * action is called filtering.
20159a2c62b5SGeorge Bișoc  *
20169a2c62b5SGeorge Bișoc  * @param[in] ExistingTokenHandle
20179a2c62b5SGeorge Bișoc  * A handle to an access token which is to be filtered.
20189a2c62b5SGeorge Bișoc  *
20199a2c62b5SGeorge Bișoc  * @param[in] Flags
20209a2c62b5SGeorge Bișoc  * Privilege flag options. This parameter argument influences how the
20219a2c62b5SGeorge Bișoc  * token's privileges are filtered. For further details see remarks.
20229a2c62b5SGeorge Bișoc  *
20239a2c62b5SGeorge Bișoc  * @param[in] SidsToDisable
20249a2c62b5SGeorge Bișoc  * Array of SIDs to disable. The action of doing so assigns the
20259a2c62b5SGeorge Bișoc  * SE_GROUP_USE_FOR_DENY_ONLY attribute to the respective group
20269a2c62b5SGeorge Bișoc  * SID and takes away SE_GROUP_ENABLED and SE_GROUP_ENABLED_BY_DEFAULT.
20279a2c62b5SGeorge Bișoc  * This parameter can be NULL. This can be a UM pointer.
20289a2c62b5SGeorge Bișoc  *
20299a2c62b5SGeorge Bișoc  * @param[in] PrivilegesToDelete
20309a2c62b5SGeorge Bișoc  * Array of privileges to delete. The function will walk within this
20319a2c62b5SGeorge Bișoc  * array to determine if the specified privileges do exist in the
20329a2c62b5SGeorge Bișoc  * access token. Any missing privileges gets ignored. This parameter
20339a2c62b5SGeorge Bișoc  * can be NULL. This can be a UM pointer.
20349a2c62b5SGeorge Bișoc  *
20359a2c62b5SGeorge Bișoc  * @param[in] RestrictedSids
20369a2c62b5SGeorge Bișoc  * An array list of restricted groups SID to be added in the access
20379a2c62b5SGeorge Bișoc  * token. A token that is already restricted the newly added restricted
20389a2c62b5SGeorge Bișoc  * SIDs are redundant information in addition to the existing restricted
20399a2c62b5SGeorge Bișoc  * SIDs in the token. This parameter can be NULL. This can be a UM pointer.
20409a2c62b5SGeorge Bișoc  *
20419a2c62b5SGeorge Bișoc  * @param[out] NewTokenHandle
20429a2c62b5SGeorge Bișoc  * A new handle to the restricted (filtered) access token. This can be a
20439a2c62b5SGeorge Bișoc  * UM pointer.
20449a2c62b5SGeorge Bișoc  *
20459a2c62b5SGeorge Bișoc  * @return
20469a2c62b5SGeorge Bișoc  * Returns STATUS_SUCCESS if the routine has successfully filtered the
20479a2c62b5SGeorge Bișoc  * access token. STATUS_INVALID_PARAMETER is returned if one or more
20489a2c62b5SGeorge Bișoc  * parameters are not valid (see SepPerformTokenFiltering routine call
20499a2c62b5SGeorge Bișoc  * for more information). A failure NTSTATUS code is returned otherwise.
20509a2c62b5SGeorge Bișoc  *
20519a2c62b5SGeorge Bișoc  * @remarks
20529a2c62b5SGeorge Bișoc  * The Flags parameter determines the final outcome of how the privileges
20539a2c62b5SGeorge Bișoc  * in an access token are filtered. This parameter can take these supported
20549a2c62b5SGeorge Bișoc  * values (these can be combined):
20559a2c62b5SGeorge Bișoc  *
20569a2c62b5SGeorge Bișoc  * 0 -- Filter the token's privileges in the usual way. The function expects
20579a2c62b5SGeorge Bișoc  *      that the caller MUST PROVIDE a valid array list of privileges to be
20589a2c62b5SGeorge Bișoc  *      deleted (that is, PrivilegesToDelete MUSTN'T BE NULL).
20599a2c62b5SGeorge Bișoc  *
20609a2c62b5SGeorge Bișoc  * DISABLE_MAX_PRIVILEGE -- Disables (deletes) all the privileges except SeChangeNotifyPrivilege
20619a2c62b5SGeorge Bișoc  *                          in the new access token. Bear in mind if this flag is specified
20629a2c62b5SGeorge Bișoc  *                          the routine ignores PrivilegesToDelete.
20639a2c62b5SGeorge Bișoc  *
20649a2c62b5SGeorge Bișoc  * SANDBOX_INERT -- Stores the TOKEN_SANDBOX_INERT token flag within the access token.
20659a2c62b5SGeorge Bișoc  *
20669a2c62b5SGeorge Bișoc  * LUA_TOKEN -- The newly filtered access token is a LUA token. This flag is not
20679a2c62b5SGeorge Bișoc  *              supported in Windows Server 2003.
20689a2c62b5SGeorge Bișoc  *
20699a2c62b5SGeorge Bișoc  * WRITE_RESTRICTED -- The newly filtered token has the restricted SIDs that are
20709a2c62b5SGeorge Bișoc  *                     considered only when evaluating write access onto the token.
20719a2c62b5SGeorge Bișoc  *                     This value is not supported in Windows Server 2003.
20729a2c62b5SGeorge Bișoc  */
20739a2c62b5SGeorge Bișoc NTSTATUS
20749a2c62b5SGeorge Bișoc 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)20759a2c62b5SGeorge Bișoc NtFilterToken(
20769a2c62b5SGeorge Bișoc     _In_ HANDLE ExistingTokenHandle,
20779a2c62b5SGeorge Bișoc     _In_ ULONG Flags,
20789a2c62b5SGeorge Bișoc     _In_opt_ PTOKEN_GROUPS SidsToDisable,
20799a2c62b5SGeorge Bișoc     _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,
20809a2c62b5SGeorge Bișoc     _In_opt_ PTOKEN_GROUPS RestrictedSids,
20819a2c62b5SGeorge Bișoc     _Out_ PHANDLE NewTokenHandle)
20829a2c62b5SGeorge Bișoc {
20839a2c62b5SGeorge Bișoc     PTOKEN Token, FilteredToken;
20849a2c62b5SGeorge Bișoc     HANDLE FilteredTokenHandle;
20859a2c62b5SGeorge Bișoc     NTSTATUS Status;
20869a2c62b5SGeorge Bișoc     KPROCESSOR_MODE PreviousMode;
20879a2c62b5SGeorge Bișoc     OBJECT_HANDLE_INFORMATION HandleInfo;
20889a2c62b5SGeorge Bișoc     ULONG ResultLength;
20899a2c62b5SGeorge Bișoc     ULONG CapturedSidsCount = 0;
20909a2c62b5SGeorge Bișoc     ULONG CapturedPrivilegesCount = 0;
20919a2c62b5SGeorge Bișoc     ULONG CapturedRestrictedSidsCount = 0;
20929a2c62b5SGeorge Bișoc     ULONG ProbeSize = 0;
20939a2c62b5SGeorge Bișoc     PSID_AND_ATTRIBUTES CapturedSids = NULL;
20949a2c62b5SGeorge Bișoc     PSID_AND_ATTRIBUTES CapturedRestrictedSids = NULL;
20959a2c62b5SGeorge Bișoc     PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
20969a2c62b5SGeorge Bișoc 
20979a2c62b5SGeorge Bișoc     PAGED_CODE();
20989a2c62b5SGeorge Bișoc 
20999a2c62b5SGeorge Bișoc     PreviousMode = ExGetPreviousMode();
21009a2c62b5SGeorge Bișoc 
21019a2c62b5SGeorge Bișoc     _SEH2_TRY
21029a2c62b5SGeorge Bișoc     {
21039a2c62b5SGeorge Bișoc         /* Probe SidsToDisable */
21049a2c62b5SGeorge Bișoc         if (SidsToDisable != NULL)
21059a2c62b5SGeorge Bișoc         {
21069a2c62b5SGeorge Bișoc             /* Probe the header */
21079a2c62b5SGeorge Bișoc             ProbeForRead(SidsToDisable, sizeof(*SidsToDisable), sizeof(ULONG));
21089a2c62b5SGeorge Bișoc 
21099a2c62b5SGeorge Bișoc             CapturedSidsCount = SidsToDisable->GroupCount;
21109a2c62b5SGeorge Bișoc             ProbeSize = FIELD_OFFSET(TOKEN_GROUPS, Groups[CapturedSidsCount]);
21119a2c62b5SGeorge Bișoc 
21129a2c62b5SGeorge Bișoc             ProbeForRead(SidsToDisable, ProbeSize, sizeof(ULONG));
21139a2c62b5SGeorge Bișoc         }
21149a2c62b5SGeorge Bișoc 
21159a2c62b5SGeorge Bișoc         /* Probe PrivilegesToDelete */
21169a2c62b5SGeorge Bișoc         if (PrivilegesToDelete != NULL)
21179a2c62b5SGeorge Bișoc         {
21189a2c62b5SGeorge Bișoc             /* Probe the header */
21199a2c62b5SGeorge Bișoc             ProbeForRead(PrivilegesToDelete, sizeof(*PrivilegesToDelete), sizeof(ULONG));
21209a2c62b5SGeorge Bișoc 
21219a2c62b5SGeorge Bișoc             CapturedPrivilegesCount = PrivilegesToDelete->PrivilegeCount;
21229a2c62b5SGeorge Bișoc             ProbeSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedPrivilegesCount]);
21239a2c62b5SGeorge Bișoc 
21249a2c62b5SGeorge Bișoc             ProbeForRead(PrivilegesToDelete, ProbeSize, sizeof(ULONG));
21259a2c62b5SGeorge Bișoc         }
21269a2c62b5SGeorge Bișoc 
21279a2c62b5SGeorge Bișoc         /* Probe RestrictedSids */
21289a2c62b5SGeorge Bișoc         if (RestrictedSids != NULL)
21299a2c62b5SGeorge Bișoc         {
21309a2c62b5SGeorge Bișoc             /* Probe the header */
21319a2c62b5SGeorge Bișoc             ProbeForRead(RestrictedSids, sizeof(*RestrictedSids), sizeof(ULONG));
21329a2c62b5SGeorge Bișoc 
21339a2c62b5SGeorge Bișoc             CapturedRestrictedSidsCount = RestrictedSids->GroupCount;
21349a2c62b5SGeorge Bișoc             ProbeSize = FIELD_OFFSET(TOKEN_GROUPS, Groups[CapturedRestrictedSidsCount]);
21359a2c62b5SGeorge Bișoc 
21369a2c62b5SGeorge Bișoc             ProbeForRead(RestrictedSids, ProbeSize, sizeof(ULONG));
21379a2c62b5SGeorge Bișoc         }
21389a2c62b5SGeorge Bișoc 
21399a2c62b5SGeorge Bișoc         /* Probe the handle */
21409a2c62b5SGeorge Bișoc         ProbeForWriteHandle(NewTokenHandle);
21419a2c62b5SGeorge Bișoc     }
21429a2c62b5SGeorge Bișoc     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
21439a2c62b5SGeorge Bișoc     {
21449a2c62b5SGeorge Bișoc         /* Return the exception code */
21459a2c62b5SGeorge Bișoc         _SEH2_YIELD(return _SEH2_GetExceptionCode());
21469a2c62b5SGeorge Bișoc     }
21479a2c62b5SGeorge Bișoc     _SEH2_END;
21489a2c62b5SGeorge Bișoc 
21499a2c62b5SGeorge Bișoc     /* Reference the token */
21509a2c62b5SGeorge Bișoc     Status = ObReferenceObjectByHandle(ExistingTokenHandle,
21519a2c62b5SGeorge Bișoc                                        TOKEN_DUPLICATE,
21529a2c62b5SGeorge Bișoc                                        SeTokenObjectType,
21539a2c62b5SGeorge Bișoc                                        PreviousMode,
21549a2c62b5SGeorge Bișoc                                        (PVOID*)&Token,
21559a2c62b5SGeorge Bișoc                                        &HandleInfo);
21569a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
21579a2c62b5SGeorge Bișoc     {
21589a2c62b5SGeorge Bișoc         DPRINT1("NtFilterToken(): Failed to reference the token (Status 0x%lx)\n", Status);
21599a2c62b5SGeorge Bișoc         return Status;
21609a2c62b5SGeorge Bișoc     }
21619a2c62b5SGeorge Bișoc 
21629a2c62b5SGeorge Bișoc     /* Capture the group SIDs */
21639a2c62b5SGeorge Bișoc     if (SidsToDisable != NULL)
21649a2c62b5SGeorge Bișoc     {
21659a2c62b5SGeorge Bișoc         Status = SeCaptureSidAndAttributesArray(SidsToDisable->Groups,
21669a2c62b5SGeorge Bișoc                                                 CapturedSidsCount,
21679a2c62b5SGeorge Bișoc                                                 PreviousMode,
21689a2c62b5SGeorge Bișoc                                                 NULL,
21699a2c62b5SGeorge Bișoc                                                 0,
21709a2c62b5SGeorge Bișoc                                                 PagedPool,
21719a2c62b5SGeorge Bișoc                                                 TRUE,
21729a2c62b5SGeorge Bișoc                                                 &CapturedSids,
21739a2c62b5SGeorge Bișoc                                                 &ResultLength);
21749a2c62b5SGeorge Bișoc         if (!NT_SUCCESS(Status))
21759a2c62b5SGeorge Bișoc         {
21769a2c62b5SGeorge Bișoc             DPRINT1("NtFilterToken(): Failed to capture the SIDs (Status 0x%lx)\n", Status);
21779a2c62b5SGeorge Bișoc             goto Quit;
21789a2c62b5SGeorge Bișoc         }
21799a2c62b5SGeorge Bișoc     }
21809a2c62b5SGeorge Bișoc 
21819a2c62b5SGeorge Bișoc     /* Capture the privileges */
21829a2c62b5SGeorge Bișoc     if (PrivilegesToDelete != NULL)
21839a2c62b5SGeorge Bișoc     {
21849a2c62b5SGeorge Bișoc         Status = SeCaptureLuidAndAttributesArray(PrivilegesToDelete->Privileges,
21859a2c62b5SGeorge Bișoc                                                  CapturedPrivilegesCount,
21869a2c62b5SGeorge Bișoc                                                  PreviousMode,
21879a2c62b5SGeorge Bișoc                                                  NULL,
21889a2c62b5SGeorge Bișoc                                                  0,
21899a2c62b5SGeorge Bișoc                                                  PagedPool,
21909a2c62b5SGeorge Bișoc                                                  TRUE,
21919a2c62b5SGeorge Bișoc                                                  &CapturedPrivileges,
21929a2c62b5SGeorge Bișoc                                                  &ResultLength);
21939a2c62b5SGeorge Bișoc         if (!NT_SUCCESS(Status))
21949a2c62b5SGeorge Bișoc         {
21959a2c62b5SGeorge Bișoc             DPRINT1("NtFilterToken(): Failed to capture the privileges (Status 0x%lx)\n", Status);
21969a2c62b5SGeorge Bișoc             goto Quit;
21979a2c62b5SGeorge Bișoc         }
21989a2c62b5SGeorge Bișoc     }
21999a2c62b5SGeorge Bișoc 
22009a2c62b5SGeorge Bișoc     /* Capture the restricted SIDs */
22019a2c62b5SGeorge Bișoc     if (RestrictedSids != NULL)
22029a2c62b5SGeorge Bișoc     {
22039a2c62b5SGeorge Bișoc         Status = SeCaptureSidAndAttributesArray(RestrictedSids->Groups,
22049a2c62b5SGeorge Bișoc                                                 CapturedRestrictedSidsCount,
22059a2c62b5SGeorge Bișoc                                                 PreviousMode,
22069a2c62b5SGeorge Bișoc                                                 NULL,
22079a2c62b5SGeorge Bișoc                                                 0,
22089a2c62b5SGeorge Bișoc                                                 PagedPool,
22099a2c62b5SGeorge Bișoc                                                 TRUE,
22109a2c62b5SGeorge Bișoc                                                 &CapturedRestrictedSids,
22119a2c62b5SGeorge Bișoc                                                 &ResultLength);
22129a2c62b5SGeorge Bișoc         if (!NT_SUCCESS(Status))
22139a2c62b5SGeorge Bișoc         {
22149a2c62b5SGeorge Bișoc             DPRINT1("NtFilterToken(): Failed to capture the restricted SIDs (Status 0x%lx)\n", Status);
22159a2c62b5SGeorge Bișoc             goto Quit;
22169a2c62b5SGeorge Bișoc         }
22179a2c62b5SGeorge Bișoc     }
22189a2c62b5SGeorge Bișoc 
22199a2c62b5SGeorge Bișoc     /* Call the internal API */
22209a2c62b5SGeorge Bișoc     Status = SepPerformTokenFiltering(Token,
22219a2c62b5SGeorge Bișoc                                       CapturedPrivileges,
22229a2c62b5SGeorge Bișoc                                       CapturedSids,
22239a2c62b5SGeorge Bișoc                                       CapturedRestrictedSids,
22249a2c62b5SGeorge Bișoc                                       CapturedPrivilegesCount,
22259a2c62b5SGeorge Bișoc                                       CapturedSidsCount,
22269a2c62b5SGeorge Bișoc                                       CapturedRestrictedSidsCount,
22279a2c62b5SGeorge Bișoc                                       Flags,
22289a2c62b5SGeorge Bișoc                                       PreviousMode,
22299a2c62b5SGeorge Bișoc                                       &FilteredToken);
22309a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
22319a2c62b5SGeorge Bișoc     {
22329a2c62b5SGeorge Bișoc         DPRINT1("NtFilterToken(): Failed to filter the token (Status 0x%lx)\n", Status);
22339a2c62b5SGeorge Bișoc         goto Quit;
22349a2c62b5SGeorge Bișoc     }
22359a2c62b5SGeorge Bișoc 
22369a2c62b5SGeorge Bișoc     /* Insert the filtered token and retrieve a handle to it */
22379a2c62b5SGeorge Bișoc     Status = ObInsertObject(FilteredToken,
22389a2c62b5SGeorge Bișoc                             NULL,
22399a2c62b5SGeorge Bișoc                             HandleInfo.GrantedAccess,
22409a2c62b5SGeorge Bișoc                             0,
22419a2c62b5SGeorge Bișoc                             NULL,
22429a2c62b5SGeorge Bișoc                             &FilteredTokenHandle);
22439a2c62b5SGeorge Bișoc     if (!NT_SUCCESS(Status))
22449a2c62b5SGeorge Bișoc     {
22459a2c62b5SGeorge Bișoc         DPRINT1("NtFilterToken(): Failed to insert the filtered token (Status 0x%lx)\n", Status);
22469a2c62b5SGeorge Bișoc         goto Quit;
22479a2c62b5SGeorge Bișoc     }
22489a2c62b5SGeorge Bișoc 
22499a2c62b5SGeorge Bișoc     /* And return it to the caller once we're done */
22509a2c62b5SGeorge Bișoc     _SEH2_TRY
22519a2c62b5SGeorge Bișoc     {
22529a2c62b5SGeorge Bișoc         *NewTokenHandle = FilteredTokenHandle;
22539a2c62b5SGeorge Bișoc     }
22549a2c62b5SGeorge Bișoc     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
22559a2c62b5SGeorge Bișoc     {
22569a2c62b5SGeorge Bișoc         Status = _SEH2_GetExceptionCode();
22579a2c62b5SGeorge Bișoc         _SEH2_YIELD(goto Quit);
22589a2c62b5SGeorge Bișoc     }
22599a2c62b5SGeorge Bișoc     _SEH2_END;
22609a2c62b5SGeorge Bișoc 
22619a2c62b5SGeorge Bișoc Quit:
22629a2c62b5SGeorge Bișoc     /* Dereference the token */
22639a2c62b5SGeorge Bișoc     ObDereferenceObject(Token);
22649a2c62b5SGeorge Bișoc 
22659a2c62b5SGeorge Bișoc     /* Release all the captured data */
22669a2c62b5SGeorge Bișoc     if (CapturedSids != NULL)
22679a2c62b5SGeorge Bișoc     {
22689a2c62b5SGeorge Bișoc         SeReleaseSidAndAttributesArray(CapturedSids,
22699a2c62b5SGeorge Bișoc                                        PreviousMode,
22709a2c62b5SGeorge Bișoc                                        TRUE);
22719a2c62b5SGeorge Bișoc     }
22729a2c62b5SGeorge Bișoc 
22739a2c62b5SGeorge Bișoc     if (CapturedPrivileges != NULL)
22749a2c62b5SGeorge Bișoc     {
22759a2c62b5SGeorge Bișoc         SeReleaseLuidAndAttributesArray(CapturedPrivileges,
22769a2c62b5SGeorge Bișoc                                         PreviousMode,
22779a2c62b5SGeorge Bișoc                                         TRUE);
22789a2c62b5SGeorge Bișoc     }
22799a2c62b5SGeorge Bișoc 
22809a2c62b5SGeorge Bișoc     if (CapturedRestrictedSids != NULL)
22819a2c62b5SGeorge Bișoc     {
22829a2c62b5SGeorge Bișoc         SeReleaseSidAndAttributesArray(CapturedRestrictedSids,
22839a2c62b5SGeorge Bișoc                                        PreviousMode,
22849a2c62b5SGeorge Bișoc                                        TRUE);
22859a2c62b5SGeorge Bișoc     }
22869a2c62b5SGeorge Bișoc 
22879a2c62b5SGeorge Bișoc     return Status;
22889a2c62b5SGeorge Bișoc }
22899a2c62b5SGeorge Bișoc 
22909a2c62b5SGeorge Bișoc /* EOF */
2291