implemented some stubs needed by ClamWin
[reactos.git] / reactos / lib / advapi32 / token / token.c
index 97a8e19..fba94fb 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: token.c,v 1.11 2004/07/06 22:07:25 gvg Exp $
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
  * FILE:            lib/advapi32/token/token.c
@@ -9,9 +8,11 @@
  *                  Created 01/11/98
  */
 
-#define NTOS_MODE_USER
-#include <ntos.h>
-#include <windows.h>
+#include <advapi32.h>
+
+#define NDEBUG
+#include <wine/debug.h>
+#include <debug.h>
 
 /*
  * @implemented
@@ -143,6 +144,7 @@ AccessCheck (PSECURITY_DESCRIPTOR pSecurityDescriptor,
             LPBOOL AccessStatus)
 {
   NTSTATUS Status;
+  NTSTATUS AccessStat;
 
   Status = NtAccessCheck (pSecurityDescriptor,
                          ClientToken,
@@ -150,14 +152,23 @@ AccessCheck (PSECURITY_DESCRIPTOR pSecurityDescriptor,
                          GenericMapping,
                          PrivilegeSet,
                          (PULONG)PrivilegeSetLength,
-                         (PULONG)GrantedAccess,
-                         (PBOOLEAN)AccessStatus);
+                         (PACCESS_MASK)GrantedAccess,
+                         &AccessStat);
   if (!NT_SUCCESS (Status))
     {
       SetLastError (RtlNtStatusToDosError (Status));
       return FALSE;
     }
 
+  if (!NT_SUCCESS (AccessStat))
+    {
+      SetLastError (RtlNtStatusToDosError (Status));
+      *AccessStatus = FALSE;
+      return TRUE;
+    }
+
+  *AccessStatus = TRUE;
+
   return TRUE;
 }
 
@@ -214,19 +225,17 @@ OpenThreadToken (HANDLE ThreadHandle,
  * @implemented
  */
 BOOL STDCALL
-SetThreadToken (PHANDLE ThreadHandle,
-                HANDLE TokenHandle)
+SetThreadToken (IN PHANDLE ThreadHandle  OPTIONAL,
+                IN HANDLE TokenHandle)
 {
   NTSTATUS Status;
   HANDLE hThread;
 
-  hThread = NtCurrentThread();
-  if (ThreadHandle != NULL)
-    hThread = ThreadHandle;
+  hThread = ((ThreadHandle != NULL) ? *ThreadHandle : NtCurrentThread());
 
   Status = NtSetInformationThread (hThread,
                                   ThreadImpersonationToken,
-                                  TokenHandle,
+                                  &TokenHandle,
                                   sizeof(HANDLE));
   if (!NT_SUCCESS(Status))
     {
@@ -242,34 +251,47 @@ SetThreadToken (PHANDLE ThreadHandle,
  * @implemented
  */
 BOOL STDCALL
-DuplicateTokenEx (HANDLE ExistingTokenHandle,
-                  DWORD  dwDesiredAccess,
-                  LPSECURITY_ATTRIBUTES lpTokenAttributes,
-                  SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
-                  TOKEN_TYPE TokenType,
-                  PHANDLE DuplicateTokenHandle)
+DuplicateTokenEx (IN HANDLE ExistingTokenHandle,
+                  IN DWORD dwDesiredAccess,
+                  IN LPSECURITY_ATTRIBUTES lpTokenAttributes  OPTIONAL,
+                  IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
+                  IN TOKEN_TYPE TokenType,
+                  OUT PHANDLE DuplicateTokenHandle)
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
-  HANDLE NewToken;
   NTSTATUS Status;
+  SECURITY_QUALITY_OF_SERVICE Sqos;
 
-  ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
-  ObjectAttributes.RootDirectory = NULL;
-  ObjectAttributes.ObjectName = NULL;
-  ObjectAttributes.Attributes = 0;
-  if (lpTokenAttributes->bInheritHandle)
+  Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
+  Sqos.ImpersonationLevel = ImpersonationLevel;
+  Sqos.ContextTrackingMode = 0;
+  Sqos.EffectiveOnly = FALSE;
+
+  if (lpTokenAttributes != NULL)
     {
-      ObjectAttributes.Attributes |= OBJ_INHERIT;
+      InitializeObjectAttributes(&ObjectAttributes,
+                                 NULL,
+                                 lpTokenAttributes->bInheritHandle ? OBJ_INHERIT : 0,
+                                 NULL,
+                                 lpTokenAttributes->lpSecurityDescriptor);
     }
-  ObjectAttributes.SecurityDescriptor = lpTokenAttributes->lpSecurityDescriptor;
-  ObjectAttributes.SecurityQualityOfService = NULL;
+  else
+    {
+      InitializeObjectAttributes(&ObjectAttributes,
+                                 NULL,
+                                 0,
+                                 NULL,
+                                 NULL);
+    }
+
+  ObjectAttributes.SecurityQualityOfService = &Sqos;
 
   Status = NtDuplicateToken (ExistingTokenHandle,
                             dwDesiredAccess,
                             &ObjectAttributes,
-                            ImpersonationLevel,
+                            FALSE,
                             TokenType,
-                            &NewToken);
+                            DuplicateTokenHandle);
   if (!NT_SUCCESS(Status))
     {
       SetLastError(RtlNtStatusToDosError(Status));
@@ -284,16 +306,293 @@ DuplicateTokenEx (HANDLE ExistingTokenHandle,
  * @implemented
  */
 BOOL STDCALL
-DuplicateToken (HANDLE ExistingTokenHandle,
-                SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
-                PHANDLE DuplicateTokenHandle)
+DuplicateToken (IN HANDLE ExistingTokenHandle,
+                IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
+                OUT PHANDLE DuplicateTokenHandle)
 {
   return DuplicateTokenEx (ExistingTokenHandle,
-                           TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY,
+                           TOKEN_IMPERSONATE | TOKEN_QUERY,
                            NULL,
                            ImpersonationLevel,
                            TokenImpersonation,
                            DuplicateTokenHandle);
 }
 
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+CheckTokenMembership(IN HANDLE ExistingTokenHandle,
+                     IN PSID SidToCheck,
+                     OUT PBOOL IsMember)
+{
+    PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
+    ACCESS_MASK GrantedAccess;
+    struct
+    {
+        PRIVILEGE_SET PrivilegeSet;
+        LUID_AND_ATTRIBUTES Privileges[4];
+    } PrivBuffer;
+    ULONG PrivBufferSize = sizeof(PrivBuffer);
+    GENERIC_MAPPING GenericMapping =
+    {
+        STANDARD_RIGHTS_READ,
+        STANDARD_RIGHTS_WRITE,
+        STANDARD_RIGHTS_EXECUTE,
+        STANDARD_RIGHTS_ALL
+    };
+    PACL Dacl;
+    ULONG SidLen;
+    HANDLE hToken = NULL;
+    NTSTATUS Status, AccessStatus;
+
+    /* doesn't return gracefully if IsMember is NULL! */
+    *IsMember = FALSE;
+
+    SidLen = RtlLengthSid(SidToCheck);
+
+    if (ExistingTokenHandle == NULL)
+    {
+        Status = NtOpenThreadToken(NtCurrentThread(),
+                                   TOKEN_QUERY,
+                                   FALSE,
+                                   &hToken);
+
+        if (Status == STATUS_NO_TOKEN)
+        {
+            /* we're not impersonating, open the primary token */
+            Status = NtOpenProcessToken(NtCurrentProcess(),
+                                        TOKEN_QUERY | TOKEN_DUPLICATE,
+                                        &hToken);
+            if (NT_SUCCESS(Status))
+            {
+                HANDLE hNewToken = FALSE;
+                BOOL DupRet;
+
+                /* duplicate the primary token to create an impersonation token */
+                DupRet = DuplicateTokenEx(hToken,
+                                          TOKEN_QUERY | TOKEN_IMPERSONATE,
+                                          NULL,
+                                          SecurityImpersonation,
+                                          TokenImpersonation,
+                                          &hNewToken);
+
+                NtClose(hToken);
+
+                if (!DupRet)
+                {
+                    DPRINT1("Failed to duplicate the primary token!\n");
+                    return FALSE;
+                }
+
+                hToken = hNewToken;
+            }
+        }
+
+        if (!NT_SUCCESS(Status))
+        {
+            goto Cleanup;
+        }
+    }
+    else
+    {
+        hToken = ExistingTokenHandle;
+    }
+
+    /* create a security descriptor */
+    SecurityDescriptor = RtlAllocateHeap(RtlGetProcessHeap(),
+                                         0,
+                                         sizeof(SECURITY_DESCRIPTOR) +
+                                             sizeof(ACL) + SidLen +
+                                             sizeof(ACCESS_ALLOWED_ACE));
+    if (SecurityDescriptor == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto Cleanup;
+    }
+
+    Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
+                                         SECURITY_DESCRIPTOR_REVISION);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* set the owner and group */
+    Status = RtlSetOwnerSecurityDescriptor(SecurityDescriptor,
+                                           SidToCheck,
+                                           FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    Status = RtlSetGroupSecurityDescriptor(SecurityDescriptor,
+                                           SidToCheck,
+                                           FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* create the DACL */
+    Dacl = (PACL)(SecurityDescriptor + 1);
+    Status = RtlCreateAcl(Dacl,
+                          sizeof(ACL) + SidLen + sizeof(ACCESS_ALLOWED_ACE),
+                          ACL_REVISION);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    Status = RtlAddAccessAllowedAce(Dacl,
+                                    ACL_REVISION,
+                                    0x1,
+                                    SidToCheck);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* assign the DACL to the security descriptor */
+    Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor,
+                                          TRUE,
+                                          Dacl,
+                                          FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Cleanup;
+    }
+
+    /* it's time to perform the access check. Just use _some_ desired access right
+       (same as for the ACE) and see if we're getting it granted. This indicates
+       our SID is a member of the token. We however can't use a generic access
+       right as those aren't mapped and return an error (STATUS_GENERIC_NOT_MAPPED). */
+    Status = NtAccessCheck(SecurityDescriptor,
+                           hToken,
+                           0x1,
+                           &GenericMapping,
+                           &PrivBuffer.PrivilegeSet,
+                           &PrivBufferSize,
+                           &GrantedAccess,
+                           &AccessStatus);
+
+    if (NT_SUCCESS(Status) && NT_SUCCESS(AccessStatus) && (GrantedAccess == 0x1))
+    {
+        *IsMember = TRUE;
+    }
+
+Cleanup:
+    if (hToken != NULL && hToken != ExistingTokenHandle)
+    {
+        NtClose(hToken);
+    }
+
+    if (SecurityDescriptor != NULL)
+    {
+        RtlFreeHeap(RtlGetProcessHeap(),
+                    0,
+                    SecurityDescriptor);
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        SetLastError(RtlNtStatusToDosError(Status));
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+IsTokenRestricted(HANDLE TokenHandle)
+{
+  ULONG RetLength;
+  PTOKEN_GROUPS lpGroups;
+  NTSTATUS Status;
+  BOOL Ret = FALSE;
+  
+  /* determine the required buffer size and allocate enough memory to read the
+     list of restricted SIDs */
+
+  Status = NtQueryInformationToken(TokenHandle,
+                                   TokenRestrictedSids,
+                                   NULL,
+                                   0,
+                                   &RetLength);
+  if (Status != STATUS_BUFFER_TOO_SMALL)
+  {
+    SetLastError(RtlNtStatusToDosError(Status));
+    return FALSE;
+  }
+  
+AllocAndReadRestrictedSids:
+  lpGroups = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
+                                      0,
+                                      RetLength);
+  if (lpGroups == NULL)
+  {
+    SetLastError(ERROR_OUTOFMEMORY);
+    return FALSE;
+  }
+  
+  /* actually read the list of the restricted SIDs */
+  
+  Status = NtQueryInformationToken(TokenHandle,
+                                   TokenRestrictedSids,
+                                   lpGroups,
+                                   RetLength,
+                                   &RetLength);
+  if (NT_SUCCESS(Status))
+  {
+    Ret = (lpGroups->GroupCount != 0);
+  }
+  else if (Status == STATUS_BUFFER_TOO_SMALL)
+  {
+    /* looks like the token was modified in the meanwhile, let's just try again */
+
+    HeapFree(GetProcessHeap(),
+             0,
+             lpGroups);
+
+    goto AllocAndReadRestrictedSids;
+  }
+  else
+  {
+    SetLastError(RtlNtStatusToDosError(Status));
+  }
+  
+  /* free allocated memory */
+
+  HeapFree(GetProcessHeap(),
+           0,
+           lpGroups);
+
+  return Ret;
+}
+
+BOOL STDCALL 
+CreateRestrictedToken(
+            HANDLE TokenHandle,
+            DWORD Flags,
+            DWORD DisableSidCount,
+            PSID_AND_ATTRIBUTES pSidAndAttributes,
+            DWORD DeletePrivilegeCount,
+            PLUID_AND_ATTRIBUTES pLUIDAndAttributes,
+            DWORD RestrictedSidCount,
+            PSID_AND_ATTRIBUTES pSIDAndAttributes,
+            PHANDLE NewTokenHandle
+)
+{
+    FIXME("unimplemented!\n", __FUNCTION__);
+    return FALSE;
+}
+
+
+
 /* EOF */