Sync with trunk r63935.
[reactos.git] / ntoskrnl / se / token.c
index eec1d48..692cf30 100644 (file)
 #pragma alloc_text(INIT, SepInitializeTokenImplementation)
 #endif
 
+#include <ntlsa.h>
+
+typedef struct _TOKEN_AUDIT_POLICY_INFORMATION
+{
+    ULONG PolicyCount;
+    struct
+    {
+        ULONG Category;
+        UCHAR Value;
+    } Policies[1];
+} TOKEN_AUDIT_POLICY_INFORMATION, *PTOKEN_AUDIT_POLICY_INFORMATION;
+
 /* GLOBALS ********************************************************************/
 
 POBJECT_TYPE SeTokenObjectType = NULL;
@@ -24,6 +36,7 @@ ERESOURCE SepTokenLock;
 
 TOKEN_SOURCE SeSystemTokenSource = {"*SYSTEM*", {0}};
 LUID SeSystemAuthenticationId = SYSTEM_LUID;
+LUID SeAnonymousAuthenticationId = ANONYMOUS_LOGON_LUID;
 
 static GENERIC_MAPPING SepTokenMapping = {
     TOKEN_READ,
@@ -38,11 +51,11 @@ static const INFORMATION_CLASS_INFO SeTokenInformationClass[] = {
     ICI_SQ_SAME( 0, 0, 0),
 
     /* TokenUser */
-    ICI_SQ_SAME( sizeof(TOKEN_USER),                   sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
+    ICI_SQ_SAME( sizeof(TOKEN_USER),                   sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
     /* TokenGroups */
-    ICI_SQ_SAME( sizeof(TOKEN_GROUPS),                 sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
+    ICI_SQ_SAME( sizeof(TOKEN_GROUPS),                 sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
     /* TokenPrivileges */
-    ICI_SQ_SAME( sizeof(TOKEN_PRIVILEGES),             sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
+    ICI_SQ_SAME( sizeof(TOKEN_PRIVILEGES),             sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
     /* TokenOwner */
     ICI_SQ_SAME( sizeof(TOKEN_OWNER),                  sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
     /* TokenPrimaryGroup */
@@ -50,13 +63,13 @@ static const INFORMATION_CLASS_INFO SeTokenInformationClass[] = {
     /* TokenDefaultDacl */
     ICI_SQ_SAME( sizeof(TOKEN_DEFAULT_DACL),           sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
     /* TokenSource */
-    ICI_SQ_SAME( sizeof(TOKEN_SOURCE),                 sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
+    ICI_SQ_SAME( sizeof(TOKEN_SOURCE),                 sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
     /* TokenType */
     ICI_SQ_SAME( sizeof(TOKEN_TYPE),                   sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
     /* TokenImpersonationLevel */
     ICI_SQ_SAME( sizeof(SECURITY_IMPERSONATION_LEVEL), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
     /* TokenStatistics */
-    ICI_SQ_SAME( sizeof(TOKEN_STATISTICS),             sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
+    ICI_SQ_SAME( sizeof(TOKEN_STATISTICS),             sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
     /* TokenRestrictedSids */
     ICI_SQ_SAME( sizeof(TOKEN_GROUPS),                 sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
     /* TokenSessionId */
@@ -64,13 +77,13 @@ static const INFORMATION_CLASS_INFO SeTokenInformationClass[] = {
     /* TokenGroupsAndPrivileges */
     ICI_SQ_SAME( sizeof(TOKEN_GROUPS_AND_PRIVILEGES),  sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
     /* TokenSessionReference */
-    ICI_SQ_SAME( /* FIXME */0,                         sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
+    ICI_SQ_SAME( sizeof(ULONG),                        sizeof(ULONG), ICIF_SET | ICIF_QUERY_SIZE_VARIABLE ),
     /* TokenSandBoxInert */
     ICI_SQ_SAME( sizeof(ULONG),                        sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
     /* TokenAuditPolicy */
-    ICI_SQ_SAME( /* FIXME */0,                         sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
+    ICI_SQ_SAME( /* FIXME */0,                         sizeof(ULONG), ICIF_QUERY | ICIF_SET | ICIF_QUERY_SIZE_VARIABLE ),
     /* TokenOrigin */
-    ICI_SQ_SAME( sizeof(TOKEN_ORIGIN),                 sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
+    ICI_SQ_SAME( sizeof(TOKEN_ORIGIN),                 sizeof(ULONG), ICIF_QUERY | ICIF_SET | ICIF_QUERY_SIZE_VARIABLE ),
 };
 
 /* FUNCTIONS *****************************************************************/
@@ -101,6 +114,95 @@ SepCompareTokens(IN PTOKEN FirstToken,
     return STATUS_SUCCESS;
 }
 
+static
+VOID
+SepUpdateSinglePrivilegeFlagToken(
+    _Inout_ PTOKEN Token,
+    _In_ ULONG Index)
+{
+    ULONG TokenFlag;
+    NT_ASSERT(Index < Token->PrivilegeCount);
+
+    /* The high part of all values we are interested in is 0 */
+    if (Token->Privileges[Index].Luid.HighPart != 0)
+    {
+        return;
+    }
+
+    /* Check for certain privileges to update flags */
+    if (Token->Privileges[Index].Luid.LowPart == SE_CHANGE_NOTIFY_PRIVILEGE)
+    {
+        TokenFlag = TOKEN_HAS_TRAVERSE_PRIVILEGE;
+    }
+    else if (Token->Privileges[Index].Luid.LowPart == SE_BACKUP_PRIVILEGE)
+    {
+        TokenFlag = TOKEN_HAS_BACKUP_PRIVILEGE;
+    }
+    else if (Token->Privileges[Index].Luid.LowPart == SE_RESTORE_PRIVILEGE)
+    {
+        TokenFlag = TOKEN_HAS_RESTORE_PRIVILEGE;
+    }
+    else if (Token->Privileges[Index].Luid.LowPart == SE_IMPERSONATE_PRIVILEGE)
+    {
+        TokenFlag = TOKEN_HAS_IMPERSONATE_PRIVILEGE;
+    }
+    else
+    {
+        /* Nothing to do */
+        return;
+    }
+
+    /* Check if the specified privilege is enabled */
+    if (Token->Privileges[Index].Attributes & SE_PRIVILEGE_ENABLED)
+    {
+        /* It is enabled, so set the flag */
+        Token->TokenFlags |= TokenFlag;
+    }
+    else
+    {
+        /* Is is disabled, so remove the flag */
+        Token->TokenFlags &= ~TokenFlag;
+    }
+}
+
+static
+VOID
+SepUpdatePrivilegeFlagsToken(
+    _Inout_ PTOKEN Token)
+{
+    ULONG i;
+
+    /* Loop all privileges */
+    for (i = 0; i < Token->PrivilegeCount; i++)
+    {
+        /* Updates the flags dor this privilege */
+        SepUpdateSinglePrivilegeFlagToken(Token, i);
+    }
+}
+
+static
+VOID
+SepRemovePrivilegeToken(
+    _Inout_ PTOKEN Token,
+    _In_ ULONG Index)
+{
+    ULONG MoveCount;
+    NT_ASSERT(Index < Token->PrivilegeCount);
+
+    /* Calculate the number of trailing privileges */
+    MoveCount = Token->PrivilegeCount - Index - 1;
+    if (MoveCount != 0)
+    {
+        /* Move them one location ahead */
+        RtlMoveMemory(&Token->Privileges[Index],
+                      &Token->Privileges[Index + 1],
+                      MoveCount * sizeof(LUID_AND_ATTRIBUTES));
+    }
+
+    /* Update privilege count */
+    Token->PrivilegeCount--;
+}
+
 VOID
 NTAPI
 SepFreeProxyData(PVOID ProxyData)
@@ -592,18 +694,6 @@ SepCreateToken(OUT PHANDLE TokenHandle,
         }
     }
 
-    /* Loop all privileges */
-    for (i = 0; i < PrivilegeCount; i++)
-    {
-        /* For optimization, check for change notify and impersonate rights */
-        if (((RtlEqualLuid(&Privileges[i].Luid, &SeChangeNotifyPrivilege)) &&
-            (Privileges[i].Attributes & SE_PRIVILEGE_ENABLED)))
-        {
-            /* Remember token has traverse */
-            TokenFlags |= TOKEN_HAS_TRAVERSE_PRIVILEGE;
-        }
-    }
-
     Status = ZwAllocateLocallyUniqueId(&TokenId);
     if (!NT_SUCCESS(Status))
         return Status;
@@ -623,7 +713,7 @@ SepCreateToken(OUT PHANDLE TokenHandle,
                             (PVOID*)&AccessToken);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("ObCreateObject() failed (Status %lx)\n");
+        DPRINT1("ObCreateObject() failed (Status %lx)\n", Status);
         return Status;
     }
 
@@ -661,6 +751,7 @@ SepCreateToken(OUT PHANDLE TokenHandle,
     for (i = 0; i < GroupCount; i++)
         uLength += RtlLengthSid(Groups[i].Sid);
 
+    // FIXME: should use the object itself
     AccessToken->UserAndGroups = ExAllocatePoolWithTag(PagedPool,
                                                        uLength,
                                                        TAG_TOKEN_USERS);
@@ -698,7 +789,9 @@ SepCreateToken(OUT PHANDLE TokenHandle,
     if (!NT_SUCCESS(Status))
         goto done;
 
+    // FIXME: should use the object itself
     uLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
+    if (uLength == 0) uLength = sizeof(PVOID);
     AccessToken->Privileges = ExAllocatePoolWithTag(PagedPool,
                                                     uLength,
                                                     TAG_TOKEN_PRIVILAGES);
@@ -732,18 +825,29 @@ SepCreateToken(OUT PHANDLE TokenHandle,
     if (!NT_SUCCESS(Status))
         goto done;
 
-    AccessToken->DefaultDacl = ExAllocatePoolWithTag(PagedPool,
-                                                     DefaultDacl->AclSize,
-                                                     TAG_TOKEN_ACL);
-    if (AccessToken->DefaultDacl == NULL)
+    /* Update privilege flags */
+    SepUpdatePrivilegeFlagsToken(AccessToken);
+
+    if (DefaultDacl != NULL)
     {
-        Status = STATUS_INSUFFICIENT_RESOURCES;
-        goto done;
-    }
+        // FIXME: should use the object itself
+        AccessToken->DefaultDacl = ExAllocatePoolWithTag(PagedPool,
+                                                         DefaultDacl->AclSize,
+                                                         TAG_TOKEN_ACL);
+        if (AccessToken->DefaultDacl == NULL)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            goto done;
+        }
 
-    RtlCopyMemory(AccessToken->DefaultDacl,
-                  DefaultDacl,
-                  DefaultDacl->AclSize);
+        RtlCopyMemory(AccessToken->DefaultDacl,
+                      DefaultDacl,
+                      DefaultDacl->AclSize);
+    }
+    else
+    {
+        AccessToken->DefaultDacl = NULL;
+    }
 
     if (!SystemToken)
     {
@@ -769,15 +873,7 @@ done:
     {
         if (AccessToken)
         {
-            if (AccessToken->UserAndGroups)
-                ExFreePoolWithTag(AccessToken->UserAndGroups, TAG_TOKEN_USERS);
-
-            if (AccessToken->Privileges)
-                ExFreePoolWithTag(AccessToken->Privileges, TAG_TOKEN_PRIVILAGES);
-
-            if (AccessToken->DefaultDacl)
-                ExFreePoolWithTag(AccessToken->DefaultDacl, TAG_TOKEN_ACL);
-
+            /* Dereference the token, the delete procedure will clean up */
             ObDereferenceObject(AccessToken);
         }
     }
@@ -1065,7 +1161,7 @@ NtQueryInformationToken(IN HANDLE TokenHandle,
     PTOKEN Token;
     ULONG RequiredLength;
     KPROCESSOR_MODE PreviousMode;
-    NTSTATUS Status = STATUS_SUCCESS;
+    NTSTATUS Status;
 
     PAGED_CODE();
 
@@ -1676,7 +1772,8 @@ NtSetInformationToken(IN HANDLE TokenHandle,
                     }
                     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                     {
-                        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+                        Status = _SEH2_GetExceptionCode();
+                        goto Cleanup;
                     }
                     _SEH2_END;
 
@@ -1715,7 +1812,8 @@ NtSetInformationToken(IN HANDLE TokenHandle,
                     }
                     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                     {
-                        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+                        Status = _SEH2_GetExceptionCode();
+                        goto Cleanup;
                     }
                     _SEH2_END;
 
@@ -1754,7 +1852,8 @@ NtSetInformationToken(IN HANDLE TokenHandle,
                     }
                     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                     {
-                        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+                        Status = _SEH2_GetExceptionCode();
+                        goto Cleanup;
                     }
                     _SEH2_END;
 
@@ -1808,7 +1907,8 @@ NtSetInformationToken(IN HANDLE TokenHandle,
                 }
                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                 {
-                    _SEH2_YIELD(return _SEH2_GetExceptionCode());
+                    Status = _SEH2_GetExceptionCode();
+                    goto Cleanup;
                 }
                 _SEH2_END;
 
@@ -1823,16 +1923,183 @@ NtSetInformationToken(IN HANDLE TokenHandle,
                 break;
             }
 
+            case TokenSessionReference:
+            {
+                ULONG SessionReference;
+
+                _SEH2_TRY
+                {
+                    /* Buffer size was already verified, no need to check here again */
+                    SessionReference = *(PULONG)TokenInformation;
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    Status = _SEH2_GetExceptionCode();
+                    goto Cleanup;
+                }
+                _SEH2_END;
+
+                if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
+                {
+                    Status = STATUS_PRIVILEGE_NOT_HELD;
+                    goto Cleanup;
+                }
+
+                /* Check if it is 0 */
+                if (SessionReference == 0)
+                {
+                    /* Atomically set the flag in the token */
+                    RtlInterlockedSetBits(&Token->TokenFlags,
+                                          TOKEN_SESSION_NOT_REFERENCED);
+                }
+
+                break;
+
+            }
+
+
+            case TokenAuditPolicy:
+            {
+                PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation =
+                    (PTOKEN_AUDIT_POLICY_INFORMATION)TokenInformation;
+                SEP_AUDIT_POLICY AuditPolicy;
+                ULONG i;
+
+                _SEH2_TRY
+                {
+                    ProbeForRead(PolicyInformation,
+                                 FIELD_OFFSET(TOKEN_AUDIT_POLICY_INFORMATION,
+                                              Policies[PolicyInformation->PolicyCount]),
+                                 sizeof(ULONG));
+
+                    /* Loop all policies in the structure */
+                    for (i = 0; i < PolicyInformation->PolicyCount; i++)
+                    {
+                        /* Set the corresponding bits in the packed structure */
+                        switch (PolicyInformation->Policies[i].Category)
+                        {
+                            case AuditCategorySystem:
+                                AuditPolicy.PolicyElements.System = PolicyInformation->Policies[i].Value;
+                                break;
+
+                            case AuditCategoryLogon:
+                                AuditPolicy.PolicyElements.Logon = PolicyInformation->Policies[i].Value;
+                                break;
+
+                            case AuditCategoryObjectAccess:
+                                AuditPolicy.PolicyElements.ObjectAccess = PolicyInformation->Policies[i].Value;
+                                break;
+
+                            case AuditCategoryPrivilegeUse:
+                                AuditPolicy.PolicyElements.PrivilegeUse = PolicyInformation->Policies[i].Value;
+                                break;
+
+                            case AuditCategoryDetailedTracking:
+                                AuditPolicy.PolicyElements.DetailedTracking = PolicyInformation->Policies[i].Value;
+                                break;
+
+                            case AuditCategoryPolicyChange:
+                                AuditPolicy.PolicyElements.PolicyChange = PolicyInformation->Policies[i].Value;
+                                break;
+
+                            case AuditCategoryAccountManagement:
+                                AuditPolicy.PolicyElements.AccountManagement = PolicyInformation->Policies[i].Value;
+                                break;
+
+                            case AuditCategoryDirectoryServiceAccess:
+                                AuditPolicy.PolicyElements.DirectoryServiceAccess = PolicyInformation->Policies[i].Value;
+                                break;
+
+                            case AuditCategoryAccountLogon:
+                                AuditPolicy.PolicyElements.AccountLogon = PolicyInformation->Policies[i].Value;
+                                break;
+                        }
+                    }
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    Status = _SEH2_GetExceptionCode();
+                    goto Cleanup;
+                }
+                _SEH2_END;
+
+                if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
+                                            PreviousMode))
+                {
+                    Status = STATUS_PRIVILEGE_NOT_HELD;
+                    break;
+                }
+
+                /* Lock the token */
+                SepAcquireTokenLockExclusive(Token);
+
+                /* Set the new audit policy */
+                Token->AuditPolicy = AuditPolicy;
+
+                /* Unlock the token */
+                SepReleaseTokenLock(Token);
+
+                break;
+            }
+
+            case TokenOrigin:
+            {
+                TOKEN_ORIGIN TokenOrigin;
+
+                _SEH2_TRY
+                {
+                    /* Copy the token origin */
+                    TokenOrigin = *(PTOKEN_ORIGIN)TokenInformation;
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    Status = _SEH2_GetExceptionCode();
+                    goto Cleanup;
+                }
+                _SEH2_END;
+
+                /* Check for TCB privilege */
+                if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
+                {
+                    Status = STATUS_PRIVILEGE_NOT_HELD;
+                    break;
+                }
+
+                /* Lock the token */
+                SepAcquireTokenLockExclusive(Token);
+
+                /* Check if there is no token origin set yet */
+                if ((Token->OriginatingLogonSession.LowPart == 0) &&
+                    (Token->OriginatingLogonSession.HighPart == 0))
+                {
+                    /* Set the token origin */
+                    Token->OriginatingLogonSession =
+                        TokenOrigin.OriginatingLogonSession;
+                }
+
+                /* Unlock the token */
+                SepReleaseTokenLock(Token);
+
+                break;
+            }
+
             default:
             {
-                Status = STATUS_NOT_IMPLEMENTED;
+                DPRINT1("Invalid TokenInformationClass: 0x%lx\n",
+                        TokenInformationClass);
+                Status = STATUS_INVALID_INFO_CLASS;
                 break;
             }
         }
-
+Cleanup:
         ObDereferenceObject(Token);
     }
 
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status);
+    }
+
     return Status;
 }
 
@@ -1995,16 +2262,136 @@ NtAdjustGroupsToken(IN HANDLE TokenHandle,
     return(STATUS_NOT_IMPLEMENTED);
 }
 
+
+static
+ULONG
+SepAdjustPrivileges(
+    _Inout_ PTOKEN Token,
+    _In_ BOOLEAN DisableAllPrivileges,
+    _In_opt_ PLUID_AND_ATTRIBUTES NewState,
+    _In_ ULONG NewStateCount,
+    _Out_opt_ PTOKEN_PRIVILEGES PreviousState,
+    _In_ BOOLEAN ApplyChanges,
+    _Out_ PULONG ChangedPrivileges)
+{
+    ULONG i, j, PrivilegeCount, ChangeCount, NewAttributes;
+
+    /* Count the found privileges and those that need to be changed */
+    PrivilegeCount = 0;
+    ChangeCount = 0;
+
+    /* Loop all privileges in the token */
+    for (i = 0; i < Token->PrivilegeCount; i++)
+    {
+        /* Shall all of them be disabled? */
+        if (DisableAllPrivileges)
+        {
+            /* The new attributes are the old ones, but disabled */
+            NewAttributes = Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
+        }
+        else
+        {
+            /* Otherwise loop all provided privileges */
+            for (j = 0; j < NewStateCount; j++)
+            {
+                /* Check if this is the LUID we are looking for */
+                if (RtlEqualLuid(&Token->Privileges[i].Luid, &NewState[j].Luid))
+                {
+                    DPRINT("Found privilege\n");
+
+                    /* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */
+                    NewAttributes = NewState[j].Attributes;
+                    NewAttributes &= (SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED);
+                    NewAttributes |= Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
+
+                    /* Stop looking */
+                    break;
+                }
+            }
+
+            /* Check if we didn't find the privilege */
+            if (j == NewStateCount)
+            {
+                /* Continue with the token's next privilege */
+                continue;
+            }
+        }
+
+        /* We found a privilege, count it */
+        PrivilegeCount++;
+
+        /* Does the privilege need to be changed? */
+        if (Token->Privileges[i].Attributes != NewAttributes)
+        {
+            /* Does the caller want the old privileges? */
+            if (PreviousState != NULL)
+            {
+                /* Copy the old privilege */
+                PreviousState->Privileges[ChangeCount] = Token->Privileges[i];
+            }
+
+            /* Does the caller want to apply the changes? */
+            if (ApplyChanges)
+            {
+                /* Shall we remove the privilege? */
+                if (NewAttributes & SE_PRIVILEGE_REMOVED)
+                {
+                    /* Set the token as disabled and update flags for it */
+                    Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
+                    SepUpdateSinglePrivilegeFlagToken(Token, i);
+
+                    /* Remove the privilege */
+                    SepRemovePrivilegeToken(Token, i);
+
+                    /* Fix the running index */
+                    i--;
+
+                    /* Continue with next */
+                    continue;
+                }
+
+                /* Set the new attributes and update flags */
+                Token->Privileges[i].Attributes = NewAttributes;
+                SepUpdateSinglePrivilegeFlagToken(Token, i);
+            }
+
+            /* Increment the change count */
+            ChangeCount++;
+        }
+    }
+
+    /* Set the number of saved privileges */
+    if (PreviousState != NULL)
+        PreviousState->PrivilegeCount = ChangeCount;
+
+    /* Return the number of changed privileges */
+    *ChangedPrivileges = ChangeCount;
+
+    /* Check if we missed some */
+    if (!DisableAllPrivileges && (PrivilegeCount < NewStateCount))
+    {
+        return STATUS_NOT_ALL_ASSIGNED;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+
 /*
  * @implemented
  */
-NTSTATUS NTAPI
-NtAdjustPrivilegesToken(IN HANDLE TokenHandle,
-                        IN BOOLEAN DisableAllPrivileges,
-                        IN PTOKEN_PRIVILEGES NewState,
-                        IN ULONG BufferLength,
-                        OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL,
-                        OUT PULONG ReturnLength OPTIONAL)
+_Must_inspect_result_
+__kernel_entry
+NTSTATUS
+NTAPI
+NtAdjustPrivilegesToken(
+    _In_ HANDLE TokenHandle,
+    _In_ BOOLEAN DisableAllPrivileges,
+    _In_opt_ PTOKEN_PRIVILEGES NewState,
+    _In_ ULONG BufferLength,
+    _Out_writes_bytes_to_opt_(BufferLength,*ReturnLength)
+        PTOKEN_PRIVILEGES PreviousState,
+    _When_(PreviousState!=NULL, _Out_) PULONG ReturnLength)
 {
     PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
     KPROCESSOR_MODE PreviousMode;
@@ -2012,14 +2399,12 @@ NtAdjustPrivilegesToken(IN HANDLE TokenHandle,
     ULONG CapturedLength = 0;
     ULONG NewStateSize = 0;
     ULONG ChangeCount;
+    ULONG RequiredLength;
     PTOKEN Token;
-    ULONG i;
-    ULONG j;
     NTSTATUS Status;
-
     PAGED_CODE();
 
-    DPRINT ("NtAdjustPrivilegesToken() called\n");
+    DPRINT("NtAdjustPrivilegesToken() called\n");
 
     /* Fail, if we do not disable all privileges but NewState is NULL */
     if (DisableAllPrivileges == FALSE && NewState == NULL)
@@ -2033,29 +2418,20 @@ NtAdjustPrivilegesToken(IN HANDLE TokenHandle,
             /* Probe NewState */
             if (DisableAllPrivileges == FALSE)
             {
-                ProbeForRead(NewState,
-                             sizeof(TOKEN_PRIVILEGES),
-                             sizeof(ULONG));
+                /* First probe the header */
+                ProbeForRead(NewState, sizeof(TOKEN_PRIVILEGES), sizeof(ULONG));
 
                 CapturedCount = NewState->PrivilegeCount;
-                NewStateSize = (ULONG)sizeof(TOKEN_PRIVILEGES) +
-                               ((CapturedCount - ANYSIZE_ARRAY) * (ULONG)sizeof(LUID_AND_ATTRIBUTES));
+                NewStateSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedCount]);
 
-                ProbeForRead(NewState,
-                             NewStateSize,
-                             sizeof(ULONG));
+                ProbeForRead(NewState, NewStateSize, sizeof(ULONG));
             }
 
             /* Probe PreviousState and ReturnLength */
             if (PreviousState != NULL)
             {
-                ProbeForWrite(PreviousState,
-                              BufferLength,
-                              sizeof(ULONG));
-
-                ProbeForWrite(ReturnLength,
-                              sizeof(ULONG),
-                              sizeof(ULONG));
+                ProbeForWrite(PreviousState, BufferLength, sizeof(ULONG));
+                ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
             }
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
@@ -2067,10 +2443,12 @@ NtAdjustPrivilegesToken(IN HANDLE TokenHandle,
     }
     else
     {
+        /* This is kernel mode, we trust the caller */
         if (DisableAllPrivileges == FALSE)
             CapturedCount = NewState->PrivilegeCount;
     }
 
+    /* Do we need to capture the new state? */
     if (DisableAllPrivileges == FALSE)
     {
         _SEH2_TRY
@@ -2089,7 +2467,7 @@ NtAdjustPrivilegesToken(IN HANDLE TokenHandle,
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
             /* Return the exception code */
-            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+            Status = _SEH2_GetExceptionCode();
         }
         _SEH2_END;
 
@@ -2106,7 +2484,7 @@ NtAdjustPrivilegesToken(IN HANDLE TokenHandle,
                                        NULL);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1 ("Failed to reference token (Status %lx)\n", Status);
+        DPRINT1("Failed to reference token (Status %lx)\n", Status);
 
         /* Release the captured privileges */
         if (CapturedPrivileges != NULL)
@@ -2117,51 +2495,23 @@ NtAdjustPrivilegesToken(IN HANDLE TokenHandle,
         return Status;
     }
 
-    /* Count the privileges that need to be changed */
-    ChangeCount = 0;
-    for (i = 0; i < Token->PrivilegeCount; i++)
-    {
-        if (DisableAllPrivileges)
-        {
-            if (Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED)
-            {
-                DPRINT("Privilege enabled\n");
-
-                ChangeCount++;
-            }
-        }
-        else
-        {
-            for (j = 0; j < CapturedCount; j++)
-            {
-                if (Token->Privileges[i].Luid.LowPart == CapturedPrivileges[j].Luid.LowPart &&
-                    Token->Privileges[i].Luid.HighPart == CapturedPrivileges[j].Luid.HighPart)
-                {
-                    DPRINT("Found privilege\n");
-
-                    if ((Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) !=
-                        (CapturedPrivileges[j].Attributes & SE_PRIVILEGE_ENABLED))
-                    {
-                        DPRINT("Attributes differ\n");
-                        DPRINT("Current attributes %lx  New attributes %lx\n",
-                               Token->Privileges[i].Attributes,
-                               CapturedPrivileges[j].Attributes);
+    /* Lock the token */
+    ExEnterCriticalRegionAndAcquireResourceExclusive(Token->TokenLock);
 
-                        ChangeCount++;
-                    }
-                }
-            }
-        }
-    }
+    /* Count the privileges that need to be changed, do not apply them yet */
+    Status = SepAdjustPrivileges(Token,
+                                 DisableAllPrivileges,
+                                 CapturedPrivileges,
+                                 CapturedCount,
+                                 NULL,
+                                 FALSE,
+                                 &ChangeCount);
 
-    /*
-     * Return the required buffer size and
-     * check if the available buffer is large enough
-     */
+    /* Check if the caller asked for the previous state */
     if (PreviousState != NULL)
     {
-        ULONG RequiredLength = (ULONG)sizeof(TOKEN_PRIVILEGES) +
-                               ((ChangeCount - ANYSIZE_ARRAY) * (ULONG)sizeof(LUID_AND_ATTRIBUTES));
+        /* Calculate the required length */
+        RequiredLength = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[ChangeCount]);
 
         /* Try to return the required buffer length */
         _SEH2_TRY
@@ -2170,125 +2520,44 @@ NtAdjustPrivilegesToken(IN HANDLE TokenHandle,
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            /* Dereference the token */
-            ObDereferenceObject(Token);
-
-            /* Release the captured privileges */
-            if (CapturedPrivileges != NULL)
-                SeReleaseLuidAndAttributesArray(CapturedPrivileges,
-                                                PreviousMode,
-                                                TRUE);
-
-            /* Return the exception code */
-            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+            /* Do cleanup and return the exception code */
+            Status = _SEH2_GetExceptionCode();
+            goto Cleanup;
         }
         _SEH2_END;
 
         /* Fail, if the buffer length is smaller than the required length */
         if (BufferLength < RequiredLength)
         {
-            /* Dereference the token */
-            ObDereferenceObject(Token);
-
-            /* Release the captured privileges */
-            if (CapturedPrivileges != NULL)
-                SeReleaseLuidAndAttributesArray(CapturedPrivileges,
-                                                PreviousMode,
-                                                TRUE);
-
-            return STATUS_BUFFER_TOO_SMALL;
+            Status = STATUS_BUFFER_TOO_SMALL;
+            goto Cleanup;
         }
     }
 
-    /* Change the privilege attributes */
-    ChangeCount = 0;
+    /* Now enter SEH, since we might return the old privileges */
     _SEH2_TRY
     {
-        for (i = 0; i < Token->PrivilegeCount; i++)
-        {
-            if (DisableAllPrivileges == TRUE)
-            {
-                if (Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED)
-                {
-                    DPRINT("Privilege enabled\n");
-
-                    /* Save the current privilege */
-                    if (PreviousState != NULL)
-                    {
-                        PreviousState->Privileges[ChangeCount].Luid = Token->Privileges[i].Luid;
-                        PreviousState->Privileges[ChangeCount].Attributes = Token->Privileges[i].Attributes;
-                    }
-
-                    /* Disable the current privlege */
-                    Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
-
-                    ChangeCount++;
-                }
-            }
-            else
-            {
-                for (j = 0; j < CapturedCount; j++)
-                {
-                    if (Token->Privileges[i].Luid.LowPart == CapturedPrivileges[j].Luid.LowPart &&
-                        Token->Privileges[i].Luid.HighPart == CapturedPrivileges[j].Luid.HighPart)
-                    {
-                        DPRINT("Found privilege\n");
-
-                        /* Check whether the attributes differ */
-                        if ((Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) !=
-                            (CapturedPrivileges[j].Attributes & SE_PRIVILEGE_ENABLED))
-                        {
-                            DPRINT("Attributes differ\n");
-                            DPRINT("Current attributes %lx  New attributes %lx\n",
-                                   Token->Privileges[i].Attributes,
-                                   CapturedPrivileges[j].Attributes);
-
-                            /* Save the current privilege */
-                            if (PreviousState != NULL)
-                            {
-                                PreviousState->Privileges[ChangeCount].Luid = Token->Privileges[i].Luid;
-                                PreviousState->Privileges[ChangeCount].Attributes = Token->Privileges[i].Attributes;
-                            }
-
-                            /* Update the current privlege */
-                            Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
-                            Token->Privileges[i].Attributes |=
-                            (CapturedPrivileges[j].Attributes & SE_PRIVILEGE_ENABLED);
-                            DPRINT("New attributes %lx\n",
-                                   Token->Privileges[i].Attributes);
-
-                            ChangeCount++;
-                        }
-                    }
-                }
-            }
-        }
-
-        /* Set the number of saved privileges */
-        if (PreviousState != NULL)
-            PreviousState->PrivilegeCount = ChangeCount;
+        /* This time apply the changes */
+        Status = SepAdjustPrivileges(Token,
+                                     DisableAllPrivileges,
+                                     CapturedPrivileges,
+                                     CapturedCount,
+                                     PreviousState,
+                                     TRUE,
+                                     &ChangeCount);
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        /* Dereference the token */
-        ObDereferenceObject(Token);
-
-        /* Release the captured privileges */
-        if (CapturedPrivileges != NULL)
-            SeReleaseLuidAndAttributesArray(CapturedPrivileges,
-                                            PreviousMode,
-                                            TRUE);
-
-        /* Return the exception code */
-        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        /* Do cleanup and return the exception code */
+        Status = _SEH2_GetExceptionCode();
+        goto Cleanup;
     }
     _SEH2_END;
 
-    /* Set the status */
-    Status = (ChangeCount < CapturedCount) ? STATUS_NOT_ALL_ASSIGNED : STATUS_SUCCESS;
-
-    /* Dereference the token */
-    ObDereferenceObject (Token);
+Cleanup:
+    /* Unlock and dereference the token */
+    ExReleaseResourceAndLeaveCriticalRegion(Token->TokenLock);
+    ObDereferenceObject(Token);
 
     /* Release the captured privileges */
     if (CapturedPrivileges != NULL)
@@ -2297,30 +2566,42 @@ NtAdjustPrivilegesToken(IN HANDLE TokenHandle,
                                         TRUE);
 
     DPRINT ("NtAdjustPrivilegesToken() done\n");
-
     return Status;
 }
 
 NTSTATUS
 NTAPI
-NtCreateToken(OUT PHANDLE TokenHandle,
-              IN ACCESS_MASK DesiredAccess,
-              IN 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 PTOKEN_OWNER TokenOwner,
-              IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup,
-              IN PTOKEN_DEFAULT_DACL TokenDefaultDacl,
-              IN PTOKEN_SOURCE TokenSource)
+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)
 {
     HANDLE hToken;
     KPROCESSOR_MODE PreviousMode;
-    ULONG nTokenPrivileges = 0;
+    ULONG PrivilegeCount, GroupCount;
+    PSID OwnerSid, PrimaryGroupSid;
+    PACL DefaultDacl;
     LARGE_INTEGER LocalExpirationTime = {{0, 0}};
+    LUID LocalAuthenticationId;
+    TOKEN_SOURCE LocalTokenSource;
+    SECURITY_QUALITY_OF_SERVICE LocalSecurityQos;
+    PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
+    PSID_AND_ATTRIBUTES CapturedUser = NULL;
+    PSID_AND_ATTRIBUTES CapturedGroups = NULL;
+    PSID CapturedOwnerSid = NULL;
+    PSID CapturedPrimaryGroupSid = NULL;
+    PACL CapturedDefaultDacl = NULL;
+    ULONG PrivilegesLength, UserLength, GroupsLength;
     NTSTATUS Status;
 
     PAGED_CODE();
@@ -2332,64 +2613,197 @@ NtCreateToken(OUT PHANDLE TokenHandle,
         _SEH2_TRY
         {
             ProbeForWriteHandle(TokenHandle);
+
+            if (ObjectAttributes != NULL)
+            {
+                ProbeForRead(ObjectAttributes,
+                             sizeof(OBJECT_ATTRIBUTES),
+                             sizeof(ULONG));
+                LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
+            }
+
             ProbeForRead(AuthenticationId,
                          sizeof(LUID),
                          sizeof(ULONG));
+            LocalAuthenticationId = *AuthenticationId;
+
             LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
+
             ProbeForRead(TokenUser,
                          sizeof(TOKEN_USER),
                          sizeof(ULONG));
+
             ProbeForRead(TokenGroups,
                          sizeof(TOKEN_GROUPS),
                          sizeof(ULONG));
+            GroupCount = TokenGroups->GroupCount;
+
             ProbeForRead(TokenPrivileges,
                          sizeof(TOKEN_PRIVILEGES),
                          sizeof(ULONG));
-            ProbeForRead(TokenOwner,
-                         sizeof(TOKEN_OWNER),
-                         sizeof(ULONG));
+            PrivilegeCount = TokenPrivileges->PrivilegeCount;
+
+            if (TokenOwner != NULL)
+            {
+                ProbeForRead(TokenOwner,
+                             sizeof(TOKEN_OWNER),
+                             sizeof(ULONG));
+                OwnerSid = TokenOwner->Owner;
+            }
+            else
+            {
+                OwnerSid = NULL;
+            }
+
             ProbeForRead(TokenPrimaryGroup,
                          sizeof(TOKEN_PRIMARY_GROUP),
                          sizeof(ULONG));
-            ProbeForRead(TokenDefaultDacl,
-                         sizeof(TOKEN_DEFAULT_DACL),
-                         sizeof(ULONG));
+            PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
+
+            if (TokenDefaultDacl != NULL)
+            {
+                ProbeForRead(TokenDefaultDacl,
+                             sizeof(TOKEN_DEFAULT_DACL),
+                             sizeof(ULONG));
+                DefaultDacl = TokenDefaultDacl->DefaultDacl;
+            }
+            else
+            {
+                DefaultDacl = NULL;
+            }
+
             ProbeForRead(TokenSource,
                          sizeof(TOKEN_SOURCE),
                          sizeof(ULONG));
-            nTokenPrivileges = TokenPrivileges->PrivilegeCount;
+            LocalTokenSource = *TokenSource;
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
             /* Return the exception code */
-            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+            return _SEH2_GetExceptionCode();
         }
         _SEH2_END;
     }
     else
     {
-        nTokenPrivileges = TokenPrivileges->PrivilegeCount;
+        if (ObjectAttributes != NULL)
+            LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
+        LocalAuthenticationId = *AuthenticationId;
         LocalExpirationTime = *ExpirationTime;
+        GroupCount = TokenGroups->GroupCount;
+        PrivilegeCount = TokenPrivileges->PrivilegeCount;
+        OwnerSid = TokenOwner ? TokenOwner->Owner : NULL;
+        PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
+        DefaultDacl = TokenDefaultDacl ? TokenDefaultDacl->DefaultDacl : NULL;
+        LocalTokenSource = *TokenSource;
+    }
+
+    /* Check token type */
+    if ((TokenType < TokenPrimary) ||
+        (TokenType > TokenImpersonation))
+    {
+        return STATUS_BAD_TOKEN_TYPE;
+    }
+
+    /* Capture the user SID and attributes */
+    Status = SeCaptureSidAndAttributesArray(&TokenUser->User,
+                                            1,
+                                            PreviousMode,
+                                            NULL,
+                                            0,
+                                            PagedPool,
+                                            FALSE,
+                                            &CapturedUser,
+                                            &UserLength);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
     }
 
+    /* Capture the groups SID and attributes array */
+    Status = SeCaptureSidAndAttributesArray(&TokenGroups->Groups[0],
+                                            GroupCount,
+                                            PreviousMode,
+                                            NULL,
+                                            0,
+                                            PagedPool,
+                                            FALSE,
+                                            &CapturedGroups,
+                                            &GroupsLength);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* Capture privileges */
+    Status = SeCaptureLuidAndAttributesArray(&TokenPrivileges->Privileges[0],
+                                             PrivilegeCount,
+                                             PreviousMode,
+                                             NULL,
+                                             0,
+                                             PagedPool,
+                                             FALSE,
+                                             &CapturedPrivileges,
+                                             &PrivilegesLength);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* Capture the token owner SID */
+    if (TokenOwner != NULL)
+    {
+        Status = SepCaptureSid(OwnerSid,
+                               PreviousMode,
+                               PagedPool,
+                               FALSE,
+                               &CapturedOwnerSid);
+        if (!NT_SUCCESS(Status))
+        {
+            goto Cleanup;
+        }
+    }
+
+    /* Capture the token primary group SID */
+    Status = SepCaptureSid(PrimaryGroupSid,
+                           PreviousMode,
+                           PagedPool,
+                           FALSE,
+                           &CapturedPrimaryGroupSid);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* Capture DefaultDacl */
+    if (DefaultDacl != NULL)
+    {
+        Status = SepCaptureAcl(DefaultDacl,
+                               PreviousMode,
+                               NonPagedPool,
+                               FALSE,
+                               &CapturedDefaultDacl);
+    }
+
+    /* Call the internal function */
     Status = SepCreateToken(&hToken,
                             PreviousMode,
                             DesiredAccess,
                             ObjectAttributes,
                             TokenType,
-                            ((PSECURITY_QUALITY_OF_SERVICE)(ObjectAttributes->SecurityQualityOfService))->ImpersonationLevel,
-                            AuthenticationId,
+                            LocalSecurityQos.ImpersonationLevel,
+                            &LocalAuthenticationId,
                             &LocalExpirationTime,
-                            &TokenUser->User,
-                            TokenGroups->GroupCount,
-                            TokenGroups->Groups,
+                            CapturedUser,
+                            GroupCount,
+                            CapturedGroups,
                             0, // FIXME: Should capture
-                            nTokenPrivileges,
-                            TokenPrivileges->Privileges,
-                            TokenOwner->Owner,
-                            TokenPrimaryGroup->PrimaryGroup,
-                            TokenDefaultDacl->DefaultDacl,
-                            TokenSource,
+                            PrivilegeCount,
+                            CapturedPrivileges,
+                            CapturedOwnerSid,
+                            CapturedPrimaryGroupSid,
+                            CapturedDefaultDacl,
+                            &LocalTokenSource,
                             FALSE);
     if (NT_SUCCESS(Status))
     {
@@ -2404,6 +2818,16 @@ NtCreateToken(OUT PHANDLE TokenHandle,
         _SEH2_END;
     }
 
+Cleanup:
+
+    /* Release what we captured */
+    SeReleaseSidAndAttributesArray(CapturedUser, PreviousMode, FALSE);
+    SeReleaseSidAndAttributesArray(CapturedGroups, PreviousMode, FALSE);
+    SeReleaseLuidAndAttributesArray(CapturedPrivileges, PreviousMode, FALSE);
+    SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE);
+    SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE);
+    SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE);
+
     return Status;
 }
 
@@ -2429,6 +2853,7 @@ NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
     PACL Dacl = NULL;
     KPROCESSOR_MODE PreviousMode;
     NTSTATUS Status;
+    BOOLEAN RestoreImpersonation = FALSE;
 
     PAGED_CODE();
 
@@ -2482,7 +2907,8 @@ NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
 
     if (OpenAsSelf)
     {
-        PsDisableImpersonation(PsGetCurrentThread(), &ImpersonationState);
+        RestoreImpersonation = PsDisableImpersonation(PsGetCurrentThread(),
+                                                      &ImpersonationState);
     }
 
     if (CopyOnOpen)
@@ -2533,7 +2959,7 @@ NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
 
     if (Dacl) ExFreePoolWithTag(Dacl, TAG_TOKEN_ACL);
 
-    if (OpenAsSelf)
+    if (RestoreImpersonation)
     {
         PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
     }