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