[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / se / token.c
index 09920d9..95ec269 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 *****************************************************************/
@@ -95,6 +108,8 @@ SepCompareTokens(IN PTOKEN FirstToken,
         }
 
         /* FIXME: Check if every privilege that is present in either token is also present in the other one */
+        DPRINT1("FIXME: Pretending tokens are equal!\n");
+        IsEqual = TRUE;
     }
 
     *Equal = IsEqual;
@@ -108,7 +123,7 @@ SepUpdateSinglePrivilegeFlagToken(
     _In_ ULONG Index)
 {
     ULONG TokenFlag;
-    NT_ASSERT(Index < Token->PrivilegeCount);
+    ASSERT(Index < Token->PrivilegeCount);
 
     /* The high part of all values we are interested in is 0 */
     if (Token->Privileges[Index].Luid.HighPart != 0)
@@ -174,7 +189,7 @@ SepRemovePrivilegeToken(
     _In_ ULONG Index)
 {
     ULONG MoveCount;
-    NT_ASSERT(Index < Token->PrivilegeCount);
+    ASSERT(Index < Token->PrivilegeCount);
 
     /* Calculate the number of trailing privileges */
     MoveCount = Token->PrivilegeCount - Index - 1;
@@ -218,7 +233,39 @@ SeExchangePrimaryToken(PEPROCESS Process,
     PAGED_CODE();
 
     if (NewToken->TokenType != TokenPrimary) return(STATUS_BAD_TOKEN_TYPE);
-    if (NewToken->TokenInUse) return(STATUS_TOKEN_ALREADY_IN_USE);
+    if (NewToken->TokenInUse)
+    {
+        BOOLEAN IsEqual;
+        NTSTATUS Status;
+
+        /* Maybe we're trying to set the same token */
+        OldToken = PsReferencePrimaryToken(Process);
+        if (OldToken == NewToken)
+        {
+            /* So it's a nop. */
+            *OldTokenP = OldToken;
+            return STATUS_SUCCESS;
+        }
+
+        Status = SepCompareTokens(OldToken, NewToken, &IsEqual);
+        if (!NT_SUCCESS(Status))
+        {
+            *OldTokenP = NULL;
+            PsDereferencePrimaryToken(OldToken);
+            return Status;
+        }
+
+        if (!IsEqual)
+        {
+            *OldTokenP = NULL;
+            PsDereferencePrimaryToken(OldToken);
+            return STATUS_TOKEN_ALREADY_IN_USE;
+        }
+        /* Silently return STATUS_SUCCESS but do not set the new token,
+         * as it's already in use elsewhere. */
+        *OldTokenP = OldToken;
+        return STATUS_SUCCESS;
+    }
 
     /* Mark new token in use */
     NewToken->TokenInUse = 1;
@@ -247,6 +294,9 @@ SeDeassignPrimaryToken(PEPROCESS Process)
 
     /* Mark the Old Token as free */
     OldToken->TokenInUse = 0;
+
+    /* Dereference the Token */
+    ObDereferenceObject(OldToken);
 }
 
 static ULONG
@@ -346,25 +396,14 @@ SepDuplicateToken(PTOKEN Token,
     /* Zero out the buffer */
     RtlZeroMemory(AccessToken, sizeof(TOKEN));
 
-    Status = ZwAllocateLocallyUniqueId(&AccessToken->TokenId);
-    if (!NT_SUCCESS(Status))
-    {
-        ObDereferenceObject(AccessToken);
-        return Status;
-    }
-
-    Status = ZwAllocateLocallyUniqueId(&AccessToken->ModifiedId);
-    if (!NT_SUCCESS(Status))
-    {
-        ObDereferenceObject(AccessToken);
-        return Status;
-    }
+    ExAllocateLocallyUniqueId(&AccessToken->TokenId);
 
     AccessToken->TokenLock = &SepTokenLock;
 
     AccessToken->TokenType  = TokenType;
     AccessToken->ImpersonationLevel = Level;
     RtlCopyLuid(&AccessToken->AuthenticationId, &Token->AuthenticationId);
+    RtlCopyLuid(&AccessToken->ModifiedId, &Token->ModifiedId);
 
     AccessToken->TokenSource.SourceIdentifier.LowPart = Token->TokenSource.SourceIdentifier.LowPart;
     AccessToken->TokenSource.SourceIdentifier.HighPart = Token->TokenSource.SourceIdentifier.HighPart;
@@ -444,6 +483,9 @@ SepDuplicateToken(PTOKEN Token,
 
     *NewAccessToken = AccessToken;
 
+    /* Reference the logon session */
+    SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
+
 done:
     if (!NT_SUCCESS(Status))
     {
@@ -524,13 +566,13 @@ SeIsTokenChild(IN PTOKEN Token,
     ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess());
 
     /* Get the ID */
-    ProcessLuid = ProcessToken->TokenId;
+    ProcessLuid = ProcessToken->AuthenticationId;
 
     /* Dereference the token */
     ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken);
 
     /* Get our LUID */
-    CallerLuid = Token->TokenId;
+    CallerLuid = Token->AuthenticationId;
 
     /* Compare the LUIDs */
     if (RtlEqualLuid(&CallerLuid, &ProcessLuid)) *IsChild = TRUE;
@@ -573,6 +615,11 @@ SepDeleteToken(PVOID ObjectBody)
 {
     PTOKEN AccessToken = (PTOKEN)ObjectBody;
 
+    DPRINT("SepDeleteToken()\n");
+
+    /* Dereference the logon session */
+    SepRmDereferenceLogonSession(&AccessToken->AuthenticationId);
+
     if (AccessToken->UserAndGroups)
         ExFreePoolWithTag(AccessToken->UserAndGroups, TAG_TOKEN_USERS);
 
@@ -663,6 +710,8 @@ SepCreateToken(OUT PHANDLE TokenHandle,
     NTSTATUS Status;
     ULONG TokenFlags = 0;
 
+    PAGED_CODE();
+
     /* Loop all groups */
     for (i = 0; i < GroupCount; i++)
     {
@@ -681,13 +730,8 @@ SepCreateToken(OUT PHANDLE TokenHandle,
         }
     }
 
-    Status = ZwAllocateLocallyUniqueId(&TokenId);
-    if (!NT_SUCCESS(Status))
-        return Status;
-
-    Status = ZwAllocateLocallyUniqueId(&ModifiedId);
-    if (!NT_SUCCESS(Status))
-        return Status;
+    ExAllocateLocallyUniqueId(&TokenId);
+    ExAllocateLocallyUniqueId(&ModifiedId);
 
     Status = ObCreateObject(PreviousMode,
                             SeTokenObjectType,
@@ -855,6 +899,9 @@ SepCreateToken(OUT PHANDLE TokenHandle,
         *TokenHandle = (HANDLE)AccessToken;
     }
 
+    /* Reference the logon session */
+    SepRmReferenceLogonSession(AuthenticationId);
+
 done:
     if (!NT_SUCCESS(Status))
     {
@@ -1035,8 +1082,47 @@ SeQueryInformationToken(IN PACCESS_TOKEN Token,
                         IN TOKEN_INFORMATION_CLASS TokenInformationClass,
                         OUT PVOID *TokenInformation)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+    PSECURITY_IMPERSONATION_LEVEL SeImpersonationLvl;
+    PAGED_CODE();
+
+    if (TokenInformationClass >= MaxTokenInfoClass)
+    {
+        DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
+        return STATUS_INVALID_INFO_CLASS;
+    }
+    
+    switch (TokenInformationClass)
+    {
+        case TokenImpersonationLevel:
+            /* It is mandatory to have an impersonation token */
+            if (((PTOKEN)Token)->TokenType != TokenImpersonation)
+            {
+                Status = STATUS_INVALID_INFO_CLASS;
+                break;
+            }
+
+            /* Allocate the output buffer */
+            SeImpersonationLvl = ExAllocatePoolWithTag(PagedPool, sizeof(SECURITY_IMPERSONATION_LEVEL), TAG_SE);
+            if (SeImpersonationLvl == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+
+            /* Set impersonation level and return the structure */
+            *SeImpersonationLvl = ((PTOKEN)Token)->ImpersonationLevel;
+            *TokenInformation = SeImpersonationLvl;
+            Status = STATUS_SUCCESS;
+            break;
+
+        default:
+            UNIMPLEMENTED;
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+    }
+
+    return Status;
 }
 
 /*
@@ -1759,7 +1845,8 @@ NtSetInformationToken(IN HANDLE TokenHandle,
                     }
                     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                     {
-                        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+                        Status = _SEH2_GetExceptionCode();
+                        goto Cleanup;
                     }
                     _SEH2_END;
 
@@ -1798,7 +1885,8 @@ NtSetInformationToken(IN HANDLE TokenHandle,
                     }
                     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                     {
-                        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+                        Status = _SEH2_GetExceptionCode();
+                        goto Cleanup;
                     }
                     _SEH2_END;
 
@@ -1837,7 +1925,8 @@ NtSetInformationToken(IN HANDLE TokenHandle,
                     }
                     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                     {
-                        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+                        Status = _SEH2_GetExceptionCode();
+                        goto Cleanup;
                     }
                     _SEH2_END;
 
@@ -1859,8 +1948,20 @@ NtSetInformationToken(IN HANDLE TokenHandle,
                                 ExFreePoolWithTag(Token->DefaultDacl, TAG_TOKEN_ACL);
                             }
 
-                            /* Set the new dacl */
-                            Token->DefaultDacl = CapturedAcl;
+                            Token->DefaultDacl = ExAllocatePoolWithTag(PagedPool,
+                                                                       CapturedAcl->AclSize,
+                                                                       TAG_TOKEN_ACL);
+                            if (!Token->DefaultDacl)
+                            {
+                                ExFreePoolWithTag(CapturedAcl, TAG_ACL);
+                                Status = STATUS_NO_MEMORY;
+                            }
+                            else
+                            {
+                                /* Set the new dacl */
+                                RtlCopyMemory(Token->DefaultDacl, CapturedAcl, CapturedAcl->AclSize);
+                                ExFreePoolWithTag(CapturedAcl, TAG_ACL);
+                            }
                         }
                     }
                     else
@@ -1891,7 +1992,8 @@ NtSetInformationToken(IN HANDLE TokenHandle,
                 }
                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                 {
-                    _SEH2_YIELD(return _SEH2_GetExceptionCode());
+                    Status = _SEH2_GetExceptionCode();
+                    goto Cleanup;
                 }
                 _SEH2_END;
 
@@ -1906,16 +2008,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;
 }
 
@@ -2599,6 +2868,10 @@ NtCreateToken(
                                NonPagedPool,
                                FALSE,
                                &CapturedDefaultDacl);
+        if (!NT_SUCCESS(Status))
+        {
+            goto Cleanup;
+        }
     }
 
     /* Call the internal function */
@@ -2689,10 +2962,12 @@ NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
         _SEH2_END;
     }
 
+    /* Validate object attributes */
+    HandleAttributes = ObpValidateAttributes(HandleAttributes, PreviousMode);
+
     /*
      * At first open the thread token for information access and verify
-     * that the token associated with thread is valid.
-     */
+     * that the token associated with thread is valid.     */
 
     Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_QUERY_INFORMATION,
                                        PsThreadType, PreviousMode, (PVOID*)&Thread,
@@ -2791,6 +3066,8 @@ NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
 
     if (CopyOnOpen && NewThread) ObDereferenceObject(NewThread);
 
+    ObDereferenceObject(Thread);
+
     if (NT_SUCCESS(Status))
     {
         _SEH2_TRY