xref: /reactos/ntoskrnl/se/sd.c (revision 6d8aafb6)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/se/sd.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 PSECURITY_DESCRIPTOR SePublicDefaultSd = NULL;
19 PSECURITY_DESCRIPTOR SePublicDefaultUnrestrictedSd = NULL;
20 PSECURITY_DESCRIPTOR SePublicOpenSd = NULL;
21 PSECURITY_DESCRIPTOR SePublicOpenUnrestrictedSd = NULL;
22 PSECURITY_DESCRIPTOR SeSystemDefaultSd = NULL;
23 PSECURITY_DESCRIPTOR SeUnrestrictedSd = NULL;
24 
25 /* PRIVATE FUNCTIONS **********************************************************/
26 
27 CODE_SEG("INIT")
28 BOOLEAN
29 NTAPI
30 SepInitSDs(VOID)
31 {
32     /* Create PublicDefaultSd */
33     SePublicDefaultSd = ExAllocatePoolWithTag(PagedPool,
34                                               sizeof(SECURITY_DESCRIPTOR), TAG_SD);
35     if (SePublicDefaultSd == NULL)
36         return FALSE;
37 
38     RtlCreateSecurityDescriptor(SePublicDefaultSd,
39                                 SECURITY_DESCRIPTOR_REVISION);
40     RtlSetDaclSecurityDescriptor(SePublicDefaultSd,
41                                  TRUE,
42                                  SePublicDefaultDacl,
43                                  FALSE);
44 
45     /* Create PublicDefaultUnrestrictedSd */
46     SePublicDefaultUnrestrictedSd = ExAllocatePoolWithTag(PagedPool,
47                                                           sizeof(SECURITY_DESCRIPTOR), TAG_SD);
48     if (SePublicDefaultUnrestrictedSd == NULL)
49         return FALSE;
50 
51     RtlCreateSecurityDescriptor(SePublicDefaultUnrestrictedSd,
52                                 SECURITY_DESCRIPTOR_REVISION);
53     RtlSetDaclSecurityDescriptor(SePublicDefaultUnrestrictedSd,
54                                  TRUE,
55                                  SePublicDefaultUnrestrictedDacl,
56                                  FALSE);
57 
58     /* Create PublicOpenSd */
59     SePublicOpenSd = ExAllocatePoolWithTag(PagedPool,
60                                            sizeof(SECURITY_DESCRIPTOR), TAG_SD);
61     if (SePublicOpenSd == NULL)
62         return FALSE;
63 
64     RtlCreateSecurityDescriptor(SePublicOpenSd,
65                                 SECURITY_DESCRIPTOR_REVISION);
66     RtlSetDaclSecurityDescriptor(SePublicOpenSd,
67                                  TRUE,
68                                  SePublicOpenDacl,
69                                  FALSE);
70 
71     /* Create PublicOpenUnrestrictedSd */
72     SePublicOpenUnrestrictedSd = ExAllocatePoolWithTag(PagedPool,
73                                                        sizeof(SECURITY_DESCRIPTOR), TAG_SD);
74     if (SePublicOpenUnrestrictedSd == NULL)
75         return FALSE;
76 
77     RtlCreateSecurityDescriptor(SePublicOpenUnrestrictedSd,
78                                 SECURITY_DESCRIPTOR_REVISION);
79     RtlSetDaclSecurityDescriptor(SePublicOpenUnrestrictedSd,
80                                  TRUE,
81                                  SePublicOpenUnrestrictedDacl,
82                                  FALSE);
83 
84     /* Create SystemDefaultSd */
85     SeSystemDefaultSd = ExAllocatePoolWithTag(PagedPool,
86                                               sizeof(SECURITY_DESCRIPTOR), TAG_SD);
87     if (SeSystemDefaultSd == NULL)
88         return FALSE;
89 
90     RtlCreateSecurityDescriptor(SeSystemDefaultSd,
91                                 SECURITY_DESCRIPTOR_REVISION);
92     RtlSetDaclSecurityDescriptor(SeSystemDefaultSd,
93                                  TRUE,
94                                  SeSystemDefaultDacl,
95                                  FALSE);
96 
97     /* Create UnrestrictedSd */
98     SeUnrestrictedSd = ExAllocatePoolWithTag(PagedPool,
99                                              sizeof(SECURITY_DESCRIPTOR), TAG_SD);
100     if (SeUnrestrictedSd == NULL)
101         return FALSE;
102 
103     RtlCreateSecurityDescriptor(SeUnrestrictedSd,
104                                 SECURITY_DESCRIPTOR_REVISION);
105     RtlSetDaclSecurityDescriptor(SeUnrestrictedSd,
106                                  TRUE,
107                                  SeUnrestrictedDacl,
108                                  FALSE);
109 
110     return TRUE;
111 }
112 
113 NTSTATUS
114 NTAPI
115 SeSetWorldSecurityDescriptor(SECURITY_INFORMATION SecurityInformation,
116                              PISECURITY_DESCRIPTOR SecurityDescriptor,
117                              PULONG BufferLength)
118 {
119     ULONG Current;
120     ULONG SidSize;
121     ULONG SdSize;
122     NTSTATUS Status;
123     PISECURITY_DESCRIPTOR_RELATIVE SdRel = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptor;
124 
125     DPRINT("SeSetWorldSecurityDescriptor() called\n");
126 
127     if (SecurityInformation == 0)
128     {
129         return STATUS_ACCESS_DENIED;
130     }
131 
132     /* calculate the minimum size of the buffer */
133     SidSize = RtlLengthSid(SeWorldSid);
134     SdSize = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
135     if (SecurityInformation & OWNER_SECURITY_INFORMATION)
136         SdSize += SidSize;
137     if (SecurityInformation & GROUP_SECURITY_INFORMATION)
138         SdSize += SidSize;
139     if (SecurityInformation & DACL_SECURITY_INFORMATION)
140     {
141         SdSize += sizeof(ACL) + sizeof(ACE) + SidSize;
142     }
143 
144     if (*BufferLength < SdSize)
145     {
146         *BufferLength = SdSize;
147         return STATUS_BUFFER_TOO_SMALL;
148     }
149 
150     *BufferLength = SdSize;
151 
152     Status = RtlCreateSecurityDescriptorRelative(SdRel,
153                                                  SECURITY_DESCRIPTOR_REVISION);
154     if (!NT_SUCCESS(Status))
155     {
156         return Status;
157     }
158 
159     Current = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
160 
161     if (SecurityInformation & OWNER_SECURITY_INFORMATION)
162     {
163         RtlCopyMemory((PUCHAR)SdRel + Current, SeWorldSid, SidSize);
164         SdRel->Owner = Current;
165         Current += SidSize;
166     }
167 
168     if (SecurityInformation & GROUP_SECURITY_INFORMATION)
169     {
170         RtlCopyMemory((PUCHAR)SdRel + Current, SeWorldSid, SidSize);
171         SdRel->Group = Current;
172         Current += SidSize;
173     }
174 
175     if (SecurityInformation & DACL_SECURITY_INFORMATION)
176     {
177         PACL Dacl = (PACL)((PUCHAR)SdRel + Current);
178         SdRel->Control |= SE_DACL_PRESENT;
179 
180         Status = RtlCreateAcl(Dacl,
181                               sizeof(ACL) + sizeof(ACE) + SidSize,
182                               ACL_REVISION);
183         if (!NT_SUCCESS(Status))
184             return Status;
185 
186         Status = RtlAddAccessAllowedAce(Dacl,
187                                         ACL_REVISION,
188                                         GENERIC_ALL,
189                                         SeWorldSid);
190         if (!NT_SUCCESS(Status))
191             return Status;
192 
193         SdRel->Dacl = Current;
194     }
195 
196     if (SecurityInformation & SACL_SECURITY_INFORMATION)
197     {
198         /* FIXME - SdRel->Control |= SE_SACL_PRESENT; */
199     }
200 
201     return STATUS_SUCCESS;
202 }
203 
204 
205 NTSTATUS
206 NTAPI
207 SepCaptureSecurityQualityOfService(IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
208                                    IN KPROCESSOR_MODE AccessMode,
209                                    IN POOL_TYPE PoolType,
210                                    IN BOOLEAN CaptureIfKernel,
211                                    OUT PSECURITY_QUALITY_OF_SERVICE *CapturedSecurityQualityOfService,
212                                    OUT PBOOLEAN Present)
213 {
214     PSECURITY_QUALITY_OF_SERVICE CapturedQos;
215     NTSTATUS Status = STATUS_SUCCESS;
216 
217     PAGED_CODE();
218 
219     ASSERT(CapturedSecurityQualityOfService);
220     ASSERT(Present);
221 
222     if (ObjectAttributes != NULL)
223     {
224         if (AccessMode != KernelMode)
225         {
226             SECURITY_QUALITY_OF_SERVICE SafeQos;
227 
228             _SEH2_TRY
229             {
230                 ProbeForRead(ObjectAttributes,
231                              sizeof(OBJECT_ATTRIBUTES),
232                              sizeof(ULONG));
233                 if (ObjectAttributes->Length == sizeof(OBJECT_ATTRIBUTES))
234                 {
235                     if (ObjectAttributes->SecurityQualityOfService != NULL)
236                     {
237                         ProbeForRead(ObjectAttributes->SecurityQualityOfService,
238                                      sizeof(SECURITY_QUALITY_OF_SERVICE),
239                                      sizeof(ULONG));
240 
241                         if (((PSECURITY_QUALITY_OF_SERVICE)ObjectAttributes->SecurityQualityOfService)->Length ==
242                             sizeof(SECURITY_QUALITY_OF_SERVICE))
243                         {
244                             /*
245                              * Don't allocate memory here because ExAllocate should bugcheck
246                              * the system if it's buggy, SEH would catch that! So make a local
247                              * copy of the qos structure.
248                              */
249                             RtlCopyMemory(&SafeQos,
250                                           ObjectAttributes->SecurityQualityOfService,
251                                           sizeof(SECURITY_QUALITY_OF_SERVICE));
252                             *Present = TRUE;
253                         }
254                         else
255                         {
256                             Status = STATUS_INVALID_PARAMETER;
257                         }
258                     }
259                     else
260                     {
261                         *CapturedSecurityQualityOfService = NULL;
262                         *Present = FALSE;
263                     }
264                 }
265                 else
266                 {
267                     Status = STATUS_INVALID_PARAMETER;
268                 }
269             }
270             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
271             {
272                 Status = _SEH2_GetExceptionCode();
273             }
274             _SEH2_END;
275 
276             if (NT_SUCCESS(Status))
277             {
278                 if (*Present)
279                 {
280                     CapturedQos = ExAllocatePoolWithTag(PoolType,
281                                                         sizeof(SECURITY_QUALITY_OF_SERVICE),
282                                                         TAG_QOS);
283                     if (CapturedQos != NULL)
284                     {
285                         RtlCopyMemory(CapturedQos,
286                                       &SafeQos,
287                                       sizeof(SECURITY_QUALITY_OF_SERVICE));
288                         *CapturedSecurityQualityOfService = CapturedQos;
289                     }
290                     else
291                     {
292                         Status = STATUS_INSUFFICIENT_RESOURCES;
293                     }
294                 }
295                 else
296                 {
297                     *CapturedSecurityQualityOfService = NULL;
298                 }
299             }
300         }
301         else
302         {
303             if (ObjectAttributes->Length == sizeof(OBJECT_ATTRIBUTES))
304             {
305                 if (CaptureIfKernel)
306                 {
307                     if (ObjectAttributes->SecurityQualityOfService != NULL)
308                     {
309                         if (((PSECURITY_QUALITY_OF_SERVICE)ObjectAttributes->SecurityQualityOfService)->Length ==
310                             sizeof(SECURITY_QUALITY_OF_SERVICE))
311                         {
312                             CapturedQos = ExAllocatePoolWithTag(PoolType,
313                                                                 sizeof(SECURITY_QUALITY_OF_SERVICE),
314                                                                 TAG_QOS);
315                             if (CapturedQos != NULL)
316                             {
317                                 RtlCopyMemory(CapturedQos,
318                                               ObjectAttributes->SecurityQualityOfService,
319                                               sizeof(SECURITY_QUALITY_OF_SERVICE));
320                                 *CapturedSecurityQualityOfService = CapturedQos;
321                                 *Present = TRUE;
322                             }
323                             else
324                             {
325                                 Status = STATUS_INSUFFICIENT_RESOURCES;
326                             }
327                         }
328                         else
329                         {
330                             Status = STATUS_INVALID_PARAMETER;
331                         }
332                     }
333                     else
334                     {
335                         *CapturedSecurityQualityOfService = NULL;
336                         *Present = FALSE;
337                     }
338                 }
339                 else
340                 {
341                     *CapturedSecurityQualityOfService = (PSECURITY_QUALITY_OF_SERVICE)ObjectAttributes->SecurityQualityOfService;
342                     *Present = (ObjectAttributes->SecurityQualityOfService != NULL);
343                 }
344             }
345             else
346             {
347                 Status = STATUS_INVALID_PARAMETER;
348             }
349         }
350     }
351     else
352     {
353         *CapturedSecurityQualityOfService = NULL;
354         *Present = FALSE;
355     }
356 
357     return Status;
358 }
359 
360 
361 VOID
362 NTAPI
363 SepReleaseSecurityQualityOfService(IN PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService  OPTIONAL,
364                                    IN KPROCESSOR_MODE AccessMode,
365                                    IN BOOLEAN CaptureIfKernel)
366 {
367     PAGED_CODE();
368 
369     if (CapturedSecurityQualityOfService != NULL &&
370         (AccessMode != KernelMode || CaptureIfKernel))
371     {
372         ExFreePoolWithTag(CapturedSecurityQualityOfService, TAG_QOS);
373     }
374 }
375 
376 /* PUBLIC FUNCTIONS ***********************************************************/
377 
378 static
379 ULONG
380 DetermineSIDSize(
381     PISID Sid,
382     PULONG OutSAC,
383     KPROCESSOR_MODE ProcessorMode)
384 {
385     ULONG Size;
386 
387     if (!Sid)
388     {
389         *OutSAC = 0;
390         return 0;
391     }
392 
393     if (ProcessorMode != KernelMode)
394     {
395         /* Securely access the buffers! */
396         *OutSAC = ProbeForReadUchar(&Sid->SubAuthorityCount);
397         Size = RtlLengthRequiredSid(*OutSAC);
398         ProbeForRead(Sid, Size, sizeof(ULONG));
399     }
400     else
401     {
402         *OutSAC = Sid->SubAuthorityCount;
403         Size = RtlLengthRequiredSid(*OutSAC);
404     }
405 
406     return Size;
407 }
408 
409 static
410 ULONG
411 DetermineACLSize(
412     PACL Acl,
413     KPROCESSOR_MODE ProcessorMode)
414 {
415     ULONG Size;
416 
417     if (!Acl) return 0;
418 
419     if (ProcessorMode == KernelMode) return Acl->AclSize;
420 
421     /* Probe the buffers! */
422     Size = ProbeForReadUshort(&Acl->AclSize);
423     ProbeForRead(Acl, Size, sizeof(ULONG));
424 
425     return Size;
426 }
427 
428 NTSTATUS
429 NTAPI
430 SeCaptureSecurityDescriptor(
431     IN PSECURITY_DESCRIPTOR _OriginalSecurityDescriptor,
432     IN KPROCESSOR_MODE CurrentMode,
433     IN POOL_TYPE PoolType,
434     IN BOOLEAN CaptureIfKernel,
435     OUT PSECURITY_DESCRIPTOR *CapturedSecurityDescriptor)
436 {
437     PISECURITY_DESCRIPTOR OriginalDescriptor = _OriginalSecurityDescriptor;
438     SECURITY_DESCRIPTOR DescriptorCopy;
439     PISECURITY_DESCRIPTOR_RELATIVE NewDescriptor;
440     ULONG OwnerSAC = 0, GroupSAC = 0;
441     ULONG OwnerSize = 0, GroupSize = 0;
442     ULONG SaclSize = 0, DaclSize = 0;
443     ULONG DescriptorSize = 0;
444     ULONG Offset;
445 
446     if (!OriginalDescriptor)
447     {
448         /* Nothing to do... */
449         *CapturedSecurityDescriptor = NULL;
450         return STATUS_SUCCESS;
451     }
452 
453     /* Quick path */
454     if (CurrentMode == KernelMode && !CaptureIfKernel)
455     {
456         /* Check descriptor version */
457         if (OriginalDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION1)
458         {
459             return STATUS_UNKNOWN_REVISION;
460         }
461 
462         *CapturedSecurityDescriptor = _OriginalSecurityDescriptor;
463         return STATUS_SUCCESS;
464     }
465 
466     _SEH2_TRY
467     {
468         if (CurrentMode != KernelMode)
469         {
470             ProbeForRead(OriginalDescriptor,
471                          sizeof(SECURITY_DESCRIPTOR_RELATIVE),
472                          sizeof(ULONG));
473         }
474 
475         /* Check the descriptor version */
476         if (OriginalDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION1)
477         {
478             _SEH2_YIELD(return STATUS_UNKNOWN_REVISION);
479         }
480 
481         if (CurrentMode != KernelMode)
482         {
483             /* Get the size of the descriptor */
484             DescriptorSize = (OriginalDescriptor->Control & SE_SELF_RELATIVE) ?
485                 sizeof(SECURITY_DESCRIPTOR_RELATIVE) : sizeof(SECURITY_DESCRIPTOR);
486 
487             /* Probe the entire security descriptor structure. The SIDs
488              * and ACLs will be probed and copied later though */
489             ProbeForRead(OriginalDescriptor, DescriptorSize, sizeof(ULONG));
490         }
491 
492         /* Now capture all fields and convert to an absolute descriptor */
493         DescriptorCopy.Revision = OriginalDescriptor->Revision;
494         DescriptorCopy.Sbz1 = OriginalDescriptor->Sbz1;
495         DescriptorCopy.Control = OriginalDescriptor->Control & ~SE_SELF_RELATIVE;
496         DescriptorCopy.Owner = SepGetOwnerFromDescriptor(OriginalDescriptor);
497         DescriptorCopy.Group = SepGetGroupFromDescriptor(OriginalDescriptor);
498         DescriptorCopy.Sacl = SepGetSaclFromDescriptor(OriginalDescriptor);
499         DescriptorCopy.Dacl = SepGetDaclFromDescriptor(OriginalDescriptor);
500         DescriptorSize = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
501 
502         /* Determine owner and group sizes */
503         OwnerSize = DetermineSIDSize(DescriptorCopy.Owner, &OwnerSAC, CurrentMode);
504         DescriptorSize += ROUND_UP(OwnerSize, sizeof(ULONG));
505         GroupSize = DetermineSIDSize(DescriptorCopy.Group, &GroupSAC, CurrentMode);
506         DescriptorSize += ROUND_UP(GroupSize, sizeof(ULONG));
507 
508         /* Determine the size of the ACLs */
509         if (DescriptorCopy.Control & SE_SACL_PRESENT)
510         {
511             /* Get the size and probe if user mode */
512             SaclSize = DetermineACLSize(DescriptorCopy.Sacl, CurrentMode);
513             DescriptorSize += ROUND_UP(SaclSize, sizeof(ULONG));
514         }
515 
516         if (DescriptorCopy.Control & SE_DACL_PRESENT)
517         {
518             /* Get the size and probe if user mode */
519             DaclSize = DetermineACLSize(DescriptorCopy.Dacl, CurrentMode);
520             DescriptorSize += ROUND_UP(DaclSize, sizeof(ULONG));
521         }
522     }
523     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
524     {
525         _SEH2_YIELD(return _SEH2_GetExceptionCode());
526     }
527     _SEH2_END;
528 
529     /*
530      * Allocate enough memory to store a complete copy of a self-relative
531      * security descriptor
532      */
533     NewDescriptor = ExAllocatePoolWithTag(PoolType,
534                                           DescriptorSize,
535                                           TAG_SD);
536     if (!NewDescriptor) return STATUS_INSUFFICIENT_RESOURCES;
537 
538     RtlZeroMemory(NewDescriptor, DescriptorSize);
539     NewDescriptor->Revision = DescriptorCopy.Revision;
540     NewDescriptor->Sbz1 = DescriptorCopy.Sbz1;
541     NewDescriptor->Control = DescriptorCopy.Control | SE_SELF_RELATIVE;
542 
543     _SEH2_TRY
544     {
545         /*
546          * Setup the offsets and copy the SIDs and ACLs to the new
547          * self-relative security descriptor. Probing the pointers is not
548          * neccessary anymore as we did that when collecting the sizes!
549          * Make sure to validate the SIDs and ACLs *again* as they could have
550          * been modified in the meanwhile!
551          */
552         Offset = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
553 
554         if (DescriptorCopy.Owner)
555         {
556             if (!RtlValidSid(DescriptorCopy.Owner)) RtlRaiseStatus(STATUS_INVALID_SID);
557             NewDescriptor->Owner = Offset;
558             RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
559                           DescriptorCopy.Owner,
560                           OwnerSize);
561             Offset += ROUND_UP(OwnerSize, sizeof(ULONG));
562         }
563 
564         if (DescriptorCopy.Group)
565         {
566             if (!RtlValidSid(DescriptorCopy.Group)) RtlRaiseStatus(STATUS_INVALID_SID);
567             NewDescriptor->Group = Offset;
568             RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
569                           DescriptorCopy.Group,
570                           GroupSize);
571             Offset += ROUND_UP(GroupSize, sizeof(ULONG));
572         }
573 
574         if (DescriptorCopy.Sacl)
575         {
576             if (!RtlValidAcl(DescriptorCopy.Sacl)) RtlRaiseStatus(STATUS_INVALID_ACL);
577             NewDescriptor->Sacl = Offset;
578             RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
579                           DescriptorCopy.Sacl,
580                           SaclSize);
581             Offset += ROUND_UP(SaclSize, sizeof(ULONG));
582         }
583 
584         if (DescriptorCopy.Dacl)
585         {
586             if (!RtlValidAcl(DescriptorCopy.Dacl)) RtlRaiseStatus(STATUS_INVALID_ACL);
587             NewDescriptor->Dacl = Offset;
588             RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
589                           DescriptorCopy.Dacl,
590                           DaclSize);
591             Offset += ROUND_UP(DaclSize, sizeof(ULONG));
592         }
593 
594         /* Make sure the size was correct */
595         ASSERT(Offset == DescriptorSize);
596     }
597     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
598     {
599         /* We failed to copy the data to the new descriptor */
600         ExFreePoolWithTag(NewDescriptor, TAG_SD);
601         _SEH2_YIELD(return _SEH2_GetExceptionCode());
602     }
603     _SEH2_END;
604 
605     /*
606      * We're finally done!
607      * Copy the pointer to the captured descriptor to to the caller.
608      */
609     *CapturedSecurityDescriptor = NewDescriptor;
610     return STATUS_SUCCESS;
611 }
612 
613 /*
614  * @implemented
615  */
616 _IRQL_requires_max_(PASSIVE_LEVEL)
617 NTSTATUS
618 NTAPI
619 SeQuerySecurityDescriptorInfo(
620     _In_ PSECURITY_INFORMATION SecurityInformation,
621     _Out_writes_bytes_(*Length) PSECURITY_DESCRIPTOR SecurityDescriptor,
622     _Inout_ PULONG Length,
623     _Inout_ PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor)
624 {
625     PISECURITY_DESCRIPTOR ObjectSd;
626     PISECURITY_DESCRIPTOR_RELATIVE RelSD;
627     PSID Owner = NULL;
628     PSID Group = NULL;
629     PACL Dacl = NULL;
630     PACL Sacl = NULL;
631     ULONG OwnerLength = 0;
632     ULONG GroupLength = 0;
633     ULONG DaclLength = 0;
634     ULONG SaclLength = 0;
635     SECURITY_DESCRIPTOR_CONTROL Control = 0;
636     ULONG_PTR Current;
637     ULONG SdLength;
638 
639     PAGED_CODE();
640 
641     RelSD = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptor;
642 
643     if (*ObjectsSecurityDescriptor == NULL)
644     {
645         if (*Length < sizeof(SECURITY_DESCRIPTOR_RELATIVE))
646         {
647             *Length = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
648             return STATUS_BUFFER_TOO_SMALL;
649         }
650 
651         *Length = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
652         RtlCreateSecurityDescriptorRelative(RelSD,
653                                             SECURITY_DESCRIPTOR_REVISION);
654         return STATUS_SUCCESS;
655     }
656 
657     ObjectSd = *ObjectsSecurityDescriptor;
658 
659     /* Calculate the required security descriptor length */
660     Control = SE_SELF_RELATIVE;
661     if (*SecurityInformation & OWNER_SECURITY_INFORMATION)
662     {
663         Owner = SepGetOwnerFromDescriptor(ObjectSd);
664         if (Owner != NULL)
665         {
666             OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
667             Control |= (ObjectSd->Control & SE_OWNER_DEFAULTED);
668         }
669     }
670 
671     if (*SecurityInformation & GROUP_SECURITY_INFORMATION)
672     {
673         Group = SepGetGroupFromDescriptor(ObjectSd);
674         if (Group != NULL)
675         {
676             GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
677             Control |= (ObjectSd->Control & SE_GROUP_DEFAULTED);
678         }
679     }
680 
681     if ((*SecurityInformation & DACL_SECURITY_INFORMATION) &&
682         (ObjectSd->Control & SE_DACL_PRESENT))
683     {
684         Dacl = SepGetDaclFromDescriptor(ObjectSd);
685         if (Dacl != NULL)
686         {
687             DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4);
688         }
689 
690         Control |= (ObjectSd->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
691     }
692 
693     if ((*SecurityInformation & SACL_SECURITY_INFORMATION) &&
694         (ObjectSd->Control & SE_SACL_PRESENT))
695     {
696         Sacl = SepGetSaclFromDescriptor(ObjectSd);
697         if (Sacl != NULL)
698         {
699             SaclLength = ROUND_UP(Sacl->AclSize, 4);
700         }
701 
702         Control |= (ObjectSd->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
703     }
704 
705     SdLength = OwnerLength + GroupLength + DaclLength +
706     SaclLength + sizeof(SECURITY_DESCRIPTOR_RELATIVE);
707     if (*Length < SdLength)
708     {
709         *Length = SdLength;
710         return STATUS_BUFFER_TOO_SMALL;
711     }
712 
713     /* Build the new security descrtiptor */
714     RtlCreateSecurityDescriptorRelative(RelSD,
715                                         SECURITY_DESCRIPTOR_REVISION);
716     RelSD->Control = Control;
717 
718     Current = (ULONG_PTR)(RelSD + 1);
719 
720     if (OwnerLength != 0)
721     {
722         RtlCopyMemory((PVOID)Current,
723                       Owner,
724                       OwnerLength);
725         RelSD->Owner = (ULONG)(Current - (ULONG_PTR)SecurityDescriptor);
726         Current += OwnerLength;
727     }
728 
729     if (GroupLength != 0)
730     {
731         RtlCopyMemory((PVOID)Current,
732                       Group,
733                       GroupLength);
734         RelSD->Group = (ULONG)(Current - (ULONG_PTR)SecurityDescriptor);
735         Current += GroupLength;
736     }
737 
738     if (DaclLength != 0)
739     {
740         RtlCopyMemory((PVOID)Current,
741                       Dacl,
742                       DaclLength);
743         RelSD->Dacl = (ULONG)(Current - (ULONG_PTR)SecurityDescriptor);
744         Current += DaclLength;
745     }
746 
747     if (SaclLength != 0)
748     {
749         RtlCopyMemory((PVOID)Current,
750                       Sacl,
751                       SaclLength);
752         RelSD->Sacl = (ULONG)(Current - (ULONG_PTR)SecurityDescriptor);
753         Current += SaclLength;
754     }
755 
756     *Length = SdLength;
757 
758     return STATUS_SUCCESS;
759 }
760 
761 /*
762  * @implemented
763  */
764 NTSTATUS
765 NTAPI
766 SeReleaseSecurityDescriptor(IN PSECURITY_DESCRIPTOR CapturedSecurityDescriptor,
767                             IN KPROCESSOR_MODE CurrentMode,
768                             IN BOOLEAN CaptureIfKernelMode)
769 {
770     PAGED_CODE();
771 
772     /*
773      * WARNING! You need to call this function with the same value for CurrentMode
774      * and CaptureIfKernelMode that you previously passed to
775      * SeCaptureSecurityDescriptor() in order to avoid memory leaks!
776      */
777     if (CapturedSecurityDescriptor != NULL &&
778         (CurrentMode != KernelMode ||
779          (CurrentMode == KernelMode && CaptureIfKernelMode)))
780     {
781         /* Only delete the descriptor when SeCaptureSecurityDescriptor() allocated one! */
782         ExFreePoolWithTag(CapturedSecurityDescriptor, TAG_SD);
783     }
784 
785     return STATUS_SUCCESS;
786 }
787 
788 /*
789  * @implemented
790  */
791 _IRQL_requires_max_(PASSIVE_LEVEL)
792 NTSTATUS
793 NTAPI
794 SeSetSecurityDescriptorInfo(
795     _In_opt_ PVOID Object,
796     _In_ PSECURITY_INFORMATION SecurityInformation,
797     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
798     _Inout_ PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
799     _In_ POOL_TYPE PoolType,
800     _In_ PGENERIC_MAPPING GenericMapping)
801 {
802     PAGED_CODE();
803 
804     return SeSetSecurityDescriptorInfoEx(Object,
805                                          SecurityInformation,
806                                          SecurityDescriptor,
807                                          ObjectsSecurityDescriptor,
808                                          0,
809                                          PoolType,
810                                          GenericMapping);
811 }
812 
813 /*
814  * @implemented
815  */
816 _IRQL_requires_max_(PASSIVE_LEVEL)
817 NTSTATUS
818 NTAPI
819 SeSetSecurityDescriptorInfoEx(
820     _In_opt_ PVOID Object,
821     _In_ PSECURITY_INFORMATION _SecurityInformation,
822     _In_ PSECURITY_DESCRIPTOR _SecurityDescriptor,
823     _Inout_ PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
824     _In_ ULONG AutoInheritFlags,
825     _In_ POOL_TYPE PoolType,
826     _In_ PGENERIC_MAPPING GenericMapping)
827 {
828     PISECURITY_DESCRIPTOR_RELATIVE ObjectSd;
829     PISECURITY_DESCRIPTOR_RELATIVE NewSd;
830     PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
831     PSID Owner;
832     PSID Group;
833     PACL Dacl;
834     PACL Sacl;
835     ULONG OwnerLength;
836     ULONG GroupLength;
837     ULONG DaclLength;
838     ULONG SaclLength;
839     SECURITY_DESCRIPTOR_CONTROL Control = 0;
840     ULONG Current;
841     SECURITY_INFORMATION SecurityInformation;
842 
843     PAGED_CODE();
844 
845     ObjectSd = *ObjectsSecurityDescriptor;
846 
847     /* The object does not have a security descriptor. */
848     if (!ObjectSd)
849         return STATUS_NO_SECURITY_ON_OBJECT;
850 
851     ASSERT(ObjectSd->Control & SE_SELF_RELATIVE);
852 
853     SecurityInformation = *_SecurityInformation;
854 
855     /* Get owner and owner size */
856     if (SecurityInformation & OWNER_SECURITY_INFORMATION)
857     {
858         Owner = SepGetOwnerFromDescriptor(SecurityDescriptor);
859         Control |= (SecurityDescriptor->Control & SE_OWNER_DEFAULTED);
860     }
861     else
862     {
863         Owner = SepGetOwnerFromDescriptor(ObjectSd);
864         Control |= (ObjectSd->Control & SE_OWNER_DEFAULTED);
865     }
866     OwnerLength = Owner ? RtlLengthSid(Owner) : 0;
867     ASSERT(OwnerLength % sizeof(ULONG) == 0);
868 
869     /* Get group and group size */
870     if (SecurityInformation & GROUP_SECURITY_INFORMATION)
871     {
872         Group = SepGetGroupFromDescriptor(SecurityDescriptor);
873         Control |= (SecurityDescriptor->Control & SE_GROUP_DEFAULTED);
874     }
875     else
876     {
877         Group = SepGetGroupFromDescriptor(ObjectSd);
878         Control |= (ObjectSd->Control & SE_GROUP_DEFAULTED);
879     }
880     GroupLength = Group ? RtlLengthSid(Group) : 0;
881     ASSERT(GroupLength % sizeof(ULONG) == 0);
882 
883     /* Get DACL and DACL size */
884     if (SecurityInformation & DACL_SECURITY_INFORMATION)
885     {
886         Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
887         Control |= (SecurityDescriptor->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
888     }
889     else
890     {
891         Dacl = SepGetDaclFromDescriptor(ObjectSd);
892         Control |= (ObjectSd->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
893     }
894     DaclLength = Dacl ? ROUND_UP((ULONG)Dacl->AclSize, 4) : 0;
895 
896     /* Get SACL and SACL size */
897     if (SecurityInformation & SACL_SECURITY_INFORMATION)
898     {
899         Sacl = SepGetSaclFromDescriptor(SecurityDescriptor);
900         Control |= (SecurityDescriptor->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
901     }
902     else
903     {
904         Sacl = SepGetSaclFromDescriptor(ObjectSd);
905         Control |= (ObjectSd->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
906     }
907     SaclLength = Sacl ? ROUND_UP((ULONG)Sacl->AclSize, 4) : 0;
908 
909     NewSd = ExAllocatePoolWithTag(NonPagedPool,
910                                   sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
911                                   OwnerLength + GroupLength +
912                                   DaclLength + SaclLength,
913                                   TAG_SD);
914     if (NewSd == NULL)
915     {
916         return STATUS_INSUFFICIENT_RESOURCES;
917     }
918 
919     RtlCreateSecurityDescriptorRelative(NewSd, SECURITY_DESCRIPTOR_REVISION1);
920 
921     Current = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
922 
923     if (OwnerLength != 0)
924     {
925         RtlCopyMemory((PUCHAR)NewSd + Current, Owner, OwnerLength);
926         NewSd->Owner = Current;
927         Current += OwnerLength;
928     }
929 
930     if (GroupLength != 0)
931     {
932         RtlCopyMemory((PUCHAR)NewSd + Current, Group, GroupLength);
933         NewSd->Group = Current;
934         Current += GroupLength;
935     }
936 
937     if (DaclLength != 0)
938     {
939         RtlCopyMemory((PUCHAR)NewSd + Current, Dacl, DaclLength);
940         NewSd->Dacl = Current;
941         Current += DaclLength;
942     }
943 
944     if (SaclLength != 0)
945     {
946         RtlCopyMemory((PUCHAR)NewSd + Current, Sacl, SaclLength);
947         NewSd->Sacl = Current;
948         Current += SaclLength;
949     }
950 
951     *ObjectsSecurityDescriptor = NewSd;
952     return STATUS_SUCCESS;
953 }
954 
955 
956 /*
957  * @implemented
958  */
959 BOOLEAN NTAPI
960 SeValidSecurityDescriptor(IN ULONG Length,
961                           IN PSECURITY_DESCRIPTOR _SecurityDescriptor)
962 {
963     ULONG SdLength;
964     PISID Sid;
965     PACL Acl;
966     PISECURITY_DESCRIPTOR_RELATIVE SecurityDescriptor = _SecurityDescriptor;
967 
968     if (Length < SECURITY_DESCRIPTOR_MIN_LENGTH)
969     {
970         DPRINT1("Invalid Security Descriptor revision\n");
971         return FALSE;
972     }
973 
974     if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION1)
975     {
976         DPRINT1("Invalid Security Descriptor revision\n");
977         return FALSE;
978     }
979 
980     if (!(SecurityDescriptor->Control & SE_SELF_RELATIVE))
981     {
982         DPRINT1("No self-relative Security Descriptor\n");
983         return FALSE;
984     }
985 
986     SdLength = sizeof(SECURITY_DESCRIPTOR);
987 
988     /* Check Owner SID */
989     if (!SecurityDescriptor->Owner)
990     {
991         DPRINT1("No Owner SID\n");
992         return FALSE;
993     }
994 
995     if (SecurityDescriptor->Owner % sizeof(ULONG))
996     {
997         DPRINT1("Invalid Owner SID alignment\n");
998         return FALSE;
999     }
1000 
1001     Sid = (PISID)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Owner);
1002     if (Sid->Revision != SID_REVISION)
1003     {
1004         DPRINT1("Invalid Owner SID revision\n");
1005         return FALSE;
1006     }
1007 
1008     SdLength += (sizeof(SID) + (Sid->SubAuthorityCount - 1) * sizeof(ULONG));
1009     if (Length < SdLength)
1010     {
1011         DPRINT1("Invalid Owner SID size\n");
1012         return FALSE;
1013     }
1014 
1015     /* Check Group SID */
1016     if (SecurityDescriptor->Group)
1017     {
1018         if (SecurityDescriptor->Group % sizeof(ULONG))
1019         {
1020             DPRINT1("Invalid Group SID alignment\n");
1021             return FALSE;
1022         }
1023 
1024         Sid = (PSID)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Group);
1025         if (Sid->Revision != SID_REVISION)
1026         {
1027             DPRINT1("Invalid Group SID revision\n");
1028             return FALSE;
1029         }
1030 
1031         SdLength += (sizeof(SID) + (Sid->SubAuthorityCount - 1) * sizeof(ULONG));
1032         if (Length < SdLength)
1033         {
1034             DPRINT1("Invalid Group SID size\n");
1035             return FALSE;
1036         }
1037     }
1038 
1039     /* Check DACL */
1040     if (SecurityDescriptor->Dacl)
1041     {
1042         if (SecurityDescriptor->Dacl % sizeof(ULONG))
1043         {
1044             DPRINT1("Invalid DACL alignment\n");
1045             return FALSE;
1046         }
1047 
1048         Acl = (PACL)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Dacl);
1049         if ((Acl->AclRevision < MIN_ACL_REVISION) ||
1050             (Acl->AclRevision > MAX_ACL_REVISION))
1051         {
1052             DPRINT1("Invalid DACL revision\n");
1053             return FALSE;
1054         }
1055 
1056         SdLength += Acl->AclSize;
1057         if (Length < SdLength)
1058         {
1059             DPRINT1("Invalid DACL size\n");
1060             return FALSE;
1061         }
1062     }
1063 
1064     /* Check SACL */
1065     if (SecurityDescriptor->Sacl)
1066     {
1067         if (SecurityDescriptor->Sacl % sizeof(ULONG))
1068         {
1069             DPRINT1("Invalid SACL alignment\n");
1070             return FALSE;
1071         }
1072 
1073         Acl = (PACL)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Sacl);
1074         if ((Acl->AclRevision < MIN_ACL_REVISION) ||
1075             (Acl->AclRevision > MAX_ACL_REVISION))
1076         {
1077             DPRINT1("Invalid SACL revision\n");
1078             return FALSE;
1079         }
1080 
1081         SdLength += Acl->AclSize;
1082         if (Length < SdLength)
1083         {
1084             DPRINT1("Invalid SACL size\n");
1085             return FALSE;
1086         }
1087     }
1088 
1089     return TRUE;
1090 }
1091 
1092 /*
1093  * @implemented
1094  */
1095 _IRQL_requires_max_(PASSIVE_LEVEL)
1096 NTSTATUS
1097 NTAPI
1098 SeDeassignSecurity(
1099     _Inout_ PSECURITY_DESCRIPTOR *SecurityDescriptor)
1100 {
1101     PAGED_CODE();
1102 
1103     if (*SecurityDescriptor != NULL)
1104     {
1105         ExFreePoolWithTag(*SecurityDescriptor, TAG_SD);
1106         *SecurityDescriptor = NULL;
1107     }
1108 
1109     return STATUS_SUCCESS;
1110 }
1111 
1112 /*
1113  * @implemented
1114  */
1115 _IRQL_requires_max_(PASSIVE_LEVEL)
1116 NTSTATUS
1117 NTAPI
1118 SeAssignSecurityEx(
1119     _In_opt_ PSECURITY_DESCRIPTOR _ParentDescriptor,
1120     _In_opt_ PSECURITY_DESCRIPTOR _ExplicitDescriptor,
1121     _Out_ PSECURITY_DESCRIPTOR *NewDescriptor,
1122     _In_opt_ GUID *ObjectType,
1123     _In_ BOOLEAN IsDirectoryObject,
1124     _In_ ULONG AutoInheritFlags,
1125     _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
1126     _In_ PGENERIC_MAPPING GenericMapping,
1127     _In_ POOL_TYPE PoolType)
1128 {
1129     PISECURITY_DESCRIPTOR ParentDescriptor = _ParentDescriptor;
1130     PISECURITY_DESCRIPTOR ExplicitDescriptor = _ExplicitDescriptor;
1131     PISECURITY_DESCRIPTOR_RELATIVE Descriptor;
1132     PTOKEN Token;
1133     ULONG OwnerLength;
1134     ULONG GroupLength;
1135     ULONG DaclLength;
1136     ULONG SaclLength;
1137     ULONG Length;
1138     SECURITY_DESCRIPTOR_CONTROL Control = 0;
1139     ULONG Current;
1140     PSID Owner = NULL;
1141     PSID Group = NULL;
1142     PACL ExplicitAcl;
1143     BOOLEAN ExplicitPresent;
1144     BOOLEAN ExplicitDefaulted;
1145     PACL ParentAcl;
1146     PACL Dacl = NULL;
1147     PACL Sacl = NULL;
1148     BOOLEAN DaclIsInherited;
1149     BOOLEAN SaclIsInherited;
1150     BOOLEAN DaclPresent;
1151     BOOLEAN SaclPresent;
1152     NTSTATUS Status;
1153 
1154     DBG_UNREFERENCED_PARAMETER(ObjectType);
1155     DBG_UNREFERENCED_PARAMETER(AutoInheritFlags);
1156     UNREFERENCED_PARAMETER(PoolType);
1157 
1158     PAGED_CODE();
1159 
1160     *NewDescriptor = NULL;
1161 
1162     if (!ARGUMENT_PRESENT(SubjectContext))
1163     {
1164         return STATUS_NO_TOKEN;
1165     }
1166 
1167     /* Lock subject context */
1168     SeLockSubjectContext(SubjectContext);
1169 
1170     if (SubjectContext->ClientToken != NULL)
1171     {
1172         Token = SubjectContext->ClientToken;
1173     }
1174     else
1175     {
1176         Token = SubjectContext->PrimaryToken;
1177     }
1178 
1179     /* Inherit the Owner SID */
1180     if (ExplicitDescriptor != NULL)
1181     {
1182         DPRINT("Use explicit owner sid!\n");
1183         Owner = SepGetOwnerFromDescriptor(ExplicitDescriptor);
1184     }
1185     if (!Owner)
1186     {
1187         if (AutoInheritFlags & 0x20 /* FIXME: SEF_DEFAULT_OWNER_FROM_PARENT */)
1188         {
1189             DPRINT("Use parent owner sid!\n");
1190             if (!ARGUMENT_PRESENT(ParentDescriptor))
1191             {
1192                 SeUnlockSubjectContext(SubjectContext);
1193                 return STATUS_INVALID_OWNER;
1194             }
1195 
1196             Owner = SepGetOwnerFromDescriptor(ParentDescriptor);
1197             if (!Owner)
1198             {
1199                 SeUnlockSubjectContext(SubjectContext);
1200                 return STATUS_INVALID_OWNER;
1201             }
1202         }
1203         else
1204         {
1205             DPRINT("Use token owner sid!\n");
1206             Owner = Token->UserAndGroups[Token->DefaultOwnerIndex].Sid;
1207         }
1208     }
1209     OwnerLength = RtlLengthSid(Owner);
1210     ASSERT(OwnerLength % sizeof(ULONG) == 0);
1211 
1212     /* Inherit the Group SID */
1213     if (ExplicitDescriptor != NULL)
1214     {
1215         Group = SepGetGroupFromDescriptor(ExplicitDescriptor);
1216     }
1217     if (!Group)
1218     {
1219         if (AutoInheritFlags & 0x40 /* FIXME: SEF_DEFAULT_GROUP_FROM_PARENT */)
1220         {
1221             DPRINT("Use parent group sid!\n");
1222             if (!ARGUMENT_PRESENT(ParentDescriptor))
1223             {
1224                 SeUnlockSubjectContext(SubjectContext);
1225                 return STATUS_INVALID_PRIMARY_GROUP;
1226             }
1227 
1228             Group = SepGetGroupFromDescriptor(ParentDescriptor);
1229             if (!Group)
1230             {
1231                 SeUnlockSubjectContext(SubjectContext);
1232                 return STATUS_INVALID_PRIMARY_GROUP;
1233             }
1234         }
1235         else
1236         {
1237             DPRINT("Use token group sid!\n");
1238             Group = Token->PrimaryGroup;
1239         }
1240     }
1241     if (!Group)
1242     {
1243         SeUnlockSubjectContext(SubjectContext);
1244         return STATUS_INVALID_PRIMARY_GROUP;
1245     }
1246     GroupLength = RtlLengthSid(Group);
1247     ASSERT(GroupLength % sizeof(ULONG) == 0);
1248 
1249     /* Inherit the DACL */
1250     DaclLength = 0;
1251     ExplicitAcl = NULL;
1252     ExplicitPresent = FALSE;
1253     ExplicitDefaulted = FALSE;
1254     if (ExplicitDescriptor != NULL &&
1255         (ExplicitDescriptor->Control & SE_DACL_PRESENT))
1256     {
1257         ExplicitAcl = SepGetDaclFromDescriptor(ExplicitDescriptor);
1258         ExplicitPresent = TRUE;
1259         if (ExplicitDescriptor->Control & SE_DACL_DEFAULTED)
1260             ExplicitDefaulted = TRUE;
1261     }
1262     ParentAcl = NULL;
1263     if (ParentDescriptor != NULL &&
1264         (ParentDescriptor->Control & SE_DACL_PRESENT))
1265     {
1266         ParentAcl = SepGetDaclFromDescriptor(ParentDescriptor);
1267     }
1268     Dacl = SepSelectAcl(ExplicitAcl,
1269                         ExplicitPresent,
1270                         ExplicitDefaulted,
1271                         ParentAcl,
1272                         Token->DefaultDacl,
1273                         &DaclLength,
1274                         Owner,
1275                         Group,
1276                         &DaclPresent,
1277                         &DaclIsInherited,
1278                         IsDirectoryObject,
1279                         GenericMapping);
1280     if (DaclPresent)
1281         Control |= SE_DACL_PRESENT;
1282     ASSERT(DaclLength % sizeof(ULONG) == 0);
1283 
1284     /* Inherit the SACL */
1285     SaclLength = 0;
1286     ExplicitAcl = NULL;
1287     ExplicitPresent = FALSE;
1288     ExplicitDefaulted = FALSE;
1289     if (ExplicitDescriptor != NULL &&
1290         (ExplicitDescriptor->Control & SE_SACL_PRESENT))
1291     {
1292         ExplicitAcl = SepGetSaclFromDescriptor(ExplicitDescriptor);
1293         ExplicitPresent = TRUE;
1294         if (ExplicitDescriptor->Control & SE_SACL_DEFAULTED)
1295             ExplicitDefaulted = TRUE;
1296     }
1297     ParentAcl = NULL;
1298     if (ParentDescriptor != NULL &&
1299         (ParentDescriptor->Control & SE_SACL_PRESENT))
1300     {
1301         ParentAcl = SepGetSaclFromDescriptor(ParentDescriptor);
1302     }
1303     Sacl = SepSelectAcl(ExplicitAcl,
1304                         ExplicitPresent,
1305                         ExplicitDefaulted,
1306                         ParentAcl,
1307                         NULL,
1308                         &SaclLength,
1309                         Owner,
1310                         Group,
1311                         &SaclPresent,
1312                         &SaclIsInherited,
1313                         IsDirectoryObject,
1314                         GenericMapping);
1315     if (SaclPresent)
1316         Control |= SE_SACL_PRESENT;
1317     ASSERT(SaclLength % sizeof(ULONG) == 0);
1318 
1319     /* Allocate and initialize the new security descriptor */
1320     Length = sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
1321         OwnerLength + GroupLength + DaclLength + SaclLength;
1322 
1323     DPRINT("L: sizeof(SECURITY_DESCRIPTOR) %u OwnerLength %lu GroupLength %lu DaclLength %lu SaclLength %lu\n",
1324            sizeof(SECURITY_DESCRIPTOR),
1325            OwnerLength,
1326            GroupLength,
1327            DaclLength,
1328            SaclLength);
1329 
1330     Descriptor = ExAllocatePoolWithTag(PagedPool, Length, TAG_SD);
1331     if (Descriptor == NULL)
1332     {
1333         DPRINT1("ExAlloctePool() failed\n");
1334         SeUnlockSubjectContext(SubjectContext);
1335         return STATUS_INSUFFICIENT_RESOURCES;
1336     }
1337 
1338     RtlZeroMemory(Descriptor, Length);
1339     RtlCreateSecurityDescriptor(Descriptor, SECURITY_DESCRIPTOR_REVISION);
1340 
1341     Descriptor->Control = Control | SE_SELF_RELATIVE;
1342 
1343     Current = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
1344 
1345     if (SaclLength != 0)
1346     {
1347         Status = SepPropagateAcl((PACL)((PUCHAR)Descriptor + Current),
1348                                  &SaclLength,
1349                                  Sacl,
1350                                  Owner,
1351                                  Group,
1352                                  SaclIsInherited,
1353                                  IsDirectoryObject,
1354                                  GenericMapping);
1355         ASSERT(Status == STATUS_SUCCESS);
1356         Descriptor->Sacl = Current;
1357         Current += SaclLength;
1358     }
1359 
1360     if (DaclLength != 0)
1361     {
1362         Status = SepPropagateAcl((PACL)((PUCHAR)Descriptor + Current),
1363                                  &DaclLength,
1364                                  Dacl,
1365                                  Owner,
1366                                  Group,
1367                                  DaclIsInherited,
1368                                  IsDirectoryObject,
1369                                  GenericMapping);
1370         ASSERT(Status == STATUS_SUCCESS);
1371         Descriptor->Dacl = Current;
1372         Current += DaclLength;
1373     }
1374 
1375     if (OwnerLength != 0)
1376     {
1377         RtlCopyMemory((PUCHAR)Descriptor + Current, Owner, OwnerLength);
1378         Descriptor->Owner = Current;
1379         Current += OwnerLength;
1380         DPRINT("Owner of %p at %x\n", Descriptor, Descriptor->Owner);
1381     }
1382     else
1383     {
1384         DPRINT("Owner of %p is zero length\n", Descriptor);
1385     }
1386 
1387     if (GroupLength != 0)
1388     {
1389         RtlCopyMemory((PUCHAR)Descriptor + Current, Group, GroupLength);
1390         Descriptor->Group = Current;
1391     }
1392 
1393     /* Unlock subject context */
1394     SeUnlockSubjectContext(SubjectContext);
1395 
1396     *NewDescriptor = Descriptor;
1397 
1398     DPRINT("Descriptor %p\n", Descriptor);
1399     ASSERT(RtlLengthSecurityDescriptor(Descriptor));
1400 
1401     return STATUS_SUCCESS;
1402 }
1403 
1404 /*
1405  * @implemented
1406  */
1407 _IRQL_requires_max_(PASSIVE_LEVEL)
1408 NTSTATUS
1409 NTAPI
1410 SeAssignSecurity(
1411     _In_opt_ PSECURITY_DESCRIPTOR ParentDescriptor,
1412     _In_opt_ PSECURITY_DESCRIPTOR ExplicitDescriptor,
1413     _Out_ PSECURITY_DESCRIPTOR *NewDescriptor,
1414     _In_ BOOLEAN IsDirectoryObject,
1415     _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
1416     _In_ PGENERIC_MAPPING GenericMapping,
1417     _In_ POOL_TYPE PoolType)
1418 {
1419     PAGED_CODE();
1420 
1421     return SeAssignSecurityEx(ParentDescriptor,
1422                               ExplicitDescriptor,
1423                               NewDescriptor,
1424                               NULL,
1425                               IsDirectoryObject,
1426                               0,
1427                               SubjectContext,
1428                               GenericMapping,
1429                               PoolType);
1430 }
1431 
1432 /*
1433  * @implemented
1434  */
1435 _IRQL_requires_max_(PASSIVE_LEVEL)
1436 NTSTATUS
1437 NTAPI
1438 SeComputeQuotaInformationSize(
1439     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1440     _Out_ PULONG QuotaInfoSize)
1441 {
1442     PSID Group;
1443     PACL Dacl;
1444 
1445     PAGED_CODE();
1446 
1447     *QuotaInfoSize = 0;
1448 
1449     /* Validate security descriptor revision */
1450     if (((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Revision != SECURITY_DESCRIPTOR_REVISION1)
1451     {
1452         return STATUS_UNKNOWN_REVISION;
1453     }
1454 
1455     /* Get group and DACL, if any */
1456     Group = SepGetGroupFromDescriptor(SecurityDescriptor);
1457     Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
1458 
1459     /* Return SID length if any */
1460     if (Group != NULL)
1461     {
1462         *QuotaInfoSize = ALIGN_UP_BY(RtlLengthSid(Group), sizeof(ULONG));
1463     }
1464 
1465     /* Return DACL if any */
1466     if (Dacl != NULL)
1467     {
1468         *QuotaInfoSize += ALIGN_UP_BY(Dacl->AclSize, sizeof(ULONG));
1469     }
1470 
1471     return STATUS_SUCCESS;
1472 }
1473 
1474 /* EOF */
1475