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