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