xref: /reactos/ntoskrnl/se/sd.c (revision a0bcf90f)
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     /* Ensure the Owner SID is within the bounds of the security descriptor */
1070     if ((SecurityDescriptor->Owner > Length) ||
1071         (Length - SecurityDescriptor->Owner < sizeof(SID)))
1072     {
1073         DPRINT1("Owner SID not within bounds\n");
1074         return FALSE;
1075     }
1076 
1077     /* Reference it */
1078     Sid = (PISID)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Owner);
1079     if (Sid->Revision != SID_REVISION)
1080     {
1081         DPRINT1("Invalid Owner SID revision\n");
1082         return FALSE;
1083     }
1084 
1085     // NOTE: Same as SeLengthSid(Sid); but doesn't use hardcoded values.
1086     SdLength += (sizeof(SID) + (Sid->SubAuthorityCount - 1) * sizeof(ULONG));
1087     if (Length < SdLength)
1088     {
1089         DPRINT1("Invalid Owner SID size\n");
1090         return FALSE;
1091     }
1092 
1093     /* Check Group SID */
1094     if (SecurityDescriptor->Group)
1095     {
1096         if (SecurityDescriptor->Group % sizeof(ULONG))
1097         {
1098             DPRINT1("Invalid Group SID alignment\n");
1099             return FALSE;
1100         }
1101 
1102         /* Ensure the Group SID is within the bounds of the security descriptor */
1103         if ((SecurityDescriptor->Group > Length) ||
1104             (Length - SecurityDescriptor->Group < sizeof(SID)))
1105         {
1106             DPRINT1("Group SID not within bounds\n");
1107             return FALSE;
1108         }
1109 
1110         /* Reference it */
1111         Sid = (PSID)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Group);
1112         if (Sid->Revision != SID_REVISION)
1113         {
1114             DPRINT1("Invalid Group SID revision\n");
1115             return FALSE;
1116         }
1117 
1118         // NOTE: Same as SeLengthSid(Sid); but doesn't use hardcoded values.
1119         SdLength += (sizeof(SID) + (Sid->SubAuthorityCount - 1) * sizeof(ULONG));
1120         if (Length < SdLength)
1121         {
1122             DPRINT1("Invalid Group SID size\n");
1123             return FALSE;
1124         }
1125     }
1126 
1127     /* Check DACL */
1128     if (SecurityDescriptor->Dacl)
1129     {
1130         if (SecurityDescriptor->Dacl % sizeof(ULONG))
1131         {
1132             DPRINT1("Invalid DACL alignment\n");
1133             return FALSE;
1134         }
1135 
1136         /* Ensure the DACL is within the bounds of the security descriptor */
1137         if ((SecurityDescriptor->Dacl > Length) ||
1138             (Length - SecurityDescriptor->Dacl < sizeof(ACL)))
1139         {
1140             DPRINT1("DACL not within bounds\n");
1141             return FALSE;
1142         }
1143 
1144         /* Reference it */
1145         Acl = (PACL)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Dacl);
1146 
1147         SdLength += Acl->AclSize;
1148         if (Length < SdLength)
1149         {
1150             DPRINT1("Invalid DACL size\n");
1151             return FALSE;
1152         }
1153 
1154         if (!RtlValidAcl(Acl))
1155         {
1156             DPRINT1("Invalid DACL\n");
1157             return FALSE;
1158         }
1159     }
1160 
1161     /* Check SACL */
1162     if (SecurityDescriptor->Sacl)
1163     {
1164         if (SecurityDescriptor->Sacl % sizeof(ULONG))
1165         {
1166             DPRINT1("Invalid SACL alignment\n");
1167             return FALSE;
1168         }
1169 
1170         /* Ensure the SACL is within the bounds of the security descriptor */
1171         if ((SecurityDescriptor->Sacl > Length) ||
1172             (Length - SecurityDescriptor->Sacl < sizeof(ACL)))
1173         {
1174             DPRINT1("SACL not within bounds\n");
1175             return FALSE;
1176         }
1177 
1178         /* Reference it */
1179         Acl = (PACL)((ULONG_PTR)SecurityDescriptor + SecurityDescriptor->Sacl);
1180 
1181         SdLength += Acl->AclSize;
1182         if (Length < SdLength)
1183         {
1184             DPRINT1("Invalid SACL size\n");
1185             return FALSE;
1186         }
1187 
1188         if (!RtlValidAcl(Acl))
1189         {
1190             DPRINT1("Invalid SACL\n");
1191             return FALSE;
1192         }
1193     }
1194 
1195     return TRUE;
1196 }
1197 
1198 /**
1199  * @brief
1200  * Frees a security descriptor.
1201  *
1202  * @param[in] SecurityDescriptor
1203  * A security descriptor to be freed from memory.
1204  *
1205  * @return
1206  * Returns STATUS_SUCCESS.
1207  */
1208 _IRQL_requires_max_(PASSIVE_LEVEL)
1209 NTSTATUS
1210 NTAPI
1211 SeDeassignSecurity(
1212     _Inout_ PSECURITY_DESCRIPTOR *SecurityDescriptor)
1213 {
1214     PAGED_CODE();
1215 
1216     if (*SecurityDescriptor != NULL)
1217     {
1218         ExFreePoolWithTag(*SecurityDescriptor, TAG_SD);
1219         *SecurityDescriptor = NULL;
1220     }
1221 
1222     return STATUS_SUCCESS;
1223 }
1224 
1225 /**
1226  * @brief
1227  * An extended function that assigns a security descriptor for a new
1228  * object.
1229  *
1230  * @param[in] _ParentDescriptor
1231  * A security descriptor of the parent object that is being
1232  * created.
1233  *
1234  * @param[in] _ExplicitDescriptor
1235  * An explicit security descriptor that is applied to a new
1236  * object.
1237  *
1238  * @param[out] NewDescriptor
1239  * The new allocated security descriptor.
1240  *
1241  * @param[in] ObjectType
1242  * The type of the new object.
1243  *
1244  * @param[in] IsDirectoryObject
1245  * Set this to TRUE if the newly created object is a directory
1246  * object, otherwise set this to FALSE.
1247  *
1248  * @param[in] AutoInheritFlags
1249  * Automatic inheritance flags that influence how access control
1250  * entries within ACLs from security descriptors are inherited.
1251  *
1252  * @param[in] SubjectContext
1253  * Security subject context of the new object.
1254  *
1255  * @param[in] GenericMapping
1256  * Generic mapping of access mask rights.
1257  *
1258  * @param[in] PoolType
1259  * This parameter is unused.
1260  *
1261  * @return
1262  * Returns STATUS_SUCCESS if the operations have been completed
1263  * successfully and that the security descriptor has been
1264  * assigned to the new object. STATUS_NO_TOKEN is returned
1265  * if the caller hasn't supplied a valid argument to a security
1266  * subject context. STATUS_INVALID_OWNER is returned if the caller
1267  * hasn't supplied a parent descriptor that belongs to the main
1268  * user (owner). STATUS_INVALID_PRIMARY_GROUP is returned
1269  * by the same reason as with the previous NTSTATUS code.
1270  * The two NTSTATUS codes are returned if the calling thread
1271  * stated that the owner and/or group is defaulted to the
1272  * parent descriptor (SEF_DEFAULT_OWNER_FROM_PARENT and/or
1273  * SEF_DEFAULT_GROUP_FROM_PARENT respectively).
1274  * STATUS_INSUFFICIENT_RESOURCES is returned if memory pool allocation
1275  * for the descriptor buffer has failed. A failure NTSTATUS is returned
1276  * otherwise.
1277  */
1278 _IRQL_requires_max_(PASSIVE_LEVEL)
1279 NTSTATUS
1280 NTAPI
1281 SeAssignSecurityEx(
1282     _In_opt_ PSECURITY_DESCRIPTOR _ParentDescriptor,
1283     _In_opt_ PSECURITY_DESCRIPTOR _ExplicitDescriptor,
1284     _Out_ PSECURITY_DESCRIPTOR *NewDescriptor,
1285     _In_opt_ GUID *ObjectType,
1286     _In_ BOOLEAN IsDirectoryObject,
1287     _In_ ULONG AutoInheritFlags,
1288     _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
1289     _In_ PGENERIC_MAPPING GenericMapping,
1290     _In_ POOL_TYPE PoolType)
1291 {
1292     PISECURITY_DESCRIPTOR ParentDescriptor = _ParentDescriptor;
1293     PISECURITY_DESCRIPTOR ExplicitDescriptor = _ExplicitDescriptor;
1294     PISECURITY_DESCRIPTOR_RELATIVE Descriptor;
1295     PTOKEN Token;
1296     ULONG OwnerLength;
1297     ULONG GroupLength;
1298     ULONG DaclLength;
1299     ULONG SaclLength;
1300     ULONG Length;
1301     SECURITY_DESCRIPTOR_CONTROL Control = 0;
1302     ULONG Current;
1303     PSID Owner = NULL;
1304     PSID Group = NULL;
1305     PACL ExplicitAcl;
1306     BOOLEAN ExplicitPresent;
1307     BOOLEAN ExplicitDefaulted;
1308     PACL ParentAcl;
1309     PACL Dacl = NULL;
1310     PACL Sacl = NULL;
1311     BOOLEAN DaclIsInherited;
1312     BOOLEAN SaclIsInherited;
1313     BOOLEAN DaclPresent;
1314     BOOLEAN SaclPresent;
1315     NTSTATUS Status;
1316 
1317     DBG_UNREFERENCED_PARAMETER(ObjectType);
1318     DBG_UNREFERENCED_PARAMETER(AutoInheritFlags);
1319     UNREFERENCED_PARAMETER(PoolType);
1320 
1321     PAGED_CODE();
1322 
1323     *NewDescriptor = NULL;
1324 
1325     if (!ARGUMENT_PRESENT(SubjectContext))
1326     {
1327         return STATUS_NO_TOKEN;
1328     }
1329 
1330     /* Lock subject context */
1331     SeLockSubjectContext(SubjectContext);
1332 
1333     if (SubjectContext->ClientToken != NULL)
1334     {
1335         Token = SubjectContext->ClientToken;
1336     }
1337     else
1338     {
1339         Token = SubjectContext->PrimaryToken;
1340     }
1341 
1342     /* Inherit the Owner SID */
1343     if (ExplicitDescriptor != NULL)
1344     {
1345         DPRINT("Use explicit owner sid!\n");
1346         Owner = SepGetOwnerFromDescriptor(ExplicitDescriptor);
1347     }
1348     if (!Owner)
1349     {
1350         if (AutoInheritFlags & SEF_DEFAULT_OWNER_FROM_PARENT)
1351         {
1352             DPRINT("Use parent owner sid!\n");
1353             if (!ARGUMENT_PRESENT(ParentDescriptor))
1354             {
1355                 SeUnlockSubjectContext(SubjectContext);
1356                 return STATUS_INVALID_OWNER;
1357             }
1358 
1359             Owner = SepGetOwnerFromDescriptor(ParentDescriptor);
1360             if (!Owner)
1361             {
1362                 SeUnlockSubjectContext(SubjectContext);
1363                 return STATUS_INVALID_OWNER;
1364             }
1365         }
1366         else
1367         {
1368             DPRINT("Use token owner sid!\n");
1369             Owner = Token->UserAndGroups[Token->DefaultOwnerIndex].Sid;
1370         }
1371     }
1372     OwnerLength = RtlLengthSid(Owner);
1373     ASSERT(OwnerLength % sizeof(ULONG) == 0);
1374 
1375     /* Inherit the Group SID */
1376     if (ExplicitDescriptor != NULL)
1377     {
1378         Group = SepGetGroupFromDescriptor(ExplicitDescriptor);
1379     }
1380     if (!Group)
1381     {
1382         if (AutoInheritFlags & SEF_DEFAULT_GROUP_FROM_PARENT)
1383         {
1384             DPRINT("Use parent group sid!\n");
1385             if (!ARGUMENT_PRESENT(ParentDescriptor))
1386             {
1387                 SeUnlockSubjectContext(SubjectContext);
1388                 return STATUS_INVALID_PRIMARY_GROUP;
1389             }
1390 
1391             Group = SepGetGroupFromDescriptor(ParentDescriptor);
1392             if (!Group)
1393             {
1394                 SeUnlockSubjectContext(SubjectContext);
1395                 return STATUS_INVALID_PRIMARY_GROUP;
1396             }
1397         }
1398         else
1399         {
1400             DPRINT("Use token group sid!\n");
1401             Group = Token->PrimaryGroup;
1402         }
1403     }
1404     if (!Group)
1405     {
1406         SeUnlockSubjectContext(SubjectContext);
1407         return STATUS_INVALID_PRIMARY_GROUP;
1408     }
1409     GroupLength = RtlLengthSid(Group);
1410     ASSERT(GroupLength % sizeof(ULONG) == 0);
1411 
1412     /* Inherit the DACL */
1413     DaclLength = 0;
1414     ExplicitAcl = NULL;
1415     ExplicitPresent = FALSE;
1416     ExplicitDefaulted = FALSE;
1417     if (ExplicitDescriptor != NULL &&
1418         (ExplicitDescriptor->Control & SE_DACL_PRESENT))
1419     {
1420         ExplicitAcl = SepGetDaclFromDescriptor(ExplicitDescriptor);
1421         ExplicitPresent = TRUE;
1422         if (ExplicitDescriptor->Control & SE_DACL_DEFAULTED)
1423             ExplicitDefaulted = TRUE;
1424     }
1425     ParentAcl = NULL;
1426     if (ParentDescriptor != NULL &&
1427         (ParentDescriptor->Control & SE_DACL_PRESENT))
1428     {
1429         ParentAcl = SepGetDaclFromDescriptor(ParentDescriptor);
1430     }
1431     Dacl = SepSelectAcl(ExplicitAcl,
1432                         ExplicitPresent,
1433                         ExplicitDefaulted,
1434                         ParentAcl,
1435                         Token->DefaultDacl,
1436                         &DaclLength,
1437                         Owner,
1438                         Group,
1439                         &DaclPresent,
1440                         &DaclIsInherited,
1441                         IsDirectoryObject,
1442                         GenericMapping);
1443     if (DaclPresent)
1444         Control |= SE_DACL_PRESENT;
1445     ASSERT(DaclLength % sizeof(ULONG) == 0);
1446 
1447     /* Inherit the SACL */
1448     SaclLength = 0;
1449     ExplicitAcl = NULL;
1450     ExplicitPresent = FALSE;
1451     ExplicitDefaulted = FALSE;
1452     if (ExplicitDescriptor != NULL &&
1453         (ExplicitDescriptor->Control & SE_SACL_PRESENT))
1454     {
1455         ExplicitAcl = SepGetSaclFromDescriptor(ExplicitDescriptor);
1456         ExplicitPresent = TRUE;
1457         if (ExplicitDescriptor->Control & SE_SACL_DEFAULTED)
1458             ExplicitDefaulted = TRUE;
1459     }
1460     ParentAcl = NULL;
1461     if (ParentDescriptor != NULL &&
1462         (ParentDescriptor->Control & SE_SACL_PRESENT))
1463     {
1464         ParentAcl = SepGetSaclFromDescriptor(ParentDescriptor);
1465     }
1466     Sacl = SepSelectAcl(ExplicitAcl,
1467                         ExplicitPresent,
1468                         ExplicitDefaulted,
1469                         ParentAcl,
1470                         NULL,
1471                         &SaclLength,
1472                         Owner,
1473                         Group,
1474                         &SaclPresent,
1475                         &SaclIsInherited,
1476                         IsDirectoryObject,
1477                         GenericMapping);
1478     if (SaclPresent)
1479         Control |= SE_SACL_PRESENT;
1480     ASSERT(SaclLength % sizeof(ULONG) == 0);
1481 
1482     /* Allocate and initialize the new security descriptor */
1483     Length = sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
1484         OwnerLength + GroupLength + DaclLength + SaclLength;
1485 
1486     DPRINT("L: sizeof(SECURITY_DESCRIPTOR) %u OwnerLength %lu GroupLength %lu DaclLength %lu SaclLength %lu\n",
1487            sizeof(SECURITY_DESCRIPTOR),
1488            OwnerLength,
1489            GroupLength,
1490            DaclLength,
1491            SaclLength);
1492 
1493     Descriptor = ExAllocatePoolWithTag(PagedPool, Length, TAG_SD);
1494     if (Descriptor == NULL)
1495     {
1496         DPRINT1("ExAlloctePool() failed\n");
1497         SeUnlockSubjectContext(SubjectContext);
1498         return STATUS_INSUFFICIENT_RESOURCES;
1499     }
1500 
1501     RtlZeroMemory(Descriptor, Length);
1502     RtlCreateSecurityDescriptor(Descriptor, SECURITY_DESCRIPTOR_REVISION);
1503 
1504     Descriptor->Control = Control | SE_SELF_RELATIVE;
1505 
1506     Current = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
1507 
1508     if (SaclLength != 0)
1509     {
1510         Status = SepPropagateAcl((PACL)((PUCHAR)Descriptor + Current),
1511                                  &SaclLength,
1512                                  Sacl,
1513                                  Owner,
1514                                  Group,
1515                                  SaclIsInherited,
1516                                  IsDirectoryObject,
1517                                  GenericMapping);
1518         ASSERT(Status == STATUS_SUCCESS);
1519         Descriptor->Sacl = Current;
1520         Current += SaclLength;
1521     }
1522 
1523     if (DaclLength != 0)
1524     {
1525         Status = SepPropagateAcl((PACL)((PUCHAR)Descriptor + Current),
1526                                  &DaclLength,
1527                                  Dacl,
1528                                  Owner,
1529                                  Group,
1530                                  DaclIsInherited,
1531                                  IsDirectoryObject,
1532                                  GenericMapping);
1533         ASSERT(Status == STATUS_SUCCESS);
1534         Descriptor->Dacl = Current;
1535         Current += DaclLength;
1536     }
1537 
1538     if (OwnerLength != 0)
1539     {
1540         RtlCopyMemory((PUCHAR)Descriptor + Current, Owner, OwnerLength);
1541         Descriptor->Owner = Current;
1542         Current += OwnerLength;
1543         DPRINT("Owner of %p at %x\n", Descriptor, Descriptor->Owner);
1544     }
1545     else
1546     {
1547         DPRINT("Owner of %p is zero length\n", Descriptor);
1548     }
1549 
1550     if (GroupLength != 0)
1551     {
1552         RtlCopyMemory((PUCHAR)Descriptor + Current, Group, GroupLength);
1553         Descriptor->Group = Current;
1554     }
1555 
1556     /* Unlock subject context */
1557     SeUnlockSubjectContext(SubjectContext);
1558 
1559     *NewDescriptor = Descriptor;
1560 
1561     DPRINT("Descriptor %p\n", Descriptor);
1562     ASSERT(RtlLengthSecurityDescriptor(Descriptor));
1563 
1564     return STATUS_SUCCESS;
1565 }
1566 
1567 /**
1568  * @brief
1569  * Assigns a security descriptor for a new object.
1570  *
1571  * @param[in] ParentDescriptor
1572  * A security descriptor of the parent object that is being
1573  * created.
1574  *
1575  * @param[in] ExplicitDescriptor
1576  * An explicit security descriptor that is applied to a new
1577  * object.
1578  *
1579  * @param[out] NewDescriptor
1580  * The new allocated security descriptor.
1581  *
1582  * @param[in] IsDirectoryObject
1583  * Set this to TRUE if the newly created object is a directory
1584  * object, otherwise set this to FALSE.
1585  *
1586  * @param[in] SubjectContext
1587  * Security subject context of the new object.
1588  *
1589  * @param[in] GenericMapping
1590  * Generic mapping of access mask rights.
1591  *
1592  * @param[in] PoolType
1593  * This parameter is unused.
1594  *
1595  * @return
1596  * See SeAssignSecurityEx.
1597  */
1598 _IRQL_requires_max_(PASSIVE_LEVEL)
1599 NTSTATUS
1600 NTAPI
1601 SeAssignSecurity(
1602     _In_opt_ PSECURITY_DESCRIPTOR ParentDescriptor,
1603     _In_opt_ PSECURITY_DESCRIPTOR ExplicitDescriptor,
1604     _Out_ PSECURITY_DESCRIPTOR *NewDescriptor,
1605     _In_ BOOLEAN IsDirectoryObject,
1606     _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
1607     _In_ PGENERIC_MAPPING GenericMapping,
1608     _In_ POOL_TYPE PoolType)
1609 {
1610     PAGED_CODE();
1611 
1612     return SeAssignSecurityEx(ParentDescriptor,
1613                               ExplicitDescriptor,
1614                               NewDescriptor,
1615                               NULL,
1616                               IsDirectoryObject,
1617                               0,
1618                               SubjectContext,
1619                               GenericMapping,
1620                               PoolType);
1621 }
1622 
1623 /**
1624  * @brief
1625  * Computes the quota size of a security descriptor.
1626  *
1627  * @param[in] SecurityDescriptor
1628  * A security descriptor.
1629  *
1630  * @param[out] QuotaInfoSize
1631  * The returned quota size of the given security descriptor to
1632  * the caller. The function may return 0 to this parameter if
1633  * the descriptor doesn't have a group or a discretionary
1634  * access control list (DACL) even.
1635  *
1636  * @return
1637  * Returns STATUS_SUCCESS if the quota size of a security
1638  * descriptor has been computed successfully. STATUS_UNKNOWN_REVISION
1639  * is returned if the security descriptor has an invalid revision.
1640  */
1641 _IRQL_requires_max_(PASSIVE_LEVEL)
1642 NTSTATUS
1643 NTAPI
1644 SeComputeQuotaInformationSize(
1645     _In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
1646     _Out_ PULONG QuotaInfoSize)
1647 {
1648     PSID Group;
1649     PACL Dacl;
1650 
1651     PAGED_CODE();
1652 
1653     *QuotaInfoSize = 0;
1654 
1655     /* Validate security descriptor revision */
1656     if (((PISECURITY_DESCRIPTOR)SecurityDescriptor)->Revision != SECURITY_DESCRIPTOR_REVISION1)
1657     {
1658         return STATUS_UNKNOWN_REVISION;
1659     }
1660 
1661     /* Get group and DACL, if any */
1662     Group = SepGetGroupFromDescriptor(SecurityDescriptor);
1663     Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
1664 
1665     /* Return SID length if any */
1666     if (Group != NULL)
1667     {
1668         *QuotaInfoSize = ALIGN_UP_BY(RtlLengthSid(Group), sizeof(ULONG));
1669     }
1670 
1671     /* Return DACL if any */
1672     if (Dacl != NULL)
1673     {
1674         *QuotaInfoSize += ALIGN_UP_BY(Dacl->AclSize, sizeof(ULONG));
1675     }
1676 
1677     return STATUS_SUCCESS;
1678 }
1679 
1680 /* EOF */
1681