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