* Created 01/11/98
*/
-#include "advapi32.h"
+#include <advapi32.h>
#define NDEBUG
+#include <wine/debug.h>
#include <debug.h>
/*
OUT PHANDLE DuplicateTokenHandle)
{
OBJECT_ATTRIBUTES ObjectAttributes;
- HANDLE NewToken;
NTSTATUS Status;
SECURITY_QUALITY_OF_SERVICE Sqos;
&ObjectAttributes,
FALSE,
TokenType,
- &NewToken);
+ DuplicateTokenHandle);
if (!NT_SUCCESS(Status))
{
SetLastError(RtlNtStatusToDosError(Status));
* @implemented
*/
BOOL STDCALL
-CheckTokenMembership (HANDLE ExistingTokenHandle,
- PSID SidToCheck,
- PBOOL IsMember)
+CheckTokenMembership(IN HANDLE ExistingTokenHandle,
+ IN PSID SidToCheck,
+ OUT PBOOL IsMember)
{
- HANDLE AccessToken;
- BOOL ReleaseToken = FALSE;
- BOOL Result = FALSE;
- DWORD dwSize;
- DWORD i;
- PTOKEN_GROUPS lpGroups = NULL;
- TOKEN_TYPE TokenInformation;
-
- if (IsMember == NULL)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
+ 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;
+ }
- if (ExistingTokenHandle == NULL)
- {
- /* Get impersonation token of the calling thread */
- if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &ExistingTokenHandle))
- return FALSE;
+ /* 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;
+ }
- if (!DuplicateToken(ExistingTokenHandle, SecurityAnonymous, &AccessToken))
+ Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION);
+ if (!NT_SUCCESS(Status))
{
- CloseHandle(ExistingTokenHandle);
- goto ByeBye;
+ goto Cleanup;
}
- CloseHandle(ExistingTokenHandle);
- ReleaseToken = TRUE;
- }
- else
- {
- if (!GetTokenInformation(ExistingTokenHandle, TokenType, &TokenInformation, sizeof(TokenInformation), &dwSize))
- goto ByeBye;
- if (TokenInformation != TokenImpersonation)
+
+ /* 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)
{
- /* Duplicate token to have a impersonation token */
- if (!DuplicateToken(ExistingTokenHandle, SecurityAnonymous, &AccessToken))
+ NtClose(hToken);
+ }
+
+ if (SecurityDescriptor != NULL)
+ {
+ RtlFreeHeap(RtlGetProcessHeap(),
+ 0,
+ SecurityDescriptor);
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastError(RtlNtStatusToDosError(Status));
return FALSE;
- ReleaseToken = TRUE;
}
- else
- AccessToken = ExistingTokenHandle;
+
+ 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 */
- *IsMember = FALSE;
- /* Search in groups of the token */
- if (!GetTokenInformation(AccessToken, TokenGroups, NULL, 0, &dwSize))
- goto ByeBye;
- lpGroups = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), 0, dwSize);
- if (!lpGroups)
- goto ByeBye;
- if (!GetTokenInformation(AccessToken, TokenGroups, lpGroups, dwSize, &dwSize))
- goto ByeBye;
- for (i = 0; i < lpGroups->GroupCount; i++)
+ HeapFree(GetProcessHeap(),
+ 0,
+ lpGroups);
+
+ goto AllocAndReadRestrictedSids;
+ }
+ else
{
- if (EqualSid(SidToCheck, &lpGroups->Groups[i].Sid))
- {
- Result = TRUE;
- *IsMember = TRUE;
- goto ByeBye;
- }
+ SetLastError(RtlNtStatusToDosError(Status));
}
- /* FIXME: Search in users of the token? */
- DPRINT1("CheckTokenMembership() partially implemented!\n");
- Result = TRUE;
+
+ /* free allocated memory */
-ByeBye:
- if (lpGroups != NULL)
- HeapFree(GetProcessHeap(), 0, lpGroups);
- if (ReleaseToken)
- CloseHandle(AccessToken);
+ HeapFree(GetProcessHeap(),
+ 0,
+ lpGroups);
- return Result;
+ 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 */