- Cleanup AccessCheck, and set the correct last error in the case where the check succeeds but access is denied

- Cleanup NtAccessCheck, properly set desired access when previous mode is kernel, remove a duplicate check that is performed in SeAccessCheck, and don't fail with STATUS_ACCESS_DENIED when the check succeeds but denies access -- the result of the access check is returned in the 'AccessStatus' parameter

svn path=/trunk/; revision=38510
This commit is contained in:
Stefan Ginsberg 2009-01-02 17:39:45 +00:00
parent 226c5fb558
commit fbd7681b84
2 changed files with 76 additions and 65 deletions

View file

@ -135,19 +135,21 @@ SetTokenInformation(HANDLE TokenHandle,
/* /*
* @implemented * @implemented
*/ */
BOOL WINAPI BOOL
AccessCheck(PSECURITY_DESCRIPTOR pSecurityDescriptor, WINAPI
HANDLE ClientToken, AccessCheck(IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD DesiredAccess, IN HANDLE ClientToken,
PGENERIC_MAPPING GenericMapping, IN DWORD DesiredAccess,
PPRIVILEGE_SET PrivilegeSet, IN PGENERIC_MAPPING GenericMapping,
LPDWORD PrivilegeSetLength, OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL,
LPDWORD GrantedAccess, IN OUT LPDWORD PrivilegeSetLength,
LPBOOL AccessStatus) OUT LPDWORD GrantedAccess,
OUT LPBOOL AccessStatus)
{ {
NTSTATUS Status; NTSTATUS Status;
NTSTATUS AccessStat; NTSTATUS NtAccessStatus;
/* Do the access check */
Status = NtAccessCheck(pSecurityDescriptor, Status = NtAccessCheck(pSecurityDescriptor,
ClientToken, ClientToken,
DesiredAccess, DesiredAccess,
@ -155,22 +157,30 @@ AccessCheck(PSECURITY_DESCRIPTOR pSecurityDescriptor,
PrivilegeSet, PrivilegeSet,
(PULONG)PrivilegeSetLength, (PULONG)PrivilegeSetLength,
(PACCESS_MASK)GrantedAccess, (PACCESS_MASK)GrantedAccess,
&AccessStat); &NtAccessStatus);
/* See if the access check operation succeeded */
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
/* Check failed */
SetLastError(RtlNtStatusToDosError(Status)); SetLastError(RtlNtStatusToDosError(Status));
return FALSE; return FALSE;
} }
if (!NT_SUCCESS(AccessStat)) /* Now check the access status */
if (!NT_SUCCESS(NtAccessStatus))
{ {
SetLastError(RtlNtStatusToDosError(Status)); /* Access denied */
SetLastError(RtlNtStatusToDosError(NtAccessStatus));
*AccessStatus = FALSE; *AccessStatus = FALSE;
return TRUE; }
else
{
/* Access granted */
*AccessStatus = TRUE;
} }
*AccessStatus = TRUE; /* Check succeeded */
return TRUE; return TRUE;
} }

View file

@ -619,33 +619,48 @@ SeAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
/* SYSTEM CALLS ***************************************************************/ /* SYSTEM CALLS ***************************************************************/
NTSTATUS NTAPI /*
* @implemented
*/
NTSTATUS
NTAPI
NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor, NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
IN HANDLE TokenHandle, IN HANDLE TokenHandle,
IN ACCESS_MASK DesiredAccess, IN ACCESS_MASK DesiredAccess,
IN PGENERIC_MAPPING GenericMapping, IN PGENERIC_MAPPING GenericMapping,
OUT PPRIVILEGE_SET PrivilegeSet, OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL,
OUT PULONG ReturnLength, IN OUT PULONG PrivilegeSetLength,
OUT PACCESS_MASK GrantedAccess, OUT PACCESS_MASK GrantedAccess,
OUT PNTSTATUS AccessStatus) OUT PNTSTATUS AccessStatus)
{ {
SECURITY_SUBJECT_CONTEXT SubjectSecurityContext = { NULL, 0, NULL, NULL }; SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
KPROCESSOR_MODE PreviousMode; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PTOKEN Token; PTOKEN Token;
NTSTATUS Status; NTSTATUS Status;
PAGED_CODE(); PAGED_CODE();
DPRINT("NtAccessCheck() called\n"); /* Check if this is kernel mode */
PreviousMode = KeGetPreviousMode();
if (PreviousMode == KernelMode) if (PreviousMode == KernelMode)
{ {
*GrantedAccess = DesiredAccess; /* Check if kernel wants everything */
if (DesiredAccess & MAXIMUM_ALLOWED)
{
/* Give it */
*GrantedAccess = GenericMapping->GenericAll;
*GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED);
}
else
{
/* Just give the desired access */
*GrantedAccess = DesiredAccess;
}
/* Success */
*AccessStatus = STATUS_SUCCESS; *AccessStatus = STATUS_SUCCESS;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
/* Reference the token */
Status = ObReferenceObjectByHandle(TokenHandle, Status = ObReferenceObjectByHandle(TokenHandle,
TOKEN_QUERY, TOKEN_QUERY,
SepTokenObjectType, SepTokenObjectType,
@ -657,57 +672,43 @@ NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
DPRINT1("Failed to reference token (Status %lx)\n", Status); DPRINT1("Failed to reference token (Status %lx)\n", Status);
return Status; return Status;
} }
/* Check token type */ /* Check token type */
if (Token->TokenType != TokenImpersonation) if (Token->TokenType != TokenImpersonation)
{ {
DPRINT1("No impersonation token\n"); DPRINT1("No impersonation token\n");
ObDereferenceObject(Token); ObDereferenceObject(Token);
return STATUS_ACCESS_VIOLATION; return STATUS_ACCESS_DENIED;
} }
/* Check impersonation level */ /* Set up the subject context, and lock it */
if (Token->ImpersonationLevel < SecurityIdentification)
{
DPRINT1("Invalid impersonation level\n");
ObDereferenceObject(Token);
return STATUS_ACCESS_VIOLATION;
}
SubjectSecurityContext.ClientToken = Token; SubjectSecurityContext.ClientToken = Token;
SubjectSecurityContext.ImpersonationLevel = Token->ImpersonationLevel; SubjectSecurityContext.ImpersonationLevel = Token->ImpersonationLevel;
SubjectSecurityContext.PrimaryToken = NULL;
/* Lock subject context */ SubjectSecurityContext.ProcessAuditId = NULL;
SeLockSubjectContext(&SubjectSecurityContext); SeLockSubjectContext(&SubjectSecurityContext);
if (SeAccessCheck(SecurityDescriptor, /* Now perform the access check */
&SubjectSecurityContext, SeAccessCheck(SecurityDescriptor,
TRUE, &SubjectSecurityContext,
DesiredAccess, TRUE,
0, DesiredAccess,
&PrivilegeSet, 0,
GenericMapping, &PrivilegeSet, //FIXME
PreviousMode, GenericMapping,
GrantedAccess, PreviousMode,
AccessStatus)) GrantedAccess,
{ AccessStatus);
Status = *AccessStatus;
} /* Unlock subject context and dereference the token */
else
{
Status = STATUS_ACCESS_DENIED;
}
/* Unlock subject context */
SeUnlockSubjectContext(&SubjectSecurityContext); SeUnlockSubjectContext(&SubjectSecurityContext);
ObDereferenceObject(Token); ObDereferenceObject(Token);
DPRINT("NtAccessCheck() done\n"); /* Check succeeded */
return STATUS_SUCCESS;
return Status;
} }
NTSTATUS NTSTATUS
NTAPI NTAPI
NtAccessCheckByType(IN PSECURITY_DESCRIPTOR SecurityDescriptor, NtAccessCheckByType(IN PSECURITY_DESCRIPTOR SecurityDescriptor,