implemented some stubs needed by ClamWin
[reactos.git] / reactos / lib / advapi32 / token / token.c
index 0039fdb..fba94fb 100644 (file)
 
 #include <advapi32.h>
 
+#define NDEBUG
+#include <wine/debug.h>
+#include <debug.h>
 
-WINBOOL
-STDCALL
-AdjustTokenGroups (
-                  HANDLE TokenHandle,
-                  WINBOOL ResetToDefault,
+/*
+ * @implemented
+ */
+BOOL STDCALL
+AdjustTokenGroups (HANDLE TokenHandle,
+                  BOOL ResetToDefault,
                   PTOKEN_GROUPS NewState,
                   DWORD BufferLength,
                   PTOKEN_GROUPS PreviousState,
-                  PDWORD ReturnLength
-                   )
+                  PDWORD ReturnLength)
 {
-       NTSTATUS errCode;
-       errCode = NtAdjustGroupsToken(TokenHandle,ResetToDefault,NewState,
-                       BufferLength, PreviousState, (PULONG)ReturnLength );
-       if ( !NT_SUCCESS(errCode) ) {
-               SetLastError(RtlNtStatusToDosError(errCode));
-               return FALSE;
-       }
-       return TRUE;    
+  NTSTATUS Status;
+
+  Status = NtAdjustGroupsToken (TokenHandle,
+                               ResetToDefault,
+                               NewState,
+                               BufferLength,
+                               PreviousState,
+                               (PULONG)ReturnLength);
+  if (!NT_SUCCESS (Status))
+    {
+      SetLastError (RtlNtStatusToDosError (Status));
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
-WINBOOL
-STDCALL
-AdjustTokenPrivileges (
-                      HANDLE TokenHandle,
-                      WINBOOL DisableAllPrivileges,
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+AdjustTokenPrivileges (HANDLE TokenHandle,
+                      BOOL DisableAllPrivileges,
                       PTOKEN_PRIVILEGES NewState,
                       DWORD BufferLength,
                       PTOKEN_PRIVILEGES PreviousState,
-                      PDWORD ReturnLength
-                       )
-{      NTSTATUS errCode;
-       errCode = NtAdjustPrivilegesToken(TokenHandle,DisableAllPrivileges,NewState,
-                       BufferLength, PreviousState, (PULONG)ReturnLength );
-       if ( !NT_SUCCESS(errCode) ) {
-               SetLastError(RtlNtStatusToDosError(errCode));
-               return FALSE;
-       }
-       return TRUE;    
+                      PDWORD ReturnLength)
+{
+  NTSTATUS Status;
+
+  Status = NtAdjustPrivilegesToken (TokenHandle,
+                                   DisableAllPrivileges,
+                                   NewState,
+                                   BufferLength,
+                                   PreviousState,
+                                   (PULONG)ReturnLength);
+  if (STATUS_NOT_ALL_ASSIGNED == Status)
+    {
+      SetLastError(ERROR_NOT_ALL_ASSIGNED);
+      return TRUE;
+    }
+  if (! NT_SUCCESS(Status))
+    {
+      SetLastError(RtlNtStatusToDosError(Status));
+      return FALSE;
+    }
+
+  SetLastError(ERROR_SUCCESS); /* AdjustTokenPrivileges is documented to do this */
+  return TRUE;
 }
 
 
-WINBOOL
-STDCALL
-GetTokenInformation (
-                    HANDLE TokenHandle,
+/*
+ * @implemented
+ */
+BOOL STDCALL
+GetTokenInformation (HANDLE TokenHandle,
                     TOKEN_INFORMATION_CLASS TokenInformationClass,
                     LPVOID TokenInformation,
                     DWORD TokenInformationLength,
-                    PDWORD ReturnLength
-                     )
+                    PDWORD ReturnLength)
 {
-       NTSTATUS errCode;
-       errCode = NtQueryInformationToken(TokenHandle,TokenInformationClass,TokenInformation,
-                       TokenInformationLength, (PULONG)ReturnLength);
-       if ( !NT_SUCCESS(errCode) ) {
-               SetLastError(RtlNtStatusToDosError(errCode));
-               return FALSE;
-       }
-       return TRUE;
+  NTSTATUS Status;
+
+  Status = NtQueryInformationToken (TokenHandle,
+                                   TokenInformationClass,
+                                   TokenInformation,
+                                   TokenInformationLength,
+                                   (PULONG)ReturnLength);
+  if (!NT_SUCCESS (Status))
+    {
+      SetLastError (RtlNtStatusToDosError (Status));
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
-WINBOOL
-STDCALL
-SetTokenInformation (
-                    HANDLE TokenHandle,
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+SetTokenInformation (HANDLE TokenHandle,
                     TOKEN_INFORMATION_CLASS TokenInformationClass,
                     LPVOID TokenInformation,
-                    DWORD TokenInformationLength
-                     )
+                    DWORD TokenInformationLength)
 {
-       NTSTATUS errCode;
-       errCode = NtSetInformationToken(TokenHandle,TokenInformationClass,TokenInformation,
-                       TokenInformationLength);
-       if ( !NT_SUCCESS(errCode) ) {
-               SetLastError(RtlNtStatusToDosError(errCode));
-               return FALSE;
-       }
-       return TRUE;
+  NTSTATUS Status;
+
+  Status = NtSetInformationToken (TokenHandle,
+                                 TokenInformationClass,
+                                 TokenInformation,
+                                 TokenInformationLength);
+  if (!NT_SUCCESS (Status))
+    {
+      SetLastError (RtlNtStatusToDosError (Status));
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
-WINBOOL
-STDCALL
-AccessCheck (
-            PSECURITY_DESCRIPTOR pSecurityDescriptor,
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+AccessCheck (PSECURITY_DESCRIPTOR pSecurityDescriptor,
             HANDLE ClientToken,
             DWORD DesiredAccess,
             PGENERIC_MAPPING GenericMapping,
             PPRIVILEGE_SET PrivilegeSet,
             LPDWORD PrivilegeSetLength,
             LPDWORD GrantedAccess,
-            LPBOOL AccessStatus
-             )
+            LPBOOL AccessStatus)
 {
-       NTSTATUS errCode;
-       errCode = NtAccessCheck( pSecurityDescriptor,
-            ClientToken,
-            DesiredAccess,
-            GenericMapping,
-             PrivilegeSet,
-            (PULONG)PrivilegeSetLength,
-            (PULONG)GrantedAccess,
-            (PBOOLEAN)AccessStatus);
-       if ( !NT_SUCCESS(errCode) ) {
-               SetLastError(RtlNtStatusToDosError(errCode));
-               return FALSE;
-       }
-       return TRUE;
-}
+  NTSTATUS Status;
+  NTSTATUS AccessStat;
 
+  Status = NtAccessCheck (pSecurityDescriptor,
+                         ClientToken,
+                         DesiredAccess,
+                         GenericMapping,
+                         PrivilegeSet,
+                         (PULONG)PrivilegeSetLength,
+                         (PACCESS_MASK)GrantedAccess,
+                         &AccessStat);
+  if (!NT_SUCCESS (Status))
+    {
+      SetLastError (RtlNtStatusToDosError (Status));
+      return FALSE;
+    }
 
+  if (!NT_SUCCESS (AccessStat))
+    {
+      SetLastError (RtlNtStatusToDosError (Status));
+      *AccessStatus = FALSE;
+      return TRUE;
+    }
 
-WINBOOL
-STDCALL
-OpenProcessToken (
-                 HANDLE ProcessHandle,
+  *AccessStatus = TRUE;
+
+  return TRUE;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+OpenProcessToken (HANDLE ProcessHandle,
                  DWORD DesiredAccess,
-                 PHANDLE TokenHandle
-                  )
+                 PHANDLE TokenHandle)
 {
-       NTSTATUS errCode;
-       errCode = NtOpenProcessToken(ProcessHandle,DesiredAccess,TokenHandle);
-       if ( !NT_SUCCESS(errCode) ) {
-               SetLastError(RtlNtStatusToDosError(errCode));
-               return FALSE;
-       }
-       return TRUE;
-}
+  NTSTATUS Status;
+
+  Status = NtOpenProcessToken (ProcessHandle,
+                              DesiredAccess,
+                              TokenHandle);
+  if (!NT_SUCCESS (Status))
+    {
+      SetLastError (RtlNtStatusToDosError (Status));
+      return FALSE;
+    }
 
+  return TRUE;
+}
 
 
-WINBOOL
-STDCALL
-OpenThreadToken (
-                HANDLE ThreadHandle,
+/*
+ * @implemented
+ */
+BOOL STDCALL
+OpenThreadToken (HANDLE ThreadHandle,
                 DWORD DesiredAccess,
-                WINBOOL OpenAsSelf,
-                PHANDLE TokenHandle
-                 )
+                BOOL OpenAsSelf,
+                PHANDLE TokenHandle)
 {
-       NTSTATUS errCode;
-       errCode = NtOpenThreadToken(ThreadHandle,DesiredAccess,OpenAsSelf,TokenHandle);
-       if ( !NT_SUCCESS(errCode) ) {
-               SetLastError(RtlNtStatusToDosError(errCode));
-               return FALSE;
-       }
-       return TRUE;
+  NTSTATUS Status;
+
+  Status = NtOpenThreadToken (ThreadHandle,
+                             DesiredAccess,
+                             OpenAsSelf,
+                             TokenHandle);
+  if (!NT_SUCCESS(Status))
+    {
+      SetLastError (RtlNtStatusToDosError (Status));
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+SetThreadToken (IN PHANDLE ThreadHandle  OPTIONAL,
+                IN HANDLE TokenHandle)
+{
+  NTSTATUS Status;
+  HANDLE hThread;
+
+  hThread = ((ThreadHandle != NULL) ? *ThreadHandle : NtCurrentThread());
+
+  Status = NtSetInformationThread (hThread,
+                                  ThreadImpersonationToken,
+                                  &TokenHandle,
+                                  sizeof(HANDLE));
+  if (!NT_SUCCESS(Status))
+    {
+      SetLastError (RtlNtStatusToDosError (Status));
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
 
-WINBOOL
-STDCALL
-SetThreadToken (
-                PHANDLE ThreadHandle,
-                HANDLE TokenHandle
-                 )
+/*
+ * @implemented
+ */
+BOOL STDCALL
+DuplicateTokenEx (IN HANDLE ExistingTokenHandle,
+                  IN DWORD dwDesiredAccess,
+                  IN LPSECURITY_ATTRIBUTES lpTokenAttributes  OPTIONAL,
+                  IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
+                  IN TOKEN_TYPE TokenType,
+                  OUT PHANDLE DuplicateTokenHandle)
 {
-       NTSTATUS errCode;
-       HANDLE hThread  = NtCurrentThread();
-       if ( ThreadHandle != NULL )
-               hThread = ThreadHandle;
-       errCode = NtSetInformationThread(hThread,ThreadImpersonationToken,TokenHandle,sizeof(HANDLE));
-       if ( !NT_SUCCESS(errCode) ) {
-               SetLastError(RtlNtStatusToDosError(errCode));
-               return FALSE;
-       }
-       return TRUE;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  NTSTATUS Status;
+  SECURITY_QUALITY_OF_SERVICE Sqos;
+
+  Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
+  Sqos.ImpersonationLevel = ImpersonationLevel;
+  Sqos.ContextTrackingMode = 0;
+  Sqos.EffectiveOnly = FALSE;
+
+  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,
+                            FALSE,
+                            TokenType,
+                            DuplicateTokenHandle);
+  if (!NT_SUCCESS(Status))
+    {
+      SetLastError(RtlNtStatusToDosError(Status));
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
 
-WINBOOL
-STDCALL
-DuplicateTokenEx (
-                  HANDLE ExistingTokenHandle,
-                  DWORD  dwDesiredAccess,
-                  LPSECURITY_ATTRIBUTES lpTokenAttributes,
-                  SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
-                  TOKEN_TYPE TokenType,
-                  PHANDLE DuplicateTokenHandle
-                   )
+/*
+ * @implemented
+ */
+BOOL STDCALL
+DuplicateToken (IN HANDLE ExistingTokenHandle,
+                IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
+                OUT PHANDLE DuplicateTokenHandle)
 {
-       NTSTATUS errCode;
-       HANDLE NewToken;
-
-       OBJECT_ATTRIBUTES ObjectAttributes;
-       
-
-       ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
-       ObjectAttributes.RootDirectory = NULL;
-       ObjectAttributes.ObjectName = NULL;
-       ObjectAttributes.Attributes = 0;
-       if ( lpTokenAttributes->bInheritHandle )
-               ObjectAttributes.Attributes |= OBJ_INHERIT;     
-
-       ObjectAttributes.SecurityDescriptor = lpTokenAttributes->lpSecurityDescriptor;
-       ObjectAttributes.SecurityQualityOfService = NULL;
-
-       errCode = NtDuplicateToken(  ExistingTokenHandle, dwDesiredAccess, 
-               &ObjectAttributes, ImpersonationLevel,
-               TokenType,  &NewToken     );
-
-       if ( !NT_SUCCESS(errCode) ) {
-               SetLastError(RtlNtStatusToDosError(errCode));
-               return FALSE;
-       }
-       return TRUE;
+  return DuplicateTokenEx (ExistingTokenHandle,
+                           TOKEN_IMPERSONATE | TOKEN_QUERY,
+                           NULL,
+                           ImpersonationLevel,
+                           TokenImpersonation,
+                           DuplicateTokenHandle);
 }
 
 
-WINBOOL
-STDCALL
-DuplicateToken (
-                HANDLE ExistingTokenHandle,
-                SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
-                PHANDLE DuplicateTokenHandle
-                 )
+/*
+ * @implemented
+ */
+BOOL STDCALL
+CheckTokenMembership(IN HANDLE ExistingTokenHandle,
+                     IN PSID SidToCheck,
+                     OUT PBOOL IsMember)
 {
-       return DuplicateTokenEx (
-                  ExistingTokenHandle,
-                  TOKEN_DUPLICATE|TOKEN_IMPERSONATE|TOKEN_QUERY,
-                  NULL,
-                  ImpersonationLevel,
-                  TokenImpersonation,
-                  DuplicateTokenHandle
-                   );
+    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;
+}