+User acceptable message on incompatible W32 binary modules.
[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 /*
120  * @implemented
121  */
122 NTSTATUS STDCALL
123 RtlCreateSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
124                             ULONG Revision)
125 {
126   if (Revision != SECURITY_DESCRIPTOR_REVISION)
127     return(STATUS_UNSUCCESSFUL);
128
129   SecurityDescriptor->Revision = SECURITY_DESCRIPTOR_REVISION;
130   SecurityDescriptor->Sbz1 = 0;
131   SecurityDescriptor->Control = 0;
132   SecurityDescriptor->Owner = NULL;
133   SecurityDescriptor->Group = NULL;
134   SecurityDescriptor->Sacl = NULL;
135   SecurityDescriptor->Dacl = NULL;
136
137   return(STATUS_SUCCESS);
138 }
139
140 #ifndef LIBCAPTIVE
141
142 /* FIXME: This function is somehow buggy, at least it uses '0xfc' mask
143  * instead of '0xFFFFFFFC' mask as sometimes there are PAGE_SIZE sized structures.
144  */
145 /*
146  * @implemented
147  */
148 ULONG STDCALL
149 RtlLengthSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor)
150 {
151   PSID Owner;
152   PSID Group;
153   ULONG Length;
154   PACL Dacl;
155   PACL Sacl;
156
157   Length = sizeof(SECURITY_DESCRIPTOR);
158
159   if (SecurityDescriptor->Owner != NULL)
160     {
161       Owner = SecurityDescriptor->Owner;
162       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
163         {
164           Owner = (PSID)((ULONG)Owner +
165                          (ULONG)SecurityDescriptor);
166         }
167       Length = Length + ((sizeof(SID) + (Owner->SubAuthorityCount - 1) *
168                          sizeof(ULONG) + 3) & 0xfc);
169     }
170
171   if (SecurityDescriptor->Group != NULL)
172     {
173       Group = SecurityDescriptor->Group;
174       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
175         {
176           Group = (PSID)((ULONG)Group + (ULONG)SecurityDescriptor);
177         }
178       Length = Length + ((sizeof(SID) + (Group->SubAuthorityCount - 1) *
179                          sizeof(ULONG) + 3) & 0xfc);
180     }
181
182   if (SecurityDescriptor->Control & SE_DACL_PRESENT &&
183       SecurityDescriptor->Dacl != NULL)
184     {
185       Dacl = SecurityDescriptor->Dacl;
186       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
187         {
188           Dacl = (PACL)((ULONG)Dacl + (PVOID)SecurityDescriptor);
189         }
190       Length = Length + ((Dacl->AclSize + 3) & 0xfc);
191     }
192
193   if (SecurityDescriptor->Control & SE_SACL_PRESENT &&
194       SecurityDescriptor->Sacl != NULL)
195     {
196       Sacl = SecurityDescriptor->Sacl;
197       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
198         {
199           Sacl = (PACL)((ULONG)Sacl + (PVOID)SecurityDescriptor);
200         }
201       Length = Length + ((Sacl->AclSize + 3) & 0xfc);
202     }
203
204   return(Length);
205 }
206
207
208 /*
209  * @implemented
210  */
211 NTSTATUS STDCALL
212 RtlGetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
213                              PBOOLEAN DaclPresent,
214                              PACL* Dacl,
215                              PBOOLEAN DaclDefaulted)
216 {
217   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
218     {
219       return(STATUS_UNSUCCESSFUL);
220     }
221
222   if (!(SecurityDescriptor->Control & SE_DACL_PRESENT))
223     {
224       *DaclPresent = FALSE;
225       return(STATUS_SUCCESS);
226     }
227   *DaclPresent = TRUE;
228
229   if (SecurityDescriptor->Dacl == NULL)
230     {
231       *Dacl = NULL;
232     }
233   else
234     {
235       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
236         {
237           *Dacl = (PACL)((ULONG)SecurityDescriptor->Dacl +
238                          (PVOID)SecurityDescriptor);
239         }
240       else
241         {
242           *Dacl = SecurityDescriptor->Dacl;
243         }
244     }
245
246   if (SecurityDescriptor->Control & SE_DACL_DEFAULTED)
247     {
248       *DaclDefaulted = TRUE;
249     }
250   else
251     {
252       *DaclDefaulted = FALSE;
253     }
254
255   return(STATUS_SUCCESS);
256 }
257
258 #endif /* LIBCAPTIVE */
259
260 /*
261  * @implemented
262  */
263 NTSTATUS STDCALL
264 RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
265                              BOOLEAN DaclPresent,
266                              PACL Dacl,
267                              BOOLEAN DaclDefaulted)
268 {
269   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
270     {
271       return(STATUS_UNSUCCESSFUL);
272     }
273
274   if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
275     {
276       return(STATUS_UNSUCCESSFUL);
277     }
278
279   if (!DaclPresent)
280     {
281       SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_DACL_PRESENT);
282       return(STATUS_SUCCESS);
283     }
284
285   SecurityDescriptor->Control = SecurityDescriptor->Control | SE_DACL_PRESENT;
286   SecurityDescriptor->Dacl = Dacl;
287   SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_DACL_DEFAULTED);
288
289   if (DaclDefaulted)
290     {
291       SecurityDescriptor->Control = SecurityDescriptor->Control | SE_DACL_DEFAULTED;
292     }
293
294   return(STATUS_SUCCESS);
295 }
296
297 #ifndef LIBCAPTIVE
298
299 /*
300  * @implemented
301  */
302 BOOLEAN STDCALL
303 RtlValidSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor)
304 {
305   PSID Owner;
306   PSID Group;
307   PACL Sacl;
308   PACL Dacl;
309
310   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
311     {
312       return(FALSE);
313     }
314
315   Owner = SecurityDescriptor->Owner;
316   if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
317     {
318       Owner = (PSID)((ULONG)Owner + (ULONG)SecurityDescriptor);
319     }
320
321   if (!RtlValidSid(Owner))
322     {
323       return(FALSE);
324     }
325
326   Group = SecurityDescriptor->Group;
327   if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
328     {
329       Group = (PSID)((ULONG)Group + (ULONG)SecurityDescriptor);
330     }
331
332   if (!RtlValidSid(Group))
333     {
334       return(FALSE);
335     }
336
337   if (SecurityDescriptor->Control & SE_DACL_PRESENT &&
338       SecurityDescriptor->Dacl != NULL)
339     {
340       Dacl = SecurityDescriptor->Dacl;
341       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
342         {
343           Dacl = (PACL)((ULONG)Dacl + (ULONG)SecurityDescriptor);
344         }
345
346       if (!RtlValidAcl(Dacl))
347         {
348           return(FALSE);
349         }
350     }
351
352   if (SecurityDescriptor->Control & SE_SACL_PRESENT &&
353       SecurityDescriptor->Sacl != NULL)
354     {
355       Sacl = SecurityDescriptor->Sacl;
356       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
357         {
358           Sacl = (PACL)((ULONG)Sacl + (ULONG)SecurityDescriptor);
359         }
360
361       if (!RtlValidAcl(Sacl))
362         {
363           return(FALSE);
364         }
365     }
366
367   return(TRUE);
368 }
369
370
371 /*
372  * @implemented
373  */
374 NTSTATUS STDCALL
375 RtlSetOwnerSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
376                               PSID Owner,
377                               BOOLEAN OwnerDefaulted)
378 {
379   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
380     {
381       return(STATUS_UNSUCCESSFUL);
382     }
383
384   if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
385     {
386       return(STATUS_UNSUCCESSFUL);
387     }
388
389   SecurityDescriptor->Owner = Owner;
390   SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_OWNER_DEFAULTED);
391
392   if (OwnerDefaulted)
393     {
394       SecurityDescriptor->Control = SecurityDescriptor->Control | SE_OWNER_DEFAULTED;
395     }
396
397   return(STATUS_SUCCESS);
398 }
399
400
401 /*
402  * @implemented
403  */
404 NTSTATUS STDCALL
405 RtlGetOwnerSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
406                               PSID* Owner,
407                               PBOOLEAN OwnerDefaulted)
408 {
409   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
410     {
411       return(STATUS_UNSUCCESSFUL);
412     }
413
414   if (SecurityDescriptor->Owner != NULL)
415     {
416         if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
417           {
418              *Owner = (PSID)((ULONG)SecurityDescriptor->Owner +
419                              (PVOID)SecurityDescriptor);
420           }
421         else
422           {
423              *Owner = SecurityDescriptor->Owner;
424           }
425     }
426   else
427     {
428         *Owner = NULL;
429     }
430    if (SecurityDescriptor->Control & SE_OWNER_DEFAULTED)
431      {
432         *OwnerDefaulted = 1;
433      }
434    else
435      {
436         *OwnerDefaulted = 0;
437      }
438    return(STATUS_SUCCESS);
439 }
440
441
442 /*
443  * @implemented
444  */
445 NTSTATUS STDCALL
446 RtlSetGroupSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
447                               PSID Group,
448                               BOOLEAN GroupDefaulted)
449 {
450   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
451     {
452       return(STATUS_UNSUCCESSFUL);
453     }
454
455   if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
456     {
457       return(STATUS_UNSUCCESSFUL);
458     }
459
460   SecurityDescriptor->Group = Group;
461   SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_GROUP_DEFAULTED);
462
463   if (GroupDefaulted)
464     {
465       SecurityDescriptor->Control = SecurityDescriptor->Control | SE_GROUP_DEFAULTED;
466     }
467
468   return(STATUS_SUCCESS);
469 }
470
471
472 /*
473  * @implemented
474  */
475 NTSTATUS STDCALL
476 RtlGetGroupSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
477                               PSID* Group,
478                               PBOOLEAN GroupDefaulted)
479 {
480   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
481     {
482       return(STATUS_UNSUCCESSFUL);
483     }
484
485   if (SecurityDescriptor->Group != NULL)
486     {
487       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
488         {
489           *Group = (PSID)((ULONG)SecurityDescriptor->Group +
490                           (PVOID)SecurityDescriptor);
491         }
492       else
493         {
494           *Group = SecurityDescriptor->Group;
495         }
496     }
497   else
498     {
499       *Group = NULL;
500     }
501
502   if (SecurityDescriptor->Control & SE_GROUP_DEFAULTED)
503     {
504       *GroupDefaulted = TRUE;
505     }
506   else
507     {
508       *GroupDefaulted = FALSE;
509     }
510
511   return(STATUS_SUCCESS);
512 }
513
514
515 /*
516  * @implemented
517  */
518 NTSTATUS STDCALL
519 RtlGetSaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
520                              PBOOLEAN SaclPresent,
521                              PACL *Sacl,
522                              PBOOLEAN SaclDefaulted)
523 {
524   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
525     {
526       return(STATUS_UNSUCCESSFUL);
527     }
528
529   if (!(SecurityDescriptor->Control & SE_SACL_PRESENT))
530     {
531       *SaclPresent = FALSE;
532       return(STATUS_SUCCESS);
533     }
534   *SaclPresent = TRUE;
535
536   if (SecurityDescriptor->Sacl == NULL)
537     {
538       *Sacl = NULL;
539     }
540   else
541     {
542       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
543         {
544           *Sacl = (PACL)((ULONG)SecurityDescriptor->Sacl +
545                          (PVOID)SecurityDescriptor);
546         }
547       else
548         {
549           *Sacl = SecurityDescriptor->Sacl;
550         }
551     }
552
553   if (SecurityDescriptor->Control & SE_SACL_DEFAULTED)
554     {
555       *SaclDefaulted = TRUE;
556     }
557   else
558     {
559       *SaclDefaulted = FALSE;
560     }
561
562   return(STATUS_SUCCESS);
563 }
564
565
566 /*
567  * @implemented
568  */
569 NTSTATUS STDCALL
570 RtlSetSaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
571                              BOOLEAN SaclPresent,
572                              PACL Sacl,
573                              BOOLEAN SaclDefaulted)
574 {
575   if (SecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION)
576     {
577       return(STATUS_UNSUCCESSFUL);
578     }
579   if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
580     {
581       return(STATUS_UNSUCCESSFUL);
582     }
583
584   if (!SaclPresent)
585     {
586       SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_SACL_PRESENT);
587       return(STATUS_SUCCESS);
588     }
589
590   SecurityDescriptor->Control = SecurityDescriptor->Control | SE_SACL_PRESENT;
591   SecurityDescriptor->Sacl = Sacl;
592   SecurityDescriptor->Control = SecurityDescriptor->Control & ~(SE_SACL_DEFAULTED);
593
594   if (SaclDefaulted)
595     {
596       SecurityDescriptor->Control = SecurityDescriptor->Control | SE_SACL_DEFAULTED;
597     }
598
599   return(STATUS_SUCCESS);
600 }
601
602
603 static VOID
604 RtlpQuerySecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
605                             PSID* Owner,
606                             PULONG OwnerLength,
607                             PSID* Group,
608                             PULONG GroupLength,
609                             PACL* Dacl,
610                             PULONG DaclLength,
611                             PACL* Sacl,
612                             PULONG SaclLength)
613 {
614   if (SecurityDescriptor->Owner == NULL)
615     {
616       *Owner = NULL;
617     }
618   else
619     {
620       *Owner = SecurityDescriptor->Owner;
621       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
622         {
623           *Owner = (PSID)((ULONG)*Owner + (ULONG)SecurityDescriptor);
624         }
625     }
626
627   if (*Owner != NULL)
628     {
629       *OwnerLength = (RtlLengthSid(*Owner) + 3) & ~3;
630     }
631   else
632     {
633       *OwnerLength = 0;
634     }
635
636   if ((SecurityDescriptor->Control & SE_DACL_PRESENT) &&
637       SecurityDescriptor->Dacl != NULL)
638     {
639       *Dacl = SecurityDescriptor->Dacl;
640       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
641         {
642           *Dacl = (PACL)((ULONG)*Dacl + (ULONG)SecurityDescriptor);
643         }
644     }
645   else
646     {
647       *Dacl = NULL;
648     }
649
650   if (*Dacl != NULL)
651     {
652       *DaclLength = ((*Dacl)->AclSize + 3) & ~3;
653     }
654   else
655     {
656       *DaclLength = 0;
657     }
658
659   if (SecurityDescriptor->Group != NULL)
660     {
661       *Group = NULL;
662     }
663   else
664     {
665       *Group = SecurityDescriptor->Group;
666       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
667         {
668           *Group = (PSID)((ULONG)*Group + (ULONG)SecurityDescriptor);
669         }
670     }
671
672   if (*Group != NULL)
673     {
674       *GroupLength = (RtlLengthSid(*Group) + 3) & ~3;
675     }
676   else
677     {
678       *GroupLength = 0;
679     }
680
681   if ((SecurityDescriptor->Control & SE_SACL_PRESENT) &&
682       SecurityDescriptor->Sacl != NULL)
683     {
684       *Sacl = SecurityDescriptor->Sacl;
685       if (SecurityDescriptor->Control & SE_SELF_RELATIVE)
686         {
687           *Sacl = (PACL)((ULONG)*Sacl + (ULONG)SecurityDescriptor);
688         }
689     }
690   else
691     {
692       *Sacl = NULL;
693     }
694
695   if (*Sacl != NULL)
696     {
697       *SaclLength = ((*Sacl)->AclSize + 3) & ~3;
698     }
699 }
700
701
702 /*
703  * @implemented
704  */
705 NTSTATUS STDCALL
706 RtlAbsoluteToSelfRelativeSD(PSECURITY_DESCRIPTOR AbsSD,
707                             PSECURITY_DESCRIPTOR RelSD,
708                             PULONG BufferLength)
709 {
710   PSID Owner;
711   PSID Group;
712   PACL Sacl;
713   PACL Dacl;
714   ULONG OwnerLength;
715   ULONG GroupLength;
716   ULONG SaclLength;
717   ULONG DaclLength;
718   ULONG TotalLength;
719   ULONG Current;
720
721   if (AbsSD->Control & SE_SELF_RELATIVE)
722     {
723       return(STATUS_BAD_DESCRIPTOR_FORMAT);
724     }
725
726   RtlpQuerySecurityDescriptor(AbsSD,
727                               &Owner,
728                               &OwnerLength,
729                               &Group,
730                               &GroupLength,
731                               &Dacl,
732                               &DaclLength,
733                               &Sacl,
734                               &SaclLength);
735
736   TotalLength = OwnerLength + GroupLength + SaclLength +
737                 DaclLength + sizeof(SECURITY_DESCRIPTOR);
738   if (*BufferLength < TotalLength)
739     {
740       return(STATUS_BUFFER_TOO_SMALL);
741     }
742
743   RtlZeroMemory(RelSD,
744                 TotalLength);
745   memmove(RelSD,
746           AbsSD,
747           sizeof(SECURITY_DESCRIPTOR));
748   Current = (ULONG)RelSD + sizeof(SECURITY_DESCRIPTOR);
749
750   if (SaclLength != 0)
751     {
752       memmove((PVOID)Current,
753               Sacl,
754               SaclLength);
755       RelSD->Sacl = (PACL)((ULONG)Current - (ULONG)RelSD);
756       Current += SaclLength;
757     }
758
759   if (DaclLength != 0)
760     {
761       memmove((PVOID)Current,
762               Dacl,
763               DaclLength);
764       RelSD->Dacl = (PACL)((ULONG)Current - (ULONG)RelSD);
765       Current += DaclLength;
766     }
767
768   if (OwnerLength != 0)
769     {
770       memmove((PVOID)Current,
771               Owner,
772               OwnerLength);
773       RelSD->Owner = (PSID)((ULONG)Current - (ULONG)RelSD);
774       Current += OwnerLength;
775     }
776
777   if (GroupLength != 0)
778     {
779       memmove((PVOID)Current,
780               Group,
781               GroupLength);
782       RelSD->Group = (PSID)((ULONG)Current - (ULONG)RelSD);
783     }
784
785   RelSD->Control |= SE_SELF_RELATIVE;
786
787   return(STATUS_SUCCESS);
788 }
789
790 #endif /* LIBCAPTIVE */
791
792 /* EOF */