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
));
43 SePublicDefaultDacl
= ExAllocatePoolWithTag(PagedPool
,
46 if (SePublicDefaultDacl
== NULL
)
49 RtlCreateAcl(SePublicDefaultDacl
,
53 RtlAddAccessAllowedAce(SePublicDefaultDacl
,
58 RtlAddAccessAllowedAce(SePublicDefaultDacl
,
63 /* create PublicDefaultUnrestrictedDacl */
64 AclLength
= sizeof(ACL
) +
65 (sizeof(ACE
) + RtlLengthSid(SeWorldSid
)) +
66 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
67 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
)) +
68 (sizeof(ACE
) + RtlLengthSid(SeRestrictedCodeSid
));
70 SePublicDefaultUnrestrictedDacl
= ExAllocatePoolWithTag(PagedPool
,
73 if (SePublicDefaultUnrestrictedDacl
== NULL
)
76 RtlCreateAcl(SePublicDefaultUnrestrictedDacl
,
80 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl
,
85 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl
,
90 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl
,
95 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl
,
97 GENERIC_READ
| GENERIC_EXECUTE
| READ_CONTROL
,
100 /* create PublicOpenDacl */
101 AclLength
= sizeof(ACL
) +
102 (sizeof(ACE
) + RtlLengthSid(SeWorldSid
)) +
103 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
104 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
));
106 SePublicOpenDacl
= ExAllocatePoolWithTag(PagedPool
,
109 if (SePublicOpenDacl
== NULL
)
112 RtlCreateAcl(SePublicOpenDacl
,
116 RtlAddAccessAllowedAce(SePublicOpenDacl
,
118 GENERIC_READ
| GENERIC_WRITE
| GENERIC_EXECUTE
,
121 RtlAddAccessAllowedAce(SePublicOpenDacl
,
126 RtlAddAccessAllowedAce(SePublicOpenDacl
,
131 /* create PublicOpenUnrestrictedDacl */
132 AclLength
= sizeof(ACL
) +
133 (sizeof(ACE
) + RtlLengthSid(SeWorldSid
)) +
134 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
135 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
)) +
136 (sizeof(ACE
) + RtlLengthSid(SeRestrictedCodeSid
));
138 SePublicOpenUnrestrictedDacl
= ExAllocatePoolWithTag(PagedPool
,
141 if (SePublicOpenUnrestrictedDacl
== NULL
)
144 RtlCreateAcl(SePublicOpenUnrestrictedDacl
,
148 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl
,
153 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl
,
158 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl
,
163 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl
,
165 GENERIC_READ
| GENERIC_EXECUTE
,
166 SeRestrictedCodeSid
);
168 /* create SystemDefaultDacl */
169 AclLength
= sizeof(ACL
) +
170 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
171 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
));
173 SeSystemDefaultDacl
= ExAllocatePoolWithTag(PagedPool
,
176 if (SeSystemDefaultDacl
== NULL
)
179 RtlCreateAcl(SeSystemDefaultDacl
,
183 RtlAddAccessAllowedAce(SeSystemDefaultDacl
,
188 RtlAddAccessAllowedAce(SeSystemDefaultDacl
,
190 GENERIC_READ
| GENERIC_EXECUTE
| READ_CONTROL
,
193 /* create UnrestrictedDacl */
194 AclLength
= sizeof(ACL
) +
195 (sizeof(ACE
) + RtlLengthSid(SeWorldSid
)) +
196 (sizeof(ACE
) + RtlLengthSid(SeRestrictedCodeSid
));
198 SeUnrestrictedDacl
= ExAllocatePoolWithTag(PagedPool
,
201 if (SeUnrestrictedDacl
== NULL
)
204 RtlCreateAcl(SeUnrestrictedDacl
,
208 RtlAddAccessAllowedAce(SeUnrestrictedDacl
,
213 RtlAddAccessAllowedAce(SeUnrestrictedDacl
,
215 GENERIC_READ
| GENERIC_EXECUTE
,
216 SeRestrictedCodeSid
);
222 SepCreateImpersonationTokenDacl(PTOKEN Token
,
231 AclLength
= sizeof(ACL
) +
232 (sizeof(ACE
) + RtlLengthSid(SeAliasAdminsSid
)) +
233 (sizeof(ACE
) + RtlLengthSid(SeRestrictedCodeSid
)) +
234 (sizeof(ACE
) + RtlLengthSid(SeLocalSystemSid
)) +
235 (sizeof(ACE
) + RtlLengthSid(Token
->UserAndGroups
->Sid
)) +
236 (sizeof(ACE
) + RtlLengthSid(PrimaryToken
->UserAndGroups
->Sid
));
238 TokenDacl
= ExAllocatePoolWithTag(PagedPool
, AclLength
, TAG_ACL
);
239 if (TokenDacl
== NULL
)
241 return STATUS_INSUFFICIENT_RESOURCES
;
244 RtlCreateAcl(TokenDacl
, AclLength
, ACL_REVISION
);
245 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
246 Token
->UserAndGroups
->Sid
);
247 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
248 PrimaryToken
->UserAndGroups
->Sid
);
249 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
251 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
256 if (Token
->RestrictedSids
!= NULL
|| PrimaryToken
->RestrictedSids
!= NULL
)
258 RtlAddAccessAllowedAce(TokenDacl
, ACL_REVISION
, GENERIC_ALL
,
259 SeRestrictedCodeSid
);
263 return STATUS_SUCCESS
;
268 SepCaptureAcl(IN PACL InputAcl
,
269 IN KPROCESSOR_MODE AccessMode
,
270 IN POOL_TYPE PoolType
,
271 IN BOOLEAN CaptureIfKernel
,
272 OUT PACL
*CapturedAcl
)
276 NTSTATUS Status
= STATUS_SUCCESS
;
280 if (AccessMode
!= KernelMode
)
284 ProbeForRead(InputAcl
,
287 AclSize
= InputAcl
->AclSize
;
288 ProbeForRead(InputAcl
,
292 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
294 /* Return the exception code */
295 _SEH2_YIELD(return _SEH2_GetExceptionCode());
299 NewAcl
= ExAllocatePoolWithTag(PoolType
,
306 RtlCopyMemory(NewAcl
,
310 *CapturedAcl
= NewAcl
;
312 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
314 /* Free the ACL and return the exception code */
315 ExFreePoolWithTag(NewAcl
, TAG_ACL
);
316 _SEH2_YIELD(return _SEH2_GetExceptionCode());
322 Status
= STATUS_INSUFFICIENT_RESOURCES
;
325 else if (!CaptureIfKernel
)
327 *CapturedAcl
= InputAcl
;
331 AclSize
= InputAcl
->AclSize
;
333 NewAcl
= ExAllocatePoolWithTag(PoolType
,
339 RtlCopyMemory(NewAcl
,
343 *CapturedAcl
= NewAcl
;
347 Status
= STATUS_INSUFFICIENT_RESOURCES
;
356 SepReleaseAcl(IN PACL CapturedAcl
,
357 IN KPROCESSOR_MODE AccessMode
,
358 IN BOOLEAN CaptureIfKernel
)
362 if (CapturedAcl
!= NULL
&&
363 (AccessMode
!= KernelMode
||
364 (AccessMode
== KernelMode
&& CaptureIfKernel
)))
366 ExFreePoolWithTag(CapturedAcl
, TAG_ACL
);
371 SepShouldPropagateAce(
373 _Out_ PUCHAR NewAceFlags
,
374 _In_ BOOLEAN IsInherited
,
375 _In_ BOOLEAN IsDirectoryObject
)
379 *NewAceFlags
= AceFlags
;
383 if (!IsDirectoryObject
)
385 if (AceFlags
& OBJECT_INHERIT_ACE
)
387 *NewAceFlags
= AceFlags
& ~VALID_INHERIT_FLAGS
;
393 if (AceFlags
& NO_PROPAGATE_INHERIT_ACE
)
395 if (AceFlags
& CONTAINER_INHERIT_ACE
)
397 *NewAceFlags
= AceFlags
& ~VALID_INHERIT_FLAGS
;
403 if (AceFlags
& CONTAINER_INHERIT_ACE
)
405 *NewAceFlags
= CONTAINER_INHERIT_ACE
| (AceFlags
& OBJECT_INHERIT_ACE
) | (AceFlags
& ~VALID_INHERIT_FLAGS
);
409 if (AceFlags
& OBJECT_INHERIT_ACE
)
411 *NewAceFlags
= INHERIT_ONLY_ACE
| OBJECT_INHERIT_ACE
| (AceFlags
& ~VALID_INHERIT_FLAGS
);
420 _Out_writes_bytes_opt_(DaclLength
) PACL AclDest
,
421 _Inout_ PULONG AclLength
,
422 _In_reads_bytes_(AclSource
->AclSize
) PACL AclSource
,
425 _In_ BOOLEAN IsInherited
,
426 _In_ BOOLEAN IsDirectoryObject
,
427 _In_ PGENERIC_MAPPING GenericMapping
)
430 PACCESS_ALLOWED_ACE AceSource
;
431 PACCESS_ALLOWED_ACE AceDest
;
433 PUCHAR CurrentSource
;
440 BOOLEAN WriteTwoAces
;
442 if (AclSource
->AclRevision
!= ACL_REVISION
)
444 NT_ASSERT(AclSource
->AclRevision
== ACL_REVISION
);
445 return STATUS_UNKNOWN_REVISION
;
448 NT_ASSERT(AclSource
->AclSize
% sizeof(ULONG
) == 0);
449 NT_ASSERT(AclSource
->Sbz1
== 0);
450 NT_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 NT_ASSERT((ULONG_PTR
)CurrentDest
% sizeof(ULONG
) == 0);
466 NT_ASSERT((ULONG_PTR
)CurrentSource
% sizeof(ULONG
) == 0);
467 AceDest
= (PACCESS_ALLOWED_ACE
)CurrentDest
;
468 AceSource
= (PACCESS_ALLOWED_ACE
)CurrentSource
;
470 /* These all have the same structure */
471 NT_ASSERT(AceSource
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
||
472 AceSource
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
||
473 AceSource
->Header
.AceType
== SYSTEM_AUDIT_ACE_TYPE
);
475 NT_ASSERT(AceSource
->Header
.AceSize
% sizeof(ULONG
) == 0);
476 NT_ASSERT(AceSource
->Header
.AceSize
>= sizeof(*AceSource
));
477 if (!SepShouldPropagateAce(AceSource
->Header
.AceFlags
,
482 CurrentSource
+= AceSource
->Header
.AceSize
;
486 /* FIXME: filter out duplicate ACEs */
487 AceSize
= AceSource
->Header
.AceSize
;
488 Mask
= AceSource
->Mask
;
489 Sid
= (PSID
)&AceSource
->SidStart
;
490 NT_ASSERT(AceSize
>= FIELD_OFFSET(ACCESS_ALLOWED_ACE
, SidStart
) + RtlLengthSid(Sid
));
492 WriteTwoAces
= FALSE
;
493 /* Map effective ACE to specific rights */
494 if (!(AceFlags
& INHERIT_ONLY_ACE
))
496 RtlMapGenericMask(&Mask
, GenericMapping
);
497 Mask
&= GenericMapping
->GenericAll
;
501 if (RtlEqualSid(Sid
, SeCreatorOwnerSid
))
503 else if (RtlEqualSid(Sid
, SeCreatorGroupSid
))
505 AceSize
= FIELD_OFFSET(ACCESS_ALLOWED_ACE
, SidStart
) + RtlLengthSid(Sid
);
508 * A generic container ACE becomes two ACEs:
509 * - a specific effective ACE with no inheritance flags
510 * - an inherit-only ACE that keeps the generic rights
512 if (IsDirectoryObject
&&
513 (AceFlags
& CONTAINER_INHERIT_ACE
) &&
514 (Mask
!= AceSource
->Mask
|| Sid
!= (PSID
)&AceSource
->SidStart
))
523 if (*AclLength
>= Written
+ AceSize
)
525 AceDest
->Header
.AceType
= AceSource
->Header
.AceType
;
526 AceDest
->Header
.AceFlags
= WriteTwoAces
? AceFlags
& ~VALID_INHERIT_FLAGS
528 AceDest
->Header
.AceSize
= AceSize
;
529 AceDest
->Mask
= Mask
;
530 RtlCopySid(AceSize
- FIELD_OFFSET(ACCESS_ALLOWED_ACE
, SidStart
),
531 (PSID
)&AceDest
->SidStart
,
537 CurrentDest
+= AceSize
;
542 /* Second ACE keeps all the generics from the source ACE */
543 WriteTwoAces
= FALSE
;
544 AceDest
= (PACCESS_ALLOWED_ACE
)CurrentDest
;
545 AceSize
= AceSource
->Header
.AceSize
;
546 Mask
= AceSource
->Mask
;
547 Sid
= (PSID
)&AceSource
->SidStart
;
548 AceFlags
|= INHERIT_ONLY_ACE
;
551 CurrentSource
+= AceSource
->Header
.AceSize
;
554 if (*AclLength
>= sizeof(ACL
))
556 AclDest
->AceCount
= AceCount
;
557 AclDest
->AclSize
= Written
;
560 if (Written
> *AclLength
)
562 *AclLength
= Written
;
563 return STATUS_BUFFER_TOO_SMALL
;
565 *AclLength
= Written
;
566 return STATUS_SUCCESS
;
571 _In_opt_ PACL ExplicitAcl
,
572 _In_ BOOLEAN ExplicitPresent
,
573 _In_ BOOLEAN ExplicitDefaulted
,
574 _In_opt_ PACL ParentAcl
,
575 _In_opt_ PACL DefaultAcl
,
576 _Out_ PULONG AclLength
,
579 _Out_ PBOOLEAN AclPresent
,
580 _Out_ PBOOLEAN IsInherited
,
581 _In_ BOOLEAN IsDirectoryObject
,
582 _In_ PGENERIC_MAPPING GenericMapping
)
588 if (ExplicitPresent
&& !ExplicitDefaulted
)
598 Status
= SepPropagateAcl(NULL
,
606 NT_ASSERT(Status
== STATUS_BUFFER_TOO_SMALL
);
608 /* Use the parent ACL only if it's not empty */
609 if (*AclLength
!= sizeof(ACL
))
628 *IsInherited
= FALSE
;
633 Status
= SepPropagateAcl(NULL
,
641 NT_ASSERT(Status
== STATUS_BUFFER_TOO_SMALL
);