NtDuplicateToken() must create and return a handle to the duplicated token.
[reactos.git] / reactos / ntoskrnl / se / token.c
index 6a64073..003300c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: token.c,v 1.15 2002/06/04 13:44:06 ekohl Exp $
+/* $Id: token.c,v 1.37 2004/07/13 08:43:35 ekohl Exp $
  *
  * COPYRIGHT:         See COPYING in the top level directory
  * PROJECT:           ReactOS kernel
 /* INCLUDES *****************************************************************/
 
 #include <limits.h>
-#include <ddk/ntddk.h>
+#define NTOS_MODE_KERNEL
+#include <ntos.h>
+#include <internal/ob.h>
 #include <internal/ps.h>
 #include <internal/se.h>
+#include <internal/safe.h>
 
+#define NDEBUG
 #include <internal/debug.h>
 
 /* GLOBALS *******************************************************************/
@@ -27,6 +31,8 @@ static GENERIC_MAPPING SepTokenMapping = {TOKEN_READ,
                                          TOKEN_EXECUTE,
                                          TOKEN_ALL_ACCESS};
 
+#define SYSTEM_LUID                      0x3E7;
+
 /* FUNCTIONS *****************************************************************/
 
 VOID SepFreeProxyData(PVOID ProxyData)
@@ -37,6 +43,7 @@ VOID SepFreeProxyData(PVOID ProxyData)
 NTSTATUS SepCopyProxyData(PVOID* Dest, PVOID Src)
 {
    UNIMPLEMENTED;
+   return(STATUS_NOT_IMPLEMENTED);
 }
 
 NTSTATUS SeExchangePrimaryToken(PEPROCESS Process,
@@ -65,17 +72,229 @@ NTSTATUS SeExchangePrimaryToken(PEPROCESS Process,
    return(STATUS_SUCCESS);
 }
 
-NTSTATUS SepDuplicationToken(PACCESS_TOKEN Token,
-                            POBJECT_ATTRIBUTES ObjectAttributes,
-                            TOKEN_TYPE TokenType,
-                            SECURITY_IMPERSONATION_LEVEL Level,
-                            SECURITY_IMPERSONATION_LEVEL ExistingLevel,
-                            KPROCESSOR_MODE PreviousMode,
-                            PACCESS_TOKEN* NewAccessToken)
+static ULONG
+RtlLengthSidAndAttributes(ULONG Count,
+                         PSID_AND_ATTRIBUTES Src)
 {
-   UNIMPLEMENTED;
+  ULONG i;
+  ULONG uLength;
+
+  uLength = Count * sizeof(SID_AND_ATTRIBUTES);
+  for (i = 0; i < Count; i++)
+    uLength += RtlLengthSid(Src[i].Sid);
+
+  return(uLength);
+}
+
+
+NTSTATUS
+SepFindPrimaryGroupAndDefaultOwner(PACCESS_TOKEN Token,
+                                  PSID PrimaryGroup,
+                                  PSID DefaultOwner)
+{
+  ULONG i;
+
+  Token->PrimaryGroup = 0;
+
+  if (DefaultOwner)
+    {
+      Token->DefaultOwnerIndex = Token->UserAndGroupCount;
+    }
+
+  /* Validate and set the primary group and user pointers */
+  for (i = 0; i < Token->UserAndGroupCount; i++)
+    {
+      if (DefaultOwner &&
+         RtlEqualSid(Token->UserAndGroups[i].Sid, DefaultOwner))
+       {
+         Token->DefaultOwnerIndex = i;
+       }
+
+      if (RtlEqualSid(Token->UserAndGroups[i].Sid, PrimaryGroup))
+       {
+         Token->PrimaryGroup = Token->UserAndGroups[i].Sid;
+       }
+    }
+
+  if (Token->DefaultOwnerIndex == Token->UserAndGroupCount)
+    {
+      return(STATUS_INVALID_OWNER);
+    }
+
+  if (Token->PrimaryGroup == 0)
+    {
+      return(STATUS_INVALID_PRIMARY_GROUP);
+    }
+
+  return(STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+SepDuplicateToken(PACCESS_TOKEN Token,
+                 POBJECT_ATTRIBUTES ObjectAttributes,
+                 TOKEN_TYPE TokenType,
+                 SECURITY_IMPERSONATION_LEVEL Level,
+                 SECURITY_IMPERSONATION_LEVEL ExistingLevel,
+                 KPROCESSOR_MODE PreviousMode,
+                 PACCESS_TOKEN* NewAccessToken)
+{
+  NTSTATUS Status;
+  ULONG uLength;
+  ULONG i;
+  
+  PVOID EndMem;
+
+  PACCESS_TOKEN AccessToken;
+
+  Status = ObCreateObject(PreviousMode,
+                         SepTokenObjectType,
+                         ObjectAttributes,
+                         PreviousMode,
+                         NULL,
+                         sizeof(ACCESS_TOKEN),
+                         0,
+                         0,
+                         (PVOID*)&AccessToken);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("ObCreateObject() failed (Status %lx)\n");
+      return(Status);
+    }
+
+  Status = ZwAllocateLocallyUniqueId(&AccessToken->TokenId);
+  if (!NT_SUCCESS(Status))
+    {
+      ObDereferenceObject(AccessToken);
+      return(Status);
+    }
+
+  Status = ZwAllocateLocallyUniqueId(&AccessToken->ModifiedId);
+  if (!NT_SUCCESS(Status))
+    {
+      ObDereferenceObject(AccessToken);
+      return(Status);
+    }
+
+  AccessToken->TokenInUse = 0;
+  AccessToken->TokenType  = TokenType;
+  AccessToken->ImpersonationLevel = Level;
+  AccessToken->AuthenticationId.LowPart = SYSTEM_LUID;
+  AccessToken->AuthenticationId.HighPart = 0;
+
+  AccessToken->TokenSource.SourceIdentifier.LowPart = Token->TokenSource.SourceIdentifier.LowPart;
+  AccessToken->TokenSource.SourceIdentifier.HighPart = Token->TokenSource.SourceIdentifier.HighPart;
+  memcpy(AccessToken->TokenSource.SourceName,
+        Token->TokenSource.SourceName,
+        sizeof(Token->TokenSource.SourceName));
+  AccessToken->ExpirationTime.QuadPart = Token->ExpirationTime.QuadPart;
+  AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
+  AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
+
+  uLength = sizeof(SID_AND_ATTRIBUTES) * AccessToken->UserAndGroupCount;
+  for (i = 0; i < Token->UserAndGroupCount; i++)
+    uLength += RtlLengthSid(Token->UserAndGroups[i].Sid);
+
+  AccessToken->UserAndGroups = 
+    (PSID_AND_ATTRIBUTES)ExAllocatePoolWithTag(NonPagedPool,
+                                              uLength,
+                                              TAG('T', 'O', 'K', 'u'));
+
+  EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
+
+  Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount,
+                                       Token->UserAndGroups,
+                                       uLength,
+                                       AccessToken->UserAndGroups,
+                                       EndMem,
+                                       &EndMem,
+                                       &uLength);
+  if (NT_SUCCESS(Status))
+    {
+      Status = SepFindPrimaryGroupAndDefaultOwner(
+       AccessToken,
+       Token->PrimaryGroup,
+       0);
+    }
+
+  if (NT_SUCCESS(Status))
+    {
+      AccessToken->PrivilegeCount = Token->PrivilegeCount;
+
+      uLength = AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
+      AccessToken->Privileges =
+       (PLUID_AND_ATTRIBUTES)ExAllocatePoolWithTag(NonPagedPool,
+                                                   uLength,
+                                                   TAG('T', 'O', 'K', 'p'));
+
+      for (i = 0; i < AccessToken->PrivilegeCount; i++)
+       {
+         RtlCopyLuid(&AccessToken->Privileges[i].Luid,
+           &Token->Privileges[i].Luid);
+         AccessToken->Privileges[i].Attributes = 
+           Token->Privileges[i].Attributes;
+       }
+
+      if ( Token->DefaultDacl )
+       {
+         AccessToken->DefaultDacl =
+           (PACL) ExAllocatePoolWithTag(NonPagedPool,
+                                        Token->DefaultDacl->AclSize,
+                                        TAG('T', 'O', 'K', 'd'));
+         memcpy(AccessToken->DefaultDacl,
+                Token->DefaultDacl,
+                Token->DefaultDacl->AclSize);
+       }
+      else
+       {
+         AccessToken->DefaultDacl = 0;
+       }
+    }
+
+  if ( NT_SUCCESS(Status) )
+    {
+      *NewAccessToken = AccessToken;
+      return(STATUS_SUCCESS);
+    }
+
+  ObDereferenceObject(AccessToken);
+  return(Status);
+}
+
+
+NTSTATUS
+SepInitializeNewProcess(struct _EPROCESS* NewProcess,
+                       struct _EPROCESS* ParentProcess)
+{
+  NTSTATUS Status;
+  PACCESS_TOKEN pNewToken;
+  PACCESS_TOKEN pParentToken;
+  
+  OBJECT_ATTRIBUTES ObjectAttributes;
+
+  pParentToken = (PACCESS_TOKEN) ParentProcess->Token;
+
+  InitializeObjectAttributes(&ObjectAttributes,
+                           NULL,
+                           0,
+                           NULL,
+                           NULL);
+
+  Status = SepDuplicateToken(pParentToken,
+                            &ObjectAttributes,
+                            TokenPrimary,
+                            pParentToken->ImpersonationLevel,
+                            pParentToken->ImpersonationLevel,
+                            KernelMode,
+                            &pNewToken);
+  if ( ! NT_SUCCESS(Status) )
+    return Status;
+
+  NewProcess->Token = pNewToken;
+  return(STATUS_SUCCESS);
 }
 
+
 NTSTATUS SeCopyClientToken(PACCESS_TOKEN Token,
                           SECURITY_IMPERSONATION_LEVEL Level,
                           KPROCESSOR_MODE PreviousMode,
@@ -89,7 +308,7 @@ NTSTATUS SeCopyClientToken(PACCESS_TOKEN Token,
                              0,
                              NULL,
                              NULL);
-   Status = SepDuplicationToken(Token,
+   Status = SepDuplicateToken(Token,
                                &ObjectAttributes,
                                0,
                                SecurityIdentification,
@@ -100,6 +319,9 @@ NTSTATUS SeCopyClientToken(PACCESS_TOKEN Token,
 }
 
 
+/*
+ * @implemented
+ */
 NTSTATUS STDCALL
 SeCreateClientSecurity(IN struct _ETHREAD *Thread,
                       IN PSECURITY_QUALITY_OF_SERVICE Qos,
@@ -189,6 +411,9 @@ SeCreateClientSecurity(IN struct _ETHREAD *Thread,
 }
 
 
+/*
+ * @implemented
+ */
 VOID STDCALL
 SeImpersonateClient(IN PSECURITY_CLIENT_CONTEXT ClientContext,
                    IN PETHREAD ServerThread OPTIONAL)
@@ -215,7 +440,23 @@ SeImpersonateClient(IN PSECURITY_CLIENT_CONTEXT ClientContext,
 }
 
 
-VOID
+VOID STDCALL
+SepDeleteToken(PVOID ObjectBody)
+{
+  PACCESS_TOKEN AccessToken = (PACCESS_TOKEN)ObjectBody;
+
+  if (AccessToken->UserAndGroups)
+    ExFreePool(AccessToken->UserAndGroups);
+
+  if (AccessToken->Privileges)
+    ExFreePool(AccessToken->Privileges);
+
+  if (AccessToken->DefaultDacl)
+    ExFreePool(AccessToken->DefaultDacl);
+}
+
+
+VOID INIT_FUNCTION
 SepInitializeTokenImplementation(VOID)
 {
   SepTokenObjectType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
@@ -231,7 +472,7 @@ SepInitializeTokenImplementation(VOID)
   SepTokenObjectType->Dump = NULL;
   SepTokenObjectType->Open = NULL;
   SepTokenObjectType->Close = NULL;
-  SepTokenObjectType->Delete = NULL;
+  SepTokenObjectType->Delete = SepDeleteToken;
   SepTokenObjectType->Parse = NULL;
   SepTokenObjectType->Security = NULL;
   SepTokenObjectType->QueryName = NULL;
@@ -241,41 +482,13 @@ SepInitializeTokenImplementation(VOID)
 
   RtlCreateUnicodeString(&SepTokenObjectType->TypeName,
                         L"Token");
+  ObpCreateTypeObject (SepTokenObjectType);
 }
 
 
-NTSTATUS
-RtlCopySidAndAttributesArray(ULONG Count,             // ebp + 8
-                            PSID_AND_ATTRIBUTES Src,   // ebp + C
-                            ULONG MaxLength,         // ebp + 10
-                            PSID_AND_ATTRIBUTES Dest, // ebp + 14
-                            PVOID e,    // ebp + 18
-                            PVOID* f,                 // ebp + 1C
-                            PULONG g)                 // ebp + 20
-{
-   ULONG Length; // ebp - 4
-   ULONG i;
-   
-   Length = MaxLength;
-   
-   for (i=0; i<Count; i++)
-     {
-       if (RtlLengthSid(Src[i].Sid) > Length)
-         {
-            return(STATUS_UNSUCCESSFUL);
-         }
-       Length = Length - RtlLengthSid(Src[i].Sid);
-       Dest[i].Sid = e;
-       Dest[i].Attributes = Src[i].Attributes;
-       RtlCopySid(RtlLengthSid(Src[i].Sid), e, Src[i].Sid);
-       e = e + RtlLengthSid(Src[i].Sid) + sizeof(ULONG);
-     }
-   *f = e;
-   *g = Length;
-   return(STATUS_SUCCESS);
-}
-
-
+/*
+ * @implemented
+ */
 NTSTATUS STDCALL
 NtQueryInformationToken(IN HANDLE TokenHandle,
                        IN TOKEN_INFORMATION_CLASS TokenInformationClass,
@@ -283,121 +496,256 @@ NtQueryInformationToken(IN HANDLE TokenHandle,
                        IN ULONG TokenInformationLength,
                        OUT PULONG ReturnLength)
 {
-   NTSTATUS Status;
-   PACCESS_TOKEN Token;
-   PVOID UnusedInfo;
-   PVOID EndMem;
-   PTOKEN_GROUPS PtrTokenGroups;
-   PTOKEN_DEFAULT_DACL PtrDefaultDacl;
-   PTOKEN_STATISTICS PtrTokenStatistics;
-   
-   Status = ObReferenceObjectByHandle(TokenHandle,
-                                     0,
-                                     SepTokenObjectType,
-                                     UserMode,
-                                     (PVOID*)&Token,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-   
-   switch (TokenInformationClass)
-     {
+  NTSTATUS Status;
+  PVOID UnusedInfo;
+  PVOID EndMem;
+  PACCESS_TOKEN Token;
+  ULONG Length;
+  PTOKEN_GROUPS PtrTokenGroups;
+  PTOKEN_DEFAULT_DACL PtrDefaultDacl;
+  PTOKEN_STATISTICS PtrTokenStatistics;
+
+  Status = ObReferenceObjectByHandle(TokenHandle,
+                                    (TokenInformationClass == TokenSource) ? TOKEN_QUERY_SOURCE : TOKEN_QUERY,
+                                    SepTokenObjectType,
+                                    UserMode,
+                                    (PVOID*)&Token,
+                                    NULL);
+  if (!NT_SUCCESS(Status))
+    {
+      return(Status);
+    }
+
+  switch (TokenInformationClass)
+    {
       case TokenUser:
-       Status = RtlCopySidAndAttributesArray(1,
-                                             Token->UserAndGroups,
-                                             TokenInformationLength,
-                                             TokenInformation,
-                                             TokenInformation + 8,
-                                             &UnusedInfo,
-                                             ReturnLength);
-       if (!NT_SUCCESS(Status))
+       DPRINT("NtQueryInformationToken(TokenUser)\n");
+       Length = RtlLengthSidAndAttributes(1, Token->UserAndGroups);
+       if (TokenInformationLength < Length)
          {
-            ObDereferenceObject(Token);
-            return(Status);
+           Status = MmCopyToCaller(ReturnLength, &Length, sizeof(ULONG));
+           if (NT_SUCCESS(Status))
+             Status = STATUS_BUFFER_TOO_SMALL;
+         }
+       else
+         {
+           Status = RtlCopySidAndAttributesArray(1,
+                                                 Token->UserAndGroups,
+                                                 TokenInformationLength,
+                                                 TokenInformation,
+                                                 (char*)TokenInformation + 8,
+                                                 &UnusedInfo,
+                                                 &Length);
+           if (NT_SUCCESS(Status))
+             {
+               Length = TokenInformationLength - Length;
+               Status = MmCopyToCaller(ReturnLength, &Length, sizeof(ULONG));
+             }
          }
        break;
        
-       
       case TokenGroups:
-       EndMem = TokenInformation + 
-         Token->UserAndGroupCount * sizeof(SID_AND_ATTRIBUTES);
-       PtrTokenGroups = (PTOKEN_GROUPS)TokenInformation;
-       PtrTokenGroups->GroupCount = Token->UserAndGroupCount - 1;
-       Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
-                                             &Token->UserAndGroups[1],
-                                             TokenInformationLength,
-                                             PtrTokenGroups->Groups,
-                                             EndMem,
-                                             &UnusedInfo,
-                                             ReturnLength);
-       if (!NT_SUCCESS(Status))
+       DPRINT("NtQueryInformationToken(TokenGroups)\n");
+       Length = RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]) + sizeof(ULONG);
+       if (TokenInformationLength < Length)
          {
-            ObDereferenceObject(Token);
-            return(Status);
+           Status = MmCopyToCaller(ReturnLength, &Length, sizeof(ULONG));
+           if (NT_SUCCESS(Status))
+             Status = STATUS_BUFFER_TOO_SMALL;
+         }
+       else
+         {
+           EndMem = (char*)TokenInformation + Token->UserAndGroupCount * sizeof(SID_AND_ATTRIBUTES);
+           PtrTokenGroups = (PTOKEN_GROUPS)TokenInformation;
+           PtrTokenGroups->GroupCount = Token->UserAndGroupCount - 1;
+           Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
+                                                 &Token->UserAndGroups[1],
+                                                 TokenInformationLength,
+                                                 PtrTokenGroups->Groups,
+                                                 EndMem,
+                                                 &UnusedInfo,
+                                                 &Length);
+           if (NT_SUCCESS(Status))
+             {
+               Length = TokenInformationLength - Length;
+               Status = MmCopyToCaller(ReturnLength, &Length, sizeof(ULONG));
+             }
          }
        break;
-       
+
       case TokenPrivileges:
+       DPRINT("NtQueryInformationToken(TokenPrivileges)\n");
+       Length = sizeof(ULONG) + Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
+       if (TokenInformationLength < Length)
+         {
+           Status = MmCopyToCaller(ReturnLength, &Length, sizeof(ULONG));
+           if (NT_SUCCESS(Status))
+             Status = STATUS_BUFFER_TOO_SMALL;
+         }
+       else
+         {
+           ULONG i;
+           TOKEN_PRIVILEGES* pPriv = (TOKEN_PRIVILEGES*)TokenInformation;
+
+           pPriv->PrivilegeCount = Token->PrivilegeCount;
+           for (i = 0; i < Token->PrivilegeCount; i++)
+             {
+               RtlCopyLuid(&pPriv->Privileges[i].Luid, &Token->Privileges[i].Luid);
+               pPriv->Privileges[i].Attributes = Token->Privileges[i].Attributes;
+             }
+           Status = STATUS_SUCCESS;
+         }
        break;
-       
+
       case TokenOwner:
-       ((PTOKEN_OWNER)TokenInformation)->Owner = 
-         (PSID)(((PTOKEN_OWNER)TokenInformation) + 1);
-       RtlCopySid(TokenInformationLength - sizeof(TOKEN_OWNER),
-                  ((PTOKEN_OWNER)TokenInformation)->Owner,
-                  Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
+       DPRINT("NtQueryInformationToken(TokenOwner)\n");
+       Length = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid) + sizeof(TOKEN_OWNER);
+       if (TokenInformationLength < Length)
+         {
+           Status = MmCopyToCaller(ReturnLength, &Length, sizeof(ULONG));
+           if (NT_SUCCESS(Status))
+             Status = STATUS_BUFFER_TOO_SMALL;
+         }
+       else
+         {
+           ((PTOKEN_OWNER)TokenInformation)->Owner = 
+             (PSID)(((PTOKEN_OWNER)TokenInformation) + 1);
+           RtlCopySid(TokenInformationLength - sizeof(TOKEN_OWNER),
+                      ((PTOKEN_OWNER)TokenInformation)->Owner,
+                      Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
+           Status = STATUS_SUCCESS;
+         }
        break;
-       
+
       case TokenPrimaryGroup:
-       ((PTOKEN_PRIMARY_GROUP)TokenInformation)->PrimaryGroup = 
-         (PSID)(((PTOKEN_PRIMARY_GROUP)TokenInformation) + 1);
-       RtlCopySid(TokenInformationLength - sizeof(TOKEN_OWNER),
-                  ((PTOKEN_PRIMARY_GROUP)TokenInformation)->PrimaryGroup,
-                  Token->PrimaryGroup);
+       DPRINT("NtQueryInformationToken(TokenPrimaryGroup),"
+              "Token->PrimaryGroup = 0x%08x\n", Token->PrimaryGroup);
+       Length = RtlLengthSid(Token->PrimaryGroup) + sizeof(TOKEN_PRIMARY_GROUP);
+       if (TokenInformationLength < Length)
+         {
+           Status = MmCopyToCaller(ReturnLength, &Length, sizeof(ULONG));
+           if (NT_SUCCESS(Status))
+             Status = STATUS_BUFFER_TOO_SMALL;
+         }
+       else
+         {
+           ((PTOKEN_PRIMARY_GROUP)TokenInformation)->PrimaryGroup = 
+             (PSID)(((PTOKEN_PRIMARY_GROUP)TokenInformation) + 1);
+           RtlCopySid(TokenInformationLength - sizeof(TOKEN_PRIMARY_GROUP),
+                      ((PTOKEN_PRIMARY_GROUP)TokenInformation)->PrimaryGroup,
+                      Token->PrimaryGroup);
+           Status = STATUS_SUCCESS;
+         }
        break;
-       
+
       case TokenDefaultDacl:
-       PtrDefaultDacl = (PTOKEN_DEFAULT_DACL)TokenInformation;
-       PtrDefaultDacl->DefaultDacl = (PACL)(PtrDefaultDacl + 1);
-       memmove(PtrDefaultDacl->DefaultDacl,
-               Token->DefaultDacl,
-               Token->DefaultDacl->AclSize);
+       DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n");
+       PtrDefaultDacl = (PTOKEN_DEFAULT_DACL) TokenInformation;
+       Length = (Token->DefaultDacl ? Token->DefaultDacl->AclSize : 0) + sizeof(TOKEN_DEFAULT_DACL);
+       if (TokenInformationLength < Length)
+         {
+           Status = MmCopyToCaller(ReturnLength, &Length, sizeof(ULONG));
+           if (NT_SUCCESS(Status))
+             Status = STATUS_BUFFER_TOO_SMALL;
+         }
+       else if (!Token->DefaultDacl)
+         {
+           PtrDefaultDacl->DefaultDacl = 0;
+           Status = MmCopyToCaller(ReturnLength, &Length, sizeof(ULONG));
+         }
+       else
+         {
+           PtrDefaultDacl->DefaultDacl = (PACL) (PtrDefaultDacl + 1);
+           memmove(PtrDefaultDacl->DefaultDacl,
+                   Token->DefaultDacl,
+                   Token->DefaultDacl->AclSize);
+           Status = MmCopyToCaller(ReturnLength, &Length, sizeof(ULONG));
+         }
        break;
-       
+
       case TokenSource:
-       memcpy(TokenInformation, &Token->TokenSource, sizeof(TOKEN_SOURCE));
+       DPRINT("NtQueryInformationToken(TokenSource)\n");
+       if (TokenInformationLength < sizeof(TOKEN_SOURCE))
+         {
+           Length = sizeof(TOKEN_SOURCE);
+           Status = MmCopyToCaller(ReturnLength, &Length, sizeof(ULONG));
+           if (NT_SUCCESS(Status))
+             Status = STATUS_BUFFER_TOO_SMALL;
+         }
+       else
+         {
+           Status = MmCopyToCaller(TokenInformation, &Token->TokenSource, sizeof(TOKEN_SOURCE));
+         }
        break;
-       
+
       case TokenType:
-       *((PTOKEN_TYPE)TokenInformation) = Token->TokenType;
+       DPRINT("NtQueryInformationToken(TokenType)\n");
+       if (TokenInformationLength < sizeof(TOKEN_TYPE))
+         {
+           Length = sizeof(TOKEN_TYPE);
+           Status = MmCopyToCaller(ReturnLength, &Length, sizeof(ULONG));
+           if (NT_SUCCESS(Status))
+             Status = STATUS_BUFFER_TOO_SMALL;
+         }
+       else
+         {
+           Status = MmCopyToCaller(TokenInformation, &Token->TokenType, sizeof(TOKEN_TYPE));
+         }
        break;
-       
+
       case TokenImpersonationLevel:
-       *((PSECURITY_IMPERSONATION_LEVEL)TokenInformation) =
-         Token->ImpersonationLevel;
+       DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n");
+       if (TokenInformationLength < sizeof(SECURITY_IMPERSONATION_LEVEL))
+         {
+           Length = sizeof(SECURITY_IMPERSONATION_LEVEL);
+           Status = MmCopyToCaller(ReturnLength, &Length, sizeof(ULONG));
+           if (NT_SUCCESS(Status))
+             Status = STATUS_BUFFER_TOO_SMALL;
+         }
+       else
+         {
+           Status = MmCopyToCaller(TokenInformation, &Token->ImpersonationLevel, sizeof(SECURITY_IMPERSONATION_LEVEL));
+         }
        break;
-       
+
       case TokenStatistics:
-       PtrTokenStatistics = (PTOKEN_STATISTICS)TokenInformation;
-       PtrTokenStatistics->TokenId = Token->TokenId;
-       PtrTokenStatistics->AuthenticationId = Token->AuthenticationId;
-       PtrTokenStatistics->ExpirationTime = Token->ExpirationTime;
-       PtrTokenStatistics->TokenType = Token->TokenType;
-       PtrTokenStatistics->ImpersonationLevel = Token->ImpersonationLevel;
-       PtrTokenStatistics->DynamicCharged = Token->DynamicCharged;
-       PtrTokenStatistics->DynamicAvailable = Token->DynamicAvailable;
-       PtrTokenStatistics->GroupCount = Token->UserAndGroupCount - 1;
-       PtrTokenStatistics->PrivilegeCount = Token->PrivilegeCount;
-       PtrTokenStatistics->ModifiedId = Token->ModifiedId;
+       DPRINT("NtQueryInformationToken(TokenStatistics)\n");
+       if (TokenInformationLength < sizeof(TOKEN_STATISTICS))
+         {
+           Length = sizeof(TOKEN_STATISTICS);
+           Status = MmCopyToCaller(ReturnLength, &Length, sizeof(ULONG));
+           if (NT_SUCCESS(Status))
+             Status = STATUS_BUFFER_TOO_SMALL;
+         }
+       else
+         {
+           PtrTokenStatistics = (PTOKEN_STATISTICS)TokenInformation;
+           PtrTokenStatistics->TokenId = Token->TokenId;
+           PtrTokenStatistics->AuthenticationId = Token->AuthenticationId;
+           PtrTokenStatistics->ExpirationTime = Token->ExpirationTime;
+           PtrTokenStatistics->TokenType = Token->TokenType;
+           PtrTokenStatistics->ImpersonationLevel = Token->ImpersonationLevel;
+           PtrTokenStatistics->DynamicCharged = Token->DynamicCharged;
+           PtrTokenStatistics->DynamicAvailable = Token->DynamicAvailable;
+           PtrTokenStatistics->GroupCount = Token->UserAndGroupCount - 1;
+           PtrTokenStatistics->PrivilegeCount = Token->PrivilegeCount;
+           PtrTokenStatistics->ModifiedId = Token->ModifiedId;
+
+           Status = STATUS_SUCCESS;
+         }
        break;
-     }
-   
-   ObDereferenceObject(Token);
-   return(STATUS_SUCCESS);
+    }
+
+  ObDereferenceObject(Token);
+
+  return(Status);
 }
 
+/*
+ * NtSetTokenInformation: Partly implemented.
+ * Unimplemented:
+ *  TokenOrigin, TokenDefaultDacl, TokenSessionId
+ */
 
 NTSTATUS STDCALL
 NtSetInformationToken(IN HANDLE TokenHandle,
@@ -405,10 +753,72 @@ NtSetInformationToken(IN HANDLE TokenHandle,
                      OUT PVOID TokenInformation,
                      IN ULONG TokenInformationLength)
 {
-  UNIMPLEMENTED;
+  NTSTATUS Status;
+  PACCESS_TOKEN Token;
+  TOKEN_OWNER TokenOwnerSet = { 0 };
+  TOKEN_PRIMARY_GROUP TokenPrimaryGroupSet = { 0 };
+  DWORD NeededAccess = 0;
+
+  switch (TokenInformationClass) 
+    {
+    case TokenOwner:
+    case TokenPrimaryGroup:
+      NeededAccess = TOKEN_ADJUST_DEFAULT;
+      break;
+
+    default:
+      return STATUS_NOT_IMPLEMENTED;
+    }
+
+  Status = ObReferenceObjectByHandle(TokenHandle,
+                                    NeededAccess,
+                                    SepTokenObjectType,
+                                    UserMode,
+                                    (PVOID*)&Token,
+                                    NULL);
+  if (!NT_SUCCESS(Status))
+    {
+      return(Status);
+    }
+
+  switch (TokenInformationClass)
+    {
+    case TokenOwner:
+      MmCopyFromCaller( &TokenOwnerSet, TokenInformation,
+                       min(sizeof(TokenOwnerSet),TokenInformationLength) );
+      RtlCopySid(TokenInformationLength - sizeof(TOKEN_OWNER),
+                Token->UserAndGroups[Token->DefaultOwnerIndex].Sid,
+                TokenOwnerSet.Owner);
+      Status = STATUS_SUCCESS;
+      DPRINT("NtSetInformationToken(TokenOwner)\n");
+      break;
+      
+    case TokenPrimaryGroup:
+      MmCopyFromCaller( &TokenPrimaryGroupSet, TokenInformation, 
+                       min(sizeof(TokenPrimaryGroupSet),
+                           TokenInformationLength) );
+      RtlCopySid(TokenInformationLength - sizeof(TOKEN_PRIMARY_GROUP),
+                Token->PrimaryGroup,
+                TokenPrimaryGroupSet.PrimaryGroup);
+      Status = STATUS_SUCCESS;
+      DPRINT("NtSetInformationToken(TokenPrimaryGroup),"
+            "Token->PrimaryGroup = 0x%08x\n", Token->PrimaryGroup);
+      break;
+
+    default:
+      Status = STATUS_NOT_IMPLEMENTED;
+      break;
+    }
+
+  ObDereferenceObject(Token);
+
+  return(Status);
 }
 
 
+/*
+ * @implemented
+ */
 NTSTATUS STDCALL
 NtDuplicateToken(IN HANDLE ExistingTokenHandle,
                 IN ACCESS_MASK DesiredAccess,
@@ -417,32 +827,61 @@ NtDuplicateToken(IN HANDLE ExistingTokenHandle,
                 IN TOKEN_TYPE TokenType,
                 OUT PHANDLE NewTokenHandle)
 {
-#if 0
-   PACCESS_TOKEN Token;
-   PACCESS_TOKEN NewToken;
-   NTSTATUS Status;
-   ULONG ExistingImpersonationLevel;
-   
-   Status = ObReferenceObjectByHandle(ExistingTokenHandle,
-                                     ?,
-                                     SepTokenObjectType,
-                                     UserMode,
-                                     (PVOID*)&Token,
-                                     NULL);
-   
-   ExistingImpersonationLevel = Token->ImpersonationLevel;
-   SepDuplicateToken(Token,
-                    ObjectAttributes,
-                    ImpersonationLevel,
-                    TokenType,
-                    ExistingImpersonationLevel,
-                    KeGetPreviousMode(),
-                    &NewToken);
-#else
-   UNIMPLEMENTED;
-#endif
+  KPROCESSOR_MODE PreviousMode;
+  PACCESS_TOKEN Token;
+  PACCESS_TOKEN NewToken;
+  NTSTATUS Status;
+  ULONG ExistingImpersonationLevel;
+
+  PreviousMode = KeGetPreviousMode();
+  Status = ObReferenceObjectByHandle(ExistingTokenHandle,
+                                    TOKEN_DUPLICATE,
+                                    SepTokenObjectType,
+                                    PreviousMode,
+                                    (PVOID*)&Token,
+                                    NULL);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("Failed to reference token (Status %lx)\n", Status);
+      return Status;
+    }
+
+  ExistingImpersonationLevel = Token->ImpersonationLevel;
+  Status = SepDuplicateToken(Token,
+                            ObjectAttributes,
+                            TokenType,
+                            ImpersonationLevel,
+                            ExistingImpersonationLevel,
+                            PreviousMode,
+                            &NewToken);
+
+  ObDereferenceObject(Token);
+
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("Failed to duplicate token (Status %lx)\n", Status);
+      return Status;
+    }
+
+  Status = ObInsertObject((PVOID)NewToken,
+                         NULL,
+                         DesiredAccess,
+                         0,
+                         NULL,
+                         NewTokenHandle);
+
+  ObDereferenceObject(NewToken);
+
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("Failed to create token handle (Status %lx)\n");
+      return Status;
+    }
+
+  return STATUS_SUCCESS;
 }
 
+
 VOID SepAdjustGroups(PACCESS_TOKEN Token,
                     ULONG a,
                     BOOLEAN ResetToDefault,
@@ -493,110 +932,422 @@ NtAdjustGroupsToken(IN HANDLE TokenHandle,
                   &c);
 #else
    UNIMPLEMENTED;
+   return(STATUS_NOT_IMPLEMENTED);
 #endif
 }
 
 
 #if 0
-NTSTATUS SepAdjustPrivileges(PACCESS_TOKEN Token,           // 0x8
-                            ULONG a,                       // 0xC
-                            KPROCESSOR_MODE PreviousMode,  // 0x10
-                            ULONG PrivilegeCount,          // 0x14
-                            PLUID_AND_ATTRIBUTES Privileges, // 0x18
-                            PTOKEN_PRIVILEGES* PreviousState, // 0x1C
-                            PULONG b, // 0x20
-                            PULONG c, // 0x24
-                            PULONG d) // 0x28
+NTSTATUS
+SepAdjustPrivileges(PACCESS_TOKEN Token,
+                   ULONG a,
+                   KPROCESSOR_MODE PreviousMode,
+                   ULONG PrivilegeCount,
+                   PLUID_AND_ATTRIBUTES Privileges,
+                   PTOKEN_PRIVILEGES* PreviousState,
+                   PULONG b,
+                   PULONG c,
+                   PULONG d)
 {
-   ULONG i;
-   
-   *c = 0;
-   if (Token->PrivilegeCount > 0)
-     {
-       for (i=0; i<Token->PrivilegeCount; i++)
-         {
-            if (PreviousMode != 0)
-              {
-                 if (!(Token->Privileges[i]->Attributes & 
-                       SE_PRIVILEGE_ENABLED))
+  ULONG i;
+
+  *c = 0;
+
+  if (Token->PrivilegeCount > 0)
+    {
+      for (i = 0; i < Token->PrivilegeCount; i++)
+       {
+         if (PreviousMode != KernelMode)
+           {
+             if (Token->Privileges[i]->Attributes & SE_PRIVILEGE_ENABLED == 0)
+               {
+                 if (a != 0)
                    {
-                      if (a != 0)
-                        {
-                           if (PreviousState != NULL)
-                             {
-                                memcpy(&PreviousState[i],
-                                       &Token->Privileges[i],
-                                       sizeof(LUID_AND_ATTRIBUTES));
-                             }
-                           Token->Privileges[i].Attributes = 
-                             Token->Privileges[i].Attributes & 
-                             (~SE_PRIVILEGE_ENABLED);
-                        }
+                     if (PreviousState != NULL)
+                       {
+                         memcpy(&PreviousState[i],
+                                &Token->Privileges[i],
+                                sizeof(LUID_AND_ATTRIBUTES));
+                       }
+                     Token->Privileges[i].Attributes &= (~SE_PRIVILEGE_ENABLED);
                    }
-              }
-         }
-     }
-   if (PreviousMode != 0)
-     {
-       Token->TokenFlags = Token->TokenFlags & (~1);
-     }
-   else
-     {
-       if (PrivilegeCount <= ?)
-         {
-            
-         }
+               }
+           }
+       }
+    }
+
+  if (PreviousMode != KernelMode)
+    {
+      Token->TokenFlags = Token->TokenFlags & (~1);
+    }
+  else
+    {
+      if (PrivilegeCount <= ?)
+       {
+       }
      }
    if (
 }
 #endif
 
 
+/*
+ * @implemented
+ */
 NTSTATUS STDCALL
-NtAdjustPrivilegesToken(IN HANDLE TokenHandle,
-                       IN BOOLEAN DisableAllPrivileges,
-                       IN PTOKEN_PRIVILEGES NewState,
-                       IN ULONG BufferLength,
-                       OUT PTOKEN_PRIVILEGES PreviousState,
-                       OUT PULONG ReturnLength)
+NtAdjustPrivilegesToken (IN HANDLE TokenHandle,
+                        IN BOOLEAN DisableAllPrivileges,
+                        IN PTOKEN_PRIVILEGES NewState,
+                        IN ULONG BufferLength,
+                        OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL,
+                        OUT PULONG ReturnLength OPTIONAL)
 {
+//  PLUID_AND_ATTRIBUTES Privileges;
+  KPROCESSOR_MODE PreviousMode;
+//  ULONG PrivilegeCount;
+  PACCESS_TOKEN Token;
+//  ULONG Length;
+  ULONG i;
+  ULONG j;
+  ULONG k;
+  ULONG Count;
 #if 0
-   ULONG PrivilegeCount;
-   ULONG Length;
-   PSID_AND_ATTRIBUTES Privileges;
    ULONG a;
    ULONG b;
    ULONG c;
-   
-   PrivilegeCount = NewState->PrivilegeCount;
-   
-   SeCaptureLuidAndAttributesArray(NewState->Privileges,
-                                  &PrivilegeCount,
-                                  KeGetPreviousMode(),
-                                  NULL,
-                                  0,
-                                  NonPagedPool,
-                                  1,
-                                  &Privileges.
-                                  &Length);
+#endif
+  NTSTATUS Status;
+
+  DPRINT ("NtAdjustPrivilegesToken() called\n");
+
+//  PrivilegeCount = NewState->PrivilegeCount;
+  PreviousMode = KeGetPreviousMode ();
+//  SeCaptureLuidAndAttributesArray(NewState->Privileges,
+//                               PrivilegeCount,
+//                               PreviousMode,
+//                               NULL,
+//                               0,
+//                               NonPagedPool,
+//                               1,
+//                               &Privileges,
+//                               &Length);
+
+  Status = ObReferenceObjectByHandle (TokenHandle,
+                                     TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
+                                     SepTokenObjectType,
+                                     PreviousMode,
+                                     (PVOID*)&Token,
+                                     NULL);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1 ("Failed to reference token (Status %lx)\n", Status);
+//      SeReleaseLuidAndAttributesArray(Privileges,
+//                                   PreviousMode,
+//                                   0);
+      return Status;
+    }
+
+
+#if 0
    SepAdjustPrivileges(Token,
                       0,
-                      KeGetPreviousMode(),
+                      PreviousMode,
                       PrivilegeCount,
                       Privileges,
                       PreviousState,
                       &a,
                       &b,
                       &c);
-#else
-   UNIMPLEMENTED;
 #endif
+
+  k = 0;
+  if (DisableAllPrivileges == TRUE)
+    {
+      for (i = 0; i < Token->PrivilegeCount; i++)
+       {
+         if (Token->Privileges[i].Attributes != 0)
+           {
+             DPRINT ("Attributes differ\n");
+
+             /* Save current privilege */
+             if (PreviousState != NULL && k < PreviousState->PrivilegeCount)
+               {
+                 PreviousState->Privileges[k].Luid = Token->Privileges[i].Luid;
+                 PreviousState->Privileges[k].Attributes = Token->Privileges[i].Attributes;
+                 k++;
+               }
+
+             /* Update current privlege */
+             Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
+           }
+       }
+      Status = STATUS_SUCCESS;
+    }
+  else
+    {
+      Count = 0;
+      for (i = 0; i < Token->PrivilegeCount; i++)
+       {
+         for (j = 0; j < NewState->PrivilegeCount; j++)
+           {
+             if (Token->Privileges[i].Luid.LowPart == NewState->Privileges[j].Luid.LowPart &&
+                 Token->Privileges[i].Luid.HighPart == NewState->Privileges[j].Luid.HighPart)
+               {
+                 DPRINT ("Found privilege\n");
+
+                 if ((Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) !=
+                     (NewState->Privileges[j].Attributes & SE_PRIVILEGE_ENABLED))
+                   {
+                     DPRINT ("Attributes differ\n");
+                     DPRINT ("Current attributes %lx  desired attributes %lx\n",
+                             Token->Privileges[i].Attributes,
+                             NewState->Privileges[j].Attributes);
+
+                     /* Save current privilege */
+                     if (PreviousState != NULL && k < PreviousState->PrivilegeCount)
+                       {
+                         PreviousState->Privileges[k].Luid = Token->Privileges[i].Luid;
+                         PreviousState->Privileges[k].Attributes = Token->Privileges[i].Attributes;
+                         k++;
+                       }
+
+                     /* Update current privlege */
+                     Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
+                     Token->Privileges[i].Attributes |= 
+                       (NewState->Privileges[j].Attributes & SE_PRIVILEGE_ENABLED);
+                     DPRINT ("New attributes %lx\n",
+                             Token->Privileges[i].Attributes);
+                   }
+                  Count++;
+               }
+           }
+       }
+      Status = Count < NewState->PrivilegeCount ? STATUS_NOT_ALL_ASSIGNED : STATUS_SUCCESS;
+    }
+
+  if (ReturnLength != NULL)
+    {
+      *ReturnLength = sizeof(TOKEN_PRIVILEGES) +
+                     (sizeof(LUID_AND_ATTRIBUTES) * (k - 1));
+    }
+
+  ObDereferenceObject (Token);
+
+//  SeReleaseLuidAndAttributesArray(Privileges,
+//                               PreviousMode,
+//                               0);
+
+  DPRINT ("NtAdjustPrivilegesToken() done\n");
+
+  return Status;
 }
 
+
+NTSTATUS
+SepCreateSystemProcessToken(struct _EPROCESS* Process)
+{
+  NTSTATUS Status;
+  ULONG uSize;
+  ULONG i;
+
+  ULONG uLocalSystemLength = RtlLengthSid(SeLocalSystemSid);
+  ULONG uWorldLength       = RtlLengthSid(SeWorldSid);
+  ULONG uAuthUserLength    = RtlLengthSid(SeAuthenticatedUserSid);
+  ULONG uAdminsLength      = RtlLengthSid(SeAliasAdminsSid);
+
+  PACCESS_TOKEN AccessToken;
+
+  PVOID SidArea;
+
+ /*
+  * Initialize the token
+  */
+  Status = ObCreateObject(KernelMode,
+                         SepTokenObjectType,
+                         NULL,
+                         KernelMode,
+                         NULL,
+                         sizeof(ACCESS_TOKEN),
+                         0,
+                         0,
+                         (PVOID*)&AccessToken);
+  if (!NT_SUCCESS(Status))
+    {
+      return(Status);
+    }
+
+  Status = NtAllocateLocallyUniqueId(&AccessToken->TokenId);
+  if (!NT_SUCCESS(Status))
+    {
+      ObDereferenceObject(AccessToken);
+      return(Status);
+    }
+
+  Status = NtAllocateLocallyUniqueId(&AccessToken->ModifiedId);
+  if (!NT_SUCCESS(Status))
+    {
+      ObDereferenceObject(AccessToken);
+      return(Status);
+    }
+
+  AccessToken->AuthenticationId.LowPart = SYSTEM_LUID;
+  AccessToken->AuthenticationId.HighPart = 0;
+
+  AccessToken->TokenType = TokenPrimary;
+  AccessToken->ImpersonationLevel = SecurityDelegation;
+  AccessToken->TokenSource.SourceIdentifier.LowPart = 0;
+  AccessToken->TokenSource.SourceIdentifier.HighPart = 0;
+  memcpy(AccessToken->TokenSource.SourceName, "SeMgr\0\0\0", 8);
+  AccessToken->ExpirationTime.QuadPart = -1;
+  AccessToken->UserAndGroupCount = 4;
+
+  uSize = sizeof(SID_AND_ATTRIBUTES) * AccessToken->UserAndGroupCount;
+  uSize += uLocalSystemLength;
+  uSize += uWorldLength;
+  uSize += uAuthUserLength;
+  uSize += uAdminsLength;
+
+  AccessToken->UserAndGroups = 
+    (PSID_AND_ATTRIBUTES)ExAllocatePoolWithTag(NonPagedPool,
+                                              uSize,
+                                              TAG('T', 'O', 'K', 'u'));
+  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(NonPagedPool,
+                                                   uSize,
+                                                   TAG('T', 'O', 'K', 'p'));
+
+  i = 0;
+  AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+  AccessToken->Privileges[i++].Luid = SeTcbPrivilege;
+
+  AccessToken->Privileges[i].Attributes = 0;
+  AccessToken->Privileges[i++].Luid = SeCreateTokenPrivilege;
+
+  AccessToken->Privileges[i].Attributes = 0;
+  AccessToken->Privileges[i++].Luid = SeTakeOwnershipPrivilege;
+  
+  AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+  AccessToken->Privileges[i++].Luid = SeCreatePagefilePrivilege;
+  
+  AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+  AccessToken->Privileges[i++].Luid = SeLockMemoryPrivilege;
+  
+  AccessToken->Privileges[i].Attributes = 0;
+  AccessToken->Privileges[i++].Luid = SeAssignPrimaryTokenPrivilege;
+  
+  AccessToken->Privileges[i].Attributes = 0;
+  AccessToken->Privileges[i++].Luid = SeIncreaseQuotaPrivilege;
+  
+  AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+  AccessToken->Privileges[i++].Luid = SeIncreaseBasePriorityPrivilege;
+  
+  AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+  AccessToken->Privileges[i++].Luid = SeCreatePermanentPrivilege;
+  
+  AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+  AccessToken->Privileges[i++].Luid = SeDebugPrivilege;
+  
+  AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+  AccessToken->Privileges[i++].Luid = SeAuditPrivilege;
+  
+  AccessToken->Privileges[i].Attributes = 0;
+  AccessToken->Privileges[i++].Luid = SeSecurityPrivilege;
+  
+  AccessToken->Privileges[i].Attributes = 0;
+  AccessToken->Privileges[i++].Luid = SeSystemEnvironmentPrivilege;
+  
+  AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+  AccessToken->Privileges[i++].Luid = SeChangeNotifyPrivilege;
+  
+  AccessToken->Privileges[i].Attributes = 0;
+  AccessToken->Privileges[i++].Luid = SeBackupPrivilege;
+  
+  AccessToken->Privileges[i].Attributes = 0;
+  AccessToken->Privileges[i++].Luid = SeRestorePrivilege;
+  
+  AccessToken->Privileges[i].Attributes = 0;
+  AccessToken->Privileges[i++].Luid = SeShutdownPrivilege;
+  
+  AccessToken->Privileges[i].Attributes = 0;
+  AccessToken->Privileges[i++].Luid = SeLoadDriverPrivilege;
+  
+  AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
+  AccessToken->Privileges[i++].Luid = SeProfileSingleProcessPrivilege;
+  
+  AccessToken->Privileges[i].Attributes = 0;
+  AccessToken->Privileges[i++].Luid = SeSystemtimePrivilege;
+#if 0
+  AccessToken->Privileges[i].Attributes = 0;
+  AccessToken->Privileges[i++].Luid = SeUndockPrivilege;
+
+  AccessToken->Privileges[i].Attributes = 0;
+  AccessToken->Privileges[i++].Luid = SeManageVolumePrivilege;
+#endif
+
+  assert( i == 20 );
+
+  uSize = sizeof(ACL);
+  uSize += sizeof(ACE) + uLocalSystemLength;
+  uSize += sizeof(ACE) + uAdminsLength;
+  uSize = (uSize & (~3)) + 8;
+  AccessToken->DefaultDacl =
+    (PACL) ExAllocatePoolWithTag(NonPagedPool,
+                                uSize,
+                                TAG('T', 'O', 'K', 'd'));
+  Status = RtlCreateAcl(AccessToken->DefaultDacl, uSize, ACL_REVISION);
+  if ( NT_SUCCESS(Status) )
+    {
+      Status = RtlAddAccessAllowedAce(AccessToken->DefaultDacl, ACL_REVISION, GENERIC_ALL, SeLocalSystemSid);
+    }
+
+  if ( NT_SUCCESS(Status) )
+    {
+      Status = RtlAddAccessAllowedAce(AccessToken->DefaultDacl, ACL_REVISION, GENERIC_READ|GENERIC_EXECUTE|READ_CONTROL, SeAliasAdminsSid);
+    }
+
+  if ( ! NT_SUCCESS(Status) )
+    {
+      ObDereferenceObject(AccessToken);
+      return Status;
+    }
+
+  Process->Token = AccessToken;
+  return(STATUS_SUCCESS);
+}
+
+
 NTSTATUS STDCALL
-NtCreateToken(OUT PHANDLE TokenHandle,
+NtCreateToken(OUT PHANDLE UnsafeTokenHandle,
              IN ACCESS_MASK DesiredAccess,
-             IN POBJECT_ATTRIBUTES ObjectAttributes,
+             IN POBJECT_ATTRIBUTES UnsafeObjectAttributes,
              IN TOKEN_TYPE TokenType,
              IN PLUID AuthenticationId,
              IN PLARGE_INTEGER ExpirationTime,
@@ -608,13 +1359,41 @@ NtCreateToken(OUT PHANDLE TokenHandle,
              IN PTOKEN_DEFAULT_DACL TokenDefaultDacl,
              IN PTOKEN_SOURCE TokenSource)
 {
+  HANDLE TokenHandle;
   PACCESS_TOKEN AccessToken;
   NTSTATUS Status;
+  OBJECT_ATTRIBUTES SafeObjectAttributes;
+  POBJECT_ATTRIBUTES ObjectAttributes;
+  LUID TokenId;
+  LUID ModifiedId;
+  PVOID EndMem;
+  ULONG uLength;
+  ULONG i;
 
-  Status = ObCreateObject(TokenHandle,
-                         DesiredAccess,
-                         ObjectAttributes,
+  Status = MmCopyFromCaller(&SafeObjectAttributes,
+                           UnsafeObjectAttributes,
+                           sizeof(OBJECT_ATTRIBUTES));
+  if (!NT_SUCCESS(Status))
+    return(Status);
+
+  ObjectAttributes = &SafeObjectAttributes;
+
+  Status = ZwAllocateLocallyUniqueId(&TokenId);
+  if (!NT_SUCCESS(Status))
+    return(Status);
+
+  Status = ZwAllocateLocallyUniqueId(&ModifiedId);
+  if (!NT_SUCCESS(Status))
+    return(Status);
+
+  Status = ObCreateObject(ExGetPreviousMode(),
                          SepTokenObjectType,
+                         ObjectAttributes,
+                         ExGetPreviousMode(),
+                         NULL,
+                         sizeof(ACCESS_TOKEN),
+                         0,
+                         0,
                          (PVOID*)&AccessToken);
   if (!NT_SUCCESS(Status))
     {
@@ -622,29 +1401,163 @@ NtCreateToken(OUT PHANDLE TokenHandle,
       return(Status);
     }
 
-#if 0
-   AccessToken->TokenType = TokenType;
-   RtlCopyLuid(&AccessToken->AuthenticationId, AuthenticationId);
-   AccessToken->ExpirationTime = *ExpirationTime;
-   AccessToken->
-#endif
-//     UNIMPLEMENTED;
+  Status = ObInsertObject ((PVOID)AccessToken,
+                          NULL,
+                          DesiredAccess,
+                          0,
+                          NULL,
+                          &TokenHandle);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("ObInsertObject() failed (Status %lx)\n");
+      ObDereferenceObject (AccessToken);
+      return Status;
+    }
+
+  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->UserAndGroups     = 0;
+  AccessToken->Privileges        = 0;
+
+  AccessToken->TokenType = TokenType;
+  AccessToken->ImpersonationLevel = 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(NonPagedPool,
+                                              uLength,
+                                              TAG('T', 'O', 'K', 'u'));
+
+  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(NonPagedPool,
+                                                   uLength,
+                                                   TAG('T', 'O', 'K', 'p'));
+
+      for (i = 0; i < TokenPrivileges->PrivilegeCount; i++)
+       {
+         Status = MmCopyFromCaller(&AccessToken->Privileges[i],
+                                   &TokenPrivileges->Privileges[i],
+                                   sizeof(LUID_AND_ATTRIBUTES));
+         if (!NT_SUCCESS(Status))
+           break;
+       }
+    }
+
+  if (NT_SUCCESS(Status))
+    {
+      AccessToken->DefaultDacl =
+       (PACL) ExAllocatePoolWithTag(NonPagedPool,
+                                    TokenDefaultDacl->DefaultDacl->AclSize,
+                                    TAG('T', 'O', 'K', 'd'));
+      memcpy(AccessToken->DefaultDacl,
+            TokenDefaultDacl->DefaultDacl,
+            TokenDefaultDacl->DefaultDacl->AclSize);
+    }
+
+  ObDereferenceObject(AccessToken);
+
+  if (NT_SUCCESS(Status))
+    {
+      Status = MmCopyToCaller(UnsafeTokenHandle,
+                             &TokenHandle,
+                             sizeof(HANDLE));
+    }
+
+  if (!NT_SUCCESS(Status))
+    {
+      ZwClose(TokenHandle);
+      return(Status);
+    }
 
   return(STATUS_SUCCESS);
 }
 
 
+/*
+ * @implemented
+ */
+NTSTATUS STDCALL
+SeQueryAuthenticationIdToken(IN PACCESS_TOKEN Token,
+                            OUT PLUID LogonId)
+{
+  LogonId->LowPart = Token->AuthenticationId.LowPart;
+  LogonId->HighPart = Token->AuthenticationId.HighPart;
+
+  return STATUS_SUCCESS;
+}
+
+
+/*
+ * @implemented
+ */
 SECURITY_IMPERSONATION_LEVEL STDCALL
 SeTokenImpersonationLevel(IN PACCESS_TOKEN Token)
 {
-  return(Token->ImpersonationLevel);
+  return Token->ImpersonationLevel;
 }
 
 
+/*
+ * @implemented
+ */
 TOKEN_TYPE STDCALL
 SeTokenType(IN PACCESS_TOKEN Token)
 {
-  return(Token->TokenType);
+  return Token->TokenType;
 }
 
+
+
 /* EOF */