xref: /reactos/sdk/lib/rtl/sd.c (revision 9cfd8dd9)
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 PSECURITY_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 SecurityDescriptor,
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_RELATIVE RelSd = (PISECURITY_DESCRIPTOR_RELATIVE)SelfRelativeSD;
656     PAGED_CODE_RTL();
657 
658     /* Query all components */
659     RtlpQuerySecurityDescriptor(SecurityDescriptor,
660                                 &Owner,
661                                 &OwnerLength,
662                                 &Group,
663                                 &GroupLength,
664                                 &Dacl,
665                                 &DaclLength,
666                                 &Sacl,
667                                 &SaclLength);
668 
669     /* Calculate final length */
670     TotalLength = sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
671                   OwnerLength +
672                   GroupLength +
673                   SaclLength +
674                   DaclLength;
675 
676     /* Is there enough space? */
677     if (*BufferLength < TotalLength)
678     {
679         /* Nope, return how much is needed */
680         *BufferLength = TotalLength;
681         return STATUS_BUFFER_TOO_SMALL;
682     }
683 
684     /* Start fresh */
685     RtlZeroMemory(RelSd, TotalLength);
686 
687     /* Copy the header fields */
688     RtlCopyMemory(RelSd,
689                   SecurityDescriptor,
690                   FIELD_OFFSET(SECURITY_DESCRIPTOR_RELATIVE, Owner));
691 
692     /* Set the current copy pointer */
693     Current = (ULONG_PTR)(RelSd + 1);
694 
695     /* Is there a SACL? */
696     if (SaclLength)
697     {
698         /* Copy it */
699         RtlCopyMemory((PVOID)Current, Sacl, SaclLength);
700         RelSd->Sacl = (ULONG_PTR)Current - (ULONG_PTR)RelSd;
701         Current += SaclLength;
702     }
703 
704     /* Is there a DACL? */
705     if (DaclLength)
706     {
707         /* Copy it */
708         RtlCopyMemory((PVOID)Current, Dacl, DaclLength);
709         RelSd->Dacl = (ULONG_PTR)Current - (ULONG_PTR)RelSd;
710         Current += DaclLength;
711     }
712 
713     /* Is there an owner? */
714     if (OwnerLength)
715     {
716         /* Copy it */
717         RtlCopyMemory((PVOID)Current, Owner, OwnerLength);
718         RelSd->Owner = (ULONG_PTR)Current - (ULONG_PTR)RelSd;
719         Current += OwnerLength;
720     }
721 
722     /* Is there a group? */
723     if (GroupLength)
724     {
725         /* Copy it */
726         RtlCopyMemory((PVOID)Current, Group, GroupLength);
727         RelSd->Group = (ULONG_PTR)Current - (ULONG_PTR)RelSd;
728     }
729 
730     /* Mark it as relative */
731     RelSd->Control |= SE_SELF_RELATIVE;
732 
733     /* All good */
734     return STATUS_SUCCESS;
735 }
736 
737 /*
738  * @implemented
739  */
740 NTSTATUS
741 NTAPI
742 RtlSelfRelativeToAbsoluteSD(IN PSECURITY_DESCRIPTOR SelfRelativeSD,
743                             OUT PSECURITY_DESCRIPTOR AbsoluteSD,
744                             IN PULONG AbsoluteSDSize,
745                             IN PACL Dacl,
746                             IN PULONG DaclSize,
747                             IN PACL Sacl,
748                             IN PULONG SaclSize,
749                             IN PSID Owner,
750                             IN PULONG OwnerSize,
751                             IN PSID PrimaryGroup,
752                             IN PULONG PrimaryGroupSize)
753 {
754     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)AbsoluteSD;
755     PISECURITY_DESCRIPTOR RelSd = (PISECURITY_DESCRIPTOR)SelfRelativeSD;
756     ULONG OwnerLength, GroupLength, DaclLength, SaclLength;
757     PSID pOwner, pGroup;
758     PACL pDacl, pSacl;
759     PAGED_CODE_RTL();
760 
761     /* Must be relative, otherwiise fail */
762     if (!(RelSd->Control & SE_SELF_RELATIVE)) return STATUS_BAD_DESCRIPTOR_FORMAT;
763 
764     /* Get all the components */
765     RtlpQuerySecurityDescriptor(RelSd,
766                                 &pOwner,
767                                 &OwnerLength,
768                                 &pGroup,
769                                 &GroupLength,
770                                 &pDacl,
771                                 &DaclLength,
772                                 &pSacl,
773                                 &SaclLength);
774 
775     /* Fail if there's not enough space */
776     if (!(Sd) ||
777         (sizeof(SECURITY_DESCRIPTOR) > *AbsoluteSDSize) ||
778         (OwnerLength > *OwnerSize) ||
779         (GroupLength > *PrimaryGroupSize) ||
780         (DaclLength > *DaclSize) ||
781         (SaclLength > *SaclSize))
782     {
783         /* Return how much space is needed for each components */
784         *AbsoluteSDSize = sizeof(SECURITY_DESCRIPTOR);
785         *OwnerSize = OwnerLength;
786         *PrimaryGroupSize = GroupLength;
787         *DaclSize = DaclLength;
788         *SaclSize = SaclLength;
789         return STATUS_BUFFER_TOO_SMALL;
790     }
791 
792     /* Copy the header fields */
793     RtlMoveMemory(Sd, RelSd, sizeof(SECURITY_DESCRIPTOR_RELATIVE));
794 
795     /* Wipe out the pointers and the relative flag */
796     Sd->Owner = NULL;
797     Sd->Group = NULL;
798     Sd->Sacl = NULL;
799     Sd->Dacl = NULL;
800     Sd->Control &= ~SE_SELF_RELATIVE;
801 
802     /* Is there an owner? */
803     if (pOwner)
804     {
805         /* Copy it */
806         RtlMoveMemory(Owner, pOwner, RtlLengthSid(pOwner));
807         Sd->Owner = Owner;
808     }
809 
810     /* Is there a group? */
811     if (pGroup)
812     {
813         /* Copy it */
814         RtlMoveMemory(PrimaryGroup, pGroup, RtlLengthSid(pGroup));
815         Sd->Group = PrimaryGroup;
816     }
817 
818     /* Is there a DACL? */
819     if (pDacl)
820     {
821         /* Copy it */
822         RtlMoveMemory(Dacl, pDacl, pDacl->AclSize);
823         Sd->Dacl = Dacl;
824     }
825 
826     /* Is there a SACL? */
827     if (pSacl)
828     {
829         /* Copy it */
830         RtlMoveMemory(Sacl, pSacl, pSacl->AclSize);
831         Sd->Sacl = Sacl;
832     }
833 
834     /* All good */
835     return STATUS_SUCCESS;
836 }
837 
838 /*
839  * @implemented
840  */
841 NTSTATUS
842 NTAPI
843 RtlSelfRelativeToAbsoluteSD2(IN OUT PSECURITY_DESCRIPTOR SelfRelativeSD,
844                              OUT PULONG BufferSize)
845 {
846     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SelfRelativeSD;
847     PISECURITY_DESCRIPTOR_RELATIVE RelSd = (PISECURITY_DESCRIPTOR_RELATIVE)SelfRelativeSD;
848     PVOID DataStart, DataEnd;
849     LONG MoveDelta;
850     ULONG DataSize, OwnerLength, GroupLength, DaclLength, SaclLength;
851     PSID pOwner, pGroup;
852     PACL pDacl, pSacl;
853     PAGED_CODE_RTL();
854 
855     /* Need input */
856     if (!RelSd) return STATUS_INVALID_PARAMETER_1;
857 
858     /* Need to know how much space we have */
859     if (!BufferSize) return STATUS_INVALID_PARAMETER_2;
860 
861     /* Input must be relative */
862     if (!(RelSd->Control & SE_SELF_RELATIVE)) return STATUS_BAD_DESCRIPTOR_FORMAT;
863 
864     /* Query all the component sizes */
865     RtlpQuerySecurityDescriptor(Sd,
866                                 &pOwner,
867                                 &OwnerLength,
868                                 &pGroup,
869                                 &GroupLength,
870                                 &pDacl,
871                                 &DaclLength,
872                                 &pSacl,
873                                 &SaclLength);
874 
875     /*
876      * Check if there's a difference in structure layout between relatiev and
877      * absolute descriptors. On 32-bit, there won't be, since an offset is the
878      * same size as a pointer (32-bit), but on 64-bit, the offsets remain 32-bit
879      * as they are not SIZE_T, but ULONG, while the pointers now become 64-bit
880      * and thus the structure is different */
881     MoveDelta = sizeof(SECURITY_DESCRIPTOR) - sizeof(SECURITY_DESCRIPTOR_RELATIVE);
882     if (!MoveDelta)
883     {
884         /* So on 32-bit, simply clear the flag... */
885         Sd->Control &= ~SE_SELF_RELATIVE;
886 
887         /* Ensure we're *really* on 32-bit */
888         ASSERT(sizeof(Sd->Owner) == sizeof(RelSd->Owner));
889         ASSERT(sizeof(Sd->Group) == sizeof(RelSd->Group));
890         ASSERT(sizeof(Sd->Sacl) == sizeof(RelSd->Sacl));
891         ASSERT(sizeof(Sd->Dacl) == sizeof(RelSd->Dacl));
892 
893         /* And simply set pointers where there used to be offsets */
894         Sd->Owner = pOwner;
895         Sd->Group = pGroup;
896         Sd->Sacl = pSacl;
897         Sd->Dacl = pDacl;
898         return STATUS_SUCCESS;
899     }
900 
901     /*
902      * Calculate the start and end of the data area, we simply just move the
903      * data by the difference between the size of the relative and absolute
904      * security descriptor structure
905      */
906     DataStart = pOwner;
907     DataEnd = (PVOID)((ULONG_PTR)pOwner + OwnerLength);
908 
909     /* Is there a group? */
910     if (pGroup)
911     {
912         /* Is the group higher than where we started? */
913         if (((ULONG_PTR)pGroup < (ULONG_PTR)DataStart) || !DataStart)
914         {
915             /* Update the start pointer */
916             DataStart = pGroup;
917         }
918 
919         /* Is the group beyond where we ended? */
920         if (((ULONG_PTR)pGroup + GroupLength > (ULONG_PTR)DataEnd) || !DataEnd)
921         {
922             /* Update the end pointer */
923             DataEnd = (PVOID)((ULONG_PTR)pGroup + GroupLength);
924         }
925     }
926 
927     /* Is there a DACL? */
928     if (pDacl)
929     {
930         /* Is the DACL higher than where we started? */
931         if (((ULONG_PTR)pDacl < (ULONG_PTR)DataStart) || !DataStart)
932         {
933             /* Update the start pointer */
934             DataStart = pDacl;
935         }
936 
937         /* Is the DACL beyond where we ended? */
938         if (((ULONG_PTR)pDacl + DaclLength > (ULONG_PTR)DataEnd) || !DataEnd)
939         {
940             /* Update the end pointer */
941             DataEnd = (PVOID)((ULONG_PTR)pDacl + DaclLength);
942         }
943     }
944 
945     /* Is there a SACL? */
946     if (pSacl)
947     {
948         /* Is the SACL higher than where we started? */
949         if (((ULONG_PTR)pSacl < (ULONG_PTR)DataStart) || !DataStart)
950         {
951             /* Update the start pointer */
952             DataStart = pSacl;
953         }
954 
955         /* Is the SACL beyond where we ended? */
956         if (((ULONG_PTR)pSacl + SaclLength > (ULONG_PTR)DataEnd) || !DataEnd)
957         {
958             /* Update the end pointer */
959             DataEnd = (PVOID)((ULONG_PTR)pSacl + SaclLength);
960         }
961     }
962 
963     /* Sanity check */
964     ASSERT((ULONG_PTR)DataEnd >= (ULONG_PTR)DataStart);
965 
966     /* Now compute the difference between relative and absolute */
967     DataSize = (ULONG)((ULONG_PTR)DataEnd - (ULONG_PTR)DataStart);
968 
969     /* Is the new buffer large enough for this difference? */
970     if (*BufferSize < sizeof(SECURITY_DESCRIPTOR) + DataSize)
971     {
972         /* Nope, bail out */
973         *BufferSize = sizeof(SECURITY_DESCRIPTOR) + DataSize;
974         return STATUS_BUFFER_TOO_SMALL;
975     }
976 
977     /* Is there anything actually to copy? */
978     if (DataSize)
979     {
980         /*
981          * There must be at least one SID or ACL in the security descriptor!
982          * Also the data area must be located somewhere after the end of the
983          * SECURITY_DESCRIPTOR_RELATIVE structure
984          */
985         ASSERT(DataStart != NULL);
986         ASSERT((ULONG_PTR)DataStart >= (ULONG_PTR)(RelSd + 1));
987 
988         /* It's time to move the data */
989         RtlMoveMemory((PVOID)(Sd + 1),
990                       DataStart,
991                       DataSize);
992     }
993 
994     /* Is there an owner? */
995     if (pOwner)
996     {
997         /* Set the pointer to the relative position */
998         Sd->Owner = (PSID)((LONG_PTR)pOwner + MoveDelta);
999     }
1000     else
1001     {
1002         /* No owner, clear the pointer */
1003         Sd->Owner = NULL;
1004     }
1005 
1006     /* Is there a group */
1007     if (pGroup)
1008     {
1009         /* Set the pointer to the relative position */
1010         Sd->Group = (PSID)((LONG_PTR)pGroup + MoveDelta);
1011     }
1012     else
1013     {
1014         /* No group, clear the pointer */
1015         Sd->Group = NULL;
1016     }
1017 
1018     /* Is there a SACL? */
1019     if (pSacl)
1020     {
1021         /* Set the pointer to the relative position */
1022         Sd->Sacl = (PACL)((LONG_PTR)pSacl + MoveDelta);
1023     }
1024     else
1025     {
1026         /* No SACL, clear the pointer */
1027         Sd->Sacl = NULL;
1028     }
1029 
1030     /* Is there a DACL? */
1031     if (pDacl)
1032     {
1033         /* Set the pointer to the relative position */
1034         Sd->Dacl = (PACL)((LONG_PTR)pDacl + MoveDelta);
1035     }
1036     else
1037     {
1038         /* No DACL, clear the pointer */
1039         Sd->Dacl = NULL;
1040     }
1041 
1042     /* Clear the self-relative flag */
1043     Sd->Control &= ~SE_SELF_RELATIVE;
1044 
1045     /* All good */
1046     return STATUS_SUCCESS;
1047 }
1048 
1049 /*
1050  * @implemented
1051  */
1052 BOOLEAN
1053 NTAPI
1054 RtlValidSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor)
1055 {
1056     PISECURITY_DESCRIPTOR Sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
1057     PSID Owner, Group;
1058     PACL Sacl, Dacl;
1059     PAGED_CODE_RTL();
1060 
1061     _SEH2_TRY
1062     {
1063         /* Fail on bad revisions */
1064         if (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) _SEH2_YIELD(return FALSE);
1065 
1066         /* Owner SID must be valid if present */
1067         Owner = SepGetOwnerFromDescriptor(Sd);
1068         if ((Owner) && (!RtlValidSid(Owner))) _SEH2_YIELD(return FALSE);
1069 
1070         /* Group SID must be valid if present */
1071         Group = SepGetGroupFromDescriptor(Sd);
1072         if ((Group) && (!RtlValidSid(Group))) _SEH2_YIELD(return FALSE);
1073 
1074         /* DACL must be valid if present */
1075         Dacl = SepGetDaclFromDescriptor(Sd);
1076         if ((Dacl) && (!RtlValidAcl(Dacl))) _SEH2_YIELD(return FALSE);
1077 
1078         /* SACL must be valid if present */
1079         Sacl = SepGetSaclFromDescriptor(Sd);
1080         if ((Sacl) && (!RtlValidAcl(Sacl))) _SEH2_YIELD(return FALSE);
1081     }
1082     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1083     {
1084         /* Access fault, bail out */
1085         _SEH2_YIELD(return FALSE);
1086     }
1087     _SEH2_END;
1088 
1089     /* All good */
1090     return TRUE;
1091 }
1092 
1093 /*
1094  * @implemented
1095  */
1096 BOOLEAN
1097 NTAPI
1098 RtlValidRelativeSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptorInput,
1099                                    IN ULONG SecurityDescriptorLength,
1100                                    IN SECURITY_INFORMATION RequiredInformation)
1101 {
1102     PISECURITY_DESCRIPTOR_RELATIVE Sd = (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptorInput;
1103     PSID Owner, Group;
1104     PACL Dacl, Sacl;
1105     ULONG Length;
1106     PAGED_CODE_RTL();
1107 
1108     /* Note that Windows allows no DACL/SACL even if RequiredInfo wants it */
1109 
1110     /* Do we have enough space, is the revision vaild, and is this SD relative? */
1111     if ((SecurityDescriptorLength < sizeof(SECURITY_DESCRIPTOR_RELATIVE)) ||
1112         (Sd->Revision != SECURITY_DESCRIPTOR_REVISION) ||
1113         !(Sd->Control & SE_SELF_RELATIVE))
1114     {
1115         /* Nope, bail out */
1116         return FALSE;
1117     }
1118 
1119     /* Is there an owner? */
1120     if (Sd->Owner)
1121     {
1122         /* Try to access it */
1123         if (!RtlpValidateSDOffsetAndSize(Sd->Owner,
1124                                          SecurityDescriptorLength,
1125                                          sizeof(SID),
1126                                          &Length))
1127         {
1128             /* It's beyond the buffer, fail */
1129             return FALSE;
1130         }
1131 
1132         /* Read the owner, check if it's valid and if the buffer contains it */
1133         Owner = (PSID)((ULONG_PTR)Sd->Owner + (ULONG_PTR)Sd);
1134         if (!RtlValidSid(Owner) || (Length < RtlLengthSid(Owner))) return FALSE;
1135     }
1136     else if (RequiredInformation & OWNER_SECURITY_INFORMATION)
1137     {
1138         /* No owner but the caller expects one, fail */
1139         return FALSE;
1140     }
1141 
1142     /* Is there a group? */
1143     if (Sd->Group)
1144     {
1145         /* Try to access it */
1146         if (!RtlpValidateSDOffsetAndSize(Sd->Group,
1147                                          SecurityDescriptorLength,
1148                                          sizeof(SID),
1149                                          &Length))
1150         {
1151             /* It's beyond the buffer, fail */
1152             return FALSE;
1153         }
1154 
1155         /* Read the group, check if it's valid and if the buffer contains it */
1156         Group = (PSID)((ULONG_PTR)Sd->Group + (ULONG_PTR)Sd);
1157         if (!RtlValidSid(Group) || (Length < RtlLengthSid(Group))) return FALSE;
1158     }
1159     else if (RequiredInformation & GROUP_SECURITY_INFORMATION)
1160     {
1161         /* No group, but the caller expects one, fail */
1162         return FALSE;
1163     }
1164 
1165     /* Is there a DACL? */
1166     if ((Sd->Control & SE_DACL_PRESENT) == SE_DACL_PRESENT)
1167     {
1168         /* Try to access it */
1169         if (!RtlpValidateSDOffsetAndSize(Sd->Dacl,
1170                                          SecurityDescriptorLength,
1171                                          sizeof(ACL),
1172                                          &Length))
1173         {
1174             /* It's beyond the buffer, fail */
1175             return FALSE;
1176         }
1177 
1178         /* Read the DACL, check if it's valid and if the buffer contains it */
1179         Dacl = (PSID)((ULONG_PTR)Sd->Dacl + (ULONG_PTR)Sd);
1180         if (!(RtlValidAcl(Dacl)) || (Length < Dacl->AclSize)) return FALSE;
1181     }
1182 
1183     /* Is there a SACL? */
1184     if ((Sd->Control & SE_SACL_PRESENT) == SE_SACL_PRESENT)
1185     {
1186         /* Try to access it */
1187         if (!RtlpValidateSDOffsetAndSize(Sd->Sacl,
1188                                          SecurityDescriptorLength,
1189                                          sizeof(ACL),
1190                                          &Length))
1191         {
1192             /* It's beyond the buffer, fail */
1193             return FALSE;
1194         }
1195 
1196         /* Read the SACL, check if it's valid and if the buffer contains it */
1197         Sacl = (PSID)((ULONG_PTR)Sd->Sacl + (ULONG_PTR)Sd);
1198         if (!(RtlValidAcl(Sacl)) || (Length < Sacl->AclSize)) return FALSE;
1199     }
1200 
1201     /* All good */
1202     return TRUE;
1203 }
1204 
1205 /* EOF */
1206