mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
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:
parent
0c2ceade45
commit
a4bfa110a8
1 changed files with 171 additions and 64 deletions
|
@ -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;
|
|
||||||
TOKEN_TYPE TokenInformation;
|
|
||||||
|
|
||||||
if (IsMember == NULL)
|
|
||||||
{
|
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ExistingTokenHandle == NULL)
|
|
||||||
{
|
|
||||||
/* Get impersonation token of the calling thread */
|
|
||||||
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &ExistingTokenHandle))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (!DuplicateToken(ExistingTokenHandle, SecurityAnonymous, &AccessToken))
|
|
||||||
{
|
{
|
||||||
CloseHandle(ExistingTokenHandle);
|
PRIVILEGE_SET PrivilegeSet;
|
||||||
goto ByeBye;
|
LUID_AND_ATTRIBUTES Privileges[4];
|
||||||
}
|
} PrivBuffer;
|
||||||
CloseHandle(ExistingTokenHandle);
|
ULONG PrivBufferSize = sizeof(PrivBuffer);
|
||||||
}
|
GENERIC_MAPPING GenericMapping =
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!GetTokenInformation(ExistingTokenHandle, TokenType, &TokenInformation, sizeof(TokenInformation), &dwSize))
|
|
||||||
goto ByeBye;
|
|
||||||
if (TokenInformation != TokenImpersonation)
|
|
||||||
{
|
{
|
||||||
/* Duplicate token to have a impersonation token */
|
STANDARD_RIGHTS_READ,
|
||||||
if (!DuplicateToken(ExistingTokenHandle, SecurityAnonymous, &AccessToken))
|
STANDARD_RIGHTS_WRITE,
|
||||||
return FALSE;
|
STANDARD_RIGHTS_EXECUTE,
|
||||||
|
STANDARD_RIGHTS_ALL
|
||||||
|
};
|
||||||
|
PACL Dacl;
|
||||||
|
ULONG SidLen;
|
||||||
|
HANDLE hToken;
|
||||||
|
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
|
else
|
||||||
AccessToken = ExistingTokenHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
*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++)
|
|
||||||
{
|
|
||||||
if (EqualSid(SidToCheck, &lpGroups->Groups[i].Sid))
|
|
||||||
{
|
{
|
||||||
Result = TRUE;
|
hToken = ExistingTokenHandle;
|
||||||
*IsMember = TRUE;
|
|
||||||
goto ByeBye;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/* FIXME: Search in users of the token? */
|
|
||||||
DPRINT1("CheckTokenMembership() partially implemented!\n");
|
|
||||||
Result = TRUE;
|
|
||||||
|
|
||||||
ByeBye:
|
/* create a security descriptor */
|
||||||
if (lpGroups != NULL)
|
SecurityDescriptor = RtlAllocateHeap(RtlGetProcessHeap(),
|
||||||
HeapFree(GetProcessHeap(), 0, lpGroups);
|
0,
|
||||||
if (AccessToken != NULL && AccessToken != ExistingTokenHandle)
|
sizeof(SECURITY_DESCRIPTOR) +
|
||||||
CloseHandle(AccessToken);
|
sizeof(ACL) + SidLen +
|
||||||
|
sizeof(ACCESS_ALLOWED_ACE));
|
||||||
|
if (SecurityDescriptor == NULL)
|
||||||
|
{
|
||||||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
return Result;
|
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 != ExistingTokenHandle)
|
||||||
|
{
|
||||||
|
NtClose(hToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SecurityDescriptor != NULL)
|
||||||
|
{
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(),
|
||||||
|
0,
|
||||||
|
SecurityDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
SetLastError(RtlNtStatusToDosError(Status));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue