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 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, SepInitDACLs)
20 /* GLOBALS ********************************************************************/
22 PACL SePublicDefaultDacl
= NULL
;
23 PACL SeSystemDefaultDacl
= NULL
;
24 PACL SePublicDefaultUnrestrictedDacl
= NULL
;
25 PACL SePublicOpenDacl
= NULL
;
26 PACL SePublicOpenUnrestrictedDacl
= NULL
;
27 PACL SeUnrestrictedDacl
= NULL
;
29 /* FUNCTIONS ******************************************************************/
38 /* create PublicDefaultDacl */
39 AclLength
= sizeof(ACL
) +
40 (sizeof(ACE
) + RtlLengthSid(SeWorldSid
)) +
41 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
42 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
));
44 SePublicDefaultDacl
= ExAllocatePoolWithTag(PagedPool
,
47 if (SePublicDefaultDacl
== NULL
)
50 RtlCreateAcl(SePublicDefaultDacl
,
54 RtlAddAccessAllowedAce(SePublicDefaultDacl
,
59 RtlAddAccessAllowedAce(SePublicDefaultDacl
,
64 RtlAddAccessAllowedAce(SePublicDefaultDacl
,
69 /* create PublicDefaultUnrestrictedDacl */
70 AclLength
= sizeof(ACL
) +
71 (sizeof(ACE
) + RtlLengthSid(SeWorldSid
)) +
72 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
73 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
)) +
74 (sizeof(ACE
) + RtlLengthSid(SeRestrictedCodeSid
));
76 SePublicDefaultUnrestrictedDacl
= ExAllocatePoolWithTag(PagedPool
,
79 if (SePublicDefaultUnrestrictedDacl
== NULL
)
82 RtlCreateAcl(SePublicDefaultUnrestrictedDacl
,
86 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl
,
91 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl
,
96 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl
,
101 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl
,
103 GENERIC_READ
| GENERIC_EXECUTE
| READ_CONTROL
,
104 SeRestrictedCodeSid
);
106 /* create PublicOpenDacl */
107 AclLength
= sizeof(ACL
) +
108 (sizeof(ACE
) + RtlLengthSid(SeWorldSid
)) +
109 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
110 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
));
112 SePublicOpenDacl
= ExAllocatePoolWithTag(PagedPool
,
115 if (SePublicOpenDacl
== NULL
)
118 RtlCreateAcl(SePublicOpenDacl
,
122 RtlAddAccessAllowedAce(SePublicOpenDacl
,
124 GENERIC_READ
| GENERIC_WRITE
| GENERIC_EXECUTE
,
127 RtlAddAccessAllowedAce(SePublicOpenDacl
,
132 RtlAddAccessAllowedAce(SePublicOpenDacl
,
137 /* create PublicOpenUnrestrictedDacl */
138 AclLength
= sizeof(ACL
) +
139 (sizeof(ACE
) + RtlLengthSid(SeWorldSid
)) +
140 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
141 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
)) +
142 (sizeof(ACE
) + RtlLengthSid(SeRestrictedCodeSid
));
144 SePublicOpenUnrestrictedDacl
= ExAllocatePoolWithTag(PagedPool
,
147 if (SePublicOpenUnrestrictedDacl
== NULL
)
150 RtlCreateAcl(SePublicOpenUnrestrictedDacl
,
154 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl
,
159 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl
,
164 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl
,
169 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl
,
171 GENERIC_READ
| GENERIC_EXECUTE
,
172 SeRestrictedCodeSid
);
174 /* create SystemDefaultDacl */
175 AclLength
= sizeof(ACL
) +
176 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
177 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
));
179 SeSystemDefaultDacl
= ExAllocatePoolWithTag(PagedPool
,
182 if (SeSystemDefaultDacl
== NULL
)
185 RtlCreateAcl(SeSystemDefaultDacl
,
189 RtlAddAccessAllowedAce(SeSystemDefaultDacl
,
194 RtlAddAccessAllowedAce(SeSystemDefaultDacl
,
196 GENERIC_READ
| GENERIC_EXECUTE
| READ_CONTROL
,
199 /* create UnrestrictedDacl */
200 AclLength
= sizeof(ACL
) +
201 (sizeof(ACE
) + RtlLengthSid(SeWorldSid
)) +
202 (sizeof(ACE
) + RtlLengthSid(SeRestrictedCodeSid
));
204 SeUnrestrictedDacl
= ExAllocatePoolWithTag(PagedPool
,
207 if (SeUnrestrictedDacl
== NULL
)
210 RtlCreateAcl(SeUnrestrictedDacl
,
214 RtlAddAccessAllowedAce(SeUnrestrictedDacl
,
219 RtlAddAccessAllowedAce(SeUnrestrictedDacl
,
221 GENERIC_READ
| GENERIC_EXECUTE
,
222 SeRestrictedCodeSid
);
229 SepCreateImpersonationTokenDacl(
231 _In_ PTOKEN PrimaryToken
,
241 AclLength
= sizeof(ACL
) +
242 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
)) +
243 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
244 (sizeof(ACE
) + RtlLengthSid(SeRestrictedCodeSid
)) +
245 (sizeof(ACE
) + RtlLengthSid(Token
->UserAndGroups
->Sid
)) +
246 (sizeof(ACE
) + RtlLengthSid(PrimaryToken
->UserAndGroups
->Sid
));
248 TokenDacl
= ExAllocatePoolWithTag(PagedPool
, AclLength
, TAG_ACL
);
249 if (TokenDacl
== NULL
)
251 return STATUS_INSUFFICIENT_RESOURCES
;
254 RtlCreateAcl(TokenDacl
, AclLength
, ACL_REVISION
);
255 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
256 Token
->UserAndGroups
->Sid
);
257 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
258 PrimaryToken
->UserAndGroups
->Sid
);
259 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
261 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
264 if (Token
->RestrictedSids
!= NULL
|| PrimaryToken
->RestrictedSids
!= NULL
)
266 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
267 SeRestrictedCodeSid
);
272 return STATUS_SUCCESS
;
277 SepCaptureAcl(IN PACL InputAcl
,
278 IN KPROCESSOR_MODE AccessMode
,
279 IN POOL_TYPE PoolType
,
280 IN BOOLEAN CaptureIfKernel
,
281 OUT PACL
*CapturedAcl
)
285 NTSTATUS Status
= STATUS_SUCCESS
;
289 if (AccessMode
!= KernelMode
)
293 ProbeForRead(InputAcl
,
296 AclSize
= InputAcl
->AclSize
;
297 ProbeForRead(InputAcl
,
301 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
303 /* Return the exception code */
304 _SEH2_YIELD(return _SEH2_GetExceptionCode());
308 NewAcl
= ExAllocatePoolWithTag(PoolType
,
315 RtlCopyMemory(NewAcl
,
319 *CapturedAcl
= NewAcl
;
321 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
323 /* Free the ACL and return the exception code */
324 ExFreePoolWithTag(NewAcl
, TAG_ACL
);
325 _SEH2_YIELD(return _SEH2_GetExceptionCode());
331 Status
= STATUS_INSUFFICIENT_RESOURCES
;
334 else if (!CaptureIfKernel
)
336 *CapturedAcl
= InputAcl
;
340 AclSize
= InputAcl
->AclSize
;
342 NewAcl
= ExAllocatePoolWithTag(PoolType
,
348 RtlCopyMemory(NewAcl
,
352 *CapturedAcl
= NewAcl
;
356 Status
= STATUS_INSUFFICIENT_RESOURCES
;
365 SepReleaseAcl(IN PACL CapturedAcl
,
366 IN KPROCESSOR_MODE AccessMode
,
367 IN BOOLEAN CaptureIfKernel
)
371 if (CapturedAcl
!= NULL
&&
372 (AccessMode
!= KernelMode
||
373 (AccessMode
== KernelMode
&& CaptureIfKernel
)))
375 ExFreePoolWithTag(CapturedAcl
, TAG_ACL
);
380 SepShouldPropagateAce(
382 _Out_ PUCHAR NewAceFlags
,
383 _In_ BOOLEAN IsInherited
,
384 _In_ BOOLEAN IsDirectoryObject
)
388 *NewAceFlags
= AceFlags
;
392 if (!IsDirectoryObject
)
394 if (AceFlags
& OBJECT_INHERIT_ACE
)
396 *NewAceFlags
= AceFlags
& ~VALID_INHERIT_FLAGS
;
402 if (AceFlags
& NO_PROPAGATE_INHERIT_ACE
)
404 if (AceFlags
& CONTAINER_INHERIT_ACE
)
406 *NewAceFlags
= AceFlags
& ~VALID_INHERIT_FLAGS
;
412 if (AceFlags
& CONTAINER_INHERIT_ACE
)
414 *NewAceFlags
= CONTAINER_INHERIT_ACE
| (AceFlags
& OBJECT_INHERIT_ACE
) | (AceFlags
& ~VALID_INHERIT_FLAGS
);
418 if (AceFlags
& OBJECT_INHERIT_ACE
)
420 *NewAceFlags
= INHERIT_ONLY_ACE
| OBJECT_INHERIT_ACE
| (AceFlags
& ~VALID_INHERIT_FLAGS
);
429 _Out_writes_bytes_opt_(AclLength
) PACL AclDest
,
430 _Inout_ PULONG AclLength
,
431 _In_reads_bytes_(AclSource
->AclSize
) PACL AclSource
,
434 _In_ BOOLEAN IsInherited
,
435 _In_ BOOLEAN IsDirectoryObject
,
436 _In_ PGENERIC_MAPPING GenericMapping
)
439 PACCESS_ALLOWED_ACE AceSource
;
440 PACCESS_ALLOWED_ACE AceDest
;
442 PUCHAR CurrentSource
;
449 BOOLEAN WriteTwoAces
;
451 ASSERT(RtlValidAcl(AclSource
));
452 ASSERT(AclSource
->AclSize
% sizeof(ULONG
) == 0);
453 ASSERT(AclSource
->Sbz1
== 0);
454 ASSERT(AclSource
->Sbz2
== 0);
457 if (*AclLength
>= Written
+ sizeof(ACL
))
459 RtlCopyMemory(AclDest
,
463 Written
+= sizeof(ACL
);
465 CurrentDest
= (PUCHAR
)(AclDest
+ 1);
466 CurrentSource
= (PUCHAR
)(AclSource
+ 1);
467 for (i
= 0; i
< AclSource
->AceCount
; i
++)
469 ASSERT((ULONG_PTR
)CurrentDest
% sizeof(ULONG
) == 0);
470 ASSERT((ULONG_PTR
)CurrentSource
% sizeof(ULONG
) == 0);
471 AceDest
= (PACCESS_ALLOWED_ACE
)CurrentDest
;
472 AceSource
= (PACCESS_ALLOWED_ACE
)CurrentSource
;
474 if (AceSource
->Header
.AceType
> ACCESS_MAX_MS_V2_ACE_TYPE
)
476 /* FIXME: handle object & compound ACEs */
477 AceSize
= AceSource
->Header
.AceSize
;
479 if (*AclLength
>= Written
+ AceSize
)
481 RtlCopyMemory(AceDest
, AceSource
, AceSize
);
483 CurrentDest
+= AceSize
;
484 CurrentSource
+= AceSize
;
490 /* These all have the same structure */
491 ASSERT(AceSource
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
||
492 AceSource
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
||
493 AceSource
->Header
.AceType
== SYSTEM_AUDIT_ACE_TYPE
||
494 AceSource
->Header
.AceType
== SYSTEM_ALARM_ACE_TYPE
);
496 ASSERT(AceSource
->Header
.AceSize
% sizeof(ULONG
) == 0);
497 ASSERT(AceSource
->Header
.AceSize
>= sizeof(*AceSource
));
498 if (!SepShouldPropagateAce(AceSource
->Header
.AceFlags
,
503 CurrentSource
+= AceSource
->Header
.AceSize
;
507 /* FIXME: filter out duplicate ACEs */
508 AceSize
= AceSource
->Header
.AceSize
;
509 Mask
= AceSource
->Mask
;
510 Sid
= (PSID
)&AceSource
->SidStart
;
511 ASSERT(AceSize
>= FIELD_OFFSET(ACCESS_ALLOWED_ACE
, SidStart
) + RtlLengthSid(Sid
));
513 WriteTwoAces
= FALSE
;
514 /* Map effective ACE to specific rights */
515 if (!(AceFlags
& INHERIT_ONLY_ACE
))
517 RtlMapGenericMask(&Mask
, GenericMapping
);
518 Mask
&= GenericMapping
->GenericAll
;
522 if (RtlEqualSid(Sid
, SeCreatorOwnerSid
))
524 else if (RtlEqualSid(Sid
, SeCreatorGroupSid
))
526 AceSize
= FIELD_OFFSET(ACCESS_ALLOWED_ACE
, SidStart
) + RtlLengthSid(Sid
);
529 * A generic container ACE becomes two ACEs:
530 * - a specific effective ACE with no inheritance flags
531 * - an inherit-only ACE that keeps the generic rights
533 if (IsDirectoryObject
&&
534 (AceFlags
& CONTAINER_INHERIT_ACE
) &&
535 (Mask
!= AceSource
->Mask
|| Sid
!= (PSID
)&AceSource
->SidStart
))
544 if (*AclLength
>= Written
+ AceSize
)
546 AceDest
->Header
.AceType
= AceSource
->Header
.AceType
;
547 AceDest
->Header
.AceFlags
= WriteTwoAces
? AceFlags
& ~VALID_INHERIT_FLAGS
549 AceDest
->Header
.AceSize
= AceSize
;
550 AceDest
->Mask
= Mask
;
551 RtlCopySid(AceSize
- FIELD_OFFSET(ACCESS_ALLOWED_ACE
, SidStart
),
552 (PSID
)&AceDest
->SidStart
,
558 CurrentDest
+= AceSize
;
563 /* Second ACE keeps all the generics from the source ACE */
564 WriteTwoAces
= FALSE
;
565 AceDest
= (PACCESS_ALLOWED_ACE
)CurrentDest
;
566 AceSize
= AceSource
->Header
.AceSize
;
567 Mask
= AceSource
->Mask
;
568 Sid
= (PSID
)&AceSource
->SidStart
;
569 AceFlags
|= INHERIT_ONLY_ACE
;
572 CurrentSource
+= AceSource
->Header
.AceSize
;
575 if (*AclLength
>= sizeof(ACL
))
577 AclDest
->AceCount
= AceCount
;
578 AclDest
->AclSize
= Written
;
581 if (Written
> *AclLength
)
583 *AclLength
= Written
;
584 return STATUS_BUFFER_TOO_SMALL
;
586 *AclLength
= Written
;
587 return STATUS_SUCCESS
;
592 _In_opt_ PACL ExplicitAcl
,
593 _In_ BOOLEAN ExplicitPresent
,
594 _In_ BOOLEAN ExplicitDefaulted
,
595 _In_opt_ PACL ParentAcl
,
596 _In_opt_ PACL DefaultAcl
,
597 _Out_ PULONG AclLength
,
600 _Out_ PBOOLEAN AclPresent
,
601 _Out_ PBOOLEAN IsInherited
,
602 _In_ BOOLEAN IsDirectoryObject
,
603 _In_ PGENERIC_MAPPING GenericMapping
)
609 if (ExplicitPresent
&& !ExplicitDefaulted
)
619 Status
= SepPropagateAcl(NULL
,
627 ASSERT(Status
== STATUS_BUFFER_TOO_SMALL
);
629 /* Use the parent ACL only if it's not empty */
630 if (*AclLength
!= sizeof(ACL
))
649 *IsInherited
= FALSE
;
654 Status
= SepPropagateAcl(NULL
,
662 ASSERT(Status
== STATUS_BUFFER_TOO_SMALL
);