Added missing Acl and SD functions from ntdll.
[reactos.git] / reactos / ntoskrnl / se / sd.c
1 /* $Id: sd.c,v 1.9 2003/02/15 21:07:49 ekohl Exp $
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 */