implemented some stubs needed by ClamWin
[reactos.git] / reactos / lib / advapi32 / token / token.c
index 94d68c0..fba94fb 100644 (file)
@@ -8,9 +8,10 @@
  *                  Created 01/11/98
  */
 
-#include "advapi32.h"
+#include <advapi32.h>
 
 #define NDEBUG
+#include <wine/debug.h>
 #include <debug.h>
 
 /*
@@ -224,15 +225,13 @@ 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,
@@ -252,39 +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;
-  
+
   Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
   Sqos.ImpersonationLevel = ImpersonationLevel;
   Sqos.ContextTrackingMode = 0;
   Sqos.EffectiveOnly = FALSE;
 
-  InitializeObjectAttributes(
-      &ObjectAttributes,
-      NULL,
-      lpTokenAttributes->bInheritHandle ? OBJ_INHERIT : 0,
-      NULL,
-      lpTokenAttributes->lpSecurityDescriptor
-      );
+  if (lpTokenAttributes != NULL)
+    {
+      InitializeObjectAttributes(&ObjectAttributes,
+                                 NULL,
+                                 lpTokenAttributes->bInheritHandle ? OBJ_INHERIT : 0,
+                                 NULL,
+                                 lpTokenAttributes->lpSecurityDescriptor);
+    }
+  else
+    {
+      InitializeObjectAttributes(&ObjectAttributes,
+                                 NULL,
+                                 0,
+                                 NULL,
+                                 NULL);
+    }
+
   ObjectAttributes.SecurityQualityOfService = &Sqos;
 
   Status = NtDuplicateToken (ExistingTokenHandle,
                             dwDesiredAccess,
                             &ObjectAttributes,
-              Sqos.EffectiveOnly, /* why both here _and_ in Sqos? */
+                            FALSE,
                             TokenType,
-                            &NewToken);
+                            DuplicateTokenHandle);
   if (!NT_SUCCESS(Status))
     {
       SetLastError(RtlNtStatusToDosError(Status));
@@ -299,12 +306,12 @@ 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,
@@ -313,16 +320,279 @@ DuplicateToken (HANDLE ExistingTokenHandle,
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL STDCALL
-CheckTokenMembership(HANDLE Token, PSID SidToCheck, PBOOL IsMember)
+CheckTokenMembership(IN HANDLE ExistingTokenHandle,
+                     IN PSID SidToCheck,
+                     OUT PBOOL IsMember)
 {
-  DPRINT1("CheckTokenMembership not implemented\n");
+    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;
+    }
 
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    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;
+    }
 
-  return FALSE;
+    /* 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 */