[ATL] Add CString.AllocSysString
[reactos.git] / sdk / lib / rtl / acl.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * PURPOSE: Security manager
5 * FILE: lib/rtl/acl.c
6 * PROGRAMER: David Welch <welch@cwcom.net>
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <rtl.h>
12 #include <../../ntoskrnl/include/internal/se.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* PRIVATE FUNCTIONS **********************************************************/
17
18 BOOLEAN
19 NTAPI
20 RtlFirstFreeAce(IN PACL Acl,
21 OUT PACE* FirstFreeAce)
22 {
23 PACE Current;
24 ULONG_PTR AclEnd;
25 ULONG i;
26 PAGED_CODE_RTL();
27
28 /* Assume failure */
29 *FirstFreeAce = NULL;
30
31 /* Get the start and end pointers */
32 Current = (PACE)(Acl + 1);
33 AclEnd = (ULONG_PTR)Acl + Acl->AclSize;
34
35 /* Loop all the ACEs */
36 for (i = 0; i < Acl->AceCount; i++)
37 {
38 /* If any is beyond the DACL, bail out, otherwise keep going */
39 if ((ULONG_PTR)Current >= AclEnd) return FALSE;
40 Current = (PACE)((ULONG_PTR)Current + Current->Header.AceSize);
41 }
42
43 /* If the last spot is empty and still valid, return it */
44 if ((ULONG_PTR)Current <= AclEnd) *FirstFreeAce = Current;
45 return TRUE;
46 }
47
48 VOID
49 NTAPI
50 RtlpAddData(IN PVOID AceList,
51 IN ULONG AceListLength,
52 IN PVOID Ace,
53 IN ULONG Offset)
54 {
55 /* Shift the buffer down */
56 if (Offset > 0)
57 {
58 RtlCopyMemory((PVOID)((ULONG_PTR)Ace + AceListLength),
59 Ace,
60 Offset);
61 }
62
63 /* Copy the new data in */
64 if (AceListLength) RtlCopyMemory(Ace, AceList, AceListLength);
65 }
66
67 VOID
68 NTAPI
69 RtlpDeleteData(IN PVOID Ace,
70 IN ULONG AceSize,
71 IN ULONG Offset)
72 {
73 /* Move the data up */
74 if (AceSize < Offset)
75 {
76 RtlMoveMemory(Ace,
77 (PVOID)((ULONG_PTR)Ace + AceSize),
78 Offset - AceSize);
79 }
80
81 /* Zero the rest */
82 if ((Offset - AceSize) < Offset)
83 {
84 RtlZeroMemory((PVOID)((ULONG_PTR)Ace + Offset - AceSize), AceSize);
85 }
86 }
87
88 NTSTATUS
89 NTAPI
90 RtlpAddKnownAce(IN PACL Acl,
91 IN ULONG Revision,
92 IN ULONG Flags,
93 IN ACCESS_MASK AccessMask,
94 IN PSID Sid,
95 IN UCHAR Type)
96 {
97 PKNOWN_ACE Ace;
98 ULONG AceSize, InvalidFlags;
99 PAGED_CODE_RTL();
100
101 /* Check the validity of the SID */
102 if (!RtlValidSid(Sid)) return STATUS_INVALID_SID;
103
104 /* Check the validity of the revision */
105 if ((Acl->AclRevision > ACL_REVISION4) || (Revision > ACL_REVISION4))
106 {
107 return STATUS_REVISION_MISMATCH;
108 }
109
110 /* Pick the smallest of the revisions */
111 if (Revision < Acl->AclRevision) Revision = Acl->AclRevision;
112
113 /* Validate the flags */
114 if (Type == SYSTEM_AUDIT_ACE_TYPE)
115 {
116 InvalidFlags = Flags & ~(VALID_INHERIT_FLAGS |
117 SUCCESSFUL_ACCESS_ACE_FLAG |
118 FAILED_ACCESS_ACE_FLAG);
119 }
120 else
121 {
122 InvalidFlags = Flags & ~VALID_INHERIT_FLAGS;
123 }
124
125 /* If flags are invalid, bail out */
126 if (InvalidFlags != 0) return STATUS_INVALID_PARAMETER;
127
128 /* If ACL is invalid, bail out */
129 if (!RtlValidAcl(Acl)) return STATUS_INVALID_ACL;
130
131 /* If there's no free ACE, bail out */
132 if (!RtlFirstFreeAce(Acl, (PACE*)&Ace)) return STATUS_INVALID_ACL;
133
134 /* Calculate the size of the ACE and bail out if it's too small */
135 AceSize = RtlLengthSid(Sid) + sizeof(ACE);
136 if (!(Ace) || ((ULONG_PTR)Ace + AceSize > (ULONG_PTR)Acl + Acl->AclSize))
137 {
138 return STATUS_ALLOTTED_SPACE_EXCEEDED;
139 }
140
141 /* Initialize the header and common fields */
142 Ace->Header.AceFlags = (BYTE)Flags;
143 Ace->Header.AceType = Type;
144 Ace->Header.AceSize = (WORD)AceSize;
145 Ace->Mask = AccessMask;
146
147 /* Copy the SID */
148 RtlCopySid(RtlLengthSid(Sid), &Ace->SidStart, Sid);
149
150 /* Fill out the ACL header and return */
151 Acl->AceCount++;
152 Acl->AclRevision = (BYTE)Revision;
153 return STATUS_SUCCESS;
154 }
155
156 NTSTATUS
157 NTAPI
158 RtlpAddKnownObjectAce(IN PACL Acl,
159 IN ULONG Revision,
160 IN ULONG Flags,
161 IN ACCESS_MASK AccessMask,
162 IN GUID *ObjectTypeGuid OPTIONAL,
163 IN GUID *InheritedObjectTypeGuid OPTIONAL,
164 IN PSID Sid,
165 IN UCHAR Type)
166 {
167 PKNOWN_OBJECT_ACE Ace;
168 ULONG_PTR SidStart;
169 ULONG AceSize, InvalidFlags, AceObjectFlags = 0;
170 PAGED_CODE_RTL();
171
172 /* Check the validity of the SID */
173 if (!RtlValidSid(Sid)) return STATUS_INVALID_SID;
174
175 /* Check the validity of the revision */
176 if ((Acl->AclRevision > ACL_REVISION4) || (Revision > ACL_REVISION4))
177 {
178 return STATUS_REVISION_MISMATCH;
179 }
180
181 /* Pick the smallest of the revisions */
182 if (Revision < Acl->AclRevision) Revision = Acl->AclRevision;
183
184 /* Validate the flags */
185 if ((Type == SYSTEM_AUDIT_OBJECT_ACE_TYPE) ||
186 (Type == SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE))
187 {
188 InvalidFlags = Flags & ~(VALID_INHERIT_FLAGS |
189 SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG);
190 }
191 else
192 {
193 InvalidFlags = Flags & ~VALID_INHERIT_FLAGS;
194 }
195
196 /* If flags are invalid, bail out */
197 if (InvalidFlags != 0) return STATUS_INVALID_PARAMETER;
198
199 /* If ACL is invalid, bail out */
200 if (!RtlValidAcl(Acl)) return STATUS_INVALID_ACL;
201
202 /* If there's no free ACE, bail out */
203 if (!RtlFirstFreeAce(Acl, (PACE*)&Ace)) return STATUS_INVALID_ACL;
204
205 /* Calculate the size of the ACE */
206 AceSize = RtlLengthSid(Sid) + sizeof(ACE) + sizeof(ULONG);
207
208 /* Add-in the size of the GUIDs if any and update flags as needed */
209 if (ObjectTypeGuid)
210 {
211 AceObjectFlags |= ACE_OBJECT_TYPE_PRESENT;
212 AceSize += sizeof(GUID);
213 }
214 if (InheritedObjectTypeGuid)
215 {
216 AceObjectFlags |= ACE_INHERITED_OBJECT_TYPE_PRESENT;
217 AceSize += sizeof(GUID);
218 }
219
220 /* Bail out if there's not enough space in the ACL */
221 if (!(Ace) || ((ULONG_PTR)Ace + AceSize > (ULONG_PTR)Acl + Acl->AclSize))
222 {
223 return STATUS_ALLOTTED_SPACE_EXCEEDED;
224 }
225
226 /* Initialize the header and common fields */
227 Ace->Header.AceFlags = (BYTE)Flags;
228 Ace->Header.AceType = Type;
229 Ace->Header.AceSize = (WORD)AceSize;
230 Ace->Mask = AccessMask;
231 Ace->Flags = AceObjectFlags;
232
233 /* Copy the GUIDs */
234 SidStart = (ULONG_PTR)&Ace->SidStart;
235 if (ObjectTypeGuid )
236 {
237 RtlCopyMemory((PVOID)SidStart, ObjectTypeGuid, sizeof(GUID));
238 SidStart += sizeof(GUID);
239 }
240 if (InheritedObjectTypeGuid)
241 {
242 RtlCopyMemory((PVOID)SidStart, InheritedObjectTypeGuid, sizeof(GUID));
243 SidStart += sizeof(GUID);
244 }
245
246 /* Copy the SID */
247 RtlCopySid(RtlLengthSid(Sid), (PSID)SidStart, Sid);
248
249 /* Fill out the ACL header and return */
250 Acl->AceCount++;
251 Acl->AclRevision = (BYTE)Revision;
252 return STATUS_SUCCESS;
253 }
254
255 /* PUBLIC FUNCTIONS ***********************************************************/
256
257 /*
258 * @implemented
259 */
260 NTSTATUS
261 NTAPI
262 RtlAddAccessAllowedAce(IN OUT PACL Acl,
263 IN ULONG Revision,
264 IN ACCESS_MASK AccessMask,
265 IN PSID Sid)
266 {
267 PAGED_CODE_RTL();
268
269 /* Call the worker function */
270 return RtlpAddKnownAce(Acl,
271 Revision,
272 0,
273 AccessMask,
274 Sid,
275 ACCESS_ALLOWED_ACE_TYPE);
276 }
277
278 /*
279 * @implemented
280 */
281 NTSTATUS
282 NTAPI
283 RtlAddAccessAllowedAceEx(IN OUT PACL Acl,
284 IN ULONG Revision,
285 IN ULONG Flags,
286 IN ACCESS_MASK AccessMask,
287 IN PSID Sid)
288 {
289 PAGED_CODE_RTL();
290
291 /* Call the worker function */
292 return RtlpAddKnownAce(Acl,
293 Revision,
294 Flags,
295 AccessMask,
296 Sid,
297 ACCESS_ALLOWED_ACE_TYPE);
298 }
299
300 /*
301 * @implemented
302 */
303 NTSTATUS
304 NTAPI
305 RtlAddAccessAllowedObjectAce(IN OUT PACL Acl,
306 IN ULONG Revision,
307 IN ULONG Flags,
308 IN ACCESS_MASK AccessMask,
309 IN GUID *ObjectTypeGuid OPTIONAL,
310 IN GUID *InheritedObjectTypeGuid OPTIONAL,
311 IN PSID Sid)
312 {
313 PAGED_CODE_RTL();
314
315 /* Is there no object data? */
316 if (!(ObjectTypeGuid) && !(InheritedObjectTypeGuid))
317 {
318 /* Use the usual routine */
319 return RtlpAddKnownAce(Acl,
320 Revision,
321 Flags,
322 AccessMask,
323 Sid,
324 ACCESS_ALLOWED_ACE_TYPE);
325 }
326
327 /* Use the object routine */
328 return RtlpAddKnownObjectAce(Acl,
329 Revision,
330 Flags,
331 AccessMask,
332 ObjectTypeGuid,
333 InheritedObjectTypeGuid,
334 Sid,
335 ACCESS_ALLOWED_OBJECT_ACE_TYPE);
336 }
337
338 /*
339 * @implemented
340 */
341 NTSTATUS
342 NTAPI
343 RtlAddAccessDeniedAce(IN PACL Acl,
344 IN ULONG Revision,
345 IN ACCESS_MASK AccessMask,
346 IN PSID Sid)
347 {
348 PAGED_CODE_RTL();
349
350 /* Call the worker function */
351 return RtlpAddKnownAce(Acl,
352 Revision,
353 0,
354 AccessMask,
355 Sid,
356 ACCESS_DENIED_ACE_TYPE);
357 }
358
359 /*
360 * @implemented
361 */
362 NTSTATUS
363 NTAPI
364 RtlAddAccessDeniedAceEx(IN OUT PACL Acl,
365 IN ULONG Revision,
366 IN ULONG Flags,
367 IN ACCESS_MASK AccessMask,
368 IN PSID Sid)
369 {
370 PAGED_CODE_RTL();
371
372 /* Call the worker function */
373 return RtlpAddKnownAce(Acl,
374 Revision,
375 Flags,
376 AccessMask,
377 Sid,
378 ACCESS_DENIED_ACE_TYPE);
379 }
380
381 /*
382 * @implemented
383 */
384 NTSTATUS
385 NTAPI
386 RtlAddAccessDeniedObjectAce(IN OUT PACL Acl,
387 IN ULONG Revision,
388 IN ULONG Flags,
389 IN ACCESS_MASK AccessMask,
390 IN GUID *ObjectTypeGuid OPTIONAL,
391 IN GUID *InheritedObjectTypeGuid OPTIONAL,
392 IN PSID Sid)
393 {
394 PAGED_CODE_RTL();
395
396 /* Is there no object data? */
397 if (!(ObjectTypeGuid) && !(InheritedObjectTypeGuid))
398 {
399 /* Use the usual routine */
400 return RtlpAddKnownAce(Acl,
401 Revision,
402 Flags,
403 AccessMask,
404 Sid,
405 ACCESS_DENIED_ACE_TYPE);
406 }
407
408 /* There's object data, use the object routine */
409 return RtlpAddKnownObjectAce(Acl,
410 Revision,
411 Flags,
412 AccessMask,
413 ObjectTypeGuid,
414 InheritedObjectTypeGuid,
415 Sid,
416 ACCESS_DENIED_OBJECT_ACE_TYPE);
417 }
418
419 /*
420 * @implemented
421 */
422 NTSTATUS
423 NTAPI
424 RtlAddAuditAccessAce(IN PACL Acl,
425 IN ULONG Revision,
426 IN ACCESS_MASK AccessMask,
427 IN PSID Sid,
428 IN BOOLEAN Success,
429 IN BOOLEAN Failure)
430 {
431 ULONG Flags = 0;
432 PAGED_CODE_RTL();
433
434 /* Add flags */
435 if (Success) Flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
436 if (Failure) Flags |= FAILED_ACCESS_ACE_FLAG;
437
438 /* Call the worker routine */
439 return RtlpAddKnownAce(Acl,
440 Revision,
441 Flags,
442 AccessMask,
443 Sid,
444 SYSTEM_AUDIT_ACE_TYPE);
445 }
446
447 /*
448 * @implemented
449 */
450 NTSTATUS
451 NTAPI
452 RtlAddAuditAccessAceEx(IN PACL Acl,
453 IN ULONG Revision,
454 IN ULONG Flags,
455 IN ACCESS_MASK AccessMask,
456 IN PSID Sid,
457 IN BOOLEAN Success,
458 IN BOOLEAN Failure)
459 {
460 PAGED_CODE_RTL();
461
462 /* Add flags */
463 if (Success) Flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
464 if (Failure) Flags |= FAILED_ACCESS_ACE_FLAG;
465
466 /* Call the worker routine */
467 return RtlpAddKnownAce(Acl,
468 Revision,
469 Flags,
470 AccessMask,
471 Sid,
472 SYSTEM_AUDIT_ACE_TYPE);
473 }
474
475 /*
476 * @implemented
477 */
478 NTSTATUS
479 NTAPI
480 RtlAddAuditAccessObjectAce(IN PACL Acl,
481 IN ULONG Revision,
482 IN ULONG Flags,
483 IN ACCESS_MASK AccessMask,
484 IN GUID *ObjectTypeGuid OPTIONAL,
485 IN GUID *InheritedObjectTypeGuid OPTIONAL,
486 IN PSID Sid,
487 IN BOOLEAN Success,
488 IN BOOLEAN Failure)
489 {
490 /* Add flags */
491 if (Success) Flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
492 if (Failure) Flags |= FAILED_ACCESS_ACE_FLAG;
493
494 /* Is there no object data? */
495 if (!(ObjectTypeGuid) && !(InheritedObjectTypeGuid))
496 {
497 /* Call the normal routine */
498 return RtlpAddKnownAce(Acl,
499 Revision,
500 Flags,
501 AccessMask,
502 Sid,
503 SYSTEM_AUDIT_ACE_TYPE);
504 }
505
506 /* There's object data, use the object routine */
507 return RtlpAddKnownObjectAce(Acl,
508 Revision,
509 Flags,
510 AccessMask,
511 ObjectTypeGuid,
512 InheritedObjectTypeGuid,
513 Sid,
514 SYSTEM_AUDIT_OBJECT_ACE_TYPE);
515 }
516
517 /*
518 * @implemented
519 */
520 NTSTATUS
521 NTAPI
522 RtlGetAce(IN PACL Acl,
523 IN ULONG AceIndex,
524 OUT PVOID *Ace)
525 {
526 ULONG i;
527 PAGED_CODE_RTL();
528
529 /* Bail out if the revision or the index are invalid */
530 if ((Acl->AclRevision < MIN_ACL_REVISION) ||
531 (Acl->AclRevision > MAX_ACL_REVISION) ||
532 (AceIndex >= Acl->AceCount))
533 {
534 return STATUS_INVALID_PARAMETER;
535 }
536
537 /* Loop through the ACEs */
538 *Ace = (PVOID)((PACE)(Acl + 1));
539 for (i = 0; i < AceIndex; i++)
540 {
541 /* Bail out if an invalid ACE is ever found */
542 if ((ULONG_PTR)*Ace >= (ULONG_PTR)Acl + Acl->AclSize)
543 {
544 return STATUS_INVALID_PARAMETER;
545 }
546
547 /* Keep going */
548 *Ace = (PVOID)((PACE)((ULONG_PTR)(*Ace) + ((PACE)(*Ace))->Header.AceSize));
549 }
550
551 /* Check if the last ACE is still valid */
552 if ((ULONG_PTR)*Ace >= (ULONG_PTR)Acl + Acl->AclSize)
553 {
554 return STATUS_INVALID_PARAMETER;
555 }
556
557 /* All good, return */
558 return STATUS_SUCCESS;
559 }
560
561 /*
562 * @implemented
563 */
564 NTSTATUS
565 NTAPI
566 RtlAddAce(IN PACL Acl,
567 IN ULONG AclRevision,
568 IN ULONG StartingIndex,
569 IN PVOID AceList,
570 IN ULONG AceListLength)
571 {
572 PACE Ace, FreeAce;
573 USHORT NewAceCount;
574 ULONG Index;
575 PAGED_CODE_RTL();
576
577 /* Bail out if the ACL is invalid */
578 if (!RtlValidAcl(Acl)) return STATUS_INVALID_PARAMETER;
579
580 /* Bail out if there's no space */
581 if (!RtlFirstFreeAce(Acl, &FreeAce)) return STATUS_INVALID_PARAMETER;
582
583 /* Loop over all the ACEs, keeping track of new ACEs as we go along */
584 for (Ace = AceList, NewAceCount = 0;
585 Ace < (PACE)((ULONG_PTR)AceList + AceListLength);
586 NewAceCount++)
587 {
588 /* Make sure that the revision of this ACE is valid in this list.
589 The initial check looks strange, but it is what Windows does. */
590 if (Ace->Header.AceType <= ACCESS_MAX_MS_ACE_TYPE)
591 {
592 if (Ace->Header.AceType > ACCESS_MAX_MS_V3_ACE_TYPE)
593 {
594 if (AclRevision < ACL_REVISION4) return STATUS_INVALID_PARAMETER;
595 }
596 else if (Ace->Header.AceType > ACCESS_MAX_MS_V2_ACE_TYPE)
597 {
598 if (AclRevision < ACL_REVISION3) return STATUS_INVALID_PARAMETER;
599 }
600 }
601
602 /* Move to the next ACE */
603 Ace = (PACE)((ULONG_PTR)Ace + Ace->Header.AceSize);
604 }
605
606 /* Bail out if there's no more space for us */
607 if ((ULONG_PTR)Ace > ((ULONG_PTR)AceList + AceListLength))
608 {
609 return STATUS_INVALID_PARAMETER;
610 }
611
612 /* Bail out if there's no free ACE spot, or if we would overflow it */
613 if (!(FreeAce) ||
614 ((ULONG_PTR)FreeAce + AceListLength > (ULONG_PTR)Acl + Acl->AclSize))
615 {
616 return STATUS_BUFFER_TOO_SMALL;
617 }
618
619 /* Go down the list until we find our index */
620 Ace = (PACE)(Acl + 1);
621 for (Index = 0; (Index < StartingIndex) && (Index < Acl->AceCount); Index++)
622 {
623 Ace = (PACE)((ULONG_PTR)Ace + Ace->Header.AceSize);
624 }
625
626 /* Found where we want to do, add us to the list */
627 RtlpAddData(AceList,
628 AceListLength,
629 Ace,
630 (ULONG_PTR)FreeAce - (ULONG_PTR)Ace);
631
632 /* Update the header and return */
633 Acl->AceCount += NewAceCount;
634 Acl->AclRevision = (UCHAR)min(Acl->AclRevision, AclRevision);
635 return STATUS_SUCCESS;
636 }
637
638 /*
639 * @implemented
640 */
641 NTSTATUS
642 NTAPI
643 RtlDeleteAce(IN PACL Acl,
644 IN ULONG AceIndex)
645 {
646 PACE FreeAce, Ace;
647 PAGED_CODE_RTL();
648
649 /* Bail out if the ACL is invalid */
650 if (!RtlValidAcl(Acl)) return STATUS_INVALID_PARAMETER;
651
652 /* Bail out if there's no space or if we're full */
653 if ((Acl->AceCount <= AceIndex) || !(RtlFirstFreeAce(Acl, &FreeAce)))
654 {
655 return STATUS_INVALID_PARAMETER;
656 }
657
658 /* Enumerate until the indexed ACE is reached */
659 Ace = (PACE)(Acl + 1);
660 while (AceIndex--) Ace = (PACE)((ULONG_PTR)Ace + Ace->Header.AceSize);
661
662 /* Delete this ACE */
663 RtlpDeleteData(Ace,
664 Ace->Header.AceSize,
665 (ULONG)((ULONG_PTR)FreeAce - (ULONG_PTR)Ace));
666
667 /* Decrease an ACE and return success */
668 Acl->AceCount--;
669 return STATUS_SUCCESS;
670 }
671
672 /*
673 * @implemented
674 */
675 NTSTATUS
676 NTAPI
677 RtlCreateAcl(IN PACL Acl,
678 IN ULONG AclSize,
679 IN ULONG AclRevision)
680 {
681 PAGED_CODE_RTL();
682
683 /* Bail out if too small */
684 if (AclSize < sizeof(ACL)) return STATUS_BUFFER_TOO_SMALL;
685
686 /* Bail out if too large or invalid revision */
687 if ((AclRevision < MIN_ACL_REVISION) ||
688 (AclRevision > MAX_ACL_REVISION) ||
689 (AclSize > MAXUSHORT))
690 {
691 return STATUS_INVALID_PARAMETER;
692 }
693
694 /* Setup the header */
695 Acl->AclSize = (USHORT)ROUND_UP(AclSize, 4);
696 Acl->AclRevision = (UCHAR)AclRevision;
697 Acl->AceCount = 0;
698 Acl->Sbz1 = 0;
699 Acl->Sbz2 = 0;
700 return STATUS_SUCCESS;
701 }
702
703 /*
704 * @implemented
705 */
706 NTSTATUS
707 NTAPI
708 RtlQueryInformationAcl(IN PACL Acl,
709 IN PVOID Information,
710 IN ULONG InformationLength,
711 IN ACL_INFORMATION_CLASS InformationClass)
712 {
713 PACE Ace;
714 PACL_REVISION_INFORMATION RevisionInfo;
715 PACL_SIZE_INFORMATION SizeInfo;
716 PAGED_CODE_RTL();
717
718 /* Validate the ACL revision */
719 if ((Acl->AclRevision < MIN_ACL_REVISION) ||
720 (Acl->AclRevision > MAX_ACL_REVISION))
721 {
722 return STATUS_INVALID_PARAMETER;
723 }
724
725 /* Check what the caller is querying */
726 switch (InformationClass)
727 {
728 /* Revision data */
729 case AclRevisionInformation:
730
731 /* Bail out if the buffer is too small */
732 if (InformationLength < sizeof(ACL_REVISION_INFORMATION))
733 {
734 return STATUS_BUFFER_TOO_SMALL;
735 }
736
737 /* Return the current revision */
738 RevisionInfo = (PACL_REVISION_INFORMATION)Information;
739 RevisionInfo->AclRevision = Acl->AclRevision;
740 break;
741
742 /* Size data */
743 case AclSizeInformation:
744
745 /* Bail out if the buffer is too small */
746 if (InformationLength < sizeof(ACL_SIZE_INFORMATION))
747 {
748 return STATUS_BUFFER_TOO_SMALL;
749 }
750
751 /* Bail out if there's no space in the ACL */
752 if (!RtlFirstFreeAce(Acl, &Ace)) return STATUS_INVALID_PARAMETER;
753
754 /* Read the number of ACEs and check if there was a free ACE */
755 SizeInfo = (PACL_SIZE_INFORMATION)Information;
756 SizeInfo->AceCount = Acl->AceCount;
757 if (Ace)
758 {
759 /* Return how much space there is in the ACL */
760 SizeInfo->AclBytesInUse = (ULONG_PTR)Ace - (ULONG_PTR)Acl;
761 SizeInfo->AclBytesFree = Acl->AclSize - SizeInfo->AclBytesInUse;
762 }
763 else
764 {
765 /* No free ACE, means the whole ACL is full */
766 SizeInfo->AclBytesInUse = Acl->AclSize;
767 SizeInfo->AclBytesFree = 0;
768 }
769 break;
770
771 default:
772 /* Anything else is illegal */
773 return STATUS_INVALID_INFO_CLASS;
774 }
775
776 /* All done */
777 return STATUS_SUCCESS;
778 }
779
780 /*
781 * @implemented
782 */
783 NTSTATUS
784 NTAPI
785 RtlSetInformationAcl(IN PACL Acl,
786 IN PVOID Information,
787 IN ULONG InformationLength,
788 IN ACL_INFORMATION_CLASS InformationClass)
789 {
790 PACL_REVISION_INFORMATION Info ;
791 PAGED_CODE_RTL();
792
793 /* Validate the ACL revision */
794 if ((Acl->AclRevision < MIN_ACL_REVISION) ||
795 (Acl->AclRevision > MAX_ACL_REVISION))
796 {
797 return STATUS_INVALID_PARAMETER;
798 }
799
800 /* What is the caller trying to set? */
801 switch (InformationClass)
802 {
803 /* This is the only info class */
804 case AclRevisionInformation:
805
806 /* Make sure the buffer is large enough */
807 if (InformationLength < sizeof(ACL_REVISION_INFORMATION))
808 {
809 return STATUS_BUFFER_TOO_SMALL;
810 }
811
812 /* Make sure the new revision is within the acceptable bounds*/
813 Info = (PACL_REVISION_INFORMATION)Information;
814 if (Acl->AclRevision >= Info->AclRevision)
815 {
816 return STATUS_INVALID_PARAMETER;
817 }
818
819 /* Set the new revision */
820 Acl->AclRevision = (BYTE)Info->AclRevision;
821 break;
822
823 default:
824 /* Anything else is invalid */
825 return STATUS_INVALID_INFO_CLASS;
826 }
827
828 /* All good */
829 return STATUS_SUCCESS;
830 }
831
832 /*
833 * @implemented
834 */
835 BOOLEAN
836 NTAPI
837 RtlValidAcl(IN PACL Acl)
838 {
839 PACE_HEADER Ace;
840 PISID Sid;
841 ULONG i;
842 PAGED_CODE_RTL();
843
844 _SEH2_TRY
845 {
846 /* First, validate the revision */
847 if ((Acl->AclRevision < MIN_ACL_REVISION) ||
848 (Acl->AclRevision > MAX_ACL_REVISION))
849 {
850 DPRINT1("Invalid ACL revision\n");
851 _SEH2_YIELD(return FALSE);
852 }
853
854 /* Next, validate that the ACL is USHORT-aligned */
855 if (ROUND_DOWN(Acl->AclSize, sizeof(USHORT)) != Acl->AclSize)
856 {
857 DPRINT1("Invalid ACL size\n");
858 _SEH2_YIELD(return FALSE);
859 }
860
861 /* And that it's big enough */
862 if (Acl->AclSize < sizeof(ACL))
863 {
864 DPRINT1("Invalid ACL size\n");
865 _SEH2_YIELD(return FALSE);
866 }
867
868 /* Loop each ACE */
869 Ace = (PACE_HEADER)((ULONG_PTR)Acl + sizeof(ACL));
870 for (i = 0; i < Acl->AceCount; i++)
871 {
872 /* Validate we have space for this ACE header */
873 if (((ULONG_PTR)Ace + sizeof(ACE_HEADER)) >= ((ULONG_PTR)Acl + Acl->AclSize))
874 {
875 DPRINT1("Invalid ACE size\n");
876 _SEH2_YIELD(return FALSE);
877 }
878
879 /* Validate the length of this ACE */
880 if (ROUND_DOWN(Ace->AceSize, sizeof(USHORT)) != Ace->AceSize)
881 {
882 DPRINT1("Invalid ACE size: %lx\n", Ace->AceSize);
883 _SEH2_YIELD(return FALSE);
884 }
885
886 /* Validate we have space for the entire ACE */
887 if (((ULONG_PTR)Ace + Ace->AceSize) > ((ULONG_PTR)Acl + Acl->AclSize))
888 {
889 DPRINT1("Invalid ACE size %lx %lx\n", Ace->AceSize, Acl->AclSize);
890 _SEH2_YIELD(return FALSE);
891 }
892
893 /* Check what kind of ACE this is */
894 if (Ace->AceType <= ACCESS_MAX_MS_V2_ACE_TYPE)
895 {
896 /* Validate the length of this ACE */
897 if (ROUND_DOWN(Ace->AceSize, sizeof(ULONG)) != Ace->AceSize)
898 {
899 DPRINT1("Invalid ACE size\n");
900 _SEH2_YIELD(return FALSE);
901 }
902
903 /* The ACE size should at least have enough for the header */
904 if (Ace->AceSize < sizeof(ACE_HEADER))
905 {
906 DPRINT1("Invalid ACE size: %lx %lx\n", Ace->AceSize, sizeof(ACE_HEADER));
907 _SEH2_YIELD(return FALSE);
908 }
909
910 /* Check if the SID revision is valid */
911 Sid = (PISID)&((PKNOWN_ACE)Ace)->SidStart;
912 if (Sid->Revision != SID_REVISION)
913 {
914 DPRINT1("Invalid SID\n");
915 _SEH2_YIELD(return FALSE);
916 }
917
918 /* Check if the SID is out of bounds */
919 if (Sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES)
920 {
921 DPRINT1("Invalid SID\n");
922 _SEH2_YIELD(return FALSE);
923 }
924
925 /* The ACE size should at least have enough for the header and SID */
926 if (Ace->AceSize < (sizeof(ACE_HEADER) + RtlLengthSid(Sid)))
927 {
928 DPRINT1("Invalid ACE size\n");
929 _SEH2_YIELD(return FALSE);
930 }
931 }
932 else if (Ace->AceType == ACCESS_ALLOWED_COMPOUND_ACE_TYPE)
933 {
934 DPRINT1("Unsupported ACE in ReactOS, assuming valid\n");
935 }
936 else if ((Ace->AceType >= ACCESS_MIN_MS_OBJECT_ACE_TYPE) &&
937 (Ace->AceType <= ACCESS_MAX_MS_OBJECT_ACE_TYPE))
938 {
939 DPRINT1("Unsupported ACE in ReactOS, assuming valid\n");
940 }
941 else
942 {
943 /* Unknown ACE, see if it's as big as a header at least */
944 if (Ace->AceSize < sizeof(ACE_HEADER))
945 {
946 DPRINT1("Unknown ACE\n");
947 _SEH2_YIELD(return FALSE);
948 }
949 }
950
951 /* Move to the next ace */
952 Ace = (PACE_HEADER)((ULONG_PTR)Ace + Ace->AceSize);
953 }
954 }
955 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
956 {
957 /* Something was invalid, fail */
958 _SEH2_YIELD(return FALSE);
959 }
960 _SEH2_END;
961
962 /* The ACL looks ok */
963 return TRUE;
964 }
965
966 /* EOF */