mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 06:15:26 +00:00
345 lines
9.9 KiB
C
345 lines
9.9 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS system libraries
|
|
* FILE: lib/advapi32/token/token.c
|
|
* PURPOSE: Token functions
|
|
* PROGRAMMER: Ariadne (ariadne@xs4all.nl)
|
|
* UPDATE HISTORY:
|
|
* Created 01/11/98
|
|
*/
|
|
|
|
#include <advapi32.h>
|
|
|
|
#include <ndk/setypes.h>
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(advapi);
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL WINAPI
|
|
CheckTokenMembership(IN HANDLE ExistingTokenHandle,
|
|
IN PSID SidToCheck,
|
|
OUT PBOOL IsMember)
|
|
{
|
|
PISECURITY_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)
|
|
{
|
|
WARN("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 WINAPI
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
PSID
|
|
WINAPI
|
|
GetSiteSidFromToken(IN HANDLE TokenHandle)
|
|
{
|
|
PTOKEN_GROUPS RestrictedSids;
|
|
ULONG RetLen;
|
|
UINT i;
|
|
NTSTATUS Status;
|
|
PSID PSiteSid = NULL;
|
|
SID_IDENTIFIER_AUTHORITY InternetSiteAuthority = {SECURITY_INTERNETSITE_AUTHORITY};
|
|
|
|
Status = NtQueryInformationToken(TokenHandle,
|
|
TokenRestrictedSids,
|
|
NULL,
|
|
0,
|
|
&RetLen);
|
|
if (Status != STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
SetLastError(RtlNtStatusToDosError(Status));
|
|
return NULL;
|
|
}
|
|
|
|
RestrictedSids = (PTOKEN_GROUPS)RtlAllocateHeap(RtlGetProcessHeap(),
|
|
0,
|
|
RetLen);
|
|
if (RestrictedSids == NULL)
|
|
{
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return NULL;
|
|
}
|
|
|
|
Status = NtQueryInformationToken(TokenHandle,
|
|
TokenRestrictedSids,
|
|
RestrictedSids,
|
|
RetLen,
|
|
&RetLen);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
for (i = 0; i < RestrictedSids->GroupCount; i++)
|
|
{
|
|
SID* RSSid = RestrictedSids->Groups[i].Sid;
|
|
|
|
if (RtlCompareMemory(&(RSSid->IdentifierAuthority),
|
|
&InternetSiteAuthority,
|
|
sizeof(SID_IDENTIFIER_AUTHORITY)) ==
|
|
sizeof(SID_IDENTIFIER_AUTHORITY))
|
|
{
|
|
PSiteSid = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
0,
|
|
RtlLengthSid((RestrictedSids->
|
|
Groups[i]).Sid));
|
|
if (PSiteSid == NULL)
|
|
{
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
}
|
|
else
|
|
{
|
|
RtlCopySid(RtlLengthSid(RestrictedSids->Groups[i].Sid),
|
|
PSiteSid,
|
|
RestrictedSids->Groups[i].Sid);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetLastError(RtlNtStatusToDosError(Status));
|
|
}
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedSids);
|
|
return PSiteSid;
|
|
}
|