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