2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/se/accesschk.c
5 * PURPOSE: Security manager
7 * PROGRAMMERS: No programmer listed.
10 /* INCLUDES *******************************************************************/
16 /* GLOBALS ********************************************************************/
19 /* PRIVATE FUNCTIONS **********************************************************/
21 #define OLD_ACCESS_CHECK
24 SepAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
25 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
,
26 IN ACCESS_MASK DesiredAccess
,
27 IN ACCESS_MASK PreviouslyGrantedAccess
,
28 OUT PPRIVILEGE_SET
* Privileges
,
29 IN PGENERIC_MAPPING GenericMapping
,
30 IN KPROCESSOR_MODE AccessMode
,
31 OUT PACCESS_MASK GrantedAccess
,
32 OUT PNTSTATUS AccessStatus
)
34 #ifdef OLD_ACCESS_CHECK
35 ACCESS_MASK CurrentAccess
, AccessMask
;
37 ACCESS_MASK RemainingAccess
;
38 ACCESS_MASK TempAccess
;
39 ACCESS_MASK TempGrantedAccess
= 0;
40 ACCESS_MASK TempDeniedAccess
= 0;
51 /* Check for no access desired */
54 /* Check if we had no previous access */
55 if (!PreviouslyGrantedAccess
)
57 /* Then there's nothing to give */
58 *AccessStatus
= STATUS_ACCESS_DENIED
;
62 /* Return the previous access only */
63 *GrantedAccess
= PreviouslyGrantedAccess
;
64 *AccessStatus
= STATUS_SUCCESS
;
69 /* Map given accesses */
70 RtlMapGenericMask(&DesiredAccess
, GenericMapping
);
71 if (PreviouslyGrantedAccess
)
72 RtlMapGenericMask(&PreviouslyGrantedAccess
, GenericMapping
);
74 /* Initialize remaining access rights */
75 RemainingAccess
= DesiredAccess
;
77 Token
= SubjectSecurityContext
->ClientToken
?
78 SubjectSecurityContext
->ClientToken
: SubjectSecurityContext
->PrimaryToken
;
80 /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */
81 Status
= SePrivilegePolicyCheck(&RemainingAccess
,
82 &PreviouslyGrantedAccess
,
87 if (!NT_SUCCESS(Status
))
89 *AccessStatus
= Status
;
93 /* Succeed if there are no more rights to grant */
94 if (RemainingAccess
== 0)
96 *GrantedAccess
= PreviouslyGrantedAccess
;
97 *AccessStatus
= STATUS_SUCCESS
;
102 Status
= RtlGetDaclSecurityDescriptor(SecurityDescriptor
,
106 if (!NT_SUCCESS(Status
))
108 *AccessStatus
= Status
;
112 /* RULE 1: Grant desired access if the object is unprotected */
113 if (Present
== FALSE
|| Dacl
== NULL
)
115 if (DesiredAccess
& MAXIMUM_ALLOWED
)
117 *GrantedAccess
= GenericMapping
->GenericAll
;
118 *GrantedAccess
|= (DesiredAccess
& ~MAXIMUM_ALLOWED
);
122 *GrantedAccess
= DesiredAccess
| PreviouslyGrantedAccess
;
125 *AccessStatus
= STATUS_SUCCESS
;
129 #ifdef OLD_ACCESS_CHECK
130 CurrentAccess
= PreviouslyGrantedAccess
;
133 /* Deny access if the DACL is empty */
134 if (Dacl
->AceCount
== 0)
136 if (RemainingAccess
== MAXIMUM_ALLOWED
&& PreviouslyGrantedAccess
!= 0)
138 *GrantedAccess
= PreviouslyGrantedAccess
;
139 *AccessStatus
= STATUS_SUCCESS
;
145 *AccessStatus
= STATUS_ACCESS_DENIED
;
150 /* Fail if DACL is absent */
151 if (Present
== FALSE
)
154 *AccessStatus
= STATUS_ACCESS_DENIED
;
158 /* Determine the MAXIMUM_ALLOWED access rights according to the DACL */
159 if (DesiredAccess
& MAXIMUM_ALLOWED
)
161 CurrentAce
= (PACE
)(Dacl
+ 1);
162 for (i
= 0; i
< Dacl
->AceCount
; i
++)
164 if (!(CurrentAce
->Header
.AceFlags
& INHERIT_ONLY_ACE
))
166 Sid
= (PSID
)(CurrentAce
+ 1);
167 if (CurrentAce
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
)
169 if (SepSidInToken(Token
, Sid
))
171 /* Map access rights from the ACE */
172 TempAccess
= CurrentAce
->AccessMask
;
173 RtlMapGenericMask(&TempAccess
, GenericMapping
);
175 /* Deny access rights that have not been granted yet */
176 TempDeniedAccess
|= (TempAccess
& ~TempGrantedAccess
);
179 else if (CurrentAce
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
)
181 if (SepSidInToken(Token
, Sid
))
183 /* Map access rights from the ACE */
184 TempAccess
= CurrentAce
->AccessMask
;
185 RtlMapGenericMask(&TempAccess
, GenericMapping
);
187 /* Grant access rights that have not been denied yet */
188 TempGrantedAccess
|= (TempAccess
& ~TempDeniedAccess
);
193 DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce
->Header
.AceType
);
197 /* Get the next ACE */
198 CurrentAce
= (PACE
)((ULONG_PTR
)CurrentAce
+ CurrentAce
->Header
.AceSize
);
201 /* Fail if some rights have not been granted */
202 RemainingAccess
&= ~(MAXIMUM_ALLOWED
| TempGrantedAccess
);
203 if (RemainingAccess
!= 0)
206 *AccessStatus
= STATUS_ACCESS_DENIED
;
210 /* Set granted access right and access status */
211 *GrantedAccess
= TempGrantedAccess
| PreviouslyGrantedAccess
;
212 if (*GrantedAccess
!= 0)
214 *AccessStatus
= STATUS_SUCCESS
;
219 *AccessStatus
= STATUS_ACCESS_DENIED
;
224 /* RULE 4: Grant rights according to the DACL */
225 CurrentAce
= (PACE
)(Dacl
+ 1);
226 for (i
= 0; i
< Dacl
->AceCount
; i
++)
228 if (!(CurrentAce
->Header
.AceFlags
& INHERIT_ONLY_ACE
))
230 Sid
= (PSID
)(CurrentAce
+ 1);
231 if (CurrentAce
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
)
233 if (SepSidInToken(Token
, Sid
))
235 #ifdef OLD_ACCESS_CHECK
237 *AccessStatus
= STATUS_ACCESS_DENIED
;
240 /* Map access rights from the ACE */
241 TempAccess
= CurrentAce
->AccessMask
;
242 RtlMapGenericMask(&TempAccess
, GenericMapping
);
244 /* Leave if a remaining right must be denied */
245 if (RemainingAccess
& TempAccess
)
250 else if (CurrentAce
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
)
252 if (SepSidInToken(Token
, Sid
))
254 #ifdef OLD_ACCESS_CHECK
255 AccessMask
= CurrentAce
->AccessMask
;
256 RtlMapGenericMask(&AccessMask
, GenericMapping
);
257 CurrentAccess
|= AccessMask
;
259 /* Map access rights from the ACE */
260 TempAccess
= CurrentAce
->AccessMask
;
261 RtlMapGenericMask(&TempAccess
, GenericMapping
);
263 /* Remove granted rights */
264 RemainingAccess
&= ~TempAccess
;
270 DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce
->Header
.AceType
);
274 /* Get the next ACE */
275 CurrentAce
= (PACE
)((ULONG_PTR
)CurrentAce
+ CurrentAce
->Header
.AceSize
);
278 #ifdef OLD_ACCESS_CHECK
279 DPRINT("CurrentAccess %08lx\n DesiredAccess %08lx\n",
280 CurrentAccess
, DesiredAccess
);
282 *GrantedAccess
= CurrentAccess
& DesiredAccess
;
284 if ((*GrantedAccess
& ~VALID_INHERIT_FLAGS
) ==
285 (DesiredAccess
& ~VALID_INHERIT_FLAGS
))
287 *AccessStatus
= STATUS_SUCCESS
;
292 DPRINT1("HACK: Should deny access for caller: granted 0x%lx, desired 0x%lx (generic mapping %p).\n",
293 *GrantedAccess
, DesiredAccess
, GenericMapping
);
294 //*AccessStatus = STATUS_ACCESS_DENIED;
296 *GrantedAccess
= DesiredAccess
;
297 *AccessStatus
= STATUS_SUCCESS
;
301 DPRINT("DesiredAccess %08lx\nPreviouslyGrantedAccess %08lx\nRemainingAccess %08lx\n",
302 DesiredAccess
, PreviouslyGrantedAccess
, RemainingAccess
);
304 /* Fail if some rights have not been granted */
305 if (RemainingAccess
!= 0)
308 *AccessStatus
= STATUS_ACCESS_DENIED
;
312 /* Set granted access rights */
313 *GrantedAccess
= DesiredAccess
| PreviouslyGrantedAccess
;
315 DPRINT("GrantedAccess %08lx\n", *GrantedAccess
);
317 /* Fail if no rights have been granted */
318 if (*GrantedAccess
== 0)
320 *AccessStatus
= STATUS_ACCESS_DENIED
;
324 *AccessStatus
= STATUS_SUCCESS
;
330 SepGetSDOwner(IN PSECURITY_DESCRIPTOR _SecurityDescriptor
)
332 PISECURITY_DESCRIPTOR SecurityDescriptor
= _SecurityDescriptor
;
335 if (SecurityDescriptor
->Control
& SE_SELF_RELATIVE
)
336 Owner
= (PSID
)((ULONG_PTR
)SecurityDescriptor
->Owner
+
337 (ULONG_PTR
)SecurityDescriptor
);
339 Owner
= (PSID
)SecurityDescriptor
->Owner
;
345 SepGetSDGroup(IN PSECURITY_DESCRIPTOR _SecurityDescriptor
)
347 PISECURITY_DESCRIPTOR SecurityDescriptor
= _SecurityDescriptor
;
350 if (SecurityDescriptor
->Control
& SE_SELF_RELATIVE
)
351 Group
= (PSID
)((ULONG_PTR
)SecurityDescriptor
->Group
+
352 (ULONG_PTR
)SecurityDescriptor
);
354 Group
= (PSID
)SecurityDescriptor
->Group
;
360 /* PUBLIC FUNCTIONS ***********************************************************/
367 SeAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
368 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
,
369 IN BOOLEAN SubjectContextLocked
,
370 IN ACCESS_MASK DesiredAccess
,
371 IN ACCESS_MASK PreviouslyGrantedAccess
,
372 OUT PPRIVILEGE_SET
* Privileges
,
373 IN PGENERIC_MAPPING GenericMapping
,
374 IN KPROCESSOR_MODE AccessMode
,
375 OUT PACCESS_MASK GrantedAccess
,
376 OUT PNTSTATUS AccessStatus
)
382 /* Check if this is kernel mode */
383 if (AccessMode
== KernelMode
)
385 /* Check if kernel wants everything */
386 if (DesiredAccess
& MAXIMUM_ALLOWED
)
389 *GrantedAccess
= GenericMapping
->GenericAll
;
390 *GrantedAccess
|= (DesiredAccess
&~ MAXIMUM_ALLOWED
);
391 *GrantedAccess
|= PreviouslyGrantedAccess
;
395 /* Give the desired and previous access */
396 *GrantedAccess
= DesiredAccess
| PreviouslyGrantedAccess
;
400 *AccessStatus
= STATUS_SUCCESS
;
404 /* Check if we didn't get an SD */
405 if (!SecurityDescriptor
)
407 /* Automatic failure */
408 *AccessStatus
= STATUS_ACCESS_DENIED
;
412 /* Check for invalid impersonation */
413 if ((SubjectSecurityContext
->ClientToken
) &&
414 (SubjectSecurityContext
->ImpersonationLevel
< SecurityImpersonation
))
416 *AccessStatus
= STATUS_BAD_IMPERSONATION_LEVEL
;
420 /* Acquire the lock if needed */
421 if (!SubjectContextLocked
)
422 SeLockSubjectContext(SubjectSecurityContext
);
424 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
425 if (DesiredAccess
& (WRITE_DAC
| READ_CONTROL
| MAXIMUM_ALLOWED
))
427 PACCESS_TOKEN Token
= SubjectSecurityContext
->ClientToken
?
428 SubjectSecurityContext
->ClientToken
: SubjectSecurityContext
->PrimaryToken
;
430 if (SepTokenIsOwner(Token
,
434 if (DesiredAccess
& MAXIMUM_ALLOWED
)
435 PreviouslyGrantedAccess
|= (WRITE_DAC
| READ_CONTROL
);
437 PreviouslyGrantedAccess
|= (DesiredAccess
& (WRITE_DAC
| READ_CONTROL
));
439 DesiredAccess
&= ~(WRITE_DAC
| READ_CONTROL
);
443 if (DesiredAccess
== 0)
445 *GrantedAccess
= PreviouslyGrantedAccess
;
446 *AccessStatus
= STATUS_SUCCESS
;
451 /* Call the internal function */
452 ret
= SepAccessCheck(SecurityDescriptor
,
453 SubjectSecurityContext
,
455 PreviouslyGrantedAccess
,
463 /* Release the lock if needed */
464 if (!SubjectContextLocked
)
465 SeUnlockSubjectContext(SubjectSecurityContext
);
475 SeFastTraverseCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
476 IN PACCESS_STATE AccessState
,
477 IN ACCESS_MASK DesiredAccess
,
478 IN KPROCESSOR_MODE AccessMode
)
486 NT_ASSERT(AccessMode
!= KernelMode
);
488 if (SecurityDescriptor
== NULL
)
492 Dacl
= SepGetDaclFromDescriptor(SecurityDescriptor
);
493 /* If no DACL, grant access */
501 /* Can't perform the check on restricted token */
502 if (AccessState
->Flags
& TOKEN_IS_RESTRICTED
)
505 /* Browse the ACEs */
506 for (AceIndex
= 0, Ace
= (PKNOWN_ACE
)((ULONG_PTR
)Dacl
+ sizeof(ACL
));
507 AceIndex
< Dacl
->AceCount
;
508 AceIndex
++, Ace
= (PKNOWN_ACE
)((ULONG_PTR
)Ace
+ Ace
->Header
.AceSize
))
510 if (Ace
->Header
.AceFlags
& INHERIT_ONLY_ACE
)
513 /* If access-allowed ACE */
514 if (Ace
->Header
.AceType
& ACCESS_ALLOWED_ACE_TYPE
)
516 /* Check if all accesses are granted */
517 if (!(Ace
->Mask
& DesiredAccess
))
520 /* Check SID and grant access if matching */
521 if (RtlEqualSid(SeWorldSid
, &(Ace
->SidStart
)))
524 /* If access-denied ACE */
525 else if (Ace
->Header
.AceType
& ACCESS_DENIED_ACE_TYPE
)
527 /* Here, only check if it denies all the access wanted and deny if so */
528 if (Ace
->Mask
& DesiredAccess
)
537 /* SYSTEM CALLS ***************************************************************/
544 NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
545 IN HANDLE TokenHandle
,
546 IN ACCESS_MASK DesiredAccess
,
547 IN PGENERIC_MAPPING GenericMapping
,
548 OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL
,
549 IN OUT PULONG PrivilegeSetLength
,
550 OUT PACCESS_MASK GrantedAccess
,
551 OUT PNTSTATUS AccessStatus
)
553 PSECURITY_DESCRIPTOR CapturedSecurityDescriptor
= NULL
;
554 SECURITY_SUBJECT_CONTEXT SubjectSecurityContext
;
555 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
556 ACCESS_MASK PreviouslyGrantedAccess
= 0;
561 /* Check if this is kernel mode */
562 if (PreviousMode
== KernelMode
)
564 /* Check if kernel wants everything */
565 if (DesiredAccess
& MAXIMUM_ALLOWED
)
568 *GrantedAccess
= GenericMapping
->GenericAll
;
569 *GrantedAccess
|= (DesiredAccess
&~ MAXIMUM_ALLOWED
);
573 /* Just give the desired access */
574 *GrantedAccess
= DesiredAccess
;
578 *AccessStatus
= STATUS_SUCCESS
;
579 return STATUS_SUCCESS
;
582 /* Protect probe in SEH */
585 /* Probe all pointers */
586 ProbeForRead(GenericMapping
, sizeof(GENERIC_MAPPING
), sizeof(ULONG
));
587 ProbeForRead(PrivilegeSetLength
, sizeof(ULONG
), sizeof(ULONG
));
588 ProbeForWrite(PrivilegeSet
, *PrivilegeSetLength
, sizeof(ULONG
));
589 ProbeForWrite(GrantedAccess
, sizeof(ACCESS_MASK
), sizeof(ULONG
));
590 ProbeForWrite(AccessStatus
, sizeof(NTSTATUS
), sizeof(ULONG
));
592 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
594 /* Return the exception code */
595 _SEH2_YIELD(return _SEH2_GetExceptionCode());
599 /* Check for unmapped access rights */
600 if (DesiredAccess
& (GENERIC_READ
| GENERIC_WRITE
| GENERIC_EXECUTE
| GENERIC_ALL
))
601 return STATUS_GENERIC_NOT_MAPPED
;
603 /* Reference the token */
604 Status
= ObReferenceObjectByHandle(TokenHandle
,
610 if (!NT_SUCCESS(Status
))
612 DPRINT("Failed to reference token (Status %lx)\n", Status
);
616 /* Check token type */
617 if (Token
->TokenType
!= TokenImpersonation
)
619 DPRINT("No impersonation token\n");
620 ObDereferenceObject(Token
);
621 return STATUS_NO_IMPERSONATION_TOKEN
;
624 /* Check the impersonation level */
625 if (Token
->ImpersonationLevel
< SecurityIdentification
)
627 DPRINT("Impersonation level < SecurityIdentification\n");
628 ObDereferenceObject(Token
);
629 return STATUS_BAD_IMPERSONATION_LEVEL
;
632 /* Capture the security descriptor */
633 Status
= SeCaptureSecurityDescriptor(SecurityDescriptor
,
637 &CapturedSecurityDescriptor
);
638 if (!NT_SUCCESS(Status
))
640 DPRINT("Failed to capture the Security Descriptor\n");
641 ObDereferenceObject(Token
);
645 /* Check the captured security descriptor */
646 if (CapturedSecurityDescriptor
== NULL
)
648 DPRINT("Security Descriptor is NULL\n");
649 ObDereferenceObject(Token
);
650 return STATUS_INVALID_SECURITY_DESCR
;
653 /* Check security descriptor for valid owner and group */
654 if (SepGetSDOwner(SecurityDescriptor
) == NULL
|| // FIXME: use CapturedSecurityDescriptor
655 SepGetSDGroup(SecurityDescriptor
) == NULL
) // FIXME: use CapturedSecurityDescriptor
657 DPRINT("Security Descriptor does not have a valid group or owner\n");
658 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor
,
661 ObDereferenceObject(Token
);
662 return STATUS_INVALID_SECURITY_DESCR
;
665 /* Set up the subject context, and lock it */
666 SeCaptureSubjectContext(&SubjectSecurityContext
);
669 SepAcquireTokenLockShared(Token
);
671 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
672 if (DesiredAccess
& (WRITE_DAC
| READ_CONTROL
| MAXIMUM_ALLOWED
))
674 if (SepTokenIsOwner(Token
, SecurityDescriptor
, FALSE
)) // FIXME: use CapturedSecurityDescriptor
676 if (DesiredAccess
& MAXIMUM_ALLOWED
)
677 PreviouslyGrantedAccess
|= (WRITE_DAC
| READ_CONTROL
);
679 PreviouslyGrantedAccess
|= (DesiredAccess
& (WRITE_DAC
| READ_CONTROL
));
681 DesiredAccess
&= ~(WRITE_DAC
| READ_CONTROL
);
685 if (DesiredAccess
== 0)
687 *GrantedAccess
= PreviouslyGrantedAccess
;
688 *AccessStatus
= STATUS_SUCCESS
;
692 /* Now perform the access check */
693 SepAccessCheck(SecurityDescriptor
, // FIXME: use CapturedSecurityDescriptor
694 &SubjectSecurityContext
,
696 PreviouslyGrantedAccess
,
697 &PrivilegeSet
, //FIXME
704 /* Release subject context and unlock the token */
705 SeReleaseSubjectContext(&SubjectSecurityContext
);
706 SepReleaseTokenLock(Token
);
708 /* Release the captured security descriptor */
709 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor
,
713 /* Dereference the token */
714 ObDereferenceObject(Token
);
716 /* Check succeeded */
717 return STATUS_SUCCESS
;
723 NtAccessCheckByType(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
724 IN PSID PrincipalSelfSid
,
725 IN HANDLE ClientToken
,
726 IN ACCESS_MASK DesiredAccess
,
727 IN POBJECT_TYPE_LIST ObjectTypeList
,
728 IN ULONG ObjectTypeLength
,
729 IN PGENERIC_MAPPING GenericMapping
,
730 IN PPRIVILEGE_SET PrivilegeSet
,
731 IN OUT PULONG PrivilegeSetLength
,
732 OUT PACCESS_MASK GrantedAccess
,
733 OUT PNTSTATUS AccessStatus
)
736 return STATUS_NOT_IMPLEMENTED
;
741 NtAccessCheckByTypeResultList(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
742 IN PSID PrincipalSelfSid
,
743 IN HANDLE ClientToken
,
744 IN ACCESS_MASK DesiredAccess
,
745 IN POBJECT_TYPE_LIST ObjectTypeList
,
746 IN ULONG ObjectTypeLength
,
747 IN PGENERIC_MAPPING GenericMapping
,
748 IN PPRIVILEGE_SET PrivilegeSet
,
749 IN OUT PULONG PrivilegeSetLength
,
750 OUT PACCESS_MASK GrantedAccess
,
751 OUT PNTSTATUS AccessStatus
)
754 return STATUS_NOT_IMPLEMENTED
;