branch update for HEAD-2003050101
[reactos.git] / ntoskrnl / se / sd.c
1 /* $Id$
2  *
3  * COPYRIGHT:         See COPYING in the top level directory
4  * PROJECT:           ReactOS kernel
5  * PURPOSE:           Security manager
6  * FILE:              kernel/se/sd.c
7  * PROGRAMER:         David Welch <welch@cwcom.net>
8  * REVISION HISTORY:
9  *                 26/07/98: Added stubs for security functions
10  */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/se.h>
16
17 #include <internal/debug.h>
18
19 /* GLOBALS ******************************************************************/
20
21 #ifndef LIBCAPTIVE
22 PSECURITY_DESCRIPTOR SePublicDefaultSd = NULL;
23 PSECURITY_DESCRIPTOR SePublicDefaultUnrestrictedSd = NULL;
24 PSECURITY_DESCRIPTOR SePublicOpenSd = NULL;
25 PSECURITY_DESCRIPTOR SePublicOpenUnrestrictedSd = NULL;
26 PSECURITY_DESCRIPTOR SeSystemDefaultSd = NULL;
27 PSECURITY_DESCRIPTOR SeUnrestrictedSd = NULL;
28 #endif /* LIBCAPTIVE */
29
30 /* FUNCTIONS ***************************************************************/
31
32 BOOLEAN
33 SepInitSDs(VOID)
34 {
35 #ifndef LIBCAPTIVE
36   /* Create PublicDefaultSd */
37   SePublicDefaultSd = ExAllocatePool(NonPagedPool,
38                                      sizeof(SECURITY_DESCRIPTOR));
39   if (SePublicDefaultSd == NULL)
40     return(FALSE);
41
42   RtlCreateSecurityDescriptor(SePublicDefaultSd,
43                               SECURITY_DESCRIPTOR_REVISION);
44   RtlSetDaclSecurityDescriptor(SePublicDefaultSd,
45                                TRUE,
46                                SePublicDefaultDacl,
47                                FALSE);
48
49   /* Create PublicDefaultUnrestrictedSd */
50   SePublicDefaultUnrestrictedSd = ExAllocatePool(NonPagedPool,
51                                                  sizeof(SECURITY_DESCRIPTOR));
52   if (SePublicDefaultUnrestrictedSd == NULL)
53     return(FALSE);
54
55   RtlCreateSecurityDescriptor(SePublicDefaultUnrestrictedSd,
56                               SECURITY_DESCRIPTOR_REVISION);
57   RtlSetDaclSecurityDescriptor(SePublicDefaultUnrestrictedSd,
58                                TRUE,
59                                SePublicDefaultUnrestrictedDacl,
60                                FALSE);
61
62   /* Create PublicOpenSd */
63   SePublicOpenSd = ExAllocatePool(NonPagedPool,
64                                   sizeof(SECURITY_DESCRIPTOR));
65   if (SePublicOpenSd == NULL)
66     return(FALSE);
67
68   RtlCreateSecurityDescriptor(SePublicOpenSd,
69                               SECURITY_DESCRIPTOR_REVISION);
70   RtlSetDaclSecurityDescriptor(SePublicOpenSd,
71                                TRUE,
72                                SePublicOpenDacl,
73                                FALSE);
74
75   /* Create PublicOpenUnrestrictedSd */
76   SePublicOpenUnrestrictedSd = ExAllocatePool(NonPagedPool,
77                                               sizeof(SECURITY_DESCRIPTOR));
78   if (SePublicOpenUnrestrictedSd == NULL)
79     return(FALSE);
80
81   RtlCreateSecurityDescriptor(SePublicOpenUnrestrictedSd,
82                               SECURITY_DESCRIPTOR_REVISION);
83   RtlSetDaclSecurityDescriptor(SePublicOpenUnrestrictedSd,
84                                TRUE,
85                                SePublicOpenUnrestrictedDacl,
86                                FALSE);
87
88   /* Create SystemDefaultSd */
89   SeSystemDefaultSd = ExAllocatePool(NonPagedPool,
90                                      sizeof(SECURITY_DESCRIPTOR));
91   if (SeSystemDefaultSd == NULL)
92     return(FALSE);
93
94   RtlCreateSecurityDescriptor(SeSystemDefaultSd,
95                               SECURITY_DESCRIPTOR_REVISION);
96   RtlSetDaclSecurityDescriptor(SeSystemDefaultSd,
97                                TRUE,
98                                SeSystemDefaultDacl,
99                                FALSE);
100
101   /* Create UnrestrictedSd */
102   SeUnrestrictedSd = ExAllocatePool(NonPagedPool,
103                                     sizeof(SECURITY_DESCRIPTOR));
104   if (SeUnrestrictedSd == NULL)
105     return(FALSE);
106
107   RtlCreateSecurityDescriptor(SeUnrestrictedSd,
108                               SECURITY_DESCRIPTOR_REVISION);
109   RtlSetDaclSecurityDescriptor(SeUnrestrictedSd,
110                                TRUE,
111                                SeUnrestrictedDacl,
112                                FALSE);
113 #endif /* LIBCAPTIVE */
114
115   return(TRUE);
116 }
117
118
119 NTSTATUS STDCALL
120 RtlCreateSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
121                             ULONG Revision)
122 {
123   if (Revision != SECURITY_DESCRIPTOR_REVISION)
124     return(STATUS_UNSUCCESSFUL);
125
126   SecurityDescriptor->Revision = SECURITY_DESCRIPTOR_REVISION;
127   SecurityDescriptor->Sbz1 = 0;
128   SecurityDescriptor->Control = 0;
129   SecurityDescriptor->Owner = NULL;
130   SecurityDescriptor->Group = NULL;
131   SecurityDescriptor->Sacl = NULL;
132   SecurityDescriptor->Dacl = NULL;
133
134   return(STATUS_SUCCESS);
135 }
136
137 #ifndef LIBCAPTIVE
138
139 /* FIXME: This function is somehow buggy, at least it uses '0xfc' mask
140  * instead of '0xFFFFFFFC' mask as sometimes there are PAGE_SIZE sized structures.
141  */
142 ULONG STDCALL
143 RtlLengthSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor)
144 {
145   PSID Owner;
146   PSID Group;
147   ULONG Length;
148   PACL Dacl;
149   PACL Sacl;
150
151   Length = sizeof(SECURITY_DESCRIPTOR);
152
153   if (SecurityDescriptor->Owner != NULL)
154     {
155       Owner = SecurityDescriptor->Owner;
156       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
157         {
158           Owner = (PSID)((ULONG)Owner +
159                          (ULONG)SecurityDescriptor);
160         }
161       Length = Length + ((sizeof(SID) + (Owner->SubAuthorityCount - 1) *
162                          sizeof(ULONG) + 3) & 0xfc);
163     }
164
165   if (SecurityDescriptor->Group != NULL)
166     {
167       Group = SecurityDescriptor->Group;
168       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
169         {
170           Group = (PSID)((ULONG)Group + (ULONG)SecurityDescriptor);
171         }
172       Length = Length + ((sizeof(SID) + (Group->SubAuthorityCount - 1) *
173                          sizeof(ULONG) + 3) & 0xfc);
174     }
175
176   if (SecurityDescriptor->Control & SE_DACL_PRESENT &&
177       SecurityDescriptor->Dacl != NULL)
178     {
179       Dacl = SecurityDescriptor->Dacl;
180       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
181         {
182           Dacl = (PACL)((ULONG)Dacl + (PVOID)SecurityDescriptor);
183         }
184       Length = Length + ((Dacl->AclSize + 3) & 0xfc);
185     }
186
187   if (SecurityDescriptor->Control & SE_SACL_PRESENT &&
188       SecurityDescriptor->Sacl != NULL)
189     {
190       Sacl = SecurityDescriptor->Sacl;
191       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
192         {
193           Sacl = (PACL)((ULONG)Sacl + (PVOID)SecurityDescriptor);
194         }
195       Length = Length + ((Sacl->AclSize + 3) & 0xfc);
196     }
197
198   return(Length);
199 }
200
201
202 NTSTATUS STDCALL
203 RtlGetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
204                              PBOOLEAN DaclPresent,
205                              PACL* Dacl,
206                              PBOOLEAN DaclDefaulted)
207 {
208   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
209     {
210       return(STATUS_UNSUCCESSFUL);
211     }
212
213   if (!(SecurityDescriptor->Control & SE_DACL_PRESENT))
214     {
215       *DaclPresent = FALSE;
216       return(STATUS_SUCCESS);
217     }
218   *DaclPresent = TRUE;
219
220   if (SecurityDescriptor->Dacl == NULL)
221     {
222       *Dacl = NULL;
223     }
224   else
225     {
226       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
227         {
228           *Dacl = (PACL)((ULONG)SecurityDescriptor->Dacl +
229                          (PVOID)SecurityDescriptor);
230         }
231       else
232         {
233           *Dacl = SecurityDescriptor->Dacl;
234         }
235     }
236
237   if (SecurityDescriptor->Control & SE_DACL_DEFAULTED)
238     {
239       *DaclDefaulted = TRUE;
240     }
241   else
242     {
243       *DaclDefaulted = FALSE;
244     }
245
246   return(STATUS_SUCCESS);
247 }
248
249 #endif /* LIBCAPTIVE */
250
251 NTSTATUS STDCALL
252 RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
253                              BOOLEAN DaclPresent,
254                              PACL Dacl,
255                              BOOLEAN DaclDefaulted)
256 {
257   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
258     {
259       return(STATUS_UNSUCCESSFUL);
260     }
261
262   if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
263     {
264       return(STATUS_UNSUCCESSFUL);
265     }
266
267   if (!DaclPresent)
268     {
269       SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_DACL_PRESENT);
270       return(STATUS_SUCCESS);
271     }
272
273   SecurityDescriptor->Control = SecurityDescriptor->Control | SE_DACL_PRESENT;
274   SecurityDescriptor->Dacl = Dacl;
275   SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_DACL_DEFAULTED);
276
277   if (DaclDefaulted)
278     {
279       SecurityDescriptor->Control = SecurityDescriptor->Control | SE_DACL_DEFAULTED;
280     }
281
282   return(STATUS_SUCCESS);
283 }
284
285 #ifndef LIBCAPTIVE
286
287 BOOLEAN STDCALL
288 RtlValidSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor)
289 {
290   PSID Owner;
291   PSID Group;
292   PACL Sacl;
293   PACL Dacl;
294
295   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
296     {
297       return(FALSE);
298     }
299
300   Owner = SecurityDescriptor->Owner;
301   if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
302     {
303       Owner = (PSID)((ULONG)Owner + (ULONG)SecurityDescriptor);
304     }
305
306   if (!RtlValidSid(Owner))
307     {
308       return(FALSE);
309     }
310
311   Group = SecurityDescriptor->Group;
312   if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
313     {
314       Group = (PSID)((ULONG)Group + (ULONG)SecurityDescriptor);
315     }
316
317   if (!RtlValidSid(Group))
318     {
319       return(FALSE);
320     }
321
322   if (SecurityDescriptor->Control & SE_DACL_PRESENT &&
323       SecurityDescriptor->Dacl != NULL)
324     {
325       Dacl = SecurityDescriptor->Dacl;
326       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
327         {
328           Dacl = (PACL)((ULONG)Dacl + (ULONG)SecurityDescriptor);
329         }
330
331       if (!RtlValidAcl(Dacl))
332         {
333           return(FALSE);
334         }
335     }
336
337   if (SecurityDescriptor->Control & SE_SACL_PRESENT &&
338       SecurityDescriptor->Sacl != NULL)
339     {
340       Sacl = SecurityDescriptor->Sacl;
341       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
342         {
343           Sacl = (PACL)((ULONG)Sacl + (ULONG)SecurityDescriptor);
344         }
345
346       if (!RtlValidAcl(Sacl))
347         {
348           return(FALSE);
349         }
350     }
351
352   return(TRUE);
353 }
354
355
356 NTSTATUS STDCALL
357 RtlSetOwnerSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
358                               PSID Owner,
359                               BOOLEAN OwnerDefaulted)
360 {
361   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
362     {
363       return(STATUS_UNSUCCESSFUL);
364     }
365
366   if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
367     {
368       return(STATUS_UNSUCCESSFUL);
369     }
370
371   SecurityDescriptor->Owner = Owner;
372   SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_OWNER_DEFAULTED);
373
374   if (OwnerDefaulted)
375     {
376       SecurityDescriptor->Control = SecurityDescriptor->Control | SE_OWNER_DEFAULTED;
377     }
378
379   return(STATUS_SUCCESS);
380 }
381
382
383 NTSTATUS STDCALL
384 RtlGetOwnerSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
385                               PSID* Owner,
386                               PBOOLEAN OwnerDefaulted)
387 {
388   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
389     {
390       return(STATUS_UNSUCCESSFUL);
391     }
392
393   if (SecurityDescriptor->Owner != NULL)
394     {
395         if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
396           {
397              *Owner = (PSID)((ULONG)SecurityDescriptor->Owner +
398                              (PVOID)SecurityDescriptor);
399           }
400         else
401           {
402              *Owner = SecurityDescriptor->Owner;
403           }
404     }
405   else
406     {
407         *Owner = NULL;
408     }
409    if (SecurityDescriptor->Control & SE_OWNER_DEFAULTED)
410      {
411         *OwnerDefaulted = 1;
412      }
413    else
414      {
415         *OwnerDefaulted = 0;
416      }
417    return(STATUS_SUCCESS);
418 }
419
420
421 NTSTATUS STDCALL
422 RtlSetGroupSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
423                               PSID Group,
424                               BOOLEAN GroupDefaulted)
425 {
426   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
427     {
428       return(STATUS_UNSUCCESSFUL);
429     }
430
431   if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
432     {
433       return(STATUS_UNSUCCESSFUL);
434     }
435
436   SecurityDescriptor->Group = Group;
437   SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_GROUP_DEFAULTED);
438
439   if (GroupDefaulted)
440     {
441       SecurityDescriptor->Control = SecurityDescriptor->Control | SE_GROUP_DEFAULTED;
442     }
443
444   return(STATUS_SUCCESS);
445 }
446
447
448 NTSTATUS STDCALL
449 RtlGetGroupSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
450                               PSID* Group,
451                               PBOOLEAN GroupDefaulted)
452 {
453   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
454     {
455       return(STATUS_UNSUCCESSFUL);
456     }
457
458   if (SecurityDescriptor->Group != NULL)
459     {
460       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
461         {
462           *Group = (PSID)((ULONG)SecurityDescriptor->Group +
463                           (PVOID)SecurityDescriptor);
464         }
465       else
466         {
467           *Group = SecurityDescriptor->Group;
468         }
469     }
470   else
471     {
472       *Group = NULL;
473     }
474
475   if (SecurityDescriptor->Control & SE_GROUP_DEFAULTED)
476     {
477       *GroupDefaulted = TRUE;
478     }
479   else
480     {
481       *GroupDefaulted = FALSE;
482     }
483
484   return(STATUS_SUCCESS);
485 }
486
487
488 NTSTATUS STDCALL
489 RtlGetSaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
490                              PBOOLEAN SaclPresent,
491                              PACL *Sacl,
492                              PBOOLEAN SaclDefaulted)
493 {
494   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
495     {
496       return(STATUS_UNSUCCESSFUL);
497     }
498
499   if (!(SecurityDescriptor->Control & SE_SACL_PRESENT))
500     {
501       *SaclPresent = FALSE;
502       return(STATUS_SUCCESS);
503     }
504   *SaclPresent = TRUE;
505
506   if (SecurityDescriptor->Sacl == NULL)
507     {
508       *Sacl = NULL;
509     }
510   else
511     {
512       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
513         {
514           *Sacl = (PACL)((ULONG)SecurityDescriptor->Sacl +
515                          (PVOID)SecurityDescriptor);
516         }
517       else
518         {
519           *Sacl = SecurityDescriptor->Sacl;
520         }
521     }
522
523   if (SecurityDescriptor->Control & SE_SACL_DEFAULTED)
524     {
525       *SaclDefaulted = TRUE;
526     }
527   else
528     {
529       *SaclDefaulted = FALSE;
530     }
531
532   return(STATUS_SUCCESS);
533 }
534
535
536 NTSTATUS STDCALL
537 RtlSetSaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
538                              BOOLEAN SaclPresent,
539                              PACL Sacl,
540                              BOOLEAN SaclDefaulted)
541 {
542   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
543     {
544       return(STATUS_UNSUCCESSFUL);
545     }
546   if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
547     {
548       return(STATUS_UNSUCCESSFUL);
549     }
550
551   if (!SaclPresent)
552     {
553       SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_SACL_PRESENT);
554       return(STATUS_SUCCESS);
555     }
556
557   SecurityDescriptor->Control = SecurityDescriptor->Control | SE_SACL_PRESENT;
558   SecurityDescriptor->Sacl = Sacl;
559   SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_SACL_DEFAULTED);
560
561   if (SaclDefaulted)
562     {
563       SecurityDescriptor->Control = SecurityDescriptor->Control | SE_SACL_DEFAULTED;
564     }
565
566   return(STATUS_SUCCESS);
567 }
568
569
570 static VOID
571 RtlpQuerySecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
572                             PSID* Owner,
573                             PULONG OwnerLength,
574                             PSID* Group,
575                             PULONG GroupLength,
576                             PACL* Dacl,
577                             PULONG DaclLength,
578                             PACL* Sacl,
579                             PULONG SaclLength)
580 {
581   if (SecurityDescriptor->Owner == NULL)
582     {
583       *Owner = NULL;
584     }
585   else
586     {
587       *Owner = SecurityDescriptor->Owner;
588       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
589         {
590           *Owner = (PSID)((ULONG)*Owner + (ULONG)SecurityDescriptor);
591         }
592     }
593
594   if (*Owner != NULL)
595     {
596       *OwnerLength = (RtlLengthSid(*Owner) + 3) & ~3;
597     }
598   else
599     {
600       *OwnerLength = 0;
601     }
602
603   if ((SecurityDescriptor->Control & SE_DACL_PRESENT) &&
604       SecurityDescriptor->Dacl != NULL)
605     {
606       *Dacl = SecurityDescriptor->Dacl;
607       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
608         {
609           *Dacl = (PACL)((ULONG)*Dacl + (ULONG)SecurityDescriptor);
610         }
611     }
612   else
613     {
614       *Dacl = NULL;
615     }
616
617   if (*Dacl != NULL)
618     {
619       *DaclLength = ((*Dacl)->AclSize + 3) & ~3;
620     }
621   else
622     {
623       *DaclLength = 0;
624     }
625
626   if (SecurityDescriptor->Group != NULL)
627     {
628       *Group = NULL;
629     }
630   else
631     {
632       *Group = SecurityDescriptor->Group;
633       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
634         {
635           *Group = (PSID)((ULONG)*Group + (ULONG)SecurityDescriptor);
636         }
637     }
638
639   if (*Group != NULL)
640     {
641       *GroupLength = (RtlLengthSid(*Group) + 3) & ~3;
642     }
643   else
644     {
645       *GroupLength = 0;
646     }
647
648   if ((SecurityDescriptor->Control & SE_SACL_PRESENT) &&
649       SecurityDescriptor->Sacl != NULL)
650     {
651       *Sacl = SecurityDescriptor->Sacl;
652       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
653         {
654           *Sacl = (PACL)((ULONG)*Sacl + (ULONG)SecurityDescriptor);
655         }
656     }
657   else
658     {
659       *Sacl = NULL;
660     }
661
662   if (*Sacl != NULL)
663     {
664       *SaclLength = ((*Sacl)->AclSize + 3) & ~3;
665     }
666 }
667
668
669 NTSTATUS STDCALL
670 RtlAbsoluteToSelfRelativeSD(PSECURITY_DESCRIPTOR AbsSD,
671                             PSECURITY_DESCRIPTOR RelSD,
672                             PULONG BufferLength)
673 {
674   PSID Owner;
675   PSID Group;
676   PACL Sacl;
677   PACL Dacl;
678   ULONG OwnerLength;
679   ULONG GroupLength;
680   ULONG SaclLength;
681   ULONG DaclLength;
682   ULONG TotalLength;
683   ULONG Current;
684
685   if (AbsSD->Control & SE_SELF_RELATIVE)
686     {
687       return(STATUS_BAD_DESCRIPTOR_FORMAT);
688     }
689
690   RtlpQuerySecurityDescriptor(AbsSD,
691                               &Owner,
692                               &OwnerLength,
693                               &Group,
694                               &GroupLength,
695                               &Dacl,
696                               &DaclLength,
697                               &Sacl,
698                               &SaclLength);
699
700   TotalLength = OwnerLength + GroupLength + SaclLength +
701                 DaclLength + sizeof(SECURITY_DESCRIPTOR);
702   if (*BufferLength < TotalLength)
703     {
704       return(STATUS_BUFFER_TOO_SMALL);
705     }
706
707   RtlZeroMemory(RelSD,
708                 TotalLength);
709   memmove(RelSD,
710           AbsSD,
711           sizeof(SECURITY_DESCRIPTOR));
712   Current = (ULONG)RelSD + sizeof(SECURITY_DESCRIPTOR);
713
714   if (SaclLength != 0)
715     {
716       memmove((PVOID)Current,
717               Sacl,
718               SaclLength);
719       RelSD->Sacl = (PACL)((ULONG)Current - (ULONG)RelSD);
720       Current += SaclLength;
721     }
722
723   if (DaclLength != 0)
724     {
725       memmove((PVOID)Current,
726               Dacl,
727               DaclLength);
728       RelSD->Dacl = (PACL)((ULONG)Current - (ULONG)RelSD);
729       Current += DaclLength;
730     }
731
732   if (OwnerLength != 0)
733     {
734       memmove((PVOID)Current,
735               Owner,
736               OwnerLength);
737       RelSD->Owner = (PSID)((ULONG)Current - (ULONG)RelSD);
738       Current += OwnerLength;
739     }
740
741   if (GroupLength != 0)
742     {
743       memmove((PVOID)Current,
744               Group,
745               GroupLength);
746       RelSD->Group = (PSID)((ULONG)Current - (ULONG)RelSD);
747     }
748
749   RelSD->Control |= SE_SELF_RELATIVE;
750
751   return(STATUS_SUCCESS);
752 }
753
754 #endif /* LIBCAPTIVE */
755
756 /* EOF */