xref: /reactos/sdk/lib/rtl/sd.c (revision 1734f297)
1 /*
2  * COPYRIGHT:         See COPYING in the top level directory
3  * PROJECT:           ReactOS system libraries
4  * PURPOSE:           Security descriptor functions
5  * FILE:              lib/rtl/sd.c
6  * PROGRAMER:         David Welch <welch@cwcom.net>
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include <rtl.h>
12 #include "../../ntoskrnl/include/internal/se.h"
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* PRIVATE FUNCTIONS **********************************************************/
17 
18 BOOLEAN
19 NTAPI
20 RtlpValidateSDOffsetAndSize(IN ULONG Offset,
21                             IN ULONG Length,
22                             IN ULONG MinLength,
23                             OUT PULONG MaxLength)
24 {
25     /* Assume failure */
26     *MaxLength = 0;
27 
28     /* Reject out of bounds lengths */
29     if (Offset < sizeof(SECURITY_DESCRIPTOR_RELATIVE)) return FALSE;
30     if (Offset >= Length) return FALSE;
31 
32     /* Reject insufficient lengths */
33     if ((Length - Offset) < MinLength) return FALSE;
34 
35     /* Reject unaligned offsets */
36     if (ALIGN_DOWN(Offset, ULONG) != Offset) return FALSE;
37 
38     /* Return length that is safe to read */
39     *MaxLength = Length - Offset;
40     return TRUE;
41 }
42 
43 VOID
44 NTAPI
45 RtlpQuerySecurityDescriptor(IN PISECURITY_DESCRIPTOR SecurityDescriptor,
46                             OUT PSID *Owner,
47                             OUT PULONG OwnerSize,
48                             OUT PSID *PrimaryGroup,
49                             OUT PULONG PrimaryGroupSize,
50                             OUT PACL *Dacl,
51                             OUT PULONG DaclSize,
52                             OUT PACL *Sacl,
53                             OUT PULONG SaclSize)
54 {
55     PAGED_CODE_RTL();
56 
57     /* Get the owner */
58     *Owner = SepGetOwnerFromDescriptor(SecurityDescriptor);
59     if (*Owner)
60     {
61         /* There's an owner, so align the size */
62         *OwnerSize = ROUND_UP(RtlLengthSid(*Owner), sizeof(ULONG));
63     }
64     else
65     {
66         /* No owner, no size */
67         *OwnerSize = 0;
68     }
69 
70     /* Get the group */
71     *PrimaryGroup = SepGetGroupFromDescriptor(SecurityDescriptor);
72     if (*PrimaryGroup)
73     {
74         /* There's a group, so align the size */
75         *PrimaryGroupSize = ROUND_UP(RtlLengthSid(*PrimaryGroup), sizeof(ULONG));
76     }
77     else
78     {
79         /* No group, no size */
80         *PrimaryGroupSize = 0;
81     }
82 
83     /* Get the DACL */
84     *Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
85     if (*Dacl)
86     {
87         /* There's a DACL, align the size */
88         *DaclSize = ROUND_UP((*Dacl)->AclSize, sizeof(ULONG));
89     }
90     else
91     {
92         /* No DACL, no size */
93         *DaclSize = 0;
94     }
95 
96     /* Get the SACL */
97     *Sacl = SepGetSaclFromDescriptor(SecurityDescriptor);
98     if (*Sacl)
99     {
100         /* There's a SACL, align the size */
101         *SaclSize = ROUND_UP((*Sacl)->AclSize, sizeof(ULONG));
102     }
103     else
104     {
105         /* No SACL, no size */
106         *SaclSize = 0;
107     }
108 }
109 
110 /* PUBLIC FUNCTIONS ***********************************************************/
111 
112 /*
113  * @implemented
114  */
115 NTSTATUS
116 NTAPI
117 RtlCreateSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
118                             IN ULONG Revision)
119 {
120     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
121     PAGED_CODE_RTL();
122 
123     /* Fail on invalid revisions */
124     if (Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
125 
126     /* Setup an empty SD */
127     RtlZeroMemory(Sd, sizeof(*Sd));
128     Sd->Revision = SECURITY_DESCRIPTOR_REVISION;
129 
130     /* All good */
131     return STATUS_SUCCESS;
132 }
133 
134 /*
135  * @implemented
136  */
137 NTSTATUS
138 NTAPI
139 RtlCreateSecurityDescriptorRelative(IN PISECURITY_DESCRIPTOR_RELATIVE SecurityDescriptor,
140                                     IN ULONG Revision)
141 {
142     PAGED_CODE_RTL();
143 
144     /* Fail on invalid revisions */
145     if (Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
146 
147     /* Setup an empty SD */
148     RtlZeroMemory(SecurityDescriptor, sizeof(*SecurityDescriptor));
149     SecurityDescriptor->Revision = SECURITY_DESCRIPTOR_REVISION;
150     SecurityDescriptor->Control = SE_SELF_RELATIVE;
151 
152     /* All good */
153     return STATUS_SUCCESS;
154 }
155 
156 /*
157  * @implemented
158  */
159 ULONG
160 NTAPI
161 RtlLengthSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor)
162 {
163     PISECURITY_DESCRIPTOR Sd;
164     PSID Owner, Group;
165     PACL Sacl, Dacl;
166     ULONG Length;
167     PAGED_CODE_RTL();
168 
169     /* Start with the initial length of the SD itself */
170     Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
171     if (Sd->Control & SE_SELF_RELATIVE)
172     {
173         Length = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
174     }
175     else
176     {
177         Length = sizeof(SECURITY_DESCRIPTOR);
178     }
179 
180     /* Add the length of the individual subcomponents */
181     Owner = SepGetOwnerFromDescriptor(Sd);
182     if (Owner) Length += ROUND_UP(RtlLengthSid(Owner), sizeof(ULONG));
183     Group = SepGetGroupFromDescriptor(Sd);
184     if (Group) Length += ROUND_UP(RtlLengthSid(Group), sizeof(ULONG));
185     Dacl = SepGetDaclFromDescriptor(Sd);
186     if (Dacl) Length += ROUND_UP(Dacl->AclSize, sizeof(ULONG));
187     Sacl = SepGetSaclFromDescriptor(Sd);
188     if (Sacl) Length += ROUND_UP(Sacl->AclSize, sizeof(ULONG));
189 
190     /* Return the final length */
191     return Length;
192 }
193 
194 /*
195  * @implemented
196  */
197 NTSTATUS
198 NTAPI
199 RtlGetDaclSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
200                              OUT PBOOLEAN DaclPresent,
201                              OUT PACL* Dacl,
202                              OUT PBOOLEAN DaclDefaulted)
203 {
204     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
205     PAGED_CODE_RTL();
206 
207     /* Fail on invalid revisions */
208     if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
209 
210     /* Is there a DACL? */
211     *DaclPresent = (Sd->Control & SE_DACL_PRESENT) == SE_DACL_PRESENT;
212     if (*DaclPresent)
213     {
214         /* Yes, return it, and check if defaulted */
215         *Dacl = SepGetDaclFromDescriptor(Sd);
216         *DaclDefaulted = (Sd->Control & SE_DACL_DEFAULTED) == SE_DACL_DEFAULTED;
217     }
218 
219     /* All good */
220     return STATUS_SUCCESS;
221 }
222 
223 /*
224  * @implemented
225  */
226 NTSTATUS
227 NTAPI
228 RtlGetSaclSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
229                              OUT PBOOLEAN SaclPresent,
230                              OUT PACL* Sacl,
231                              OUT PBOOLEAN SaclDefaulted)
232 {
233     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
234     PAGED_CODE_RTL();
235 
236     /* Fail on invalid revisions */
237     if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
238 
239     /* Is there a SACL? */
240     *SaclPresent = (Sd->Control & SE_SACL_PRESENT) == SE_SACL_PRESENT;
241     if (*SaclPresent)
242     {
243         /* Yes, return it, and check if defaulted */
244         *Sacl = SepGetSaclFromDescriptor(Sd);
245         *SaclDefaulted = (Sd->Control & SE_SACL_DEFAULTED) == SE_SACL_DEFAULTED;
246     }
247 
248     /* All good */
249     return STATUS_SUCCESS;
250 }
251 
252 /*
253  * @implemented
254  */
255 NTSTATUS
256 NTAPI
257 RtlGetOwnerSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
258                               OUT PSID* Owner,
259                               OUT PBOOLEAN OwnerDefaulted)
260 {
261     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
262     PAGED_CODE_RTL();
263 
264     /* Fail on invalid revision */
265     if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
266 
267     /* Get the owner and if defaulted */
268     *Owner = SepGetOwnerFromDescriptor(Sd);
269     *OwnerDefaulted = (Sd->Control & SE_OWNER_DEFAULTED) == SE_OWNER_DEFAULTED;
270 
271     /* All good */
272     return STATUS_SUCCESS;
273 }
274 
275 /*
276  * @implemented
277  */
278 NTSTATUS
279 NTAPI
280 RtlGetGroupSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
281                               OUT PSID* Group,
282                               OUT PBOOLEAN GroupDefaulted)
283 {
284     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
285     PAGED_CODE_RTL();
286 
287     /* Fail on invalid revision */
288     if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
289 
290     /* Get the group and if defaulted */
291     *Group = SepGetGroupFromDescriptor(Sd);
292     *GroupDefaulted = (Sd->Control & SE_GROUP_DEFAULTED) == SE_GROUP_DEFAULTED;
293 
294     /* All good */
295     return STATUS_SUCCESS;
296 }
297 
298 /*
299  * @implemented
300  */
301 NTSTATUS
302 NTAPI
303 RtlSetDaclSecurityDescriptor(IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
304                              IN BOOLEAN DaclPresent,
305                              IN PACL Dacl,
306                              IN BOOLEAN DaclDefaulted)
307 {
308     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
309     PAGED_CODE_RTL();
310 
311     /* Fail on invalid revision */
312     if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
313 
314     /* Fail on relative descriptors */
315     if (Sd->Control & SE_SELF_RELATIVE) return STATUS_INVALID_SECURITY_DESCR;
316 
317     /* Is there a DACL? */
318     if (!DaclPresent)
319     {
320         /* Caller is destroying the DACL, unset the flag and we're done */
321         Sd->Control = Sd->Control & ~SE_DACL_PRESENT;
322         return STATUS_SUCCESS;
323     }
324 
325     /* Caller is setting a new DACL, set the pointer and flag */
326     Sd->Dacl = Dacl;
327     Sd->Control |= SE_DACL_PRESENT;
328 
329     /* Set if defaulted */
330     Sd->Control &= ~SE_DACL_DEFAULTED;
331     if (DaclDefaulted) Sd->Control |= SE_DACL_DEFAULTED;
332 
333     /* All good */
334     return STATUS_SUCCESS;
335 }
336 
337 /*
338  * @implemented
339  */
340 NTSTATUS
341 NTAPI
342 RtlSetSaclSecurityDescriptor(IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
343                              IN BOOLEAN SaclPresent,
344                              IN PACL Sacl,
345                              IN BOOLEAN SaclDefaulted)
346 {
347     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
348     PAGED_CODE_RTL();
349 
350     /* Fail on invalid revision */
351     if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
352 
353     /* Fail on relative descriptors */
354     if (Sd->Control & SE_SELF_RELATIVE) return STATUS_INVALID_SECURITY_DESCR;
355 
356     /* Is there a SACL? */
357     if (!SaclPresent)
358     {
359         /* Caller is clearing the SACL, unset the flag and we're done */
360         Sd->Control = Sd->Control & ~SE_SACL_PRESENT;
361         return STATUS_SUCCESS;
362     }
363 
364     /* Caller is setting a new SACL, set it and the flag */
365     Sd->Sacl = Sacl;
366     Sd->Control |= SE_SACL_PRESENT;
367 
368     /* Set if defaulted */
369     Sd->Control &= ~SE_SACL_DEFAULTED;
370     if (SaclDefaulted) Sd->Control |= SE_SACL_DEFAULTED;
371 
372     /* All good */
373     return STATUS_SUCCESS;
374 }
375 
376 /*
377  * @implemented
378  */
379 NTSTATUS
380 NTAPI
381 RtlSetOwnerSecurityDescriptor(IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
382                               IN PSID Owner,
383                               IN BOOLEAN OwnerDefaulted)
384 {
385     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
386     PAGED_CODE_RTL();
387 
388     /* Fail on invalid revision */
389     if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
390 
391     /* Fail on relative descriptors */
392     if (Sd->Control & SE_SELF_RELATIVE) return STATUS_INVALID_SECURITY_DESCR;
393 
394     /* Owner being set or cleared */
395     Sd->Owner = Owner;
396 
397     /* Set if defaulted */
398     Sd->Control &= ~SE_OWNER_DEFAULTED;
399     if (OwnerDefaulted) Sd->Control |= SE_OWNER_DEFAULTED;
400 
401     /* All good */
402     return STATUS_SUCCESS;
403 }
404 
405 /*
406  * @implemented
407  */
408 NTSTATUS
409 NTAPI
410 RtlSetGroupSecurityDescriptor(IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
411                               IN PSID Group,
412                               IN BOOLEAN GroupDefaulted)
413 {
414     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
415     PAGED_CODE_RTL();
416 
417     /* Fail on invalid revision */
418     if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
419 
420     /* Fail on relative descriptors */
421     if (Sd->Control & SE_SELF_RELATIVE) return STATUS_INVALID_SECURITY_DESCR;
422 
423     /* Group being set or cleared */
424     Sd->Group = Group;
425 
426     /* Set if defaulted */
427     Sd->Control &= ~SE_GROUP_DEFAULTED;
428     if (GroupDefaulted) Sd->Control |= SE_GROUP_DEFAULTED;
429 
430     /* All good */
431     return STATUS_SUCCESS;
432 }
433 
434 /*
435  * @implemented
436  */
437 NTSTATUS
438 NTAPI
439 RtlGetControlSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
440                                 OUT PSECURITY_DESCRIPTOR_CONTROL Control,
441                                 OUT PULONG Revision)
442 {
443     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
444     PAGED_CODE_RTL();
445 
446     /* Read current revision, even if invalid */
447     *Revision = Sd->Revision;
448 
449     /* Fail on invalid revision */
450     if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
451 
452     /* Read current control */
453     *Control = Sd->Control;
454 
455     /* All good */
456     return STATUS_SUCCESS;
457 }
458 
459 /*
460  * @implemented
461  */
462 NTSTATUS
463 NTAPI
464 RtlSetControlSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
465                                 IN SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
466                                 IN SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet)
467 {
468     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
469 
470     /* Check for invalid bits */
471     if ((ControlBitsOfInterest & ~(SE_DACL_UNTRUSTED |
472                                    SE_SERVER_SECURITY |
473                                    SE_DACL_AUTO_INHERIT_REQ |
474                                    SE_SACL_AUTO_INHERIT_REQ |
475                                    SE_DACL_AUTO_INHERITED |
476                                    SE_SACL_AUTO_INHERITED |
477                                    SE_DACL_PROTECTED |
478                                    SE_SACL_PROTECTED)) ||
479         (ControlBitsToSet & ~ControlBitsOfInterest))
480     {
481         /* Fail */
482         return STATUS_INVALID_PARAMETER;
483     }
484 
485     /* Zero the 'bits of interest' */
486     Sd->Control &= ~ControlBitsOfInterest;
487 
488     /* Set the 'bits to set' */
489     Sd->Control |= (ControlBitsToSet & ControlBitsOfInterest);
490 
491     /* All good */
492     return STATUS_SUCCESS;
493 }
494 
495 /*
496  * @implemented
497  */
498 BOOLEAN
499 NTAPI
500 RtlGetSecurityDescriptorRMControl(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
501                                   OUT PUCHAR RMControl)
502 {
503     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
504     PAGED_CODE_RTL();
505 
506     /* Check if there's no valid RM control */
507     if (!(Sd->Control & SE_RM_CONTROL_VALID))
508     {
509         /* Fail and return nothing */
510         *RMControl = 0;
511         return FALSE;
512     }
513 
514     /* Return it, ironically the member is "should be zero" */
515     *RMControl = Sd->Sbz1;
516     return TRUE;
517 }
518 
519 /*
520  * @implemented
521  */
522 VOID
523 NTAPI
524 RtlSetSecurityDescriptorRMControl(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
525                                   IN PUCHAR RMControl)
526 {
527     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
528     PAGED_CODE_RTL();
529 
530     /* RM Control is being cleared or set */
531     if (!RMControl)
532     {
533         /* Clear it */
534         Sd->Control &= ~SE_RM_CONTROL_VALID;
535         Sd->Sbz1 = 0;
536     }
537     else
538     {
539         /* Set it */
540         Sd->Control |= SE_RM_CONTROL_VALID;
541         Sd->Sbz1 = *RMControl;
542     }
543 }
544 
545 /*
546  * @implemented
547  */
548 NTSTATUS
549 NTAPI
550 RtlSetAttributesSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
551                                    IN SECURITY_DESCRIPTOR_CONTROL Control,
552                                    OUT PULONG Revision)
553 {
554     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
555     PAGED_CODE_RTL();
556 
557     /* Always return revision, even if invalid */
558     *Revision = Sd->Revision;
559 
560     /* Fail on invalid revision */
561     if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
562 
563     /* Mask out flags which are not attributes */
564     Control &= SE_DACL_UNTRUSTED |
565                SE_SERVER_SECURITY |
566                SE_DACL_AUTO_INHERIT_REQ |
567                SE_SACL_AUTO_INHERIT_REQ |
568                SE_DACL_AUTO_INHERITED |
569                SE_SACL_AUTO_INHERITED |
570                SE_DACL_PROTECTED |
571                SE_SACL_PROTECTED;
572 
573     /* Call the newer API */
574     return RtlSetControlSecurityDescriptor(SecurityDescriptor, Control, Control);
575 }
576 
577 /*
578  * @implemented
579  */
580 NTSTATUS
581 NTAPI
582 RtlCopySecurityDescriptor(IN PSECURITY_DESCRIPTOR pSourceSecurityDescriptor,
583                           OUT PSECURITY_DESCRIPTOR *pDestinationSecurityDescriptor)
584 {
585     PSID Owner, Group;
586     PACL Dacl, Sacl;
587     DWORD OwnerLength, GroupLength, DaclLength, SaclLength, TotalLength;
588     PISECURITY_DESCRIPTOR Sd = pSourceSecurityDescriptor;
589 
590     /* Get all the components */
591     RtlpQuerySecurityDescriptor(Sd,
592                                 &Owner,
593                                 &OwnerLength,
594                                 &Group,
595                                 &GroupLength,
596                                 &Dacl,
597                                 &DaclLength,
598                                 &Sacl,
599                                 &SaclLength);
600 
601     /* Add up their lengths */
602     TotalLength = sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
603                   OwnerLength +
604                   GroupLength +
605                   DaclLength +
606                   SaclLength;
607 
608     /* Allocate a copy */
609     *pDestinationSecurityDescriptor = RtlAllocateHeap(RtlGetProcessHeap(),
610                                                       0,
611                                                           TotalLength);
612     if (*pDestinationSecurityDescriptor == NULL) return STATUS_NO_MEMORY;
613 
614     /* Copy the old in the new */
615     RtlCopyMemory(*pDestinationSecurityDescriptor, Sd, TotalLength);
616 
617     /* All good */
618     return STATUS_SUCCESS;
619 }
620 
621 /*
622  * @implemented
623  */
624 NTSTATUS
625 NTAPI
626 RtlAbsoluteToSelfRelativeSD(IN PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor,
627                             IN OUT PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor,
628                             IN PULONG BufferLength)
629 {
630    PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)AbsoluteSecurityDescriptor;
631    PAGED_CODE_RTL();
632 
633    /* Can't already be relative */
634    if (Sd->Control & SE_SELF_RELATIVE) return STATUS_BAD_DESCRIPTOR_FORMAT;
635 
636    /* Call the other API */
637    return RtlMakeSelfRelativeSD(AbsoluteSecurityDescriptor,
638                                 SelfRelativeSecurityDescriptor,
639                                 BufferLength);
640 }
641 
642 /*
643  * @implemented
644  */
645 NTSTATUS
646 NTAPI
647 RtlMakeSelfRelativeSD(IN PSECURITY_DESCRIPTOR AbsoluteSD,
648                       OUT PSECURITY_DESCRIPTOR SelfRelativeSD,
649                       IN OUT PULONG BufferLength)
650 {
651     PSID Owner, Group;
652     PACL Sacl, Dacl;
653     ULONG OwnerLength, GroupLength, SaclLength, DaclLength, TotalLength;
654     ULONG_PTR Current;
655     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)AbsoluteSD;
656     PISECURITY_DESCRIPTOR_RELATIVE RelSd = (PISECURITY_DESCRIPTOR_RELATIVE)SelfRelativeSD;
657     PAGED_CODE_RTL();
658 
659     /* Query all components */
660     RtlpQuerySecurityDescriptor(Sd,
661                                 &Owner,
662                                 &OwnerLength,
663                                 &Group,
664                                 &GroupLength,
665                                 &Dacl,
666                                 &DaclLength,
667                                 &Sacl,
668                                 &SaclLength);
669 
670     /* Calculate final length */
671     TotalLength = sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
672                   OwnerLength +
673                   GroupLength +
674                   SaclLength +
675                   DaclLength;
676 
677     /* Is there enough space? */
678     if (*BufferLength < TotalLength)
679     {
680         /* Nope, return how much is needed */
681         *BufferLength = TotalLength;
682         return STATUS_BUFFER_TOO_SMALL;
683     }
684 
685     /* Start fresh */
686     RtlZeroMemory(RelSd, TotalLength);
687 
688     /* Copy the header fields */
689     RtlCopyMemory(RelSd,
690                   Sd,
691                   FIELD_OFFSET(SECURITY_DESCRIPTOR_RELATIVE, Owner));
692 
693     /* Set the current copy pointer */
694     Current = (ULONG_PTR)(RelSd + 1);
695 
696     /* Is there a SACL? */
697     if (SaclLength)
698     {
699         /* Copy it */
700         RtlCopyMemory((PVOID)Current, Sacl, SaclLength);
701         RelSd->Sacl = (ULONG_PTR)Current - (ULONG_PTR)RelSd;
702         Current += SaclLength;
703     }
704 
705     /* Is there a DACL? */
706     if (DaclLength)
707     {
708         /* Copy it */
709         RtlCopyMemory((PVOID)Current, Dacl, DaclLength);
710         RelSd->Dacl = (ULONG_PTR)Current - (ULONG_PTR)RelSd;
711         Current += DaclLength;
712     }
713 
714     /* Is there an owner? */
715     if (OwnerLength)
716     {
717         /* Copy it */
718         RtlCopyMemory((PVOID)Current, Owner, OwnerLength);
719         RelSd->Owner = (ULONG_PTR)Current - (ULONG_PTR)RelSd;
720         Current += OwnerLength;
721     }
722 
723     /* Is there a group? */
724     if (GroupLength)
725     {
726         /* Copy it */
727         RtlCopyMemory((PVOID)Current, Group, GroupLength);
728         RelSd->Group = (ULONG_PTR)Current - (ULONG_PTR)RelSd;
729     }
730 
731     /* Mark it as relative */
732     RelSd->Control |= SE_SELF_RELATIVE;
733 
734     /* All good */
735     return STATUS_SUCCESS;
736 }
737 
738 /*
739  * @implemented
740  */
741 NTSTATUS
742 NTAPI
743 RtlSelfRelativeToAbsoluteSD(IN PSECURITY_DESCRIPTOR SelfRelativeSD,
744                             OUT PSECURITY_DESCRIPTOR AbsoluteSD,
745                             IN PULONG AbsoluteSDSize,
746                             IN PACL Dacl,
747                             IN PULONG DaclSize,
748                             IN PACL Sacl,
749                             IN PULONG SaclSize,
750                             IN PSID Owner,
751                             IN PULONG OwnerSize,
752                             IN PSID PrimaryGroup,
753                             IN PULONG PrimaryGroupSize)
754 {
755     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)AbsoluteSD;
756     PISECURITY_DESCRIPTOR RelSd = (PISECURITY_DESCRIPTOR)SelfRelativeSD;
757     ULONG OwnerLength, GroupLength, DaclLength, SaclLength;
758     PSID pOwner, pGroup;
759     PACL pDacl, pSacl;
760     PAGED_CODE_RTL();
761 
762     /* Must be relative, otherwiise fail */
763     if (!(RelSd->Control & SE_SELF_RELATIVE)) return STATUS_BAD_DESCRIPTOR_FORMAT;
764 
765     /* Get all the components */
766     RtlpQuerySecurityDescriptor(RelSd,
767                                 &pOwner,
768                                 &OwnerLength,
769                                 &pGroup,
770                                 &GroupLength,
771                                 &pDacl,
772                                 &DaclLength,
773                                 &pSacl,
774                                 &SaclLength);
775 
776     /* Fail if there's not enough space */
777     if (!(Sd) ||
778         (sizeof(SECURITY_DESCRIPTOR) > *AbsoluteSDSize) ||
779         (OwnerLength > *OwnerSize) ||
780         (GroupLength > *PrimaryGroupSize) ||
781         (DaclLength > *DaclSize) ||
782         (SaclLength > *SaclSize))
783     {
784         /* Return how much space is needed for each components */
785         *AbsoluteSDSize = sizeof(SECURITY_DESCRIPTOR);
786         *OwnerSize = OwnerLength;
787         *PrimaryGroupSize = GroupLength;
788         *DaclSize = DaclLength;
789         *SaclSize = SaclLength;
790         return STATUS_BUFFER_TOO_SMALL;
791     }
792 
793     /* Copy the header fields */
794     RtlMoveMemory(Sd, RelSd, sizeof(SECURITY_DESCRIPTOR_RELATIVE));
795 
796     /* Wipe out the pointers and the relative flag */
797     Sd->Owner = NULL;
798     Sd->Group = NULL;
799     Sd->Sacl = NULL;
800     Sd->Dacl = NULL;
801     Sd->Control &= ~SE_SELF_RELATIVE;
802 
803     /* Is there an owner? */
804     if (pOwner)
805     {
806         /* Copy it */
807         RtlMoveMemory(Owner, pOwner, RtlLengthSid(pOwner));
808         Sd->Owner = Owner;
809     }
810 
811     /* Is there a group? */
812     if (pGroup)
813     {
814         /* Copy it */
815         RtlMoveMemory(PrimaryGroup, pGroup, RtlLengthSid(pGroup));
816         Sd->Group = PrimaryGroup;
817     }
818 
819     /* Is there a DACL? */
820     if (pDacl)
821     {
822         /* Copy it */
823         RtlMoveMemory(Dacl, pDacl, pDacl->AclSize);
824         Sd->Dacl = Dacl;
825     }
826 
827     /* Is there a SACL? */
828     if (pSacl)
829     {
830         /* Copy it */
831         RtlMoveMemory(Sacl, pSacl, pSacl->AclSize);
832         Sd->Sacl = Sacl;
833     }
834 
835     /* All good */
836     return STATUS_SUCCESS;
837 }
838 
839 /*
840  * @implemented
841  */
842 NTSTATUS
843 NTAPI
844 RtlSelfRelativeToAbsoluteSD2(IN OUT PSECURITY_DESCRIPTOR SelfRelativeSD,
845                              OUT PULONG BufferSize)
846 {
847     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SelfRelativeSD;
848     PISECURITY_DESCRIPTOR_RELATIVE RelSd = (PISECURITY_DESCRIPTOR_RELATIVE)SelfRelativeSD;
849     PVOID DataStart, DataEnd;
850     LONG MoveDelta;
851     ULONG DataSize, OwnerLength, GroupLength, DaclLength, SaclLength;
852     PSID pOwner, pGroup;
853     PACL pDacl, pSacl;
854     PAGED_CODE_RTL();
855 
856     /* Need input */
857     if (!RelSd) return STATUS_INVALID_PARAMETER_1;
858 
859     /* Need to know how much space we have */
860     if (!BufferSize) return STATUS_INVALID_PARAMETER_2;
861 
862     /* Input must be relative */
863     if (!(RelSd->Control & SE_SELF_RELATIVE)) return STATUS_BAD_DESCRIPTOR_FORMAT;
864 
865     /* Query all the component sizes */
866     RtlpQuerySecurityDescriptor(Sd,
867                                 &pOwner,
868                                 &OwnerLength,
869                                 &pGroup,
870                                 &GroupLength,
871                                 &pDacl,
872                                 &DaclLength,
873                                 &pSacl,
874                                 &SaclLength);
875 
876     /*
877      * Check if there's a difference in structure layout between relatiev and
878      * absolute descriptors. On 32-bit, there won't be, since an offset is the
879      * same size as a pointer (32-bit), but on 64-bit, the offsets remain 32-bit
880      * as they are not SIZE_T, but ULONG, while the pointers now become 64-bit
881      * and thus the structure is different */
882     MoveDelta = sizeof(SECURITY_DESCRIPTOR) - sizeof(SECURITY_DESCRIPTOR_RELATIVE);
883     if (!MoveDelta)
884     {
885         /* So on 32-bit, simply clear the flag... */
886         Sd->Control &= ~SE_SELF_RELATIVE;
887 
888         /* Ensure we're *really* on 32-bit */
889         ASSERT(sizeof(Sd->Owner) == sizeof(RelSd->Owner));
890         ASSERT(sizeof(Sd->Group) == sizeof(RelSd->Group));
891         ASSERT(sizeof(Sd->Sacl) == sizeof(RelSd->Sacl));
892         ASSERT(sizeof(Sd->Dacl) == sizeof(RelSd->Dacl));
893 
894         /* And simply set pointers where there used to be offsets */
895         Sd->Owner = pOwner;
896         Sd->Group = pGroup;
897         Sd->Sacl = pSacl;
898         Sd->Dacl = pDacl;
899         return STATUS_SUCCESS;
900     }
901 
902     /*
903      * Calculate the start and end of the data area, we simply just move the
904      * data by the difference between the size of the relative and absolute
905      * security descriptor structure
906      */
907     DataStart = pOwner;
908     DataEnd = (PVOID)((ULONG_PTR)pOwner + OwnerLength);
909 
910     /* Is there a group? */
911     if (pGroup)
912     {
913         /* Is the group higher than where we started? */
914         if (((ULONG_PTR)pGroup < (ULONG_PTR)DataStart) || !DataStart)
915         {
916             /* Update the start pointer */
917             DataStart = pGroup;
918         }
919 
920         /* Is the group beyond where we ended? */
921         if (((ULONG_PTR)pGroup + GroupLength > (ULONG_PTR)DataEnd) || !DataEnd)
922         {
923             /* Update the end pointer */
924             DataEnd = (PVOID)((ULONG_PTR)pGroup + GroupLength);
925         }
926     }
927 
928     /* Is there a DACL? */
929     if (pDacl)
930     {
931         /* Is the DACL higher than where we started? */
932         if (((ULONG_PTR)pDacl < (ULONG_PTR)DataStart) || !DataStart)
933         {
934             /* Update the start pointer */
935             DataStart = pDacl;
936         }
937 
938         /* Is the DACL beyond where we ended? */
939         if (((ULONG_PTR)pDacl + DaclLength > (ULONG_PTR)DataEnd) || !DataEnd)
940         {
941             /* Update the end pointer */
942             DataEnd = (PVOID)((ULONG_PTR)pDacl + DaclLength);
943         }
944     }
945 
946     /* Is there a SACL? */
947     if (pSacl)
948     {
949         /* Is the SACL higher than where we started? */
950         if (((ULONG_PTR)pSacl < (ULONG_PTR)DataStart) || !DataStart)
951         {
952             /* Update the start pointer */
953             DataStart = pSacl;
954         }
955 
956         /* Is the SACL beyond where we ended? */
957         if (((ULONG_PTR)pSacl + SaclLength > (ULONG_PTR)DataEnd) || !DataEnd)
958         {
959             /* Update the end pointer */
960             DataEnd = (PVOID)((ULONG_PTR)pSacl + SaclLength);
961         }
962     }
963 
964     /* Sanity check */
965     ASSERT((ULONG_PTR)DataEnd >= (ULONG_PTR)DataStart);
966 
967     /* Now compute the difference between relative and absolute */
968     DataSize = (ULONG)((ULONG_PTR)DataEnd - (ULONG_PTR)DataStart);
969 
970     /* Is the new buffer large enough for this difference? */
971     if (*BufferSize < sizeof(SECURITY_DESCRIPTOR) + DataSize)
972     {
973         /* Nope, bail out */
974         *BufferSize = sizeof(SECURITY_DESCRIPTOR) + DataSize;
975         return STATUS_BUFFER_TOO_SMALL;
976     }
977 
978     /* Is there anything actually to copy? */
979     if (DataSize)
980     {
981         /*
982          * There must be at least one SID or ACL in the security descriptor!
983          * Also the data area must be located somewhere after the end of the
984          * SECURITY_DESCRIPTOR_RELATIVE structure
985          */
986         ASSERT(DataStart != NULL);
987         ASSERT((ULONG_PTR)DataStart >= (ULONG_PTR)(RelSd + 1));
988 
989         /* It's time to move the data */
990         RtlMoveMemory((PVOID)(Sd + 1),
991                       DataStart,
992                       DataSize);
993     }
994 
995     /* Is there an owner? */
996     if (pOwner)
997     {
998         /* Set the pointer to the relative position */
999         Sd->Owner = (PSID)((LONG_PTR)pOwner + MoveDelta);
1000     }
1001     else
1002     {
1003         /* No owner, clear the pointer */
1004         Sd->Owner = NULL;
1005     }
1006 
1007     /* Is there a group */
1008     if (pGroup)
1009     {
1010         /* Set the pointer to the relative position */
1011         Sd->Group = (PSID)((LONG_PTR)pGroup + MoveDelta);
1012     }
1013     else
1014     {
1015         /* No group, clear the pointer */
1016         Sd->Group = NULL;
1017     }
1018 
1019     /* Is there a SACL? */
1020     if (pSacl)
1021     {
1022         /* Set the pointer to the relative position */
1023         Sd->Sacl = (PACL)((LONG_PTR)pSacl + MoveDelta);
1024     }
1025     else
1026     {
1027         /* No SACL, clear the pointer */
1028         Sd->Sacl = NULL;
1029     }
1030 
1031     /* Is there a DACL? */
1032     if (pDacl)
1033     {
1034         /* Set the pointer to the relative position */
1035         Sd->Dacl = (PACL)((LONG_PTR)pDacl + MoveDelta);
1036     }
1037     else
1038     {
1039         /* No DACL, clear the pointer */
1040         Sd->Dacl = NULL;
1041     }
1042 
1043     /* Clear the self-relative flag */
1044     Sd->Control &= ~SE_SELF_RELATIVE;
1045 
1046     /* All good */
1047     return STATUS_SUCCESS;
1048 }
1049 
1050 /*
1051  * @implemented
1052  */
1053 BOOLEAN
1054 NTAPI
1055 RtlValidSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor)
1056 {
1057     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
1058     PSID Owner, Group;
1059     PACL Sacl, Dacl;
1060     PAGED_CODE_RTL();
1061 
1062     _SEH2_TRY
1063     {
1064         /* Fail on bad revisions */
1065         if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) _SEH2_YIELD(return FALSE);
1066 
1067         /* Owner SID must be valid if present */
1068         Owner = SepGetOwnerFromDescriptor(Sd);
1069         if ((Owner) && (!RtlValidSid(Owner))) _SEH2_YIELD(return FALSE);
1070 
1071         /* Group SID must be valid if present */
1072         Group = SepGetGroupFromDescriptor(Sd);
1073         if ((Group) && (!RtlValidSid(Group))) _SEH2_YIELD(return FALSE);
1074 
1075         /* DACL must be valid if present */
1076         Dacl = SepGetDaclFromDescriptor(Sd);
1077         if ((Dacl) && (!RtlValidAcl(Dacl))) _SEH2_YIELD(return FALSE);
1078 
1079         /* SACL must be valid if present */
1080         Sacl = SepGetSaclFromDescriptor(Sd);
1081         if ((Sacl) && (!RtlValidAcl(Sacl))) _SEH2_YIELD(return FALSE);
1082     }
1083     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1084     {
1085         /* Access fault, bail out */
1086         _SEH2_YIELD(return FALSE);
1087     }
1088     _SEH2_END;
1089 
1090     /* All good */
1091     return TRUE;
1092 }
1093 
1094 /*
1095  * @implemented
1096  */
1097 BOOLEAN
1098 NTAPI
1099 RtlValidRelativeSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptorInput,
1100                                    IN ULONG SecurityDescriptorLength,
1101                                    IN SECURITY_INFORMATION RequiredInformation)
1102 {
1103     PISECURITY_DESCRIPTOR_RELATIVE Sd = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptorInput;
1104     PSID Owner, Group;
1105     PACL Dacl, Sacl;
1106     ULONG Length;
1107     PAGED_CODE_RTL();
1108 
1109     /* Note that Windows allows no DACL/SACL even if RequiredInfo wants it */
1110 
1111     /* Do we have enough space, is the revision vaild, and is this SD relative? */
1112     if ((SecurityDescriptorLength < sizeof(SECURITY_DESCRIPTOR_RELATIVE)) ||
1113         (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) ||
1114         !(Sd->Control & SE_SELF_RELATIVE))
1115     {
1116         /* Nope, bail out */
1117         return FALSE;
1118     }
1119 
1120     /* Is there an owner? */
1121     if (Sd->Owner)
1122     {
1123         /* Try to access it */
1124         if (!RtlpValidateSDOffsetAndSize(Sd->Owner,
1125                                          SecurityDescriptorLength,
1126                                          sizeof(SID),
1127                                          &Length))
1128         {
1129             /* It's beyond the buffer, fail */
1130             return FALSE;
1131         }
1132 
1133         /* Read the owner, check if it's valid and if the buffer contains it */
1134         Owner = (PSID)((ULONG_PTR)Sd->Owner + (ULONG_PTR)Sd);
1135         if (!RtlValidSid(Owner) || (Length < RtlLengthSid(Owner))) return FALSE;
1136     }
1137     else if (RequiredInformation & OWNER_SECURITY_INFORMATION)
1138     {
1139         /* No owner but the caller expects one, fail */
1140         return FALSE;
1141     }
1142 
1143     /* Is there a group? */
1144     if (Sd->Group)
1145     {
1146         /* Try to access it */
1147         if (!RtlpValidateSDOffsetAndSize(Sd->Group,
1148                                          SecurityDescriptorLength,
1149                                          sizeof(SID),
1150                                          &Length))
1151         {
1152             /* It's beyond the buffer, fail */
1153             return FALSE;
1154         }
1155 
1156         /* Read the group, check if it's valid and if the buffer contains it */
1157         Group = (PSID)((ULONG_PTR)Sd->Group + (ULONG_PTR)Sd);
1158         if (!RtlValidSid(Group) || (Length < RtlLengthSid(Group))) return FALSE;
1159     }
1160     else if (RequiredInformation & GROUP_SECURITY_INFORMATION)
1161     {
1162         /* No group, but the caller expects one, fail */
1163         return FALSE;
1164     }
1165 
1166     /* Is there a DACL? */
1167     if ((Sd->Control & SE_DACL_PRESENT) == SE_DACL_PRESENT)
1168     {
1169         /* Try to access it */
1170         if (!RtlpValidateSDOffsetAndSize(Sd->Dacl,
1171                                          SecurityDescriptorLength,
1172                                          sizeof(ACL),
1173                                          &Length))
1174         {
1175             /* It's beyond the buffer, fail */
1176             return FALSE;
1177         }
1178 
1179         /* Read the DACL, check if it's valid and if the buffer contains it */
1180         Dacl = (PSID)((ULONG_PTR)Sd->Dacl + (ULONG_PTR)Sd);
1181         if (!(RtlValidAcl(Dacl)) || (Length < Dacl->AclSize)) return FALSE;
1182     }
1183 
1184     /* Is there a SACL? */
1185     if ((Sd->Control & SE_SACL_PRESENT) == SE_SACL_PRESENT)
1186     {
1187         /* Try to access it */
1188         if (!RtlpValidateSDOffsetAndSize(Sd->Sacl,
1189                                          SecurityDescriptorLength,
1190                                          sizeof(ACL),
1191                                          &Length))
1192         {
1193             /* It's beyond the buffer, fail */
1194             return FALSE;
1195         }
1196 
1197         /* Read the SACL, check if it's valid and if the buffer contains it */
1198         Sacl = (PSID)((ULONG_PTR)Sd->Sacl + (ULONG_PTR)Sd);
1199         if (!(RtlValidAcl(Sacl)) || (Length < Sacl->AclSize)) return FALSE;
1200     }
1201 
1202     /* All good */
1203     return TRUE;
1204 }
1205 
1206 /* EOF */
1207