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 **********************************************************/
22 SepAccessCheckEx(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
23 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
,
24 IN ACCESS_MASK DesiredAccess
,
25 IN POBJECT_TYPE_LIST ObjectTypeList
,
26 IN ULONG ObjectTypeListLength
,
27 IN ACCESS_MASK PreviouslyGrantedAccess
,
28 OUT PPRIVILEGE_SET
* Privileges
,
29 IN PGENERIC_MAPPING GenericMapping
,
30 IN KPROCESSOR_MODE AccessMode
,
31 OUT PACCESS_MASK GrantedAccessList
,
32 OUT PNTSTATUS AccessStatusList
,
33 IN BOOLEAN UseResultList
)
35 ACCESS_MASK RemainingAccess
;
36 ACCESS_MASK TempAccess
;
37 ACCESS_MASK TempGrantedAccess
= 0;
38 ACCESS_MASK TempDeniedAccess
= 0;
40 ULONG i
, ResultListLength
;
49 DPRINT("SepAccessCheckEx()\n");
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 Status
= STATUS_ACCESS_DENIED
;
59 goto ReturnCommonStatus
;
62 /* Return the previous access only */
63 Status
= STATUS_SUCCESS
;
65 goto ReturnCommonStatus
;
68 /* Map given accesses */
69 RtlMapGenericMask(&DesiredAccess
, GenericMapping
);
70 if (PreviouslyGrantedAccess
)
71 RtlMapGenericMask(&PreviouslyGrantedAccess
, GenericMapping
);
73 /* Initialize remaining access rights */
74 RemainingAccess
= DesiredAccess
;
76 Token
= SubjectSecurityContext
->ClientToken
?
77 SubjectSecurityContext
->ClientToken
: SubjectSecurityContext
->PrimaryToken
;
79 /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */
80 Status
= SePrivilegePolicyCheck(&RemainingAccess
,
81 &PreviouslyGrantedAccess
,
86 if (!NT_SUCCESS(Status
))
88 goto ReturnCommonStatus
;
91 /* Succeed if there are no more rights to grant */
92 if (RemainingAccess
== 0)
94 Status
= STATUS_SUCCESS
;
95 goto ReturnCommonStatus
;
99 Status
= RtlGetDaclSecurityDescriptor(SecurityDescriptor
,
103 if (!NT_SUCCESS(Status
))
105 goto ReturnCommonStatus
;
108 /* RULE 1: Grant desired access if the object is unprotected */
109 if (Present
== FALSE
|| Dacl
== NULL
)
111 PreviouslyGrantedAccess
|= RemainingAccess
;
112 if (RemainingAccess
& MAXIMUM_ALLOWED
)
114 PreviouslyGrantedAccess
&= ~MAXIMUM_ALLOWED
;
115 PreviouslyGrantedAccess
|= GenericMapping
->GenericAll
;
118 Status
= STATUS_SUCCESS
;
119 goto ReturnCommonStatus
;
122 /* Deny access if the DACL is empty */
123 if (Dacl
->AceCount
== 0)
125 if (RemainingAccess
== MAXIMUM_ALLOWED
&& PreviouslyGrantedAccess
!= 0)
127 Status
= STATUS_SUCCESS
;
131 PreviouslyGrantedAccess
= 0;
132 Status
= STATUS_ACCESS_DENIED
;
134 goto ReturnCommonStatus
;
137 /* Determine the MAXIMUM_ALLOWED access rights according to the DACL */
138 if (DesiredAccess
& MAXIMUM_ALLOWED
)
140 CurrentAce
= (PACE
)(Dacl
+ 1);
141 for (i
= 0; i
< Dacl
->AceCount
; i
++)
143 if (!(CurrentAce
->Header
.AceFlags
& INHERIT_ONLY_ACE
))
145 Sid
= (PSID
)(CurrentAce
+ 1);
146 if (CurrentAce
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
)
148 if (SepSidInToken(Token
, Sid
))
150 /* Map access rights from the ACE */
151 TempAccess
= CurrentAce
->AccessMask
;
152 RtlMapGenericMask(&TempAccess
, GenericMapping
);
154 /* Deny access rights that have not been granted yet */
155 TempDeniedAccess
|= (TempAccess
& ~TempGrantedAccess
);
158 else if (CurrentAce
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
)
160 if (SepSidInToken(Token
, Sid
))
162 /* Map access rights from the ACE */
163 TempAccess
= CurrentAce
->AccessMask
;
164 RtlMapGenericMask(&TempAccess
, GenericMapping
);
166 /* Grant access rights that have not been denied yet */
167 TempGrantedAccess
|= (TempAccess
& ~TempDeniedAccess
);
172 DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce
->Header
.AceType
);
176 /* Get the next ACE */
177 CurrentAce
= (PACE
)((ULONG_PTR
)CurrentAce
+ CurrentAce
->Header
.AceSize
);
180 /* Fail if some rights have not been granted */
181 RemainingAccess
&= ~(MAXIMUM_ALLOWED
| TempGrantedAccess
);
182 if (RemainingAccess
!= 0)
184 PreviouslyGrantedAccess
= 0;
185 Status
= STATUS_ACCESS_DENIED
;
186 goto ReturnCommonStatus
;
189 /* Set granted access right and access status */
190 PreviouslyGrantedAccess
|= TempGrantedAccess
;
191 if (PreviouslyGrantedAccess
!= 0)
193 Status
= STATUS_SUCCESS
;
197 Status
= STATUS_ACCESS_DENIED
;
199 goto ReturnCommonStatus
;
202 /* RULE 4: Grant rights according to the DACL */
203 CurrentAce
= (PACE
)(Dacl
+ 1);
204 for (i
= 0; i
< Dacl
->AceCount
; i
++)
206 if (!(CurrentAce
->Header
.AceFlags
& INHERIT_ONLY_ACE
))
208 Sid
= (PSID
)(CurrentAce
+ 1);
209 if (CurrentAce
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
)
211 if (SepSidInToken(Token
, Sid
))
213 /* Map access rights from the ACE */
214 TempAccess
= CurrentAce
->AccessMask
;
215 RtlMapGenericMask(&TempAccess
, GenericMapping
);
217 /* Leave if a remaining right must be denied */
218 if (RemainingAccess
& TempAccess
)
222 else if (CurrentAce
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
)
224 if (SepSidInToken(Token
, Sid
))
226 /* Map access rights from the ACE */
227 TempAccess
= CurrentAce
->AccessMask
;
228 DPRINT("TempAccess 0x%08lx\n", TempAccess
);
229 RtlMapGenericMask(&TempAccess
, GenericMapping
);
231 /* Remove granted rights */
232 DPRINT("RemainingAccess 0x%08lx TempAccess 0x%08lx\n", RemainingAccess
, TempAccess
);
233 RemainingAccess
&= ~TempAccess
;
234 DPRINT("RemainingAccess 0x%08lx\n", RemainingAccess
);
239 DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce
->Header
.AceType
);
243 /* Get the next ACE */
244 CurrentAce
= (PACE
)((ULONG_PTR
)CurrentAce
+ CurrentAce
->Header
.AceSize
);
247 DPRINT("DesiredAccess %08lx\nPreviouslyGrantedAccess %08lx\nRemainingAccess %08lx\n",
248 DesiredAccess
, PreviouslyGrantedAccess
, RemainingAccess
);
250 /* Fail if some rights have not been granted */
251 if (RemainingAccess
!= 0)
253 DPRINT("HACK: RemainingAccess = 0x%08lx DesiredAccess = 0x%08lx\n", RemainingAccess
, DesiredAccess
);
256 Status
= STATUS_ACCESS_DENIED
;
257 goto ReturnCommonStatus
;
261 /* Set granted access rights */
262 PreviouslyGrantedAccess
|= DesiredAccess
;
264 /* Fail if no rights have been granted */
265 if (PreviouslyGrantedAccess
== 0)
267 DPRINT1("PreviouslyGrantedAccess == 0 DesiredAccess = %08lx\n", DesiredAccess
);
268 Status
= STATUS_ACCESS_DENIED
;
269 goto ReturnCommonStatus
;
272 Status
= STATUS_SUCCESS
;
273 goto ReturnCommonStatus
;
276 ResultListLength
= UseResultList
? ObjectTypeListLength
: 1;
277 for (i
= 0; i
< ResultListLength
; i
++)
279 GrantedAccessList
[i
] = PreviouslyGrantedAccess
;
280 AccessStatusList
[i
] = Status
;
283 return NT_SUCCESS(Status
);
287 SepAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
288 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
,
289 IN ACCESS_MASK DesiredAccess
,
290 IN ACCESS_MASK PreviouslyGrantedAccess
,
291 OUT PPRIVILEGE_SET
* Privileges
,
292 IN PGENERIC_MAPPING GenericMapping
,
293 IN KPROCESSOR_MODE AccessMode
,
294 OUT PACCESS_MASK GrantedAccess
,
295 OUT PNTSTATUS AccessStatus
)
297 return SepAccessCheckEx(SecurityDescriptor
,
298 SubjectSecurityContext
,
302 PreviouslyGrantedAccess
,
312 SepGetSDOwner(IN PSECURITY_DESCRIPTOR _SecurityDescriptor
)
314 PISECURITY_DESCRIPTOR SecurityDescriptor
= _SecurityDescriptor
;
317 if (SecurityDescriptor
->Control
& SE_SELF_RELATIVE
)
318 Owner
= (PSID
)((ULONG_PTR
)SecurityDescriptor
->Owner
+
319 (ULONG_PTR
)SecurityDescriptor
);
321 Owner
= (PSID
)SecurityDescriptor
->Owner
;
327 SepGetSDGroup(IN PSECURITY_DESCRIPTOR _SecurityDescriptor
)
329 PISECURITY_DESCRIPTOR SecurityDescriptor
= _SecurityDescriptor
;
332 if (SecurityDescriptor
->Control
& SE_SELF_RELATIVE
)
333 Group
= (PSID
)((ULONG_PTR
)SecurityDescriptor
->Group
+
334 (ULONG_PTR
)SecurityDescriptor
);
336 Group
= (PSID
)SecurityDescriptor
->Group
;
342 /* PUBLIC FUNCTIONS ***********************************************************/
349 SeAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
350 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
,
351 IN BOOLEAN SubjectContextLocked
,
352 IN ACCESS_MASK DesiredAccess
,
353 IN ACCESS_MASK PreviouslyGrantedAccess
,
354 OUT PPRIVILEGE_SET
* Privileges
,
355 IN PGENERIC_MAPPING GenericMapping
,
356 IN KPROCESSOR_MODE AccessMode
,
357 OUT PACCESS_MASK GrantedAccess
,
358 OUT PNTSTATUS AccessStatus
)
364 /* Check if this is kernel mode */
365 if (AccessMode
== KernelMode
)
367 /* Check if kernel wants everything */
368 if (DesiredAccess
& MAXIMUM_ALLOWED
)
371 *GrantedAccess
= GenericMapping
->GenericAll
;
372 *GrantedAccess
|= (DesiredAccess
&~ MAXIMUM_ALLOWED
);
373 *GrantedAccess
|= PreviouslyGrantedAccess
;
377 /* Give the desired and previous access */
378 *GrantedAccess
= DesiredAccess
| PreviouslyGrantedAccess
;
382 *AccessStatus
= STATUS_SUCCESS
;
386 /* Check if we didn't get an SD */
387 if (!SecurityDescriptor
)
389 /* Automatic failure */
390 *AccessStatus
= STATUS_ACCESS_DENIED
;
394 /* Check for invalid impersonation */
395 if ((SubjectSecurityContext
->ClientToken
) &&
396 (SubjectSecurityContext
->ImpersonationLevel
< SecurityImpersonation
))
398 *AccessStatus
= STATUS_BAD_IMPERSONATION_LEVEL
;
402 /* Acquire the lock if needed */
403 if (!SubjectContextLocked
)
404 SeLockSubjectContext(SubjectSecurityContext
);
406 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
407 if (DesiredAccess
& (WRITE_DAC
| READ_CONTROL
| MAXIMUM_ALLOWED
))
409 PACCESS_TOKEN Token
= SubjectSecurityContext
->ClientToken
?
410 SubjectSecurityContext
->ClientToken
: SubjectSecurityContext
->PrimaryToken
;
412 if (SepTokenIsOwner(Token
,
416 if (DesiredAccess
& MAXIMUM_ALLOWED
)
417 PreviouslyGrantedAccess
|= (WRITE_DAC
| READ_CONTROL
);
419 PreviouslyGrantedAccess
|= (DesiredAccess
& (WRITE_DAC
| READ_CONTROL
));
421 DesiredAccess
&= ~(WRITE_DAC
| READ_CONTROL
);
425 if (DesiredAccess
== 0)
427 *GrantedAccess
= PreviouslyGrantedAccess
;
428 if (PreviouslyGrantedAccess
== 0)
430 DPRINT1("Request for zero access to an object. Denying.\n");
431 *AccessStatus
= STATUS_ACCESS_DENIED
;
436 *AccessStatus
= STATUS_SUCCESS
;
442 /* Call the internal function */
443 ret
= SepAccessCheck(SecurityDescriptor
,
444 SubjectSecurityContext
,
446 PreviouslyGrantedAccess
,
454 /* Release the lock if needed */
455 if (!SubjectContextLocked
)
456 SeUnlockSubjectContext(SubjectSecurityContext
);
466 SeFastTraverseCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
467 IN PACCESS_STATE AccessState
,
468 IN ACCESS_MASK DesiredAccess
,
469 IN KPROCESSOR_MODE AccessMode
)
477 ASSERT(AccessMode
!= KernelMode
);
479 if (SecurityDescriptor
== NULL
)
483 Dacl
= SepGetDaclFromDescriptor(SecurityDescriptor
);
484 /* If no DACL, grant access */
492 /* Can't perform the check on restricted token */
493 if (AccessState
->Flags
& TOKEN_IS_RESTRICTED
)
496 /* Browse the ACEs */
497 for (AceIndex
= 0, Ace
= (PKNOWN_ACE
)((ULONG_PTR
)Dacl
+ sizeof(ACL
));
498 AceIndex
< Dacl
->AceCount
;
499 AceIndex
++, Ace
= (PKNOWN_ACE
)((ULONG_PTR
)Ace
+ Ace
->Header
.AceSize
))
501 if (Ace
->Header
.AceFlags
& INHERIT_ONLY_ACE
)
504 /* If access-allowed ACE */
505 if (Ace
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
)
507 /* Check if all accesses are granted */
508 if (!(Ace
->Mask
& DesiredAccess
))
511 /* Check SID and grant access if matching */
512 if (RtlEqualSid(SeWorldSid
, &(Ace
->SidStart
)))
515 /* If access-denied ACE */
516 else if (Ace
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
)
518 /* Here, only check if it denies any access wanted and deny if so */
519 if (Ace
->Mask
& DesiredAccess
)
528 /* SYSTEM CALLS ***************************************************************/
535 NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
536 IN HANDLE TokenHandle
,
537 IN ACCESS_MASK DesiredAccess
,
538 IN PGENERIC_MAPPING GenericMapping
,
539 OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL
,
540 IN OUT PULONG PrivilegeSetLength
,
541 OUT PACCESS_MASK GrantedAccess
,
542 OUT PNTSTATUS AccessStatus
)
544 PSECURITY_DESCRIPTOR CapturedSecurityDescriptor
= NULL
;
545 SECURITY_SUBJECT_CONTEXT SubjectSecurityContext
;
546 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
547 ACCESS_MASK PreviouslyGrantedAccess
= 0;
552 /* Check if this is kernel mode */
553 if (PreviousMode
== KernelMode
)
555 /* Check if kernel wants everything */
556 if (DesiredAccess
& MAXIMUM_ALLOWED
)
559 *GrantedAccess
= GenericMapping
->GenericAll
;
560 *GrantedAccess
|= (DesiredAccess
&~ MAXIMUM_ALLOWED
);
564 /* Just give the desired access */
565 *GrantedAccess
= DesiredAccess
;
569 *AccessStatus
= STATUS_SUCCESS
;
570 return STATUS_SUCCESS
;
573 /* Protect probe in SEH */
576 /* Probe all pointers */
577 ProbeForRead(GenericMapping
, sizeof(GENERIC_MAPPING
), sizeof(ULONG
));
578 ProbeForRead(PrivilegeSetLength
, sizeof(ULONG
), sizeof(ULONG
));
579 ProbeForWrite(PrivilegeSet
, *PrivilegeSetLength
, sizeof(ULONG
));
580 ProbeForWrite(GrantedAccess
, sizeof(ACCESS_MASK
), sizeof(ULONG
));
581 ProbeForWrite(AccessStatus
, sizeof(NTSTATUS
), sizeof(ULONG
));
583 /* Initialize the privilege set */
584 PrivilegeSet
->PrivilegeCount
= 0;
586 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
588 /* Return the exception code */
589 _SEH2_YIELD(return _SEH2_GetExceptionCode());
593 /* Check for unmapped access rights */
594 if (DesiredAccess
& (GENERIC_READ
| GENERIC_WRITE
| GENERIC_EXECUTE
| GENERIC_ALL
))
595 return STATUS_GENERIC_NOT_MAPPED
;
597 /* Reference the token */
598 Status
= ObReferenceObjectByHandle(TokenHandle
,
604 if (!NT_SUCCESS(Status
))
606 DPRINT("Failed to reference token (Status %lx)\n", Status
);
610 /* Check token type */
611 if (Token
->TokenType
!= TokenImpersonation
)
613 DPRINT("No impersonation token\n");
614 ObDereferenceObject(Token
);
615 return STATUS_NO_IMPERSONATION_TOKEN
;
618 /* Check the impersonation level */
619 if (Token
->ImpersonationLevel
< SecurityIdentification
)
621 DPRINT("Impersonation level < SecurityIdentification\n");
622 ObDereferenceObject(Token
);
623 return STATUS_BAD_IMPERSONATION_LEVEL
;
626 /* Capture the security descriptor */
627 Status
= SeCaptureSecurityDescriptor(SecurityDescriptor
,
631 &CapturedSecurityDescriptor
);
632 if (!NT_SUCCESS(Status
))
634 DPRINT("Failed to capture the Security Descriptor\n");
635 ObDereferenceObject(Token
);
639 /* Check the captured security descriptor */
640 if (CapturedSecurityDescriptor
== NULL
)
642 DPRINT("Security Descriptor is NULL\n");
643 ObDereferenceObject(Token
);
644 return STATUS_INVALID_SECURITY_DESCR
;
647 /* Check security descriptor for valid owner and group */
648 if (SepGetSDOwner(SecurityDescriptor
) == NULL
|| // FIXME: use CapturedSecurityDescriptor
649 SepGetSDGroup(SecurityDescriptor
) == NULL
) // FIXME: use CapturedSecurityDescriptor
651 DPRINT("Security Descriptor does not have a valid group or owner\n");
652 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor
,
655 ObDereferenceObject(Token
);
656 return STATUS_INVALID_SECURITY_DESCR
;
659 /* Set up the subject context, and lock it */
660 SeCaptureSubjectContext(&SubjectSecurityContext
);
663 SepAcquireTokenLockShared(Token
);
665 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
666 if (DesiredAccess
& (WRITE_DAC
| READ_CONTROL
| MAXIMUM_ALLOWED
))
668 if (SepTokenIsOwner(Token
, SecurityDescriptor
, FALSE
)) // FIXME: use CapturedSecurityDescriptor
670 if (DesiredAccess
& MAXIMUM_ALLOWED
)
671 PreviouslyGrantedAccess
|= (WRITE_DAC
| READ_CONTROL
);
673 PreviouslyGrantedAccess
|= (DesiredAccess
& (WRITE_DAC
| READ_CONTROL
));
675 DesiredAccess
&= ~(WRITE_DAC
| READ_CONTROL
);
679 if (DesiredAccess
== 0)
681 *GrantedAccess
= PreviouslyGrantedAccess
;
682 *AccessStatus
= STATUS_SUCCESS
;
686 /* Now perform the access check */
687 SepAccessCheck(SecurityDescriptor
, // FIXME: use CapturedSecurityDescriptor
688 &SubjectSecurityContext
,
690 PreviouslyGrantedAccess
,
691 &PrivilegeSet
, //FIXME
698 /* Release subject context and unlock the token */
699 SeReleaseSubjectContext(&SubjectSecurityContext
);
700 SepReleaseTokenLock(Token
);
702 /* Release the captured security descriptor */
703 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor
,
707 /* Dereference the token */
708 ObDereferenceObject(Token
);
710 /* Check succeeded */
711 return STATUS_SUCCESS
;
717 NtAccessCheckByType(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
718 IN PSID PrincipalSelfSid
,
719 IN HANDLE ClientToken
,
720 IN ACCESS_MASK DesiredAccess
,
721 IN POBJECT_TYPE_LIST ObjectTypeList
,
722 IN ULONG ObjectTypeLength
,
723 IN PGENERIC_MAPPING GenericMapping
,
724 IN PPRIVILEGE_SET PrivilegeSet
,
725 IN OUT PULONG PrivilegeSetLength
,
726 OUT PACCESS_MASK GrantedAccess
,
727 OUT PNTSTATUS AccessStatus
)
730 return STATUS_NOT_IMPLEMENTED
;
735 NtAccessCheckByTypeResultList(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
736 IN PSID PrincipalSelfSid
,
737 IN HANDLE ClientToken
,
738 IN ACCESS_MASK DesiredAccess
,
739 IN POBJECT_TYPE_LIST ObjectTypeList
,
740 IN ULONG ObjectTypeLength
,
741 IN PGENERIC_MAPPING GenericMapping
,
742 IN PPRIVILEGE_SET PrivilegeSet
,
743 IN OUT PULONG PrivilegeSetLength
,
744 OUT PACCESS_MASK GrantedAccess
,
745 OUT PNTSTATUS AccessStatus
)
748 return STATUS_NOT_IMPLEMENTED
;