xref: /reactos/ntoskrnl/se/acl.c (revision aea948a7)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/se/acl.c
5  * PURPOSE:         Security manager
6  *
7  * PROGRAMMERS:     David Welch <welch@cwcom.net>
8  */
9 
10 /* INCLUDES *******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS ********************************************************************/
17 
18 PACL SePublicDefaultDacl = NULL;
19 PACL SeSystemDefaultDacl = NULL;
20 PACL SePublicDefaultUnrestrictedDacl = NULL;
21 PACL SePublicOpenDacl = NULL;
22 PACL SePublicOpenUnrestrictedDacl = NULL;
23 PACL SeUnrestrictedDacl = NULL;
24 PACL SeSystemAnonymousLogonDacl = NULL;
25 
26 /* FUNCTIONS ******************************************************************/
27 
28 CODE_SEG("INIT")
29 BOOLEAN
30 NTAPI
31 SepInitDACLs(VOID)
32 {
33     ULONG AclLength;
34 
35     /* create PublicDefaultDacl */
36     AclLength = sizeof(ACL) +
37                 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
38                 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
39                 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid));
40 
41     SePublicDefaultDacl = ExAllocatePoolWithTag(PagedPool,
42                                                 AclLength,
43                                                 TAG_ACL);
44     if (SePublicDefaultDacl == NULL)
45         return FALSE;
46 
47     RtlCreateAcl(SePublicDefaultDacl,
48                  AclLength,
49                  ACL_REVISION);
50 
51     RtlAddAccessAllowedAce(SePublicDefaultDacl,
52                            ACL_REVISION,
53                            GENERIC_EXECUTE,
54                            SeWorldSid);
55 
56     RtlAddAccessAllowedAce(SePublicDefaultDacl,
57                            ACL_REVISION,
58                            GENERIC_ALL,
59                            SeLocalSystemSid);
60 
61     RtlAddAccessAllowedAce(SePublicDefaultDacl,
62                            ACL_REVISION,
63                            GENERIC_ALL,
64                            SeAliasAdminsSid);
65 
66     /* create PublicDefaultUnrestrictedDacl */
67     AclLength = sizeof(ACL) +
68                 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
69                 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
70                 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) +
71                 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid));
72 
73     SePublicDefaultUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool,
74                                                             AclLength,
75                                                             TAG_ACL);
76     if (SePublicDefaultUnrestrictedDacl == NULL)
77         return FALSE;
78 
79     RtlCreateAcl(SePublicDefaultUnrestrictedDacl,
80                  AclLength,
81                  ACL_REVISION);
82 
83     RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl,
84                            ACL_REVISION,
85                            GENERIC_EXECUTE,
86                            SeWorldSid);
87 
88     RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl,
89                            ACL_REVISION,
90                            GENERIC_ALL,
91                            SeLocalSystemSid);
92 
93     RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl,
94                            ACL_REVISION,
95                            GENERIC_ALL,
96                            SeAliasAdminsSid);
97 
98     RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl,
99                            ACL_REVISION,
100                            GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL,
101                            SeRestrictedCodeSid);
102 
103     /* create PublicOpenDacl */
104     AclLength = sizeof(ACL) +
105                 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
106                 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
107                 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid));
108 
109     SePublicOpenDacl = ExAllocatePoolWithTag(PagedPool,
110                                              AclLength,
111                                              TAG_ACL);
112     if (SePublicOpenDacl == NULL)
113         return FALSE;
114 
115     RtlCreateAcl(SePublicOpenDacl,
116                  AclLength,
117                  ACL_REVISION);
118 
119     RtlAddAccessAllowedAce(SePublicOpenDacl,
120                            ACL_REVISION,
121                            GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
122                            SeWorldSid);
123 
124     RtlAddAccessAllowedAce(SePublicOpenDacl,
125                            ACL_REVISION,
126                            GENERIC_ALL,
127                            SeLocalSystemSid);
128 
129     RtlAddAccessAllowedAce(SePublicOpenDacl,
130                            ACL_REVISION,
131                            GENERIC_ALL,
132                            SeAliasAdminsSid);
133 
134     /* create PublicOpenUnrestrictedDacl */
135     AclLength = sizeof(ACL) +
136                 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
137                 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
138                 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) +
139                 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid));
140 
141     SePublicOpenUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool,
142                                                          AclLength,
143                                                          TAG_ACL);
144     if (SePublicOpenUnrestrictedDacl == NULL)
145         return FALSE;
146 
147     RtlCreateAcl(SePublicOpenUnrestrictedDacl,
148                  AclLength,
149                  ACL_REVISION);
150 
151     RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl,
152                            ACL_REVISION,
153                            GENERIC_ALL,
154                            SeWorldSid);
155 
156     RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl,
157                            ACL_REVISION,
158                            GENERIC_ALL,
159                            SeLocalSystemSid);
160 
161     RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl,
162                            ACL_REVISION,
163                            GENERIC_ALL,
164                            SeAliasAdminsSid);
165 
166     RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl,
167                            ACL_REVISION,
168                            GENERIC_READ | GENERIC_EXECUTE,
169                            SeRestrictedCodeSid);
170 
171     /* create SystemDefaultDacl */
172     AclLength = sizeof(ACL) +
173                 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
174                 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid));
175 
176     SeSystemDefaultDacl = ExAllocatePoolWithTag(PagedPool,
177                                                 AclLength,
178                                                 TAG_ACL);
179     if (SeSystemDefaultDacl == NULL)
180         return FALSE;
181 
182     RtlCreateAcl(SeSystemDefaultDacl,
183                  AclLength,
184                  ACL_REVISION);
185 
186     RtlAddAccessAllowedAce(SeSystemDefaultDacl,
187                            ACL_REVISION,
188                            GENERIC_ALL,
189                            SeLocalSystemSid);
190 
191     RtlAddAccessAllowedAce(SeSystemDefaultDacl,
192                            ACL_REVISION,
193                            GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL,
194                            SeAliasAdminsSid);
195 
196     /* create UnrestrictedDacl */
197     AclLength = sizeof(ACL) +
198                 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
199                 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid));
200 
201     SeUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool,
202                                                AclLength,
203                                                TAG_ACL);
204     if (SeUnrestrictedDacl == NULL)
205         return FALSE;
206 
207     RtlCreateAcl(SeUnrestrictedDacl,
208                  AclLength,
209                  ACL_REVISION);
210 
211     RtlAddAccessAllowedAce(SeUnrestrictedDacl,
212                            ACL_REVISION,
213                            GENERIC_ALL,
214                            SeWorldSid);
215 
216     RtlAddAccessAllowedAce(SeUnrestrictedDacl,
217                            ACL_REVISION,
218                            GENERIC_READ | GENERIC_EXECUTE,
219                            SeRestrictedCodeSid);
220 
221     /* create SystemAnonymousLogonDacl */
222     AclLength = sizeof(ACL) +
223                 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
224                 (sizeof(ACE) + RtlLengthSid(SeAnonymousLogonSid));
225 
226     SeSystemAnonymousLogonDacl = ExAllocatePoolWithTag(PagedPool,
227                                                        AclLength,
228                                                        TAG_ACL);
229     if (SeSystemAnonymousLogonDacl == NULL)
230         return FALSE;
231 
232     RtlCreateAcl(SeSystemAnonymousLogonDacl,
233                  AclLength,
234                  ACL_REVISION);
235 
236     RtlAddAccessAllowedAce(SeSystemAnonymousLogonDacl,
237                            ACL_REVISION,
238                            GENERIC_ALL,
239                            SeWorldSid);
240 
241     RtlAddAccessAllowedAce(SeSystemAnonymousLogonDacl,
242                            ACL_REVISION,
243                            GENERIC_ALL,
244                            SeAnonymousLogonSid);
245 
246     return TRUE;
247 }
248 
249 NTSTATUS
250 NTAPI
251 SepCreateImpersonationTokenDacl(
252     _In_ PTOKEN Token,
253     _In_ PTOKEN PrimaryToken,
254     _Out_ PACL* Dacl)
255 {
256     ULONG AclLength;
257     PACL TokenDacl;
258 
259     PAGED_CODE();
260 
261     *Dacl = NULL;
262 
263     AclLength = sizeof(ACL) +
264         (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) +
265         (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
266         (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid)) +
267         (sizeof(ACE) + RtlLengthSid(Token->UserAndGroups->Sid)) +
268         (sizeof(ACE) + RtlLengthSid(PrimaryToken->UserAndGroups->Sid));
269 
270     TokenDacl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_ACL);
271     if (TokenDacl == NULL)
272     {
273         return STATUS_INSUFFICIENT_RESOURCES;
274     }
275 
276     RtlCreateAcl(TokenDacl, AclLength, ACL_REVISION);
277     RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
278                            Token->UserAndGroups->Sid);
279     RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
280                            PrimaryToken->UserAndGroups->Sid);
281     RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
282                            SeAliasAdminsSid);
283     RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
284                            SeLocalSystemSid);
285 
286     if (Token->RestrictedSids != NULL || PrimaryToken->RestrictedSids != NULL)
287     {
288         RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
289                                SeRestrictedCodeSid);
290     }
291 
292     *Dacl = TokenDacl;
293 
294     return STATUS_SUCCESS;
295 }
296 
297 NTSTATUS
298 NTAPI
299 SepCaptureAcl(IN PACL InputAcl,
300               IN KPROCESSOR_MODE AccessMode,
301               IN POOL_TYPE PoolType,
302               IN BOOLEAN CaptureIfKernel,
303               OUT PACL *CapturedAcl)
304 {
305     PACL NewAcl;
306     ULONG AclSize = 0;
307     NTSTATUS Status = STATUS_SUCCESS;
308 
309     PAGED_CODE();
310 
311     if (AccessMode != KernelMode)
312     {
313         _SEH2_TRY
314         {
315             ProbeForRead(InputAcl,
316                          sizeof(ACL),
317                          sizeof(ULONG));
318             AclSize = InputAcl->AclSize;
319             ProbeForRead(InputAcl,
320                          AclSize,
321                          sizeof(ULONG));
322         }
323         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
324         {
325             /* Return the exception code */
326             _SEH2_YIELD(return _SEH2_GetExceptionCode());
327         }
328         _SEH2_END;
329 
330         NewAcl = ExAllocatePoolWithTag(PoolType,
331                                        AclSize,
332                                        TAG_ACL);
333         if (NewAcl != NULL)
334         {
335             _SEH2_TRY
336             {
337                 RtlCopyMemory(NewAcl,
338                               InputAcl,
339                               AclSize);
340 
341                 *CapturedAcl = NewAcl;
342             }
343             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
344             {
345                 /* Free the ACL and return the exception code */
346                 ExFreePoolWithTag(NewAcl, TAG_ACL);
347                 _SEH2_YIELD(return _SEH2_GetExceptionCode());
348             }
349             _SEH2_END;
350         }
351         else
352         {
353             Status = STATUS_INSUFFICIENT_RESOURCES;
354         }
355     }
356     else if (!CaptureIfKernel)
357     {
358         *CapturedAcl = InputAcl;
359     }
360     else
361     {
362         AclSize = InputAcl->AclSize;
363 
364         NewAcl = ExAllocatePoolWithTag(PoolType,
365                                        AclSize,
366                                        TAG_ACL);
367 
368         if (NewAcl != NULL)
369         {
370             RtlCopyMemory(NewAcl,
371                           InputAcl,
372                           AclSize);
373 
374             *CapturedAcl = NewAcl;
375         }
376         else
377         {
378             Status = STATUS_INSUFFICIENT_RESOURCES;
379         }
380     }
381 
382     return Status;
383 }
384 
385 VOID
386 NTAPI
387 SepReleaseAcl(IN PACL CapturedAcl,
388               IN KPROCESSOR_MODE AccessMode,
389               IN BOOLEAN CaptureIfKernel)
390 {
391     PAGED_CODE();
392 
393     if (CapturedAcl != NULL &&
394         (AccessMode != KernelMode ||
395          (AccessMode == KernelMode && CaptureIfKernel)))
396     {
397         ExFreePoolWithTag(CapturedAcl, TAG_ACL);
398     }
399 }
400 
401 BOOLEAN
402 SepShouldPropagateAce(
403     _In_ UCHAR AceFlags,
404     _Out_ PUCHAR NewAceFlags,
405     _In_ BOOLEAN IsInherited,
406     _In_ BOOLEAN IsDirectoryObject)
407 {
408     if (!IsInherited)
409     {
410         *NewAceFlags = AceFlags;
411         return TRUE;
412     }
413 
414     if (!IsDirectoryObject)
415     {
416         if (AceFlags & OBJECT_INHERIT_ACE)
417         {
418             *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS;
419             return TRUE;
420         }
421         return FALSE;
422     }
423 
424     if (AceFlags & NO_PROPAGATE_INHERIT_ACE)
425     {
426         if (AceFlags & CONTAINER_INHERIT_ACE)
427         {
428             *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS;
429             return TRUE;
430         }
431         return FALSE;
432     }
433 
434     if (AceFlags & CONTAINER_INHERIT_ACE)
435     {
436         *NewAceFlags = CONTAINER_INHERIT_ACE | (AceFlags & OBJECT_INHERIT_ACE) | (AceFlags & ~VALID_INHERIT_FLAGS);
437         return TRUE;
438     }
439 
440     if (AceFlags & OBJECT_INHERIT_ACE)
441     {
442         *NewAceFlags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | (AceFlags & ~VALID_INHERIT_FLAGS);
443         return TRUE;
444     }
445 
446     return FALSE;
447 }
448 
449 NTSTATUS
450 SepPropagateAcl(
451     _Out_writes_bytes_opt_(AclLength) PACL AclDest,
452     _Inout_ PULONG AclLength,
453     _In_reads_bytes_(AclSource->AclSize) PACL AclSource,
454     _In_ PSID Owner,
455     _In_ PSID Group,
456     _In_ BOOLEAN IsInherited,
457     _In_ BOOLEAN IsDirectoryObject,
458     _In_ PGENERIC_MAPPING GenericMapping)
459 {
460     ACCESS_MASK Mask;
461     PACCESS_ALLOWED_ACE AceSource;
462     PACCESS_ALLOWED_ACE AceDest;
463     PUCHAR CurrentDest;
464     PUCHAR CurrentSource;
465     ULONG i;
466     ULONG Written;
467     UCHAR AceFlags;
468     USHORT AceSize;
469     USHORT AceCount = 0;
470     PSID Sid;
471     BOOLEAN WriteTwoAces;
472 
473     ASSERT(RtlValidAcl(AclSource));
474     ASSERT(AclSource->AclSize % sizeof(ULONG) == 0);
475     ASSERT(AclSource->Sbz1 == 0);
476     ASSERT(AclSource->Sbz2 == 0);
477 
478     Written = 0;
479     if (*AclLength >= Written + sizeof(ACL))
480     {
481         RtlCopyMemory(AclDest,
482                       AclSource,
483                       sizeof(ACL));
484     }
485     Written += sizeof(ACL);
486 
487     CurrentDest = (PUCHAR)(AclDest + 1);
488     CurrentSource = (PUCHAR)(AclSource + 1);
489     for (i = 0; i < AclSource->AceCount; i++)
490     {
491         ASSERT((ULONG_PTR)CurrentDest % sizeof(ULONG) == 0);
492         ASSERT((ULONG_PTR)CurrentSource % sizeof(ULONG) == 0);
493         AceDest = (PACCESS_ALLOWED_ACE)CurrentDest;
494         AceSource = (PACCESS_ALLOWED_ACE)CurrentSource;
495 
496         if (AceSource->Header.AceType > ACCESS_MAX_MS_V2_ACE_TYPE)
497         {
498             /* FIXME: handle object & compound ACEs */
499             AceSize = AceSource->Header.AceSize;
500 
501             if (*AclLength >= Written + AceSize)
502             {
503                 RtlCopyMemory(AceDest, AceSource, AceSize);
504             }
505             CurrentDest += AceSize;
506             CurrentSource += AceSize;
507             Written += AceSize;
508             AceCount++;
509             continue;
510         }
511 
512         /* These all have the same structure */
513         ASSERT(AceSource->Header.AceType == ACCESS_ALLOWED_ACE_TYPE ||
514                AceSource->Header.AceType == ACCESS_DENIED_ACE_TYPE ||
515                AceSource->Header.AceType == SYSTEM_AUDIT_ACE_TYPE ||
516                AceSource->Header.AceType == SYSTEM_ALARM_ACE_TYPE);
517 
518         ASSERT(AceSource->Header.AceSize % sizeof(ULONG) == 0);
519         ASSERT(AceSource->Header.AceSize >= sizeof(*AceSource));
520         if (!SepShouldPropagateAce(AceSource->Header.AceFlags,
521                                    &AceFlags,
522                                    IsInherited,
523                                    IsDirectoryObject))
524         {
525             CurrentSource += AceSource->Header.AceSize;
526             continue;
527         }
528 
529         /* FIXME: filter out duplicate ACEs */
530         AceSize = AceSource->Header.AceSize;
531         Mask = AceSource->Mask;
532         Sid = (PSID)&AceSource->SidStart;
533         ASSERT(AceSize >= FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid));
534 
535         WriteTwoAces = FALSE;
536         /* Map effective ACE to specific rights */
537         if (!(AceFlags & INHERIT_ONLY_ACE))
538         {
539             RtlMapGenericMask(&Mask, GenericMapping);
540             Mask &= GenericMapping->GenericAll;
541 
542             if (IsInherited)
543             {
544                 if (RtlEqualSid(Sid, SeCreatorOwnerSid))
545                     Sid = Owner;
546                 else if (RtlEqualSid(Sid, SeCreatorGroupSid))
547                     Sid = Group;
548                 AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid);
549 
550                 /*
551                  * A generic container ACE becomes two ACEs:
552                  * - a specific effective ACE with no inheritance flags
553                  * - an inherit-only ACE that keeps the generic rights
554                  */
555                 if (IsDirectoryObject &&
556                     (AceFlags & CONTAINER_INHERIT_ACE) &&
557                     (Mask != AceSource->Mask || Sid != (PSID)&AceSource->SidStart))
558                 {
559                     WriteTwoAces = TRUE;
560                 }
561             }
562         }
563 
564         while (1)
565         {
566             if (*AclLength >= Written + AceSize)
567             {
568                 AceDest->Header.AceType = AceSource->Header.AceType;
569                 AceDest->Header.AceFlags = WriteTwoAces ? AceFlags & ~VALID_INHERIT_FLAGS
570                                                         : AceFlags;
571                 AceDest->Header.AceSize = AceSize;
572                 AceDest->Mask = Mask;
573                 RtlCopySid(AceSize - FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart),
574                            (PSID)&AceDest->SidStart,
575                            Sid);
576             }
577             Written += AceSize;
578 
579             AceCount++;
580             CurrentDest += AceSize;
581 
582             if (!WriteTwoAces)
583                 break;
584 
585             /* Second ACE keeps all the generics from the source ACE */
586             WriteTwoAces = FALSE;
587             AceDest = (PACCESS_ALLOWED_ACE)CurrentDest;
588             AceSize = AceSource->Header.AceSize;
589             Mask = AceSource->Mask;
590             Sid = (PSID)&AceSource->SidStart;
591             AceFlags |= INHERIT_ONLY_ACE;
592         }
593 
594         CurrentSource += AceSource->Header.AceSize;
595     }
596 
597     if (*AclLength >= sizeof(ACL))
598     {
599         AclDest->AceCount = AceCount;
600         AclDest->AclSize = Written;
601     }
602 
603     if (Written > *AclLength)
604     {
605         *AclLength = Written;
606         return STATUS_BUFFER_TOO_SMALL;
607     }
608     *AclLength = Written;
609     return STATUS_SUCCESS;
610 }
611 
612 PACL
613 SepSelectAcl(
614     _In_opt_ PACL ExplicitAcl,
615     _In_ BOOLEAN ExplicitPresent,
616     _In_ BOOLEAN ExplicitDefaulted,
617     _In_opt_ PACL ParentAcl,
618     _In_opt_ PACL DefaultAcl,
619     _Out_ PULONG AclLength,
620     _In_ PSID Owner,
621     _In_ PSID Group,
622     _Out_ PBOOLEAN AclPresent,
623     _Out_ PBOOLEAN IsInherited,
624     _In_ BOOLEAN IsDirectoryObject,
625     _In_ PGENERIC_MAPPING GenericMapping)
626 {
627     PACL Acl;
628     NTSTATUS Status;
629 
630     *AclPresent = TRUE;
631     if (ExplicitPresent && !ExplicitDefaulted)
632     {
633         Acl = ExplicitAcl;
634     }
635     else
636     {
637         if (ParentAcl)
638         {
639             *IsInherited = TRUE;
640             *AclLength = 0;
641             Status = SepPropagateAcl(NULL,
642                                      AclLength,
643                                      ParentAcl,
644                                      Owner,
645                                      Group,
646                                      *IsInherited,
647                                      IsDirectoryObject,
648                                      GenericMapping);
649             ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
650 
651             /* Use the parent ACL only if it's not empty */
652             if (*AclLength != sizeof(ACL))
653                 return ParentAcl;
654         }
655 
656         if (ExplicitPresent)
657         {
658             Acl = ExplicitAcl;
659         }
660         else if (DefaultAcl)
661         {
662             Acl = DefaultAcl;
663         }
664         else
665         {
666             *AclPresent = FALSE;
667             Acl = NULL;
668         }
669     }
670 
671     *IsInherited = FALSE;
672     *AclLength = 0;
673     if (Acl)
674     {
675         /* Get the length */
676         Status = SepPropagateAcl(NULL,
677                                  AclLength,
678                                  Acl,
679                                  Owner,
680                                  Group,
681                                  *IsInherited,
682                                  IsDirectoryObject,
683                                  GenericMapping);
684         ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
685     }
686     return Acl;
687 }
688 
689 /* EOF */
690