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 DPRINT1("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 *AccessStatus
= STATUS_SUCCESS
;
433 /* Call the internal function */
434 ret
= SepAccessCheck(SecurityDescriptor
,
435 SubjectSecurityContext
,
437 PreviouslyGrantedAccess
,
445 /* Release the lock if needed */
446 if (!SubjectContextLocked
)
447 SeUnlockSubjectContext(SubjectSecurityContext
);
457 SeFastTraverseCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
458 IN PACCESS_STATE AccessState
,
459 IN ACCESS_MASK DesiredAccess
,
460 IN KPROCESSOR_MODE AccessMode
)
468 NT_ASSERT(AccessMode
!= KernelMode
);
470 if (SecurityDescriptor
== NULL
)
474 Dacl
= SepGetDaclFromDescriptor(SecurityDescriptor
);
475 /* If no DACL, grant access */
483 /* Can't perform the check on restricted token */
484 if (AccessState
->Flags
& TOKEN_IS_RESTRICTED
)
487 /* Browse the ACEs */
488 for (AceIndex
= 0, Ace
= (PKNOWN_ACE
)((ULONG_PTR
)Dacl
+ sizeof(ACL
));
489 AceIndex
< Dacl
->AceCount
;
490 AceIndex
++, Ace
= (PKNOWN_ACE
)((ULONG_PTR
)Ace
+ Ace
->Header
.AceSize
))
492 if (Ace
->Header
.AceFlags
& INHERIT_ONLY_ACE
)
495 /* If access-allowed ACE */
496 if (Ace
->Header
.AceType
& ACCESS_ALLOWED_ACE_TYPE
)
498 /* Check if all accesses are granted */
499 if (!(Ace
->Mask
& DesiredAccess
))
502 /* Check SID and grant access if matching */
503 if (RtlEqualSid(SeWorldSid
, &(Ace
->SidStart
)))
506 /* If access-denied ACE */
507 else if (Ace
->Header
.AceType
& ACCESS_DENIED_ACE_TYPE
)
509 /* Here, only check if it denies all the access wanted and deny if so */
510 if (Ace
->Mask
& DesiredAccess
)
519 /* SYSTEM CALLS ***************************************************************/
526 NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
527 IN HANDLE TokenHandle
,
528 IN ACCESS_MASK DesiredAccess
,
529 IN PGENERIC_MAPPING GenericMapping
,
530 OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL
,
531 IN OUT PULONG PrivilegeSetLength
,
532 OUT PACCESS_MASK GrantedAccess
,
533 OUT PNTSTATUS AccessStatus
)
535 PSECURITY_DESCRIPTOR CapturedSecurityDescriptor
= NULL
;
536 SECURITY_SUBJECT_CONTEXT SubjectSecurityContext
;
537 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
538 ACCESS_MASK PreviouslyGrantedAccess
= 0;
543 /* Check if this is kernel mode */
544 if (PreviousMode
== KernelMode
)
546 /* Check if kernel wants everything */
547 if (DesiredAccess
& MAXIMUM_ALLOWED
)
550 *GrantedAccess
= GenericMapping
->GenericAll
;
551 *GrantedAccess
|= (DesiredAccess
&~ MAXIMUM_ALLOWED
);
555 /* Just give the desired access */
556 *GrantedAccess
= DesiredAccess
;
560 *AccessStatus
= STATUS_SUCCESS
;
561 return STATUS_SUCCESS
;
564 /* Protect probe in SEH */
567 /* Probe all pointers */
568 ProbeForRead(GenericMapping
, sizeof(GENERIC_MAPPING
), sizeof(ULONG
));
569 ProbeForRead(PrivilegeSetLength
, sizeof(ULONG
), sizeof(ULONG
));
570 ProbeForWrite(PrivilegeSet
, *PrivilegeSetLength
, sizeof(ULONG
));
571 ProbeForWrite(GrantedAccess
, sizeof(ACCESS_MASK
), sizeof(ULONG
));
572 ProbeForWrite(AccessStatus
, sizeof(NTSTATUS
), sizeof(ULONG
));
574 /* Initialize the privilege set */
575 PrivilegeSet
->PrivilegeCount
= 0;
577 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
579 /* Return the exception code */
580 _SEH2_YIELD(return _SEH2_GetExceptionCode());
584 /* Check for unmapped access rights */
585 if (DesiredAccess
& (GENERIC_READ
| GENERIC_WRITE
| GENERIC_EXECUTE
| GENERIC_ALL
))
586 return STATUS_GENERIC_NOT_MAPPED
;
588 /* Reference the token */
589 Status
= ObReferenceObjectByHandle(TokenHandle
,
595 if (!NT_SUCCESS(Status
))
597 DPRINT("Failed to reference token (Status %lx)\n", Status
);
601 /* Check token type */
602 if (Token
->TokenType
!= TokenImpersonation
)
604 DPRINT("No impersonation token\n");
605 ObDereferenceObject(Token
);
606 return STATUS_NO_IMPERSONATION_TOKEN
;
609 /* Check the impersonation level */
610 if (Token
->ImpersonationLevel
< SecurityIdentification
)
612 DPRINT("Impersonation level < SecurityIdentification\n");
613 ObDereferenceObject(Token
);
614 return STATUS_BAD_IMPERSONATION_LEVEL
;
617 /* Capture the security descriptor */
618 Status
= SeCaptureSecurityDescriptor(SecurityDescriptor
,
622 &CapturedSecurityDescriptor
);
623 if (!NT_SUCCESS(Status
))
625 DPRINT("Failed to capture the Security Descriptor\n");
626 ObDereferenceObject(Token
);
630 /* Check the captured security descriptor */
631 if (CapturedSecurityDescriptor
== NULL
)
633 DPRINT("Security Descriptor is NULL\n");
634 ObDereferenceObject(Token
);
635 return STATUS_INVALID_SECURITY_DESCR
;
638 /* Check security descriptor for valid owner and group */
639 if (SepGetSDOwner(SecurityDescriptor
) == NULL
|| // FIXME: use CapturedSecurityDescriptor
640 SepGetSDGroup(SecurityDescriptor
) == NULL
) // FIXME: use CapturedSecurityDescriptor
642 DPRINT("Security Descriptor does not have a valid group or owner\n");
643 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor
,
646 ObDereferenceObject(Token
);
647 return STATUS_INVALID_SECURITY_DESCR
;
650 /* Set up the subject context, and lock it */
651 SeCaptureSubjectContext(&SubjectSecurityContext
);
654 SepAcquireTokenLockShared(Token
);
656 /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
657 if (DesiredAccess
& (WRITE_DAC
| READ_CONTROL
| MAXIMUM_ALLOWED
))
659 if (SepTokenIsOwner(Token
, SecurityDescriptor
, FALSE
)) // FIXME: use CapturedSecurityDescriptor
661 if (DesiredAccess
& MAXIMUM_ALLOWED
)
662 PreviouslyGrantedAccess
|= (WRITE_DAC
| READ_CONTROL
);
664 PreviouslyGrantedAccess
|= (DesiredAccess
& (WRITE_DAC
| READ_CONTROL
));
666 DesiredAccess
&= ~(WRITE_DAC
| READ_CONTROL
);
670 if (DesiredAccess
== 0)
672 *GrantedAccess
= PreviouslyGrantedAccess
;
673 *AccessStatus
= STATUS_SUCCESS
;
677 /* Now perform the access check */
678 SepAccessCheck(SecurityDescriptor
, // FIXME: use CapturedSecurityDescriptor
679 &SubjectSecurityContext
,
681 PreviouslyGrantedAccess
,
682 &PrivilegeSet
, //FIXME
689 /* Release subject context and unlock the token */
690 SeReleaseSubjectContext(&SubjectSecurityContext
);
691 SepReleaseTokenLock(Token
);
693 /* Release the captured security descriptor */
694 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor
,
698 /* Dereference the token */
699 ObDereferenceObject(Token
);
701 /* Check succeeded */
702 return STATUS_SUCCESS
;
708 NtAccessCheckByType(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
709 IN PSID PrincipalSelfSid
,
710 IN HANDLE ClientToken
,
711 IN ACCESS_MASK DesiredAccess
,
712 IN POBJECT_TYPE_LIST ObjectTypeList
,
713 IN ULONG ObjectTypeLength
,
714 IN PGENERIC_MAPPING GenericMapping
,
715 IN PPRIVILEGE_SET PrivilegeSet
,
716 IN OUT PULONG PrivilegeSetLength
,
717 OUT PACCESS_MASK GrantedAccess
,
718 OUT PNTSTATUS AccessStatus
)
721 return STATUS_NOT_IMPLEMENTED
;
726 NtAccessCheckByTypeResultList(IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
727 IN PSID PrincipalSelfSid
,
728 IN HANDLE ClientToken
,
729 IN ACCESS_MASK DesiredAccess
,
730 IN POBJECT_TYPE_LIST ObjectTypeList
,
731 IN ULONG ObjectTypeLength
,
732 IN PGENERIC_MAPPING GenericMapping
,
733 IN PPRIVILEGE_SET PrivilegeSet
,
734 IN OUT PULONG PrivilegeSetLength
,
735 OUT PACCESS_MASK GrantedAccess
,
736 OUT PNTSTATUS AccessStatus
)
739 return STATUS_NOT_IMPLEMENTED
;