some fixes for CheckTokenMembership:

- properly create an impersonation token from the primary token in case the thread is not impersonating
- use NtAccessCheck to perform the access check

svn path=/trunk/; revision=18392
This commit is contained in:
Thomas Bluemel 2005-10-10 11:44:37 +00:00
parent 0c2ceade45
commit a4bfa110a8

View file

@ -323,79 +323,186 @@ DuplicateToken (IN HANDLE ExistingTokenHandle,
* @implemented * @implemented
*/ */
BOOL STDCALL BOOL STDCALL
CheckTokenMembership (HANDLE ExistingTokenHandle, CheckTokenMembership(IN HANDLE ExistingTokenHandle,
PSID SidToCheck, IN PSID SidToCheck,
PBOOL IsMember) OUT PBOOL IsMember)
{ {
HANDLE AccessToken = NULL; PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
BOOL Result = FALSE; ACCESS_MASK GrantedAccess;
DWORD dwSize; struct
DWORD i; {
PTOKEN_GROUPS lpGroups = NULL; PRIVILEGE_SET PrivilegeSet;
TOKEN_TYPE TokenInformation; 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;
NTSTATUS Status, AccessStatus;
if (IsMember == NULL) /* doesn't return gracefully if IsMember is NULL! */
{ *IsMember = FALSE;
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE; SidLen = RtlLengthSid(SidToCheck);
}
if (ExistingTokenHandle == NULL) if (ExistingTokenHandle == NULL)
{ {
/* Get impersonation token of the calling thread */ Status = NtOpenThreadToken(NtCurrentThread(),
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &ExistingTokenHandle)) TOKEN_QUERY,
return FALSE; FALSE,
&hToken);
if (!DuplicateToken(ExistingTokenHandle, SecurityAnonymous, &AccessToken)) if (Status == STATUS_NO_TOKEN)
{ {
CloseHandle(ExistingTokenHandle); /* we're not impersonating, open the primary token */
goto ByeBye; 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;
} }
CloseHandle(ExistingTokenHandle);
} }
else else
{ {
if (!GetTokenInformation(ExistingTokenHandle, TokenType, &TokenInformation, sizeof(TokenInformation), &dwSize)) hToken = ExistingTokenHandle;
goto ByeBye;
if (TokenInformation != TokenImpersonation)
{
/* Duplicate token to have a impersonation token */
if (!DuplicateToken(ExistingTokenHandle, SecurityAnonymous, &AccessToken))
return FALSE;
}
else
AccessToken = ExistingTokenHandle;
} }
*IsMember = FALSE; /* create a security descriptor */
/* Search in groups of the token */ SecurityDescriptor = RtlAllocateHeap(RtlGetProcessHeap(),
if (!GetTokenInformation(AccessToken, TokenGroups, NULL, 0, &dwSize)) 0,
goto ByeBye; sizeof(SECURITY_DESCRIPTOR) +
lpGroups = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), 0, dwSize); sizeof(ACL) + SidLen +
if (!lpGroups) sizeof(ACCESS_ALLOWED_ACE));
goto ByeBye; if (SecurityDescriptor == NULL)
if (!GetTokenInformation(AccessToken, TokenGroups, lpGroups, dwSize, &dwSize))
goto ByeBye;
for (i = 0; i < lpGroups->GroupCount; i++)
{ {
if (EqualSid(SidToCheck, &lpGroups->Groups[i].Sid)) 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))
{ {
Result = TRUE;
*IsMember = TRUE; *IsMember = TRUE;
goto ByeBye;
} }
Cleanup:
if (hToken != ExistingTokenHandle)
{
NtClose(hToken);
} }
/* FIXME: Search in users of the token? */
DPRINT1("CheckTokenMembership() partially implemented!\n");
Result = TRUE;
ByeBye: if (SecurityDescriptor != NULL)
if (lpGroups != NULL) {
HeapFree(GetProcessHeap(), 0, lpGroups); RtlFreeHeap(RtlGetProcessHeap(),
if (AccessToken != NULL && AccessToken != ExistingTokenHandle) 0,
CloseHandle(AccessToken); SecurityDescriptor);
}
return Result; if (!NT_SUCCESS(Status))
{
SetLastError(RtlNtStatusToDosError(Status));
return FALSE;
}
return TRUE;
} }