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