[NTOS]
[reactos.git] / reactos / ntoskrnl / se / token.c
index 38e5012..44481d6 100644 (file)
@@ -22,6 +22,9 @@
 POBJECT_TYPE SepTokenObjectType = NULL;
 ERESOURCE SepTokenLock;
 
+TOKEN_SOURCE SeSystemTokenSource = {"*SYSTEM*", {0}};
+LUID SeSystemAuthenticationId = SYSTEM_LUID;
+
 static GENERIC_MAPPING SepTokenMapping = {TOKEN_READ,
     TOKEN_WRITE,
     TOKEN_EXECUTE,
@@ -244,7 +247,7 @@ SepDuplicateToken(PTOKEN Token,
                             (PVOID*)&AccessToken);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("ObCreateObject() failed (Status %lx)\n");
+        DPRINT1("ObCreateObject() failed (Status %lx)\n", Status);
         return(Status);
     }
 
@@ -510,34 +513,80 @@ SeAssignPrimaryToken(IN PEPROCESS Process,
     ObInitializeFastReference(&Process->Token, Token);
 }
 
-PTOKEN
+
+NTSTATUS
 NTAPI
-SepCreateSystemProcessToken(VOID)
-{
-    NTSTATUS Status;
-    ULONG uSize;
-    ULONG i;
-    ULONG uLocalSystemLength;
-    ULONG uWorldLength;
-    ULONG uAuthUserLength;
-    ULONG uAdminsLength;
+SepCreateToken(OUT PHANDLE TokenHandle,
+              IN KPROCESSOR_MODE PreviousMode,
+              IN ACCESS_MASK DesiredAccess,
+              IN 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 GroupLength,
+              IN ULONG PrivilegeCount,
+              IN PLUID_AND_ATTRIBUTES Privileges,
+              IN PSID Owner,
+              IN PSID PrimaryGroup,
+              IN PACL DefaultDacl,
+              IN PTOKEN_SOURCE TokenSource,
+              IN BOOLEAN SystemToken)
+{                  
     PTOKEN AccessToken;
-    PVOID SidArea;
+    LUID TokenId;
+    LUID ModifiedId;
+    PVOID EndMem;
+    ULONG uLength;
+    ULONG i;
+    NTSTATUS Status;
+    ULONG TokenFlags = 0;
     
-    PAGED_CODE();
+    /* Loop all groups */
+    for (i = 0; i < GroupCount; i++)
+    {
+        /* Check for mandatory groups */
+        if (Groups[i].Attributes & SE_GROUP_MANDATORY)
+        {
+            /* Force them to be enabled */
+            Groups[i].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
+        }
+        
+        /* Check of the group is an admin group */
+        if (RtlEqualSid(SeAliasAdminsSid, Groups[i].Sid))
+        {
+            /* Remember this so we can optimize queries later */
+            TokenFlags |= TOKEN_HAS_ADMIN_GROUP;
+        }
+    }
     
-    uLocalSystemLength = RtlLengthSid(SeLocalSystemSid);
-    uWorldLength       = RtlLengthSid(SeWorldSid);
-    uAuthUserLength    = RtlLengthSid(SeAuthenticatedUserSid);
-    uAdminsLength      = RtlLengthSid(SeAliasAdminsSid);
+    /* 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);
     
-    /*
-     * Initialize the token
-     */
-    Status = ObCreateObject(KernelMode,
+    Status = ZwAllocateLocallyUniqueId(&ModifiedId);
+    if (!NT_SUCCESS(Status))
+        return(Status);
+    
+    Status = ObCreateObject(PreviousMode,
                             SepTokenObjectType,
-                            NULL,
-                            KernelMode,
+                            ObjectAttributes,
+                            PreviousMode,
                             NULL,
                             sizeof(TOKEN),
                             0,
@@ -545,180 +594,279 @@ SepCreateSystemProcessToken(VOID)
                             (PVOID*)&AccessToken);
     if (!NT_SUCCESS(Status))
     {
-        return NULL;
+        DPRINT1("ObCreateObject() failed (Status %lx)\n");
+        return(Status);
     }
 
     /* Zero out the buffer */
     RtlZeroMemory(AccessToken, sizeof(TOKEN));
     
-    Status = ExpAllocateLocallyUniqueId(&AccessToken->TokenId);
-    if (!NT_SUCCESS(Status))
-    {
-        ObDereferenceObject(AccessToken);
-        return NULL;
-    }
+    AccessToken->TokenLock = &SepTokenLock;
     
-    Status = ExpAllocateLocallyUniqueId(&AccessToken->ModifiedId);
-    if (!NT_SUCCESS(Status))
-    {
-        ObDereferenceObject(AccessToken);
-        return NULL;
-    }
+    RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier,
+                &TokenSource->SourceIdentifier);
+    memcpy(AccessToken->TokenSource.SourceName,
+           TokenSource->SourceName,
+           sizeof(TokenSource->SourceName));
     
-    Status = ExpAllocateLocallyUniqueId(&AccessToken->AuthenticationId);
-    if (!NT_SUCCESS(Status))
-    {
-        ObDereferenceObject(AccessToken);
-        return NULL;
-    }
+    RtlCopyLuid(&AccessToken->TokenId, &TokenId);
+    RtlCopyLuid(&AccessToken->AuthenticationId, AuthenticationId);
+    AccessToken->ExpirationTime = *ExpirationTime;
+    RtlCopyLuid(&AccessToken->ModifiedId, &ModifiedId);
     
-    AccessToken->TokenLock = &SepTokenLock;
+    AccessToken->UserAndGroupCount = GroupCount + 1;
+    AccessToken->PrivilegeCount = PrivilegeCount;
     
-    AccessToken->TokenType = TokenPrimary;
-    AccessToken->ImpersonationLevel = SecurityDelegation;
-    memcpy(AccessToken->TokenSource.SourceName, "SeMgr\0\0\0", 8);
-    AccessToken->ExpirationTime.QuadPart = -1;
-    AccessToken->UserAndGroupCount = 4;
+    AccessToken->TokenFlags = TokenFlags;
+    AccessToken->TokenType = TokenType;
+    AccessToken->ImpersonationLevel = ImpersonationLevel;
     
-    uSize = sizeof(SID_AND_ATTRIBUTES) * AccessToken->UserAndGroupCount;
-    uSize += uLocalSystemLength;
-    uSize += uWorldLength;
-    uSize += uAuthUserLength;
-    uSize += uAdminsLength;
+    /*
+     * Normally we would just point these members into the variable information
+     * area; however, our ObCreateObject() call can't allocate a variable information
+     * area, so we allocate them seperately and provide a destroy function.
+     */
+    
+    uLength = sizeof(SID_AND_ATTRIBUTES) * AccessToken->UserAndGroupCount;
+    uLength += RtlLengthSid(User);
+    for (i = 0; i < GroupCount; i++)
+        uLength += RtlLengthSid(Groups[i].Sid);
     
     AccessToken->UserAndGroups =
     (PSID_AND_ATTRIBUTES)ExAllocatePoolWithTag(PagedPool,
-                                               uSize,
+                                               uLength,
                                                'uKOT');
-    SidArea = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
     
-    i = 0;
-    AccessToken->UserAndGroups[i].Sid = (PSID) SidArea;
-    AccessToken->UserAndGroups[i++].Attributes = 0;
-    RtlCopySid(uLocalSystemLength, SidArea, SeLocalSystemSid);
-    SidArea = (char*)SidArea + uLocalSystemLength;
-    
-    AccessToken->DefaultOwnerIndex = i;
-    AccessToken->UserAndGroups[i].Sid = (PSID) SidArea;
-    AccessToken->PrimaryGroup = (PSID) SidArea;
-    AccessToken->UserAndGroups[i++].Attributes = SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT;
-    Status = RtlCopySid(uAdminsLength, SidArea, SeAliasAdminsSid);
-    SidArea = (char*)SidArea + uAdminsLength;
-    
-    AccessToken->UserAndGroups[i].Sid = (PSID) SidArea;
-    AccessToken->UserAndGroups[i++].Attributes = SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY;
-    RtlCopySid(uWorldLength, SidArea, SeWorldSid);
-    SidArea = (char*)SidArea + uWorldLength;
-    
-    AccessToken->UserAndGroups[i].Sid = (PSID) SidArea;
-    AccessToken->UserAndGroups[i++].Attributes = SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY;
-    RtlCopySid(uAuthUserLength, SidArea, SeAuthenticatedUserSid);
-    SidArea = (char*)SidArea + uAuthUserLength;
-    
-    AccessToken->PrivilegeCount = 20;
-    
-    uSize = AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
-    AccessToken->Privileges =
-    (PLUID_AND_ATTRIBUTES)ExAllocatePoolWithTag(PagedPool,
-                                                uSize,
-                                                'pKOT');
+    EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
     
-    i = 0;
-    AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
-    AccessToken->Privileges[i++].Luid = SeTcbPrivilege;
+    Status = RtlCopySidAndAttributesArray(1,
+                                          User,
+                                          uLength,
+                                          AccessToken->UserAndGroups,
+                                          EndMem,
+                                          &EndMem,
+                                          &uLength);
+    if (NT_SUCCESS(Status))
+    {
+        Status = RtlCopySidAndAttributesArray(GroupCount,
+                                              Groups,
+                                              uLength,
+                                              &AccessToken->UserAndGroups[1],
+                                              EndMem,
+                                              &EndMem,
+                                              &uLength);
+    }
     
-    AccessToken->Privileges[i].Attributes = 0;
-    AccessToken->Privileges[i++].Luid = SeCreateTokenPrivilege;
+    if (NT_SUCCESS(Status))
+    {
+        Status = SepFindPrimaryGroupAndDefaultOwner(
+                                                    AccessToken,
+                                                    PrimaryGroup,
+                                                    Owner);
+    }
     
-    AccessToken->Privileges[i].Attributes = 0;
-    AccessToken->Privileges[i++].Luid = SeTakeOwnershipPrivilege;
+    if (NT_SUCCESS(Status))
+    {
+        uLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
+        AccessToken->Privileges =
+        (PLUID_AND_ATTRIBUTES)ExAllocatePoolWithTag(PagedPool,
+                                                    uLength,
+                                                    'pKOT');
+        
+        if (PreviousMode != KernelMode)
+        {
+            _SEH2_TRY
+            {
+                RtlCopyMemory(AccessToken->Privileges,
+                              Privileges,
+                              PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+        }
+        else
+        {
+            RtlCopyMemory(AccessToken->Privileges,
+                          Privileges,
+                          PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
+        }
+    }
     
-    AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
-    AccessToken->Privileges[i++].Luid = SeCreatePagefilePrivilege;
+    if (NT_SUCCESS(Status))
+    {
+        AccessToken->DefaultDacl =
+        (PACL) ExAllocatePoolWithTag(PagedPool,
+                                     DefaultDacl->AclSize,
+                                     'kDOT');
+        memcpy(AccessToken->DefaultDacl,
+               DefaultDacl,
+               DefaultDacl->AclSize);
+    }
     
-    AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
-    AccessToken->Privileges[i++].Luid = SeLockMemoryPrivilege;
+    if (!SystemToken)
+    {
+        
+        Status = ObInsertObject ((PVOID)AccessToken,
+                                 NULL,
+                                 DesiredAccess,
+                                 0,
+                                 NULL,
+                                 TokenHandle);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("ObInsertObject() failed (Status %lx)\n", Status);
+        }
+    }
+    else
+    {
+        /* Return pointer instead of handle */
+        *TokenHandle = (HANDLE)AccessToken;
+    }
+
+    return Status;
+}
+
+PTOKEN
+NTAPI
+SepCreateSystemProcessToken(VOID)
+{
+    LUID_AND_ATTRIBUTES Privileges[25];
+    ULONG GroupAttributes, OwnerAttributes;
+    SID_AND_ATTRIBUTES Groups[32];
+    LARGE_INTEGER Expiration;
+    SID_AND_ATTRIBUTES UserSid;
+    ULONG GroupLength;
+    PSID PrimaryGroup;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    PSID Owner;
+    ULONG i;
+    PTOKEN Token;
+    NTSTATUS Status;
     
-    AccessToken->Privileges[i].Attributes = 0;
-    AccessToken->Privileges[i++].Luid = SeAssignPrimaryTokenPrivilege;
+    /* Don't ever expire */
+    Expiration.QuadPart = -1;
+    
+    /* All groups mandatory and enabled */
+    GroupAttributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT;
+    OwnerAttributes = SE_GROUP_ENABLED | SE_GROUP_OWNER | SE_GROUP_ENABLED_BY_DEFAULT;
+    
+    /* User is system */
+    UserSid.Sid = SeLocalSystemSid;
+    UserSid.Attributes = 0;
+    
+    /* Primary group is local system */
+    PrimaryGroup = SeLocalSystemSid;
+    
+    /* Owner is admins */
+    Owner = SeAliasAdminsSid;
+    
+    /* Groups are admins, world, and authenticated users */
+    Groups[0].Sid = SeAliasAdminsSid;
+    Groups[0].Attributes = OwnerAttributes;
+    Groups[1].Sid = SeWorldSid;
+    Groups[1].Attributes = GroupAttributes;
+    Groups[2].Sid = SeAuthenticatedUserSid;
+    Groups[2].Attributes = OwnerAttributes;
+    GroupLength = sizeof(SID_AND_ATTRIBUTES) +
+                  SeLengthSid(Groups[0].Sid) +
+                  SeLengthSid(Groups[1].Sid) +
+                  SeLengthSid(Groups[2].Sid);
+    ASSERT(GroupLength <= sizeof(Groups));
+
+    /* Setup the privileges */
+    i = 0;
+    Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
+    Privileges[i++].Luid = SeTcbPrivilege;
     
-    AccessToken->Privileges[i].Attributes = 0;
-    AccessToken->Privileges[i++].Luid = SeIncreaseQuotaPrivilege;
+    Privileges[i].Attributes = 0;
+    Privileges[i++].Luid = SeCreateTokenPrivilege;
     
-    AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
-    AccessToken->Privileges[i++].Luid = SeIncreaseBasePriorityPrivilege;
+    Privileges[i].Attributes = 0;
+    Privileges[i++].Luid = SeTakeOwnershipPrivilege;
     
-    AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
-    AccessToken->Privileges[i++].Luid = SeCreatePermanentPrivilege;
+    Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+    Privileges[i++].Luid = SeCreatePagefilePrivilege;
     
-    AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
-    AccessToken->Privileges[i++].Luid = SeDebugPrivilege;
+    Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+    Privileges[i++].Luid = SeLockMemoryPrivilege;
     
-    AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
-    AccessToken->Privileges[i++].Luid = SeAuditPrivilege;
+    Privileges[i].Attributes = 0;
+    Privileges[i++].Luid = SeAssignPrimaryTokenPrivilege;
     
-    AccessToken->Privileges[i].Attributes = 0;
-    AccessToken->Privileges[i++].Luid = SeSecurityPrivilege;
+    Privileges[i].Attributes = 0;
+    Privileges[i++].Luid = SeIncreaseQuotaPrivilege;
     
-    AccessToken->Privileges[i].Attributes = 0;
-    AccessToken->Privileges[i++].Luid = SeSystemEnvironmentPrivilege;
+    Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+    Privileges[i++].Luid = SeIncreaseBasePriorityPrivilege;
     
-    AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
-    AccessToken->Privileges[i++].Luid = SeChangeNotifyPrivilege;
+    Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+    Privileges[i++].Luid = SeCreatePermanentPrivilege;
     
-    AccessToken->Privileges[i].Attributes = 0;
-    AccessToken->Privileges[i++].Luid = SeBackupPrivilege;
+    Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+    Privileges[i++].Luid = SeDebugPrivilege;
     
-    AccessToken->Privileges[i].Attributes = 0;
-    AccessToken->Privileges[i++].Luid = SeRestorePrivilege;
+    Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+    Privileges[i++].Luid = SeAuditPrivilege;
     
-    AccessToken->Privileges[i].Attributes = 0;
-    AccessToken->Privileges[i++].Luid = SeShutdownPrivilege;
+    Privileges[i].Attributes = 0;
+    Privileges[i++].Luid = SeSecurityPrivilege;
     
-    AccessToken->Privileges[i].Attributes = 0;
-    AccessToken->Privileges[i++].Luid = SeLoadDriverPrivilege;
+    Privileges[i].Attributes = 0;
+    Privileges[i++].Luid = SeSystemEnvironmentPrivilege;
     
-    AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
-    AccessToken->Privileges[i++].Luid = SeProfileSingleProcessPrivilege;
+    Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+    Privileges[i++].Luid = SeChangeNotifyPrivilege;
     
-    AccessToken->Privileges[i].Attributes = 0;
-    AccessToken->Privileges[i++].Luid = SeSystemtimePrivilege;
-#if 0
-    AccessToken->Privileges[i].Attributes = 0;
-    AccessToken->Privileges[i++].Luid = SeUndockPrivilege;
+    Privileges[i].Attributes = 0;
+    Privileges[i++].Luid = SeBackupPrivilege;
     
-    AccessToken->Privileges[i].Attributes = 0;
-    AccessToken->Privileges[i++].Luid = SeManageVolumePrivilege;
-#endif
+    Privileges[i].Attributes = 0;
+    Privileges[i++].Luid = SeRestorePrivilege;
     
-    ASSERT(i == 20);
+    Privileges[i].Attributes = 0;
+    Privileges[i++].Luid = SeShutdownPrivilege;
     
-    uSize = sizeof(ACL);
-    uSize += sizeof(ACE) + uLocalSystemLength;
-    uSize += sizeof(ACE) + uAdminsLength;
-    uSize = (uSize & (~3)) + 8;
-    AccessToken->DefaultDacl =
-    (PACL) ExAllocatePoolWithTag(PagedPool,
-                                 uSize,
-                                 'kDOT');
-    Status = RtlCreateAcl(AccessToken->DefaultDacl, uSize, ACL_REVISION);
-    if ( NT_SUCCESS(Status) )
-    {
-        Status = RtlAddAccessAllowedAce(AccessToken->DefaultDacl, ACL_REVISION, GENERIC_ALL, SeLocalSystemSid);
-    }
+    Privileges[i].Attributes = 0;
+    Privileges[i++].Luid = SeLoadDriverPrivilege;
     
-    if ( NT_SUCCESS(Status) )
-    {
-        Status = RtlAddAccessAllowedAce(AccessToken->DefaultDacl, ACL_REVISION, GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE|READ_CONTROL, SeAliasAdminsSid);
-    }
+    Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+    Privileges[i++].Luid = SeProfileSingleProcessPrivilege;
     
-    if ( ! NT_SUCCESS(Status) )
-    {
-        ObDereferenceObject(AccessToken);
-        return NULL;
-    }
+    Privileges[i].Attributes = 0;
+    Privileges[i++].Luid = SeSystemtimePrivilege;
+    ASSERT(i == 20);
     
-    return AccessToken;
+    /* Setup the object attributes */
+    InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
+    ASSERT(SeSystemDefaultDacl != NULL);
+    
+    /* Create the token */
+    Status = SepCreateToken((PHANDLE)&Token,
+                            KernelMode,
+                            0,
+                            &ObjectAttributes,
+                            TokenPrimary,
+                            0,
+                            &SeSystemAuthenticationId,
+                            &Expiration,
+                            &UserSid,
+                            3,
+                            Groups,
+                            GroupLength,
+                            20,
+                            Privileges,
+                            Owner,
+                            PrimaryGroup,
+                            SeSystemDefaultDacl,
+                            &SeSystemTokenSource,
+                            TRUE);
+    ASSERT(Status == STATUS_SUCCESS);
+    
+    /* Return the token */
+    return Token;
 }
 
 /* PUBLIC FUNCTIONS ***********************************************************/
@@ -1920,7 +2068,8 @@ NtAdjustPrivilegesToken (IN HANDLE TokenHandle,
     return Status;
 }
 
-NTSTATUS NTAPI
+NTSTATUS
+NTAPI
 NtCreateToken(OUT PHANDLE TokenHandle,
               IN ACCESS_MASK DesiredAccess,
               IN POBJECT_ATTRIBUTES ObjectAttributes,
@@ -1936,12 +2085,6 @@ NtCreateToken(OUT PHANDLE TokenHandle,
               IN PTOKEN_SOURCE TokenSource)
 {
     HANDLE hToken;
-    PTOKEN AccessToken;
-    LUID TokenId;
-    LUID ModifiedId;
-    PVOID EndMem;
-    ULONG uLength;
-    ULONG i;
     KPROCESSOR_MODE PreviousMode;
     ULONG nTokenPrivileges = 0;
     LARGE_INTEGER LocalExpirationTime = {{0, 0}};
@@ -1996,148 +2139,25 @@ NtCreateToken(OUT PHANDLE TokenHandle,
         LocalExpirationTime = *ExpirationTime;
     }
     
-    Status = ZwAllocateLocallyUniqueId(&TokenId);
-    if (!NT_SUCCESS(Status))
-        return(Status);
-    
-    Status = ZwAllocateLocallyUniqueId(&ModifiedId);
-    if (!NT_SUCCESS(Status))
-        return(Status);
-    
-    Status = ObCreateObject(PreviousMode,
-                            SepTokenObjectType,
-                            ObjectAttributes,
+    Status = SepCreateToken(&hToken,
                             PreviousMode,
-                            NULL,
-                            sizeof(TOKEN),
-                            0,
-                            0,
-                            (PVOID*)&AccessToken);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("ObCreateObject() failed (Status %lx)\n");
-        return(Status);
-    }
-
-    /* Zero out the buffer */
-    RtlZeroMemory(AccessToken, sizeof(TOKEN));
-    
-    AccessToken->TokenLock = &SepTokenLock;
-    
-    RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier,
-                &TokenSource->SourceIdentifier);
-    memcpy(AccessToken->TokenSource.SourceName,
-           TokenSource->SourceName,
-           sizeof(TokenSource->SourceName));
-    
-    RtlCopyLuid(&AccessToken->TokenId, &TokenId);
-    RtlCopyLuid(&AccessToken->AuthenticationId, AuthenticationId);
-    AccessToken->ExpirationTime = *ExpirationTime;
-    RtlCopyLuid(&AccessToken->ModifiedId, &ModifiedId);
-    
-    AccessToken->UserAndGroupCount = TokenGroups->GroupCount + 1;
-    AccessToken->PrivilegeCount    = TokenPrivileges->PrivilegeCount;
-    
-    AccessToken->TokenType = TokenType;
-    AccessToken->ImpersonationLevel = ((PSECURITY_QUALITY_OF_SERVICE)
-                                       (ObjectAttributes->SecurityQualityOfService))->ImpersonationLevel;
-    
-    /*
-     * Normally we would just point these members into the variable information
-     * area; however, our ObCreateObject() call can't allocate a variable information
-     * area, so we allocate them seperately and provide a destroy function.
-     */
-    
-    uLength = sizeof(SID_AND_ATTRIBUTES) * AccessToken->UserAndGroupCount;
-    uLength += RtlLengthSid(TokenUser->User.Sid);
-    for (i = 0; i < TokenGroups->GroupCount; i++)
-        uLength += RtlLengthSid(TokenGroups->Groups[i].Sid);
-    
-    AccessToken->UserAndGroups =
-    (PSID_AND_ATTRIBUTES)ExAllocatePoolWithTag(PagedPool,
-                                               uLength,
-                                               'uKOT');
-    
-    EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
-    
-    Status = RtlCopySidAndAttributesArray(1,
-                                          &TokenUser->User,
-                                          uLength,
-                                          AccessToken->UserAndGroups,
-                                          EndMem,
-                                          &EndMem,
-                                          &uLength);
-    if (NT_SUCCESS(Status))
-    {
-        Status = RtlCopySidAndAttributesArray(TokenGroups->GroupCount,
-                                              TokenGroups->Groups,
-                                              uLength,
-                                              &AccessToken->UserAndGroups[1],
-                                              EndMem,
-                                              &EndMem,
-                                              &uLength);
-    }
-    
-    if (NT_SUCCESS(Status))
-    {
-        Status = SepFindPrimaryGroupAndDefaultOwner(
-                                                    AccessToken,
-                                                    TokenPrimaryGroup->PrimaryGroup,
-                                                    TokenOwner->Owner);
-    }
-    
-    if (NT_SUCCESS(Status))
-    {
-        uLength = TokenPrivileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
-        AccessToken->Privileges =
-        (PLUID_AND_ATTRIBUTES)ExAllocatePoolWithTag(PagedPool,
-                                                    uLength,
-                                                    'pKOT');
-        
-        if (PreviousMode != KernelMode)
-        {
-            _SEH2_TRY
-            {
-                RtlCopyMemory(AccessToken->Privileges,
-                              TokenPrivileges->Privileges,
-                              nTokenPrivileges * sizeof(LUID_AND_ATTRIBUTES));
-            }
-            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-            {
-                Status = _SEH2_GetExceptionCode();
-            }
-            _SEH2_END;
-        }
-        else
-        {
-            RtlCopyMemory(AccessToken->Privileges,
-                          TokenPrivileges->Privileges,
-                          nTokenPrivileges * sizeof(LUID_AND_ATTRIBUTES));
-        }
-    }
-    
-    if (NT_SUCCESS(Status))
-    {
-        AccessToken->DefaultDacl =
-        (PACL) ExAllocatePoolWithTag(PagedPool,
-                                     TokenDefaultDacl->DefaultDacl->AclSize,
-                                     'kDOT');
-        memcpy(AccessToken->DefaultDacl,
-               TokenDefaultDacl->DefaultDacl,
-               TokenDefaultDacl->DefaultDacl->AclSize);
-    }
-    
-    Status = ObInsertObject ((PVOID)AccessToken,
-                             NULL,
-                             DesiredAccess,
-                             0,
-                             NULL,
-                             &hToken);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("ObInsertObject() failed (Status %lx)\n", Status);
-    }
-    
+                            DesiredAccess,
+                            ObjectAttributes,
+                            TokenType,
+                            ((PSECURITY_QUALITY_OF_SERVICE)(ObjectAttributes->SecurityQualityOfService))->ImpersonationLevel,
+                            AuthenticationId,
+                            &LocalExpirationTime,
+                            &TokenUser->User,
+                            TokenGroups->GroupCount,
+                            TokenGroups->Groups,
+                            0, // FIXME: Should capture
+                            nTokenPrivileges,
+                            TokenPrivileges->Privileges,
+                            TokenOwner->Owner,
+                            TokenPrimaryGroup->PrimaryGroup,
+                            TokenDefaultDacl->DefaultDacl,
+                            TokenSource,
+                            FALSE);
     if (NT_SUCCESS(Status))
     {
         _SEH2_TRY
@@ -2165,9 +2185,9 @@ NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
                     IN ULONG HandleAttributes,
                     OUT PHANDLE TokenHandle)
 {
-    PETHREAD Thread;
+    PETHREAD Thread, NewThread;
     HANDLE hToken;
-    PTOKEN Token, NewToken, PrimaryToken;
+    PTOKEN Token, NewToken = NULL, PrimaryToken;
     BOOLEAN CopyOnOpen, EffectiveOnly;
     SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
     SE_IMPERSONATION_STATE ImpersonationState;
@@ -2215,12 +2235,11 @@ NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
         ObDereferenceObject(Thread);
         return STATUS_NO_TOKEN;
     }
-    
-    ObDereferenceObject(Thread);
-    
+       
     if (ImpersonationLevel == SecurityAnonymous)
     {
-        ObDereferenceObject(Token);
+        PsDereferenceImpersonationToken(Token);
+        ObDereferenceObject(Thread);
         return STATUS_CANT_OPEN_ANONYMOUS;
     }
     
@@ -2236,58 +2255,41 @@ NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
     if (CopyOnOpen)
     {
         Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS,
-                                           PsThreadType, PreviousMode,
-                                           (PVOID*)&Thread, NULL);
-        if (!NT_SUCCESS(Status))
-        {
-            ObDereferenceObject(Token);
-            if (OpenAsSelf)
-            {
-                PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
-            }
-            return Status;
-        }
-        
-        PrimaryToken = PsReferencePrimaryToken(Thread->ThreadsProcess);
-        Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl);
-        ASSERT(FALSE);
-        ObDereferenceObject(PrimaryToken);
-        ObDereferenceObject(Thread);
-        if (!NT_SUCCESS(Status))
+                                           PsThreadType, KernelMode,
+                                           (PVOID*)&NewThread, NULL);
+        if (NT_SUCCESS(Status))
         {
-            ObDereferenceObject(Token);
-            if (OpenAsSelf)
+            PrimaryToken = PsReferencePrimaryToken(NewThread->ThreadsProcess);
+            
+            Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl);
+
+            ObFastDereferenceObject(&NewThread->ThreadsProcess->Token, PrimaryToken);
+            
+            if (NT_SUCCESS(Status))
             {
-                PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
-            }
-            return Status;
-        }
-        
-        RtlCreateSecurityDescriptor(&SecurityDescriptor,
-                                    SECURITY_DESCRIPTOR_REVISION);
-        RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl,
-                                     FALSE);
-        
-        InitializeObjectAttributes(&ObjectAttributes, NULL, HandleAttributes,
-                                   NULL, &SecurityDescriptor);
+                if (Dacl)
+                {
+                    RtlCreateSecurityDescriptor(&SecurityDescriptor,
+                                                SECURITY_DESCRIPTOR_REVISION);
+                    RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl,
+                                                 FALSE);
+                }
         
-        Status = SepDuplicateToken(Token, &ObjectAttributes, EffectiveOnly,
-                                   TokenImpersonation, ImpersonationLevel,
-                                   KernelMode, &NewToken);
-        ExFreePool(Dacl);
-        if (!NT_SUCCESS(Status))
-        {
-            ObDereferenceObject(Token);
-            if (OpenAsSelf)
-            {
-                PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
+                InitializeObjectAttributes(&ObjectAttributes, NULL, HandleAttributes,
+                                           NULL, Dacl ? &SecurityDescriptor : NULL);
+            
+
+                Status = SepDuplicateToken(Token, &ObjectAttributes, EffectiveOnly,
+                                           TokenImpersonation, ImpersonationLevel,
+                                           KernelMode, &NewToken);
+                if (NT_SUCCESS(Status))
+                {
+                    ObReferenceObject(NewToken);
+                    Status = ObInsertObject(NewToken, NULL, DesiredAccess, 0, NULL,
+                                            &hToken);
+                }
             }
-            return Status;
         }
-        
-        Status = ObInsertObject(NewToken, NULL, DesiredAccess, 0, NULL,
-                                &hToken);
-        
     }
     else
     {
@@ -2296,13 +2298,24 @@ NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
                                        PreviousMode, &hToken);
     }
     
-    ObDereferenceObject(Token);
+    if (Dacl) ExFreePool(Dacl);
     
     if (OpenAsSelf)
     {
         PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
     }
     
+    ObDereferenceObject(Token);
+    
+    if (NT_SUCCESS(Status) && CopyOnOpen)
+    {
+        PsImpersonateClient(Thread, NewToken, FALSE, EffectiveOnly, ImpersonationLevel);
+    }
+    
+    if (NewToken) ObDereferenceObject(NewToken);
+
+    if (CopyOnOpen && NewThread) ObDereferenceObject(NewThread);
+
     if(NT_SUCCESS(Status))
     {
         _SEH2_TRY