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