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 **********************************************************/
25 SepAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
26 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
,
27 IN ACCESS_MASK DesiredAccess
,
28 IN POBJECT_TYPE_LIST ObjectTypeList
,
29 IN ULONG ObjectTypeListLength
,
30 IN ACCESS_MASK PreviouslyGrantedAccess
,
31 OUT PPRIVILEGE_SET
* Privileges
,
32 IN PGENERIC_MAPPING GenericMapping
,
33 IN KPROCESSOR_MODE AccessMode
,
34 OUT PACCESS_MASK GrantedAccessList
,
35 OUT PNTSTATUS AccessStatusList
,
36 IN BOOLEAN UseResultList
)
38 ACCESS_MASK RemainingAccess
;
39 ACCESS_MASK TempAccess
;
40 ACCESS_MASK TempGrantedAccess
= 0;
41 ACCESS_MASK TempDeniedAccess
= 0;
43 ULONG i
, ResultListLength
;
52 DPRINT("SepAccessCheck()\n");
54 /* Check for no access desired */
57 /* Check if we had no previous access */
58 if (!PreviouslyGrantedAccess
)
60 /* Then there's nothing to give */
61 Status
= STATUS_ACCESS_DENIED
;
62 goto ReturnCommonStatus
;
65 /* Return the previous access only */
66 Status
= STATUS_SUCCESS
;
68 goto ReturnCommonStatus
;
71 /* Map given accesses */
72 RtlMapGenericMask(&DesiredAccess
, GenericMapping
);
73 if (PreviouslyGrantedAccess
)
74 RtlMapGenericMask(&PreviouslyGrantedAccess
, GenericMapping
);
76 /* Initialize remaining access rights */
77 RemainingAccess
= DesiredAccess
;
79 Token
= SubjectSecurityContext
->ClientToken
?
80 SubjectSecurityContext
->ClientToken
: SubjectSecurityContext
->PrimaryToken
;
82 /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */
83 Status
= SePrivilegePolicyCheck(&RemainingAccess
,
84 &PreviouslyGrantedAccess
,
89 if (!NT_SUCCESS(Status
))
91 goto ReturnCommonStatus
;
94 /* Succeed if there are no more rights to grant */
95 if (RemainingAccess
== 0)
97 Status
= STATUS_SUCCESS
;
98 goto ReturnCommonStatus
;
102 Status
= RtlGetDaclSecurityDescriptor(SecurityDescriptor
,
106 if (!NT_SUCCESS(Status
))
108 goto ReturnCommonStatus
;
111 /* RULE 1: Grant desired access if the object is unprotected */
112 if (Present
== FALSE
|| Dacl
== NULL
)
114 PreviouslyGrantedAccess
|= RemainingAccess
;
115 if (RemainingAccess
& MAXIMUM_ALLOWED
)
117 PreviouslyGrantedAccess
&= ~MAXIMUM_ALLOWED
;
118 PreviouslyGrantedAccess
|= GenericMapping
->GenericAll
;
121 Status
= STATUS_SUCCESS
;
122 goto ReturnCommonStatus
;
125 /* Deny access if the DACL is empty */
126 if (Dacl
->AceCount
== 0)
128 if (RemainingAccess
== MAXIMUM_ALLOWED
&& PreviouslyGrantedAccess
!= 0)
130 Status
= STATUS_SUCCESS
;
134 PreviouslyGrantedAccess
= 0;
135 Status
= STATUS_ACCESS_DENIED
;
137 goto ReturnCommonStatus
;
140 /* Determine the MAXIMUM_ALLOWED access rights according to the DACL */
141 if (DesiredAccess
& MAXIMUM_ALLOWED
)
143 CurrentAce
= (PACE
)(Dacl
+ 1);
144 for (i
= 0; i
< Dacl
->AceCount
; i
++)
146 if (!(CurrentAce
->Header
.AceFlags
& INHERIT_ONLY_ACE
))
148 Sid
= (PSID
)(CurrentAce
+ 1);
149 if (CurrentAce
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
)
151 if (SepSidInToken(Token
, Sid
))
153 /* Map access rights from the ACE */
154 TempAccess
= CurrentAce
->AccessMask
;
155 RtlMapGenericMask(&TempAccess
, GenericMapping
);
157 /* Deny access rights that have not been granted yet */
158 TempDeniedAccess
|= (TempAccess
& ~TempGrantedAccess
);
161 else if (CurrentAce
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
)
163 if (SepSidInToken(Token
, Sid
))
165 /* Map access rights from the ACE */
166 TempAccess
= CurrentAce
->AccessMask
;
167 RtlMapGenericMask(&TempAccess
, GenericMapping
);
169 /* Grant access rights that have not been denied yet */
170 TempGrantedAccess
|= (TempAccess
& ~TempDeniedAccess
);
175 DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce
->Header
.AceType
);
179 /* Get the next ACE */
180 CurrentAce
= (PACE
)((ULONG_PTR
)CurrentAce
+ CurrentAce
->Header
.AceSize
);
183 /* Fail if some rights have not been granted */
184 RemainingAccess
&= ~(MAXIMUM_ALLOWED
| TempGrantedAccess
);
185 if (RemainingAccess
!= 0)
187 PreviouslyGrantedAccess
= 0;
188 Status
= STATUS_ACCESS_DENIED
;
189 goto ReturnCommonStatus
;
192 /* Set granted access right and access status */
193 PreviouslyGrantedAccess
|= TempGrantedAccess
;
194 if (PreviouslyGrantedAccess
!= 0)
196 Status
= STATUS_SUCCESS
;
200 Status
= STATUS_ACCESS_DENIED
;
202 goto ReturnCommonStatus
;
205 /* RULE 4: Grant rights according to the DACL */
206 CurrentAce
= (PACE
)(Dacl
+ 1);
207 for (i
= 0; i
< Dacl
->AceCount
; i
++)
209 if (!(CurrentAce
->Header
.AceFlags
& INHERIT_ONLY_ACE
))
211 Sid
= (PSID
)(CurrentAce
+ 1);
212 if (CurrentAce
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
)
214 if (SepSidInToken(Token
, Sid
))
216 /* Map access rights from the ACE */
217 TempAccess
= CurrentAce
->AccessMask
;
218 RtlMapGenericMask(&TempAccess
, GenericMapping
);
220 /* Leave if a remaining right must be denied */
221 if (RemainingAccess
& TempAccess
)
225 else if (CurrentAce
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
)
227 if (SepSidInToken(Token
, Sid
))
229 /* Map access rights from the ACE */
230 TempAccess
= CurrentAce
->AccessMask
;
231 DPRINT("TempAccess 0x%08lx\n", TempAccess
);
232 RtlMapGenericMask(&TempAccess
, GenericMapping
);
234 /* Remove granted rights */
235 DPRINT("RemainingAccess 0x%08lx TempAccess 0x%08lx\n", RemainingAccess
, TempAccess
);
236 RemainingAccess
&= ~TempAccess
;
237 DPRINT("RemainingAccess 0x%08lx\n", RemainingAccess
);
242 DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce
->Header
.AceType
);
246 /* Get the next ACE */
247 CurrentAce
= (PACE
)((ULONG_PTR
)CurrentAce
+ CurrentAce
->Header
.AceSize
);
250 DPRINT("DesiredAccess %08lx\nPreviouslyGrantedAccess %08lx\nRemainingAccess %08lx\n",
251 DesiredAccess
, PreviouslyGrantedAccess
, RemainingAccess
);
253 /* Fail if some rights have not been granted */
254 if (RemainingAccess
!= 0)
256 DPRINT("HACK: RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", RemainingAccess
, DesiredAccess
);
259 Status
= STATUS_ACCESS_DENIED
;
260 goto ReturnCommonStatus
;
264 /* Set granted access rights */
265 PreviouslyGrantedAccess
|= DesiredAccess
;
267 /* Fail if no rights have been granted */
268 if (PreviouslyGrantedAccess
== 0)
270 DPRINT1("PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess
);
271 Status
= STATUS_ACCESS_DENIED
;
272 goto ReturnCommonStatus
;
275 Status
= STATUS_SUCCESS
;
276 goto ReturnCommonStatus
;
279 ResultListLength
= UseResultList
? ObjectTypeListLength
: 1;
280 for (i
= 0; i
< ResultListLength
; i
++)
282 GrantedAccessList
[i
] = PreviouslyGrantedAccess
;
283 AccessStatusList
[i
] = Status
;
286 return NT_SUCCESS(Status
);
290 SepGetSDOwner(IN PSECURITY_DESCRIPTOR _SecurityDescriptor
)
292 PISECURITY_DESCRIPTOR SecurityDescriptor
= _SecurityDescriptor
;
295 if (SecurityDescriptor
->Control
& SE_SELF_RELATIVE
)
296 Owner
= (PSID
)((ULONG_PTR
)SecurityDescriptor
->Owner
+
297 (ULONG_PTR
)SecurityDescriptor
);
299 Owner
= (PSID
)SecurityDescriptor
->Owner
;
305 SepGetSDGroup(IN PSECURITY_DESCRIPTOR _SecurityDescriptor
)
307 PISECURITY_DESCRIPTOR SecurityDescriptor
= _SecurityDescriptor
;
310 if (SecurityDescriptor
->Control
& SE_SELF_RELATIVE
)
311 Group
= (PSID
)((ULONG_PTR
)SecurityDescriptor
->Group
+
312 (ULONG_PTR
)SecurityDescriptor
);
314 Group
= (PSID
)SecurityDescriptor
->Group
;
320 /* PUBLIC FUNCTIONS ***********************************************************/
327 SeAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
328 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
,
329 IN BOOLEAN SubjectContextLocked
,
330 IN ACCESS_MASK DesiredAccess
,
331 IN ACCESS_MASK PreviouslyGrantedAccess
,
332 OUT PPRIVILEGE_SET
* Privileges
,
333 IN PGENERIC_MAPPING GenericMapping
,
334 IN KPROCESSOR_MODE AccessMode
,
335 OUT PACCESS_MASK GrantedAccess
,
336 OUT PNTSTATUS AccessStatus
)
342 /* Check if this is kernel mode */
343 if (AccessMode
== KernelMode
)
345 /* Check if kernel wants everything */
346 if (DesiredAccess
& MAXIMUM_ALLOWED
)
349 *GrantedAccess
= GenericMapping
->GenericAll
;
350 *GrantedAccess
|= (DesiredAccess
&~ MAXIMUM_ALLOWED
);
351 *GrantedAccess
|= PreviouslyGrantedAccess
;
355 /* Give the desired and previous access */
356 *GrantedAccess
= DesiredAccess
| PreviouslyGrantedAccess
;
360 *AccessStatus
= STATUS_SUCCESS
;
364 /* Check if we didn't get an SD */
365 if (!SecurityDescriptor
)
367 /* Automatic failure */
368 *AccessStatus
= STATUS_ACCESS_DENIED
;
372 /* Check for invalid impersonation */
373 if ((SubjectSecurityContext
->ClientToken
) &&
374 (SubjectSecurityContext
->ImpersonationLevel
< SecurityImpersonation
))
376 *AccessStatus
= STATUS_BAD_IMPERSONATION_LEVEL
;
380 /* Acquire the lock if needed */
381 if (!SubjectContextLocked
)
382 SeLockSubjectContext(SubjectSecurityContext
);
384 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
385 if (DesiredAccess
& (WRITE_DAC
| READ_CONTROL
| MAXIMUM_ALLOWED
))
387 PACCESS_TOKEN Token
= SubjectSecurityContext
->ClientToken
?
388 SubjectSecurityContext
->ClientToken
: SubjectSecurityContext
->PrimaryToken
;
390 if (SepTokenIsOwner(Token
,
394 if (DesiredAccess
& MAXIMUM_ALLOWED
)
395 PreviouslyGrantedAccess
|= (WRITE_DAC
| READ_CONTROL
);
397 PreviouslyGrantedAccess
|= (DesiredAccess
& (WRITE_DAC
| READ_CONTROL
));
399 DesiredAccess
&= ~(WRITE_DAC
| READ_CONTROL
);
403 if (DesiredAccess
== 0)
405 *GrantedAccess
= PreviouslyGrantedAccess
;
406 if (PreviouslyGrantedAccess
== 0)
408 DPRINT1("Request for zero access to an object. Denying.\n");
409 *AccessStatus
= STATUS_ACCESS_DENIED
;
414 *AccessStatus
= STATUS_SUCCESS
;
420 /* Call the internal function */
421 ret
= SepAccessCheck(SecurityDescriptor
,
422 SubjectSecurityContext
,
426 PreviouslyGrantedAccess
,
435 /* Release the lock if needed */
436 if (!SubjectContextLocked
)
437 SeUnlockSubjectContext(SubjectSecurityContext
);
447 SeFastTraverseCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
448 IN PACCESS_STATE AccessState
,
449 IN ACCESS_MASK DesiredAccess
,
450 IN KPROCESSOR_MODE AccessMode
)
458 ASSERT(AccessMode
!= KernelMode
);
460 if (SecurityDescriptor
== NULL
)
464 Dacl
= SepGetDaclFromDescriptor(SecurityDescriptor
);
465 /* If no DACL, grant access */
473 /* Can't perform the check on restricted token */
474 if (AccessState
->Flags
& TOKEN_IS_RESTRICTED
)
477 /* Browse the ACEs */
478 for (AceIndex
= 0, Ace
= (PKNOWN_ACE
)((ULONG_PTR
)Dacl
+ sizeof(ACL
));
479 AceIndex
< Dacl
->AceCount
;
480 AceIndex
++, Ace
= (PKNOWN_ACE
)((ULONG_PTR
)Ace
+ Ace
->Header
.AceSize
))
482 if (Ace
->Header
.AceFlags
& INHERIT_ONLY_ACE
)
485 /* If access-allowed ACE */
486 if (Ace
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
)
488 /* Check if all accesses are granted */
489 if (!(Ace
->Mask
& DesiredAccess
))
492 /* Check SID and grant access if matching */
493 if (RtlEqualSid(SeWorldSid
, &(Ace
->SidStart
)))
496 /* If access-denied ACE */
497 else if (Ace
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
)
499 /* Here, only check if it denies any access wanted and deny if so */
500 if (Ace
->Mask
& DesiredAccess
)
509 /* SYSTEM CALLS ***************************************************************/
516 NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
517 IN HANDLE TokenHandle
,
518 IN ACCESS_MASK DesiredAccess
,
519 IN PGENERIC_MAPPING GenericMapping
,
520 OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL
,
521 IN OUT PULONG PrivilegeSetLength
,
522 OUT PACCESS_MASK GrantedAccess
,
523 OUT PNTSTATUS AccessStatus
)
525 PSECURITY_DESCRIPTOR CapturedSecurityDescriptor
= NULL
;
526 SECURITY_SUBJECT_CONTEXT SubjectSecurityContext
;
527 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
528 ACCESS_MASK PreviouslyGrantedAccess
= 0;
533 /* Check if this is kernel mode */
534 if (PreviousMode
== KernelMode
)
536 /* Check if kernel wants everything */
537 if (DesiredAccess
& MAXIMUM_ALLOWED
)
540 *GrantedAccess
= GenericMapping
->GenericAll
;
541 *GrantedAccess
|= (DesiredAccess
&~ MAXIMUM_ALLOWED
);
545 /* Just give the desired access */
546 *GrantedAccess
= DesiredAccess
;
550 *AccessStatus
= STATUS_SUCCESS
;
551 return STATUS_SUCCESS
;
554 /* Protect probe in SEH */
557 /* Probe all pointers */
558 ProbeForRead(GenericMapping
, sizeof(GENERIC_MAPPING
), sizeof(ULONG
));
559 ProbeForRead(PrivilegeSetLength
, sizeof(ULONG
), sizeof(ULONG
));
560 ProbeForWrite(PrivilegeSet
, *PrivilegeSetLength
, sizeof(ULONG
));
561 ProbeForWrite(GrantedAccess
, sizeof(ACCESS_MASK
), sizeof(ULONG
));
562 ProbeForWrite(AccessStatus
, sizeof(NTSTATUS
), sizeof(ULONG
));
564 /* Initialize the privilege set */
565 PrivilegeSet
->PrivilegeCount
= 0;
567 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
569 /* Return the exception code */
570 _SEH2_YIELD(return _SEH2_GetExceptionCode());
574 /* Check for unmapped access rights */
575 if (DesiredAccess
& (GENERIC_READ
| GENERIC_WRITE
| GENERIC_EXECUTE
| GENERIC_ALL
))
576 return STATUS_GENERIC_NOT_MAPPED
;
578 /* Reference the token */
579 Status
= ObReferenceObjectByHandle(TokenHandle
,
585 if (!NT_SUCCESS(Status
))
587 DPRINT("Failed to reference token (Status %lx)\n", Status
);
591 /* Check token type */
592 if (Token
->TokenType
!= TokenImpersonation
)
594 DPRINT("No impersonation token\n");
595 ObDereferenceObject(Token
);
596 return STATUS_NO_IMPERSONATION_TOKEN
;
599 /* Check the impersonation level */
600 if (Token
->ImpersonationLevel
< SecurityIdentification
)
602 DPRINT("Impersonation level < SecurityIdentification\n");
603 ObDereferenceObject(Token
);
604 return STATUS_BAD_IMPERSONATION_LEVEL
;
607 /* Capture the security descriptor */
608 Status
= SeCaptureSecurityDescriptor(SecurityDescriptor
,
612 &CapturedSecurityDescriptor
);
613 if (!NT_SUCCESS(Status
))
615 DPRINT("Failed to capture the Security Descriptor\n");
616 ObDereferenceObject(Token
);
620 /* Check the captured security descriptor */
621 if (CapturedSecurityDescriptor
== NULL
)
623 DPRINT("Security Descriptor is NULL\n");
624 ObDereferenceObject(Token
);
625 return STATUS_INVALID_SECURITY_DESCR
;
628 /* Check security descriptor for valid owner and group */
629 if (SepGetSDOwner(SecurityDescriptor
) == NULL
|| // FIXME: use CapturedSecurityDescriptor
630 SepGetSDGroup(SecurityDescriptor
) == NULL
) // FIXME: use CapturedSecurityDescriptor
632 DPRINT("Security Descriptor does not have a valid group or owner\n");
633 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor
,
636 ObDereferenceObject(Token
);
637 return STATUS_INVALID_SECURITY_DESCR
;
640 /* Set up the subject context, and lock it */
641 SeCaptureSubjectContext(&SubjectSecurityContext
);
644 SepAcquireTokenLockShared(Token
);
646 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
647 if (DesiredAccess
& (WRITE_DAC
| READ_CONTROL
| MAXIMUM_ALLOWED
))
649 if (SepTokenIsOwner(Token
, SecurityDescriptor
, FALSE
)) // FIXME: use CapturedSecurityDescriptor
651 if (DesiredAccess
& MAXIMUM_ALLOWED
)
652 PreviouslyGrantedAccess
|= (WRITE_DAC
| READ_CONTROL
);
654 PreviouslyGrantedAccess
|= (DesiredAccess
& (WRITE_DAC
| READ_CONTROL
));
656 DesiredAccess
&= ~(WRITE_DAC
| READ_CONTROL
);
660 if (DesiredAccess
== 0)
662 *GrantedAccess
= PreviouslyGrantedAccess
;
663 *AccessStatus
= STATUS_SUCCESS
;
667 /* Now perform the access check */
668 SepAccessCheck(SecurityDescriptor
, // FIXME: use CapturedSecurityDescriptor
669 &SubjectSecurityContext
,
673 PreviouslyGrantedAccess
,
674 &PrivilegeSet
, //FIXME
682 /* Release subject context and unlock the token */
683 SeReleaseSubjectContext(&SubjectSecurityContext
);
684 SepReleaseTokenLock(Token
);
686 /* Release the captured security descriptor */
687 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor
,
691 /* Dereference the token */
692 ObDereferenceObject(Token
);
694 /* Check succeeded */
695 return STATUS_SUCCESS
;
701 NtAccessCheckByType(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
702 IN PSID PrincipalSelfSid
,
703 IN HANDLE ClientToken
,
704 IN ACCESS_MASK DesiredAccess
,
705 IN POBJECT_TYPE_LIST ObjectTypeList
,
706 IN ULONG ObjectTypeLength
,
707 IN PGENERIC_MAPPING GenericMapping
,
708 IN PPRIVILEGE_SET PrivilegeSet
,
709 IN OUT PULONG PrivilegeSetLength
,
710 OUT PACCESS_MASK GrantedAccess
,
711 OUT PNTSTATUS AccessStatus
)
714 return STATUS_NOT_IMPLEMENTED
;
719 NtAccessCheckByTypeResultList(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
720 IN PSID PrincipalSelfSid
,
721 IN HANDLE ClientToken
,
722 IN ACCESS_MASK DesiredAccess
,
723 IN POBJECT_TYPE_LIST ObjectTypeList
,
724 IN ULONG ObjectTypeLength
,
725 IN PGENERIC_MAPPING GenericMapping
,
726 IN PPRIVILEGE_SET PrivilegeSet
,
727 IN OUT PULONG PrivilegeSetLength
,
728 OUT PACCESS_MASK GrantedAccess
,
729 OUT PNTSTATUS AccessStatus
)
732 return STATUS_NOT_IMPLEMENTED
;