xref: /reactos/ntoskrnl/se/sd.c (revision 45fd48bd)
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 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, SepInitSDs)
18 #endif
19 
20 /* GLOBALS ********************************************************************/
21 
22 PSECURITY_DESCRIPTOR SePublicDefaultSd = NULL;
23 PSECURITY_DESCRIPTOR SePublicDefaultUnrestrictedSd = NULL;
24 PSECURITY_DESCRIPTOR SePublicOpenSd = NULL;
25 PSECURITY_DESCRIPTOR SePublicOpenUnrestrictedSd = NULL;
26 PSECURITY_DESCRIPTOR SeSystemDefaultSd = NULL;
27 PSECURITY_DESCRIPTOR SeUnrestrictedSd = NULL;
28 
29 /* PRIVATE FUNCTIONS **********************************************************/
30 
31 BOOLEAN
32 INIT_FUNCTION
33 NTAPI
34 SepInitSDs(VOID)
35 {
36     /* Create PublicDefaultSd */
37     SePublicDefaultSd = ExAllocatePoolWithTag(PagedPool,
38                                               sizeof(SECURITY_DESCRIPTOR), TAG_SD);
39     if (SePublicDefaultSd == NULL)
40         return FALSE;
41 
42     RtlCreateSecurityDescriptor(SePublicDefaultSd,
43                                 SECURITY_DESCRIPTOR_REVISION);
44     RtlSetDaclSecurityDescriptor(SePublicDefaultSd,
45                                  TRUE,
46                                  SePublicDefaultDacl,
47                                  FALSE);
48 
49     /* Create PublicDefaultUnrestrictedSd */
50     SePublicDefaultUnrestrictedSd = ExAllocatePoolWithTag(PagedPool,
51                                                           sizeof(SECURITY_DESCRIPTOR), TAG_SD);
52     if (SePublicDefaultUnrestrictedSd == NULL)
53         return FALSE;
54 
55     RtlCreateSecurityDescriptor(SePublicDefaultUnrestrictedSd,
56                                 SECURITY_DESCRIPTOR_REVISION);
57     RtlSetDaclSecurityDescriptor(SePublicDefaultUnrestrictedSd,
58                                  TRUE,
59                                  SePublicDefaultUnrestrictedDacl,
60                                  FALSE);
61 
62     /* Create PublicOpenSd */
63     SePublicOpenSd = ExAllocatePoolWithTag(PagedPool,
64                                            sizeof(SECURITY_DESCRIPTOR), TAG_SD);
65     if (SePublicOpenSd == NULL)
66         return FALSE;
67 
68     RtlCreateSecurityDescriptor(SePublicOpenSd,
69                                 SECURITY_DESCRIPTOR_REVISION);
70     RtlSetDaclSecurityDescriptor(SePublicOpenSd,
71                                  TRUE,
72                                  SePublicOpenDacl,
73                                  FALSE);
74 
75     /* Create PublicOpenUnrestrictedSd */
76     SePublicOpenUnrestrictedSd = ExAllocatePoolWithTag(PagedPool,
77                                                        sizeof(SECURITY_DESCRIPTOR), TAG_SD);
78     if (SePublicOpenUnrestrictedSd == NULL)
79         return FALSE;
80 
81     RtlCreateSecurityDescriptor(SePublicOpenUnrestrictedSd,
82                                 SECURITY_DESCRIPTOR_REVISION);
83     RtlSetDaclSecurityDescriptor(SePublicOpenUnrestrictedSd,
84                                  TRUE,
85                                  SePublicOpenUnrestrictedDacl,
86                                  FALSE);
87 
88     /* Create SystemDefaultSd */
89     SeSystemDefaultSd = ExAllocatePoolWithTag(PagedPool,
90                                               sizeof(SECURITY_DESCRIPTOR), TAG_SD);
91     if (SeSystemDefaultSd == NULL)
92         return FALSE;
93 
94     RtlCreateSecurityDescriptor(SeSystemDefaultSd,
95                                 SECURITY_DESCRIPTOR_REVISION);
96     RtlSetDaclSecurityDescriptor(SeSystemDefaultSd,
97                                  TRUE,
98                                  SeSystemDefaultDacl,
99                                  FALSE);
100 
101     /* Create UnrestrictedSd */
102     SeUnrestrictedSd = ExAllocatePoolWithTag(PagedPool,
103                                              sizeof(SECURITY_DESCRIPTOR), TAG_SD);
104     if (SeUnrestrictedSd == NULL)
105         return FALSE;
106 
107     RtlCreateSecurityDescriptor(SeUnrestrictedSd,
108                                 SECURITY_DESCRIPTOR_REVISION);
109     RtlSetDaclSecurityDescriptor(SeUnrestrictedSd,
110                                  TRUE,
111                                  SeUnrestrictedDacl,
112                                  FALSE);
113 
114     return TRUE;
115 }
116 
117 NTSTATUS
118 NTAPI
119 SeSetWorldSecurityDescriptor(SECURITY_INFORMATION SecurityInformation,
120                              PISECURITY_DESCRIPTOR SecurityDescriptor,
121                              PULONG BufferLength)
122 {
123     ULONG Current;
124     ULONG SidSize;
125     ULONG SdSize;
126     NTSTATUS Status;
127     PISECURITY_DESCRIPTOR_RELATIVE SdRel = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptor;
128 
129     DPRINT("SeSetWorldSecurityDescriptor() called\n");
130 
131     if (SecurityInformation == 0)
132     {
133         return STATUS_ACCESS_DENIED;
134     }
135 
136     /* calculate the minimum size of the buffer */
137     SidSize = RtlLengthSid(SeWorldSid);
138     SdSize = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
139     if (SecurityInformation & OWNER_SECURITY_INFORMATION)
140         SdSize += SidSize;
141     if (SecurityInformation & GROUP_SECURITY_INFORMATION)
142         SdSize += SidSize;
143     if (SecurityInformation & DACL_SECURITY_INFORMATION)
144     {
145         SdSize += sizeof(ACL) + sizeof(ACE) + SidSize;
146     }
147 
148     if (*BufferLength < SdSize)
149     {
150         *BufferLength = SdSize;
151         return STATUS_BUFFER_TOO_SMALL;
152     }
153 
154     *BufferLength = SdSize;
155 
156     Status = RtlCreateSecurityDescriptorRelative(SdRel,
157                                                  SECURITY_DESCRIPTOR_REVISION);
158     if (!NT_SUCCESS(Status))
159     {
160         return Status;
161     }
162 
163     Current = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
164 
165     if (SecurityInformation & OWNER_SECURITY_INFORMATION)
166     {
167         RtlCopyMemory((PUCHAR)SdRel + Current, SeWorldSid, SidSize);
168         SdRel->Owner = Current;
169         Current += SidSize;
170     }
171 
172     if (SecurityInformation & GROUP_SECURITY_INFORMATION)
173     {
174         RtlCopyMemory((PUCHAR)SdRel + Current, SeWorldSid, SidSize);
175         SdRel->Group = Current;
176         Current += SidSize;
177     }
178 
179     if (SecurityInformation & DACL_SECURITY_INFORMATION)
180     {
181         PACL Dacl = (PACL)((PUCHAR)SdRel + Current);
182         SdRel->Control |= SE_DACL_PRESENT;
183 
184         Status = RtlCreateAcl(Dacl,
185                               sizeof(ACL) + sizeof(ACE) + SidSize,
186                               ACL_REVISION);
187         if (!NT_SUCCESS(Status))
188             return Status;
189 
190         Status = RtlAddAccessAllowedAce(Dacl,
191                                         ACL_REVISION,
192                                         GENERIC_ALL,
193                                         SeWorldSid);
194         if (!NT_SUCCESS(Status))
195             return Status;
196 
197         SdRel->Dacl = Current;
198     }
199 
200     if (SecurityInformation & SACL_SECURITY_INFORMATION)
201     {
202         /* FIXME - SdRel->Control |= SE_SACL_PRESENT; */
203     }
204 
205     return STATUS_SUCCESS;
206 }
207 
208 
209 NTSTATUS
210 NTAPI
211 SepCaptureSecurityQualityOfService(IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
212                                    IN KPROCESSOR_MODE AccessMode,
213                                    IN POOL_TYPE PoolType,
214                                    IN BOOLEAN CaptureIfKernel,
215                                    OUT PSECURITY_QUALITY_OF_SERVICE *CapturedSecurityQualityOfService,
216                                    OUT PBOOLEAN Present)
217 {
218     PSECURITY_QUALITY_OF_SERVICE CapturedQos;
219     NTSTATUS Status = STATUS_SUCCESS;
220 
221     PAGED_CODE();
222 
223     ASSERT(CapturedSecurityQualityOfService);
224     ASSERT(Present);
225 
226     if (ObjectAttributes != NULL)
227     {
228         if (AccessMode != KernelMode)
229         {
230             SECURITY_QUALITY_OF_SERVICE SafeQos;
231 
232             _SEH2_TRY
233             {
234                 ProbeForRead(ObjectAttributes,
235                              sizeof(OBJECT_ATTRIBUTES),
236                              sizeof(ULONG));
237                 if (ObjectAttributes->Length == sizeof(OBJECT_ATTRIBUTES))
238                 {
239                     if (ObjectAttributes->SecurityQualityOfService != NULL)
240                     {
241                         ProbeForRead(ObjectAttributes->SecurityQualityOfService,
242                                      sizeof(SECURITY_QUALITY_OF_SERVICE),
243                                      sizeof(ULONG));
244 
245                         if (((PSECURITY_QUALITY_OF_SERVICE)ObjectAttributes->SecurityQualityOfService)->Length ==
246                             sizeof(SECURITY_QUALITY_OF_SERVICE))
247                         {
248                             /*
249                              * Don't allocate memory here because ExAllocate should bugcheck
250                              * the system if it's buggy, SEH would catch that! So make a local
251                              * copy of the qos structure.
252                              */
253                             RtlCopyMemory(&SafeQos,
254                                           ObjectAttributes->SecurityQualityOfService,
255                                           sizeof(SECURITY_QUALITY_OF_SERVICE));
256                             *Present = TRUE;
257                         }
258                         else
259                         {
260                             Status = STATUS_INVALID_PARAMETER;
261                         }
262                     }
263                     else
264                     {
265                         *CapturedSecurityQualityOfService = NULL;
266                         *Present = FALSE;
267                     }
268                 }
269                 else
270                 {
271                     Status = STATUS_INVALID_PARAMETER;
272                 }
273             }
274             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
275             {
276                 Status = _SEH2_GetExceptionCode();
277             }
278             _SEH2_END;
279 
280             if (NT_SUCCESS(Status))
281             {
282                 if (*Present)
283                 {
284                     CapturedQos = ExAllocatePoolWithTag(PoolType,
285                                                         sizeof(SECURITY_QUALITY_OF_SERVICE),
286                                                         TAG_QOS);
287                     if (CapturedQos != NULL)
288                     {
289                         RtlCopyMemory(CapturedQos,
290                                       &SafeQos,
291                                       sizeof(SECURITY_QUALITY_OF_SERVICE));
292                         *CapturedSecurityQualityOfService = CapturedQos;
293                     }
294                     else
295                     {
296                         Status = STATUS_INSUFFICIENT_RESOURCES;
297                     }
298                 }
299                 else
300                 {
301                     *CapturedSecurityQualityOfService = NULL;
302                 }
303             }
304         }
305         else
306         {
307             if (ObjectAttributes->Length == sizeof(OBJECT_ATTRIBUTES))
308             {
309                 if (CaptureIfKernel)
310                 {
311                     if (ObjectAttributes->SecurityQualityOfService != NULL)
312                     {
313                         if (((PSECURITY_QUALITY_OF_SERVICE)ObjectAttributes->SecurityQualityOfService)->Length ==
314                             sizeof(SECURITY_QUALITY_OF_SERVICE))
315                         {
316                             CapturedQos = ExAllocatePoolWithTag(PoolType,
317                                                                 sizeof(SECURITY_QUALITY_OF_SERVICE),
318                                                                 TAG_QOS);
319                             if (CapturedQos != NULL)
320                             {
321                                 RtlCopyMemory(CapturedQos,
322                                               ObjectAttributes->SecurityQualityOfService,
323                                               sizeof(SECURITY_QUALITY_OF_SERVICE));
324                                 *CapturedSecurityQualityOfService = CapturedQos;
325                                 *Present = TRUE;
326                             }
327                             else
328                             {
329                                 Status = STATUS_INSUFFICIENT_RESOURCES;
330                             }
331                         }
332                         else
333                         {
334                             Status = STATUS_INVALID_PARAMETER;
335                         }
336                     }
337                     else
338                     {
339                         *CapturedSecurityQualityOfService = NULL;
340                         *Present = FALSE;
341                     }
342                 }
343                 else
344                 {
345                     *CapturedSecurityQualityOfService = (PSECURITY_QUALITY_OF_SERVICE)ObjectAttributes->SecurityQualityOfService;
346                     *Present = (ObjectAttributes->SecurityQualityOfService != NULL);
347                 }
348             }
349             else
350             {
351                 Status = STATUS_INVALID_PARAMETER;
352             }
353         }
354     }
355     else
356     {
357         *CapturedSecurityQualityOfService = NULL;
358         *Present = FALSE;
359     }
360 
361     return Status;
362 }
363 
364 
365 VOID
366 NTAPI
367 SepReleaseSecurityQualityOfService(IN PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService  OPTIONAL,
368                                    IN KPROCESSOR_MODE AccessMode,
369                                    IN BOOLEAN CaptureIfKernel)
370 {
371     PAGED_CODE();
372 
373     if (CapturedSecurityQualityOfService != NULL &&
374         (AccessMode != KernelMode || CaptureIfKernel))
375     {
376         ExFreePoolWithTag(CapturedSecurityQualityOfService, TAG_QOS);
377     }
378 }
379 
380 /* PUBLIC FUNCTIONS ***********************************************************/
381 
382 static
383 ULONG
384 DetermineSIDSize(
385     PISID Sid,
386     PULONG OutSAC,
387     KPROCESSOR_MODE ProcessorMode)
388 {
389     ULONG Size;
390 
391     if (!Sid)
392     {
393         *OutSAC = 0;
394         return 0;
395     }
396 
397     if (ProcessorMode != KernelMode)
398     {
399         /* Securely access the buffers! */
400         *OutSAC = ProbeForReadUchar(&Sid->SubAuthorityCount);
401         Size = RtlLengthRequiredSid(*OutSAC);
402         ProbeForRead(Sid, Size, sizeof(ULONG));
403     }
404     else
405     {
406         *OutSAC = Sid->SubAuthorityCount;
407         Size = RtlLengthRequiredSid(*OutSAC);
408     }
409 
410     return Size;
411 }
412 
413 static
414 ULONG
415 DetermineACLSize(
416     PACL Acl,
417     KPROCESSOR_MODE ProcessorMode)
418 {
419     ULONG Size;
420 
421     if (!Acl) return 0;
422 
423     if (ProcessorMode == KernelMode) return Acl->AclSize;
424 
425     /* Probe the buffers! */
426     Size = ProbeForReadUshort(&Acl->AclSize);
427     ProbeForRead(Acl, Size, sizeof(ULONG));
428 
429     return Size;
430 }
431 
432 NTSTATUS
433 NTAPI
434 SeCaptureSecurityDescriptor(
435     IN PSECURITY_DESCRIPTOR _OriginalSecurityDescriptor,
436     IN KPROCESSOR_MODE CurrentMode,
437     IN POOL_TYPE PoolType,
438     IN BOOLEAN CaptureIfKernel,
439     OUT PSECURITY_DESCRIPTOR *CapturedSecurityDescriptor)
440 {
441     PISECURITY_DESCRIPTOR OriginalDescriptor = _OriginalSecurityDescriptor;
442     SECURITY_DESCRIPTOR DescriptorCopy;
443     PISECURITY_DESCRIPTOR_RELATIVE NewDescriptor;
444     ULONG OwnerSAC = 0, GroupSAC = 0;
445     ULONG OwnerSize = 0, GroupSize = 0;
446     ULONG SaclSize = 0, DaclSize = 0;
447     ULONG DescriptorSize = 0;
448     ULONG Offset;
449 
450     if (!OriginalDescriptor)
451     {
452         /* Nothing to do... */
453         *CapturedSecurityDescriptor = NULL;
454         return STATUS_SUCCESS;
455     }
456 
457     /* Quick path */
458     if (CurrentMode == KernelMode && !CaptureIfKernel)
459     {
460         /* Check descriptor version */
461         if (OriginalDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION1)
462         {
463             return STATUS_UNKNOWN_REVISION;
464         }
465 
466         *CapturedSecurityDescriptor = _OriginalSecurityDescriptor;
467         return STATUS_SUCCESS;
468     }
469 
470     _SEH2_TRY
471     {
472         if (CurrentMode != KernelMode)
473         {
474             ProbeForRead(OriginalDescriptor,
475                          sizeof(SECURITY_DESCRIPTOR_RELATIVE),
476                          sizeof(ULONG));
477         }
478 
479         /* Check the descriptor version */
480         if (OriginalDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION1)
481         {
482             _SEH2_YIELD(return STATUS_UNKNOWN_REVISION);
483         }
484 
485         if (CurrentMode != KernelMode)
486         {
487             /* Get the size of the descriptor */
488             DescriptorSize = (OriginalDescriptor->Control & SE_SELF_RELATIVE) ?
489                 sizeof(SECURITY_DESCRIPTOR_RELATIVE) : sizeof(SECURITY_DESCRIPTOR);
490 
491             /* Probe the entire security descriptor structure. The SIDs
492              * and ACLs will be probed and copied later though */
493             ProbeForRead(OriginalDescriptor, DescriptorSize, sizeof(ULONG));
494         }
495 
496         /* Now capture all fields and convert to an absolute descriptor */
497         DescriptorCopy.Revision = OriginalDescriptor->Revision;
498         DescriptorCopy.Sbz1 = OriginalDescriptor->Sbz1;
499         DescriptorCopy.Control = OriginalDescriptor->Control & ~SE_SELF_RELATIVE;
500         DescriptorCopy.Owner = SepGetOwnerFromDescriptor(OriginalDescriptor);
501         DescriptorCopy.Group = SepGetGroupFromDescriptor(OriginalDescriptor);
502         DescriptorCopy.Sacl = SepGetSaclFromDescriptor(OriginalDescriptor);
503         DescriptorCopy.Dacl = SepGetDaclFromDescriptor(OriginalDescriptor);
504         DescriptorSize = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
505 
506         /* Determine owner and group sizes */
507         OwnerSize = DetermineSIDSize(DescriptorCopy.Owner, &OwnerSAC, CurrentMode);
508         DescriptorSize += ROUND_UP(OwnerSize, sizeof(ULONG));
509         GroupSize = DetermineSIDSize(DescriptorCopy.Group, &GroupSAC, CurrentMode);
510         DescriptorSize += ROUND_UP(GroupSize, sizeof(ULONG));
511 
512         /* Determine the size of the ACLs */
513         if (DescriptorCopy.Control & SE_SACL_PRESENT)
514         {
515             /* Get the size and probe if user mode */
516             SaclSize = DetermineACLSize(DescriptorCopy.Sacl, CurrentMode);
517             DescriptorSize += ROUND_UP(SaclSize, sizeof(ULONG));
518         }
519 
520         if (DescriptorCopy.Control & SE_DACL_PRESENT)
521         {
522             /* Get the size and probe if user mode */
523             DaclSize = DetermineACLSize(DescriptorCopy.Dacl, CurrentMode);
524             DescriptorSize += ROUND_UP(DaclSize, sizeof(ULONG));
525         }
526     }
527     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
528     {
529         _SEH2_YIELD(return _SEH2_GetExceptionCode());
530     }
531     _SEH2_END;
532 
533     /*
534      * Allocate enough memory to store a complete copy of a self-relative
535      * security descriptor
536      */
537     NewDescriptor = ExAllocatePoolWithTag(PoolType,
538                                           DescriptorSize,
539                                           TAG_SD);
540     if (!NewDescriptor) return STATUS_INSUFFICIENT_RESOURCES;
541 
542     RtlZeroMemory(NewDescriptor, DescriptorSize);
543     NewDescriptor->Revision = DescriptorCopy.Revision;
544     NewDescriptor->Sbz1 = DescriptorCopy.Sbz1;
545     NewDescriptor->Control = DescriptorCopy.Control | SE_SELF_RELATIVE;
546 
547     _SEH2_TRY
548     {
549         /*
550          * Setup the offsets and copy the SIDs and ACLs to the new
551          * self-relative security descriptor. Probing the pointers is not
552          * neccessary anymore as we did that when collecting the sizes!
553          * Make sure to validate the SIDs and ACLs *again* as they could have
554          * been modified in the meanwhile!
555          */
556         Offset = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
557 
558         if (DescriptorCopy.Owner)
559         {
560             if (!RtlValidSid(DescriptorCopy.Owner)) RtlRaiseStatus(STATUS_INVALID_SID);
561             NewDescriptor->Owner = Offset;
562             RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
563                           DescriptorCopy.Owner,
564                           OwnerSize);
565             Offset += ROUND_UP(OwnerSize, sizeof(ULONG));
566         }
567 
568         if (DescriptorCopy.Group)
569         {
570             if (!RtlValidSid(DescriptorCopy.Group)) RtlRaiseStatus(STATUS_INVALID_SID);
571             NewDescriptor->Group = Offset;
572             RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
573                           DescriptorCopy.Group,
574                           GroupSize);
575             Offset += ROUND_UP(GroupSize, sizeof(ULONG));
576         }
577 
578         if (DescriptorCopy.Sacl)
579         {
580             if (!RtlValidAcl(DescriptorCopy.Sacl)) RtlRaiseStatus(STATUS_INVALID_ACL);
581             NewDescriptor->Sacl = Offset;
582             RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
583                           DescriptorCopy.Sacl,
584                           SaclSize);
585             Offset += ROUND_UP(SaclSize, sizeof(ULONG));
586         }
587 
588         if (DescriptorCopy.Dacl)
589         {
590             if (!RtlValidAcl(DescriptorCopy.Dacl)) RtlRaiseStatus(STATUS_INVALID_ACL);
591             NewDescriptor->Dacl = Offset;
592             RtlCopyMemory((PUCHAR)NewDescriptor + Offset,
593                           DescriptorCopy.Dacl,
594                           DaclSize);
595             Offset += ROUND_UP(DaclSize, sizeof(ULONG));
596         }
597 
598         /* Make sure the size was correct */
599         ASSERT(Offset == DescriptorSize);
600     }
601     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
602     {
603         /* We failed to copy the data to the new descriptor */
604         ExFreePoolWithTag(NewDescriptor, TAG_SD);
605         _SEH2_YIELD(return _SEH2_GetExceptionCode());
606     }
607     _SEH2_END;
608 
609     /*
610      * We're finally done!
611      * Copy the pointer to the captured descriptor to to the caller.
612      */
613     *CapturedSecurityDescriptor = NewDescriptor;
614     return STATUS_SUCCESS;
615 }
616 
617 /*
618  * @implemented
619  */
620 _IRQL_requires_max_(PASSIVE_LEVEL)
621 NTSTATUS
622 NTAPI
623 SeQuerySecurityDescriptorInfo(
624     _In_ PSECURITY_INFORMATION SecurityInformation,
625     _Out_writes_bytes_(*Length) PSECURITY_DESCRIPTOR SecurityDescriptor,
626     _Inout_ PULONG Length,
627     _Inout_ PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor)
628 {
629     PISECURITY_DESCRIPTOR ObjectSd;
630     PISECURITY_DESCRIPTOR_RELATIVE RelSD;
631     PSID Owner = NULL;
632     PSID Group = NULL;
633     PACL Dacl = NULL;
634     PACL Sacl = NULL;
635     ULONG OwnerLength = 0;
636     ULONG GroupLength = 0;
637     ULONG DaclLength = 0;
638     ULONG SaclLength = 0;
639     SECURITY_DESCRIPTOR_CONTROL Control = 0;
640     ULONG_PTR Current;
641     ULONG SdLength;
642 
643     PAGED_CODE();
644 
645     RelSD = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptor;
646 
647     if (*ObjectsSecurityDescriptor == NULL)
648     {
649         if (*Length < sizeof(SECURITY_DESCRIPTOR_RELATIVE))
650         {
651             *Length = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
652             return STATUS_BUFFER_TOO_SMALL;
653         }
654 
655         *Length = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
656         RtlCreateSecurityDescriptorRelative(RelSD,
657                                             SECURITY_DESCRIPTOR_REVISION);
658         return STATUS_SUCCESS;
659     }
660 
661     ObjectSd = *ObjectsSecurityDescriptor;
662 
663     /* Calculate the required security descriptor length */
664     Control = SE_SELF_RELATIVE;
665     if ((*SecurityInformation & OWNER_SECURITY_INFORMATION) &&
666         (ObjectSd->Owner != NULL))
667     {
668         Owner = (PSID)((ULONG_PTR)ObjectSd->Owner + (ULONG_PTR)ObjectSd);
669         OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
670         Control |= (ObjectSd->Control & SE_OWNER_DEFAULTED);
671     }
672 
673     if ((*SecurityInformation & GROUP_SECURITY_INFORMATION) &&
674         (ObjectSd->Group != NULL))
675     {
676         Group = (PSID)((ULONG_PTR)ObjectSd->Group + (ULONG_PTR)ObjectSd);
677         GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
678         Control |= (ObjectSd->Control & SE_GROUP_DEFAULTED);
679     }
680 
681     if ((*SecurityInformation & DACL_SECURITY_INFORMATION) &&
682         (ObjectSd->Control & SE_DACL_PRESENT))
683     {
684         if (ObjectSd->Dacl != NULL)
685         {
686             Dacl = (PACL)((ULONG_PTR)ObjectSd->Dacl + (ULONG_PTR)ObjectSd);
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         if (ObjectSd->Sacl != NULL)
697         {
698             Sacl = (PACL)((ULONG_PTR)ObjectSd->Sacl + (ULONG_PTR)ObjectSd);
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 /* EOF */
1433