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