/****************************************************************************** * AccessCheck [ADVAPI32.@] * * FIXME check cast LPBOOL to PBOOLEAN */ BOOL WINAPI AccessCheck( PSECURITY_DESCRIPTOR SecurityDescriptor, HANDLE ClientToken, DWORD DesiredAccess, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess, LPBOOL AccessStatus) { CallWin32ToNt (NtAccessCheck(SecurityDescriptor, ClientToken, DesiredAccess, GenericMapping, PrivilegeSet, PrivilegeSetLength, GrantedAccess, (PBOOLEAN)AccessStatus)); }
/* * @implemented */ BOOL WINAPI AccessCheck(IN PSECURITY_DESCRIPTOR pSecurityDescriptor, IN HANDLE ClientToken, IN DWORD DesiredAccess, IN PGENERIC_MAPPING GenericMapping, OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL, IN OUT LPDWORD PrivilegeSetLength, OUT LPDWORD GrantedAccess, OUT LPBOOL AccessStatus) { NTSTATUS Status; NTSTATUS NtAccessStatus; /* Do the access check */ Status = NtAccessCheck(pSecurityDescriptor, ClientToken, DesiredAccess, GenericMapping, PrivilegeSet, (PULONG)PrivilegeSetLength, (PACCESS_MASK)GrantedAccess, &NtAccessStatus); /* See if the access check operation succeeded */ if (!NT_SUCCESS(Status)) { /* Check failed */ SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } /* Now check the access status */ if (!NT_SUCCESS(NtAccessStatus)) { /* Access denied */ SetLastError(RtlNtStatusToDosError(NtAccessStatus)); *AccessStatus = FALSE; } else { /* Access granted */ *AccessStatus = TRUE; } /* Check succeeded */ return TRUE; }
BOOLEAN TestAccessCheck() { UCHAR AclBuffer[1024]; SECURITY_DESCRIPTOR SecurityDescriptor; PACL Acl; UCHAR TokenBuffer[512]; PACCESS_TOKEN Token; NTSTATUS Status; Acl = (PACL)AclBuffer; BuildAcl( Fred, Acl, 1024 ); Token = (PACCESS_TOKEN)TokenBuffer; BuildToken( Fred, Token ); DiscretionarySecurityDescriptor( &SecurityDescriptor, Acl ); // // Test should be successful based on aces // if (!NT_SUCCESS(Status = NtAccessCheck( &SecurityDescriptor, Token, 0x00000001, NULL ))) { DbgPrint("NtAccessCheck Error should allow access : %8lx\n", Status); return FALSE; } // // Test should be successful based on owner // if (!NT_SUCCESS(Status = NtAccessCheck( &SecurityDescriptor, Token, READ_CONTROL, &FredGuid ))) { DbgPrint("NtAccessCheck Error should allow owner : %8lx\n", Status); return FALSE; } // // Test should be unsuccessful based on aces // if (NT_SUCCESS(Status = NtAccessCheck( &SecurityDescriptor, Token, 0x0000000f, &FredGuid ))) { DbgPrint("NtAccessCheck Error shouldn't allow access : %8lx\n", Status); return FALSE; } // // Test should be unsuccessful based on non owner // if (NT_SUCCESS(Status = NtAccessCheck( &SecurityDescriptor, Token, READ_CONTROL, &BarneyGuid ))) { DbgPrint("NtAccessCheck Error shouldn't allow non owner access : %8lx\n", Status); return FALSE; } return TRUE; }
/* * @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; }