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
);
228 SepCreateImpersonationTokenDacl(PTOKEN Token
,
237 AclLength
= sizeof(ACL
) +
238 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
)) +
239 (sizeof(ACE
) + RtlLengthSid(SeRestrictedCodeSid
)) +
240 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
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
,
262 if (Token
->RestrictedSids
!= NULL
|| PrimaryToken
->RestrictedSids
!= NULL
)
264 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
265 SeRestrictedCodeSid
);
269 return STATUS_SUCCESS
;
274 SepCaptureAcl(IN PACL InputAcl
,
275 IN KPROCESSOR_MODE AccessMode
,
276 IN POOL_TYPE PoolType
,
277 IN BOOLEAN CaptureIfKernel
,
278 OUT PACL
*CapturedAcl
)
282 NTSTATUS Status
= STATUS_SUCCESS
;
286 if (AccessMode
!= KernelMode
)
290 ProbeForRead(InputAcl
,
293 AclSize
= InputAcl
->AclSize
;
294 ProbeForRead(InputAcl
,
298 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
300 /* Return the exception code */
301 _SEH2_YIELD(return _SEH2_GetExceptionCode());
305 NewAcl
= ExAllocatePoolWithTag(PoolType
,
312 RtlCopyMemory(NewAcl
,
316 *CapturedAcl
= NewAcl
;
318 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
320 /* Free the ACL and return the exception code */
321 ExFreePoolWithTag(NewAcl
, TAG_ACL
);
322 _SEH2_YIELD(return _SEH2_GetExceptionCode());
328 Status
= STATUS_INSUFFICIENT_RESOURCES
;
331 else if (!CaptureIfKernel
)
333 *CapturedAcl
= InputAcl
;
337 AclSize
= InputAcl
->AclSize
;
339 NewAcl
= ExAllocatePoolWithTag(PoolType
,
345 RtlCopyMemory(NewAcl
,
349 *CapturedAcl
= NewAcl
;
353 Status
= STATUS_INSUFFICIENT_RESOURCES
;
362 SepReleaseAcl(IN PACL CapturedAcl
,
363 IN KPROCESSOR_MODE AccessMode
,
364 IN BOOLEAN CaptureIfKernel
)
368 if (CapturedAcl
!= NULL
&&
369 (AccessMode
!= KernelMode
||
370 (AccessMode
== KernelMode
&& CaptureIfKernel
)))
372 ExFreePoolWithTag(CapturedAcl
, TAG_ACL
);
377 SepShouldPropagateAce(
379 _Out_ PUCHAR NewAceFlags
,
380 _In_ BOOLEAN IsInherited
,
381 _In_ BOOLEAN IsDirectoryObject
)
385 *NewAceFlags
= AceFlags
;
389 if (!IsDirectoryObject
)
391 if (AceFlags
& OBJECT_INHERIT_ACE
)
393 *NewAceFlags
= AceFlags
& ~VALID_INHERIT_FLAGS
;
399 if (AceFlags
& NO_PROPAGATE_INHERIT_ACE
)
401 if (AceFlags
& CONTAINER_INHERIT_ACE
)
403 *NewAceFlags
= AceFlags
& ~VALID_INHERIT_FLAGS
;
409 if (AceFlags
& CONTAINER_INHERIT_ACE
)
411 *NewAceFlags
= CONTAINER_INHERIT_ACE
| (AceFlags
& OBJECT_INHERIT_ACE
) | (AceFlags
& ~VALID_INHERIT_FLAGS
);
415 if (AceFlags
& OBJECT_INHERIT_ACE
)
417 *NewAceFlags
= INHERIT_ONLY_ACE
| OBJECT_INHERIT_ACE
| (AceFlags
& ~VALID_INHERIT_FLAGS
);
426 _Out_writes_bytes_opt_(AclLength
) PACL AclDest
,
427 _Inout_ PULONG AclLength
,
428 _In_reads_bytes_(AclSource
->AclSize
) PACL AclSource
,
431 _In_ BOOLEAN IsInherited
,
432 _In_ BOOLEAN IsDirectoryObject
,
433 _In_ PGENERIC_MAPPING GenericMapping
)
436 PACCESS_ALLOWED_ACE AceSource
;
437 PACCESS_ALLOWED_ACE AceDest
;
439 PUCHAR CurrentSource
;
446 BOOLEAN WriteTwoAces
;
448 ASSERT(RtlValidAcl(AclSource
));
449 ASSERT(AclSource
->AclSize
% sizeof(ULONG
) == 0);
450 ASSERT(AclSource
->Sbz1
== 0);
451 ASSERT(AclSource
->Sbz2
== 0);
454 if (*AclLength
>= Written
+ sizeof(ACL
))
456 RtlCopyMemory(AclDest
,
460 Written
+= sizeof(ACL
);
462 CurrentDest
= (PUCHAR
)(AclDest
+ 1);
463 CurrentSource
= (PUCHAR
)(AclSource
+ 1);
464 for (i
= 0; i
< AclSource
->AceCount
; i
++)
466 ASSERT((ULONG_PTR
)CurrentDest
% sizeof(ULONG
) == 0);
467 ASSERT((ULONG_PTR
)CurrentSource
% sizeof(ULONG
) == 0);
468 AceDest
= (PACCESS_ALLOWED_ACE
)CurrentDest
;
469 AceSource
= (PACCESS_ALLOWED_ACE
)CurrentSource
;
471 if (AceSource
->Header
.AceType
> ACCESS_MAX_MS_V2_ACE_TYPE
)
473 /* FIXME: handle object & compound ACEs */
474 AceSize
= AceSource
->Header
.AceSize
;
476 if (*AclLength
>= Written
+ AceSize
)
478 RtlCopyMemory(AceDest
, AceSource
, AceSize
);
480 CurrentDest
+= AceSize
;
481 CurrentSource
+= AceSize
;
487 /* These all have the same structure */
488 ASSERT(AceSource
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
||
489 AceSource
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
||
490 AceSource
->Header
.AceType
== SYSTEM_AUDIT_ACE_TYPE
||
491 AceSource
->Header
.AceType
== SYSTEM_ALARM_ACE_TYPE
);
493 ASSERT(AceSource
->Header
.AceSize
% sizeof(ULONG
) == 0);
494 ASSERT(AceSource
->Header
.AceSize
>= sizeof(*AceSource
));
495 if (!SepShouldPropagateAce(AceSource
->Header
.AceFlags
,
500 CurrentSource
+= AceSource
->Header
.AceSize
;
504 /* FIXME: filter out duplicate ACEs */
505 AceSize
= AceSource
->Header
.AceSize
;
506 Mask
= AceSource
->Mask
;
507 Sid
= (PSID
)&AceSource
->SidStart
;
508 ASSERT(AceSize
>= FIELD_OFFSET(ACCESS_ALLOWED_ACE
, SidStart
) + RtlLengthSid(Sid
));
510 WriteTwoAces
= FALSE
;
511 /* Map effective ACE to specific rights */
512 if (!(AceFlags
& INHERIT_ONLY_ACE
))
514 RtlMapGenericMask(&Mask
, GenericMapping
);
515 Mask
&= GenericMapping
->GenericAll
;
519 if (RtlEqualSid(Sid
, SeCreatorOwnerSid
))
521 else if (RtlEqualSid(Sid
, SeCreatorGroupSid
))
523 AceSize
= FIELD_OFFSET(ACCESS_ALLOWED_ACE
, SidStart
) + RtlLengthSid(Sid
);
526 * A generic container ACE becomes two ACEs:
527 * - a specific effective ACE with no inheritance flags
528 * - an inherit-only ACE that keeps the generic rights
530 if (IsDirectoryObject
&&
531 (AceFlags
& CONTAINER_INHERIT_ACE
) &&
532 (Mask
!= AceSource
->Mask
|| Sid
!= (PSID
)&AceSource
->SidStart
))
541 if (*AclLength
>= Written
+ AceSize
)
543 AceDest
->Header
.AceType
= AceSource
->Header
.AceType
;
544 AceDest
->Header
.AceFlags
= WriteTwoAces
? AceFlags
& ~VALID_INHERIT_FLAGS
546 AceDest
->Header
.AceSize
= AceSize
;
547 AceDest
->Mask
= Mask
;
548 RtlCopySid(AceSize
- FIELD_OFFSET(ACCESS_ALLOWED_ACE
, SidStart
),
549 (PSID
)&AceDest
->SidStart
,
555 CurrentDest
+= AceSize
;
560 /* Second ACE keeps all the generics from the source ACE */
561 WriteTwoAces
= FALSE
;
562 AceDest
= (PACCESS_ALLOWED_ACE
)CurrentDest
;
563 AceSize
= AceSource
->Header
.AceSize
;
564 Mask
= AceSource
->Mask
;
565 Sid
= (PSID
)&AceSource
->SidStart
;
566 AceFlags
|= INHERIT_ONLY_ACE
;
569 CurrentSource
+= AceSource
->Header
.AceSize
;
572 if (*AclLength
>= sizeof(ACL
))
574 AclDest
->AceCount
= AceCount
;
575 AclDest
->AclSize
= Written
;
578 if (Written
> *AclLength
)
580 *AclLength
= Written
;
581 return STATUS_BUFFER_TOO_SMALL
;
583 *AclLength
= Written
;
584 return STATUS_SUCCESS
;
589 _In_opt_ PACL ExplicitAcl
,
590 _In_ BOOLEAN ExplicitPresent
,
591 _In_ BOOLEAN ExplicitDefaulted
,
592 _In_opt_ PACL ParentAcl
,
593 _In_opt_ PACL DefaultAcl
,
594 _Out_ PULONG AclLength
,
597 _Out_ PBOOLEAN AclPresent
,
598 _Out_ PBOOLEAN IsInherited
,
599 _In_ BOOLEAN IsDirectoryObject
,
600 _In_ PGENERIC_MAPPING GenericMapping
)
606 if (ExplicitPresent
&& !ExplicitDefaulted
)
616 Status
= SepPropagateAcl(NULL
,
624 ASSERT(Status
== STATUS_BUFFER_TOO_SMALL
);
626 /* Use the parent ACL only if it's not empty */
627 if (*AclLength
!= sizeof(ACL
))
646 *IsInherited
= FALSE
;
651 Status
= SepPropagateAcl(NULL
,
659 ASSERT(Status
== STATUS_BUFFER_TOO_SMALL
);