2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/se/acl.c
5 * PURPOSE: Security manager
7 * PROGRAMMERS: David Welch <welch@cwcom.net>
10 /* INCLUDES *******************************************************************/
16 /* GLOBALS ********************************************************************/
18 PACL SePublicDefaultDacl
= NULL
;
19 PACL SeSystemDefaultDacl
= NULL
;
20 PACL SePublicDefaultUnrestrictedDacl
= NULL
;
21 PACL SePublicOpenDacl
= NULL
;
22 PACL SePublicOpenUnrestrictedDacl
= NULL
;
23 PACL SeUnrestrictedDacl
= NULL
;
25 /* FUNCTIONS ******************************************************************/
34 /* create PublicDefaultDacl */
35 AclLength
= sizeof(ACL
) +
36 (sizeof(ACE
) + RtlLengthSid(SeWorldSid
)) +
37 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
38 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
));
40 SePublicDefaultDacl
= ExAllocatePoolWithTag(PagedPool
,
43 if (SePublicDefaultDacl
== NULL
)
46 RtlCreateAcl(SePublicDefaultDacl
,
50 RtlAddAccessAllowedAce(SePublicDefaultDacl
,
55 RtlAddAccessAllowedAce(SePublicDefaultDacl
,
60 RtlAddAccessAllowedAce(SePublicDefaultDacl
,
65 /* create PublicDefaultUnrestrictedDacl */
66 AclLength
= sizeof(ACL
) +
67 (sizeof(ACE
) + RtlLengthSid(SeWorldSid
)) +
68 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
69 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
)) +
70 (sizeof(ACE
) + RtlLengthSid(SeRestrictedCodeSid
));
72 SePublicDefaultUnrestrictedDacl
= ExAllocatePoolWithTag(PagedPool
,
75 if (SePublicDefaultUnrestrictedDacl
== NULL
)
78 RtlCreateAcl(SePublicDefaultUnrestrictedDacl
,
82 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl
,
87 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl
,
92 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl
,
97 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl
,
99 GENERIC_READ
| GENERIC_EXECUTE
| READ_CONTROL
,
100 SeRestrictedCodeSid
);
102 /* create PublicOpenDacl */
103 AclLength
= sizeof(ACL
) +
104 (sizeof(ACE
) + RtlLengthSid(SeWorldSid
)) +
105 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
106 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
));
108 SePublicOpenDacl
= ExAllocatePoolWithTag(PagedPool
,
111 if (SePublicOpenDacl
== NULL
)
114 RtlCreateAcl(SePublicOpenDacl
,
118 RtlAddAccessAllowedAce(SePublicOpenDacl
,
120 GENERIC_READ
| GENERIC_WRITE
| GENERIC_EXECUTE
,
123 RtlAddAccessAllowedAce(SePublicOpenDacl
,
128 RtlAddAccessAllowedAce(SePublicOpenDacl
,
133 /* create PublicOpenUnrestrictedDacl */
134 AclLength
= sizeof(ACL
) +
135 (sizeof(ACE
) + RtlLengthSid(SeWorldSid
)) +
136 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
137 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
)) +
138 (sizeof(ACE
) + RtlLengthSid(SeRestrictedCodeSid
));
140 SePublicOpenUnrestrictedDacl
= ExAllocatePoolWithTag(PagedPool
,
143 if (SePublicOpenUnrestrictedDacl
== NULL
)
146 RtlCreateAcl(SePublicOpenUnrestrictedDacl
,
150 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl
,
155 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl
,
160 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl
,
165 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl
,
167 GENERIC_READ
| GENERIC_EXECUTE
,
168 SeRestrictedCodeSid
);
170 /* create SystemDefaultDacl */
171 AclLength
= sizeof(ACL
) +
172 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
173 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
));
175 SeSystemDefaultDacl
= ExAllocatePoolWithTag(PagedPool
,
178 if (SeSystemDefaultDacl
== NULL
)
181 RtlCreateAcl(SeSystemDefaultDacl
,
185 RtlAddAccessAllowedAce(SeSystemDefaultDacl
,
190 RtlAddAccessAllowedAce(SeSystemDefaultDacl
,
192 GENERIC_READ
| GENERIC_EXECUTE
| READ_CONTROL
,
195 /* create UnrestrictedDacl */
196 AclLength
= sizeof(ACL
) +
197 (sizeof(ACE
) + RtlLengthSid(SeWorldSid
)) +
198 (sizeof(ACE
) + RtlLengthSid(SeRestrictedCodeSid
));
200 SeUnrestrictedDacl
= ExAllocatePoolWithTag(PagedPool
,
203 if (SeUnrestrictedDacl
== NULL
)
206 RtlCreateAcl(SeUnrestrictedDacl
,
210 RtlAddAccessAllowedAce(SeUnrestrictedDacl
,
215 RtlAddAccessAllowedAce(SeUnrestrictedDacl
,
217 GENERIC_READ
| GENERIC_EXECUTE
,
218 SeRestrictedCodeSid
);
225 SepCreateImpersonationTokenDacl(
227 _In_ PTOKEN PrimaryToken
,
237 AclLength
= sizeof(ACL
) +
238 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
)) +
239 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
240 (sizeof(ACE
) + RtlLengthSid(SeRestrictedCodeSid
)) +
241 (sizeof(ACE
) + RtlLengthSid(Token
->UserAndGroups
->Sid
)) +
242 (sizeof(ACE
) + RtlLengthSid(PrimaryToken
->UserAndGroups
->Sid
));
244 TokenDacl
= ExAllocatePoolWithTag(PagedPool
, AclLength
, TAG_ACL
);
245 if (TokenDacl
== NULL
)
247 return STATUS_INSUFFICIENT_RESOURCES
;
250 RtlCreateAcl(TokenDacl
, AclLength
, ACL_REVISION
);
251 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
252 Token
->UserAndGroups
->Sid
);
253 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
254 PrimaryToken
->UserAndGroups
->Sid
);
255 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
257 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
260 if (Token
->RestrictedSids
!= NULL
|| PrimaryToken
->RestrictedSids
!= NULL
)
262 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
263 SeRestrictedCodeSid
);
268 return STATUS_SUCCESS
;
273 SepCaptureAcl(IN PACL InputAcl
,
274 IN KPROCESSOR_MODE AccessMode
,
275 IN POOL_TYPE PoolType
,
276 IN BOOLEAN CaptureIfKernel
,
277 OUT PACL
*CapturedAcl
)
281 NTSTATUS Status
= STATUS_SUCCESS
;
285 if (AccessMode
!= KernelMode
)
289 ProbeForRead(InputAcl
,
292 AclSize
= InputAcl
->AclSize
;
293 ProbeForRead(InputAcl
,
297 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
299 /* Return the exception code */
300 _SEH2_YIELD(return _SEH2_GetExceptionCode());
304 NewAcl
= ExAllocatePoolWithTag(PoolType
,
311 RtlCopyMemory(NewAcl
,
315 *CapturedAcl
= NewAcl
;
317 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
319 /* Free the ACL and return the exception code */
320 ExFreePoolWithTag(NewAcl
, TAG_ACL
);
321 _SEH2_YIELD(return _SEH2_GetExceptionCode());
327 Status
= STATUS_INSUFFICIENT_RESOURCES
;
330 else if (!CaptureIfKernel
)
332 *CapturedAcl
= InputAcl
;
336 AclSize
= InputAcl
->AclSize
;
338 NewAcl
= ExAllocatePoolWithTag(PoolType
,
344 RtlCopyMemory(NewAcl
,
348 *CapturedAcl
= NewAcl
;
352 Status
= STATUS_INSUFFICIENT_RESOURCES
;
361 SepReleaseAcl(IN PACL CapturedAcl
,
362 IN KPROCESSOR_MODE AccessMode
,
363 IN BOOLEAN CaptureIfKernel
)
367 if (CapturedAcl
!= NULL
&&
368 (AccessMode
!= KernelMode
||
369 (AccessMode
== KernelMode
&& CaptureIfKernel
)))
371 ExFreePoolWithTag(CapturedAcl
, TAG_ACL
);
376 SepShouldPropagateAce(
378 _Out_ PUCHAR NewAceFlags
,
379 _In_ BOOLEAN IsInherited
,
380 _In_ BOOLEAN IsDirectoryObject
)
384 *NewAceFlags
= AceFlags
;
388 if (!IsDirectoryObject
)
390 if (AceFlags
& OBJECT_INHERIT_ACE
)
392 *NewAceFlags
= AceFlags
& ~VALID_INHERIT_FLAGS
;
398 if (AceFlags
& NO_PROPAGATE_INHERIT_ACE
)
400 if (AceFlags
& CONTAINER_INHERIT_ACE
)
402 *NewAceFlags
= AceFlags
& ~VALID_INHERIT_FLAGS
;
408 if (AceFlags
& CONTAINER_INHERIT_ACE
)
410 *NewAceFlags
= CONTAINER_INHERIT_ACE
| (AceFlags
& OBJECT_INHERIT_ACE
) | (AceFlags
& ~VALID_INHERIT_FLAGS
);
414 if (AceFlags
& OBJECT_INHERIT_ACE
)
416 *NewAceFlags
= INHERIT_ONLY_ACE
| OBJECT_INHERIT_ACE
| (AceFlags
& ~VALID_INHERIT_FLAGS
);
425 _Out_writes_bytes_opt_(AclLength
) PACL AclDest
,
426 _Inout_ PULONG AclLength
,
427 _In_reads_bytes_(AclSource
->AclSize
) PACL AclSource
,
430 _In_ BOOLEAN IsInherited
,
431 _In_ BOOLEAN IsDirectoryObject
,
432 _In_ PGENERIC_MAPPING GenericMapping
)
435 PACCESS_ALLOWED_ACE AceSource
;
436 PACCESS_ALLOWED_ACE AceDest
;
438 PUCHAR CurrentSource
;
445 BOOLEAN WriteTwoAces
;
447 ASSERT(RtlValidAcl(AclSource
));
448 ASSERT(AclSource
->AclSize
% sizeof(ULONG
) == 0);
449 ASSERT(AclSource
->Sbz1
== 0);
450 ASSERT(AclSource
->Sbz2
== 0);
453 if (*AclLength
>= Written
+ sizeof(ACL
))
455 RtlCopyMemory(AclDest
,
459 Written
+= sizeof(ACL
);
461 CurrentDest
= (PUCHAR
)(AclDest
+ 1);
462 CurrentSource
= (PUCHAR
)(AclSource
+ 1);
463 for (i
= 0; i
< AclSource
->AceCount
; i
++)
465 ASSERT((ULONG_PTR
)CurrentDest
% sizeof(ULONG
) == 0);
466 ASSERT((ULONG_PTR
)CurrentSource
% sizeof(ULONG
) == 0);
467 AceDest
= (PACCESS_ALLOWED_ACE
)CurrentDest
;
468 AceSource
= (PACCESS_ALLOWED_ACE
)CurrentSource
;
470 if (AceSource
->Header
.AceType
> ACCESS_MAX_MS_V2_ACE_TYPE
)
472 /* FIXME: handle object & compound ACEs */
473 AceSize
= AceSource
->Header
.AceSize
;
475 if (*AclLength
>= Written
+ AceSize
)
477 RtlCopyMemory(AceDest
, AceSource
, AceSize
);
479 CurrentDest
+= AceSize
;
480 CurrentSource
+= AceSize
;
486 /* These all have the same structure */
487 ASSERT(AceSource
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
||
488 AceSource
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
||
489 AceSource
->Header
.AceType
== SYSTEM_AUDIT_ACE_TYPE
||
490 AceSource
->Header
.AceType
== SYSTEM_ALARM_ACE_TYPE
);
492 ASSERT(AceSource
->Header
.AceSize
% sizeof(ULONG
) == 0);
493 ASSERT(AceSource
->Header
.AceSize
>= sizeof(*AceSource
));
494 if (!SepShouldPropagateAce(AceSource
->Header
.AceFlags
,
499 CurrentSource
+= AceSource
->Header
.AceSize
;
503 /* FIXME: filter out duplicate ACEs */
504 AceSize
= AceSource
->Header
.AceSize
;
505 Mask
= AceSource
->Mask
;
506 Sid
= (PSID
)&AceSource
->SidStart
;
507 ASSERT(AceSize
>= FIELD_OFFSET(ACCESS_ALLOWED_ACE
, SidStart
) + RtlLengthSid(Sid
));
509 WriteTwoAces
= FALSE
;
510 /* Map effective ACE to specific rights */
511 if (!(AceFlags
& INHERIT_ONLY_ACE
))
513 RtlMapGenericMask(&Mask
, GenericMapping
);
514 Mask
&= GenericMapping
->GenericAll
;
518 if (RtlEqualSid(Sid
, SeCreatorOwnerSid
))
520 else if (RtlEqualSid(Sid
, SeCreatorGroupSid
))
522 AceSize
= FIELD_OFFSET(ACCESS_ALLOWED_ACE
, SidStart
) + RtlLengthSid(Sid
);
525 * A generic container ACE becomes two ACEs:
526 * - a specific effective ACE with no inheritance flags
527 * - an inherit-only ACE that keeps the generic rights
529 if (IsDirectoryObject
&&
530 (AceFlags
& CONTAINER_INHERIT_ACE
) &&
531 (Mask
!= AceSource
->Mask
|| Sid
!= (PSID
)&AceSource
->SidStart
))
540 if (*AclLength
>= Written
+ AceSize
)
542 AceDest
->Header
.AceType
= AceSource
->Header
.AceType
;
543 AceDest
->Header
.AceFlags
= WriteTwoAces
? AceFlags
& ~VALID_INHERIT_FLAGS
545 AceDest
->Header
.AceSize
= AceSize
;
546 AceDest
->Mask
= Mask
;
547 RtlCopySid(AceSize
- FIELD_OFFSET(ACCESS_ALLOWED_ACE
, SidStart
),
548 (PSID
)&AceDest
->SidStart
,
554 CurrentDest
+= AceSize
;
559 /* Second ACE keeps all the generics from the source ACE */
560 WriteTwoAces
= FALSE
;
561 AceDest
= (PACCESS_ALLOWED_ACE
)CurrentDest
;
562 AceSize
= AceSource
->Header
.AceSize
;
563 Mask
= AceSource
->Mask
;
564 Sid
= (PSID
)&AceSource
->SidStart
;
565 AceFlags
|= INHERIT_ONLY_ACE
;
568 CurrentSource
+= AceSource
->Header
.AceSize
;
571 if (*AclLength
>= sizeof(ACL
))
573 AclDest
->AceCount
= AceCount
;
574 AclDest
->AclSize
= Written
;
577 if (Written
> *AclLength
)
579 *AclLength
= Written
;
580 return STATUS_BUFFER_TOO_SMALL
;
582 *AclLength
= Written
;
583 return STATUS_SUCCESS
;
588 _In_opt_ PACL ExplicitAcl
,
589 _In_ BOOLEAN ExplicitPresent
,
590 _In_ BOOLEAN ExplicitDefaulted
,
591 _In_opt_ PACL ParentAcl
,
592 _In_opt_ PACL DefaultAcl
,
593 _Out_ PULONG AclLength
,
596 _Out_ PBOOLEAN AclPresent
,
597 _Out_ PBOOLEAN IsInherited
,
598 _In_ BOOLEAN IsDirectoryObject
,
599 _In_ PGENERIC_MAPPING GenericMapping
)
605 if (ExplicitPresent
&& !ExplicitDefaulted
)
615 Status
= SepPropagateAcl(NULL
,
623 ASSERT(Status
== STATUS_BUFFER_TOO_SMALL
);
625 /* Use the parent ACL only if it's not empty */
626 if (*AclLength
!= sizeof(ACL
))
645 *IsInherited
= FALSE
;
650 Status
= SepPropagateAcl(NULL
,
658 ASSERT(Status
== STATUS_BUFFER_TOO_SMALL
);