Make rtl use a single header. Helps for PCH and will help for the new Headers (no...
[reactos.git] / reactos / lib / rtl / acl.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * PURPOSE: Security manager
6 * FILE: lib/rtl/acl.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 "rtl.h"
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* FUNCTIONS ***************************************************************/
20
21 BOOLEAN STDCALL
22 RtlFirstFreeAce(PACL Acl,
23 PACE* Ace)
24 {
25 PACE Current;
26 PVOID AclEnd;
27 ULONG i;
28
29 PAGED_CODE_RTL();
30
31 Current = (PACE)(Acl + 1);
32 *Ace = NULL;
33 i = 0;
34 if (Acl->AceCount == 0)
35 {
36 *Ace = Current;
37 return(TRUE);
38 }
39 AclEnd = Acl->AclSize + (PVOID)Acl;
40 do
41 {
42 if ((PVOID)Current >= AclEnd)
43 {
44 return(FALSE);
45 }
46 if (Current->Header.AceType == ACCESS_ALLOWED_COMPOUND_ACE_TYPE &&
47 Acl->AclRevision < ACL_REVISION3)
48 {
49 return(FALSE);
50 }
51 Current = (PACE)((ULONG_PTR)Current + (ULONG_PTR)Current->Header.AceSize);
52 i++;
53 }
54 while (i < Acl->AceCount);
55
56 if ((PVOID)Current < AclEnd)
57 {
58 *Ace = Current;
59 }
60
61 return(TRUE);
62 }
63
64
65 /*
66 * @implemented
67 */
68 NTSTATUS STDCALL
69 RtlGetAce(PACL Acl,
70 ULONG AceIndex,
71 PACE *Ace)
72 {
73 ULONG i;
74
75 PAGED_CODE_RTL();
76
77 *Ace = (PACE)(Acl + 1);
78
79 if (Acl->AclRevision < MIN_ACL_REVISION ||
80 Acl->AclRevision > MAX_ACL_REVISION)
81 {
82 return(STATUS_INVALID_PARAMETER);
83 }
84
85 if (AceIndex >= Acl->AceCount)
86 {
87 return(STATUS_INVALID_PARAMETER);
88 }
89
90 for (i = 0; i < AceIndex; i++)
91 {
92 if ((PVOID)*Ace >= (PVOID)Acl + Acl->AclSize)
93 {
94 return(STATUS_INVALID_PARAMETER);
95 }
96 *Ace = (PACE)((PVOID)(*Ace) + (ULONG)(*Ace)->Header.AceSize);
97 }
98
99 if ((PVOID)*Ace >= (PVOID)Acl + Acl->AclSize)
100 {
101 return(STATUS_INVALID_PARAMETER);
102 }
103
104 return(STATUS_SUCCESS);
105 }
106
107
108 static NTSTATUS
109 RtlpAddKnownAce (PACL Acl,
110 ULONG Revision,
111 ULONG Flags,
112 ACCESS_MASK AccessMask,
113 PSID Sid,
114 ULONG Type)
115 {
116 PACE Ace;
117
118 PAGED_CODE_RTL();
119
120 if (!RtlValidSid(Sid))
121 {
122 return(STATUS_INVALID_SID);
123 }
124 if (Acl->AclRevision > MAX_ACL_REVISION ||
125 Revision > MAX_ACL_REVISION)
126 {
127 return(STATUS_UNKNOWN_REVISION);
128 }
129 if (Revision < Acl->AclRevision)
130 {
131 Revision = Acl->AclRevision;
132 }
133 if (!RtlFirstFreeAce(Acl, &Ace))
134 {
135 return(STATUS_INVALID_ACL);
136 }
137 if (Ace == NULL)
138 {
139 return(STATUS_ALLOTTED_SPACE_EXCEEDED);
140 }
141 if ((ULONG_PTR)Ace + RtlLengthSid(Sid) + sizeof(ACE) >
142 (ULONG_PTR)Acl + Acl->AclSize)
143 {
144 return(STATUS_ALLOTTED_SPACE_EXCEEDED);
145 }
146 Ace->Header.AceFlags = Flags;
147 Ace->Header.AceType = Type;
148 Ace->Header.AceSize = RtlLengthSid(Sid) + sizeof(ACE);
149 Ace->AccessMask = AccessMask;
150 RtlCopySid(RtlLengthSid(Sid), (PSID)(Ace + 1), Sid);
151 Acl->AceCount++;
152 Acl->AclRevision = Revision;
153 return(STATUS_SUCCESS);
154 }
155
156
157 /*
158 * @implemented
159 */
160 NTSTATUS STDCALL
161 RtlAddAccessAllowedAce (IN OUT PACL Acl,
162 IN ULONG Revision,
163 IN ACCESS_MASK AccessMask,
164 IN PSID Sid)
165 {
166 PAGED_CODE_RTL();
167
168 return RtlpAddKnownAce (Acl,
169 Revision,
170 0,
171 AccessMask,
172 Sid,
173 ACCESS_ALLOWED_ACE_TYPE);
174 }
175
176
177 /*
178 * @implemented
179 */
180 NTSTATUS STDCALL
181 RtlAddAccessAllowedAceEx (IN OUT PACL Acl,
182 IN ULONG Revision,
183 IN ULONG Flags,
184 IN ACCESS_MASK AccessMask,
185 IN PSID Sid)
186 {
187 PAGED_CODE_RTL();
188
189 return RtlpAddKnownAce (Acl,
190 Revision,
191 Flags,
192 AccessMask,
193 Sid,
194 ACCESS_ALLOWED_ACE_TYPE);
195 }
196
197
198 /*
199 * @implemented
200 */
201 NTSTATUS STDCALL
202 RtlAddAccessDeniedAce (PACL Acl,
203 ULONG Revision,
204 ACCESS_MASK AccessMask,
205 PSID Sid)
206 {
207 PAGED_CODE_RTL();
208
209 return RtlpAddKnownAce (Acl,
210 Revision,
211 0,
212 AccessMask,
213 Sid,
214 ACCESS_DENIED_ACE_TYPE);
215 }
216
217
218 /*
219 * @implemented
220 */
221 NTSTATUS STDCALL
222 RtlAddAccessDeniedAceEx (IN OUT PACL Acl,
223 IN ULONG Revision,
224 IN ULONG Flags,
225 IN ACCESS_MASK AccessMask,
226 IN PSID Sid)
227 {
228 PAGED_CODE_RTL();
229
230 return RtlpAddKnownAce (Acl,
231 Revision,
232 Flags,
233 AccessMask,
234 Sid,
235 ACCESS_DENIED_ACE_TYPE);
236 }
237
238
239 static VOID
240 RtlpAddData(PVOID AceList,
241 ULONG AceListLength,
242 PVOID Ace,
243 ULONG Offset)
244 {
245 if (Offset > 0)
246 {
247 memcpy((PVOID)Ace + AceListLength,
248 Ace,
249 Offset);
250 }
251
252 if (AceListLength != 0)
253 {
254 memcpy(Ace,
255 AceList,
256 AceListLength);
257 }
258 }
259
260
261 /*
262 * @implemented
263 */
264 NTSTATUS STDCALL
265 RtlAddAce(PACL Acl,
266 ULONG AclRevision,
267 ULONG StartingIndex,
268 PACE AceList,
269 ULONG AceListLength)
270 {
271 PACE Ace;
272 ULONG i;
273 PACE Current;
274 ULONG j;
275
276 PAGED_CODE_RTL();
277
278 if (Acl->AclRevision < MIN_ACL_REVISION ||
279 Acl->AclRevision > MAX_ACL_REVISION)
280 {
281 return(STATUS_INVALID_PARAMETER);
282 }
283
284 if (!RtlFirstFreeAce(Acl,&Ace))
285 {
286 return(STATUS_INVALID_PARAMETER);
287 }
288
289 if (Acl->AclRevision <= AclRevision)
290 {
291 AclRevision = Acl->AclRevision;
292 }
293
294 if (((PVOID)AceList + AceListLength) <= (PVOID)AceList)
295 {
296 return(STATUS_INVALID_PARAMETER);
297 }
298
299 i = 0;
300 Current = (PACE)(Acl + 1);
301 while ((PVOID)Current < ((PVOID)AceList + AceListLength))
302 {
303 if (AceList->Header.AceType == ACCESS_ALLOWED_COMPOUND_ACE_TYPE &&
304 AclRevision < ACL_REVISION3)
305 {
306 return(STATUS_INVALID_PARAMETER);
307 }
308 Current = (PACE)((PVOID)Current + Current->Header.AceSize);
309 }
310
311 if (Ace == NULL)
312 {
313 return(STATUS_BUFFER_TOO_SMALL);
314 }
315
316 if (((PVOID)Ace + AceListLength) >= ((PVOID)Acl + Acl->AclSize))
317 {
318 return(STATUS_BUFFER_TOO_SMALL);
319 }
320
321 if (StartingIndex != 0)
322 {
323 if (Acl->AceCount > 0)
324 {
325 Current = (PACE)(Acl + 1);
326 for (j = 0; j < StartingIndex; j++)
327 {
328 Current = (PACE)((PVOID)Current + Current->Header.AceSize);
329 }
330 }
331 }
332
333 RtlpAddData(AceList,
334 AceListLength,
335 Current,
336 (ULONG)Ace - (ULONG)Current);
337 Acl->AceCount = Acl->AceCount + i;
338 Acl->AclRevision = AclRevision;
339
340 return(STATUS_SUCCESS);
341 }
342
343
344 /*
345 * @implemented
346 */
347 NTSTATUS STDCALL
348 RtlAddAuditAccessAce(PACL Acl,
349 ULONG Revision,
350 ACCESS_MASK AccessMask,
351 PSID Sid,
352 BOOLEAN Success,
353 BOOLEAN Failure)
354 {
355 PACE Ace;
356 ULONG Flags = 0;
357
358 PAGED_CODE_RTL();
359
360 if (Success != FALSE)
361 {
362 Flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
363 }
364
365 if (Failure != FALSE)
366 {
367 Flags |= FAILED_ACCESS_ACE_FLAG;
368 }
369
370 if (!RtlValidSid(Sid))
371 {
372 return(STATUS_INVALID_SID);
373 }
374
375 if (Acl->AclRevision > MAX_ACL_REVISION ||
376 Revision > MAX_ACL_REVISION)
377 {
378 return(STATUS_REVISION_MISMATCH);
379 }
380
381 if (Revision < Acl->AclRevision)
382 {
383 Revision = Acl->AclRevision;
384 }
385
386 if (!RtlFirstFreeAce(Acl, &Ace))
387 {
388 return(STATUS_INVALID_ACL);
389 }
390
391 if (Ace == NULL)
392 {
393 return(STATUS_ALLOTTED_SPACE_EXCEEDED);
394 }
395
396 if (((PVOID)Ace + RtlLengthSid(Sid) + sizeof(ACE)) >= ((PVOID)Acl + Acl->AclSize))
397 {
398 return(STATUS_ALLOTTED_SPACE_EXCEEDED);
399 }
400
401 Ace->Header.AceFlags = Flags;
402 Ace->Header.AceType = SYSTEM_AUDIT_ACE_TYPE;
403 Ace->Header.AceSize = RtlLengthSid(Sid) + sizeof(ACE);
404 Ace->AccessMask = AccessMask;
405 RtlCopySid(RtlLengthSid(Sid),
406 (PSID)(Ace + 1),
407 Sid);
408 Acl->AceCount++;
409 Acl->AclRevision = Revision;
410
411 return(STATUS_SUCCESS);
412 }
413
414
415 /*
416 * @implemented
417 */
418 NTSTATUS STDCALL
419 RtlAddAuditAccessAceEx(PACL Acl,
420 ULONG Revision,
421 ULONG Flags,
422 ACCESS_MASK AccessMask,
423 PSID Sid,
424 BOOLEAN Success,
425 BOOLEAN Failure)
426 {
427 PACE Ace;
428
429 PAGED_CODE_RTL();
430
431 if (Success != FALSE)
432 {
433 Flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
434 }
435
436 if (Failure != FALSE)
437 {
438 Flags |= FAILED_ACCESS_ACE_FLAG;
439 }
440
441 if (!RtlValidSid(Sid))
442 {
443 return STATUS_INVALID_SID;
444 }
445
446 if (Acl->AclRevision > MAX_ACL_REVISION ||
447 Revision > MAX_ACL_REVISION)
448 {
449 return STATUS_REVISION_MISMATCH;
450 }
451
452 if (Revision < Acl->AclRevision)
453 {
454 Revision = Acl->AclRevision;
455 }
456
457 if (!RtlFirstFreeAce(Acl, &Ace))
458 {
459 return STATUS_INVALID_ACL;
460 }
461
462 if (Ace == NULL)
463 {
464 return STATUS_ALLOTTED_SPACE_EXCEEDED;
465 }
466
467 if (((PVOID)Ace + RtlLengthSid(Sid) + sizeof(ACE)) >= ((PVOID)Acl + Acl->AclSize))
468 {
469 return STATUS_ALLOTTED_SPACE_EXCEEDED;
470 }
471
472 Ace->Header.AceFlags = Flags;
473 Ace->Header.AceType = SYSTEM_AUDIT_ACE_TYPE;
474 Ace->Header.AceSize = RtlLengthSid(Sid) + sizeof(ACE);
475 Ace->AccessMask = AccessMask;
476 RtlCopySid(RtlLengthSid(Sid),
477 (PSID)(Ace + 1),
478 Sid);
479 Acl->AceCount++;
480 Acl->AclRevision = Revision;
481
482 return STATUS_SUCCESS;
483 }
484
485
486 static VOID
487 RtlpDeleteData(PVOID Ace,
488 ULONG AceSize,
489 ULONG Offset)
490 {
491 if (AceSize < Offset)
492 {
493 memcpy(Ace,
494 (PUCHAR)Ace + AceSize,
495 Offset - AceSize);
496 }
497
498 if (Offset - AceSize < Offset)
499 {
500 memset((PUCHAR)Ace + Offset - AceSize,
501 0,
502 AceSize);
503 }
504 }
505
506
507 /*
508 * @implemented
509 */
510 NTSTATUS STDCALL
511 RtlDeleteAce(PACL Acl,
512 ULONG AceIndex)
513 {
514 PACE Ace;
515 PACE Current;
516
517 PAGED_CODE_RTL();
518
519 if (Acl->AclRevision < MIN_ACL_REVISION ||
520 Acl->AclRevision > MAX_ACL_REVISION)
521 {
522 return(STATUS_INVALID_PARAMETER);
523 }
524
525 if (Acl->AceCount <= AceIndex)
526 {
527 return(STATUS_INVALID_PARAMETER);
528 }
529
530 if (!RtlFirstFreeAce(Acl, &Ace))
531 {
532 return(STATUS_INVALID_PARAMETER);
533 }
534
535 Current = (PACE)(Acl + 1);
536
537 while(AceIndex--)
538 {
539 Current = (PACE)((PVOID)Current + Current->Header.AceSize);
540 }
541
542 RtlpDeleteData(Current,
543 Current->Header.AceSize,
544 Ace - Current);
545 Acl->AceCount++;
546
547 return(STATUS_SUCCESS);
548 }
549
550
551 /*
552 * @implemented
553 */
554 NTSTATUS STDCALL
555 RtlCreateAcl(PACL Acl,
556 ULONG AclSize,
557 ULONG AclRevision)
558 {
559 PAGED_CODE_RTL();
560
561 if (AclSize < 8)
562 {
563 return(STATUS_BUFFER_TOO_SMALL);
564 }
565
566 if (AclRevision < MIN_ACL_REVISION ||
567 AclRevision > MAX_ACL_REVISION)
568 {
569 return(STATUS_INVALID_PARAMETER);
570 }
571
572 if (AclSize > 0xffff)
573 {
574 return(STATUS_INVALID_PARAMETER);
575 }
576
577 AclSize = ROUND_UP(AclSize, 4);
578 Acl->AclSize = AclSize;
579 Acl->AclRevision = AclRevision;
580 Acl->AceCount = 0;
581 Acl->Sbz1 = 0;
582 Acl->Sbz2 = 0;
583
584 return(STATUS_SUCCESS);
585 }
586
587
588 /*
589 * @implemented
590 */
591 NTSTATUS STDCALL
592 RtlQueryInformationAcl(PACL Acl,
593 PVOID Information,
594 ULONG InformationLength,
595 ACL_INFORMATION_CLASS InformationClass)
596 {
597 PACE Ace;
598
599 PAGED_CODE_RTL();
600
601 if (Acl->AclRevision < MIN_ACL_REVISION ||
602 Acl->AclRevision > MAX_ACL_REVISION)
603 {
604 return(STATUS_INVALID_PARAMETER);
605 }
606
607 switch (InformationClass)
608 {
609 case AclRevisionInformation:
610 {
611 PACL_REVISION_INFORMATION Info = (PACL_REVISION_INFORMATION)Information;
612
613 if (InformationLength < sizeof(ACL_REVISION_INFORMATION))
614 {
615 return(STATUS_BUFFER_TOO_SMALL);
616 }
617 Info->AclRevision = Acl->AclRevision;
618 }
619 break;
620
621 case AclSizeInformation:
622 {
623 PACL_SIZE_INFORMATION Info = (PACL_SIZE_INFORMATION)Information;
624
625 if (InformationLength < sizeof(ACL_SIZE_INFORMATION))
626 {
627 return(STATUS_BUFFER_TOO_SMALL);
628 }
629
630 if (!RtlFirstFreeAce(Acl, &Ace))
631 {
632 return(STATUS_INVALID_PARAMETER);
633 }
634
635 Info->AceCount = Acl->AceCount;
636 if (Ace != NULL)
637 {
638 Info->AclBytesInUse = (PVOID)Ace - (PVOID)Acl;
639 Info->AclBytesFree = Acl->AclSize - Info->AclBytesInUse;
640 }
641 else
642 {
643 Info->AclBytesInUse = Acl->AclSize;
644 Info->AclBytesFree = 0;
645 }
646 }
647 break;
648
649 default:
650 return(STATUS_INVALID_INFO_CLASS);
651 }
652
653 return(STATUS_SUCCESS);
654 }
655
656
657 /*
658 * @implemented
659 */
660 NTSTATUS STDCALL
661 RtlSetInformationAcl(PACL Acl,
662 PVOID Information,
663 ULONG InformationLength,
664 ACL_INFORMATION_CLASS InformationClass)
665 {
666 PAGED_CODE_RTL();
667
668 if (Acl->AclRevision < MIN_ACL_REVISION ||
669 Acl->AclRevision > MAX_ACL_REVISION)
670 {
671 return(STATUS_INVALID_PARAMETER);
672 }
673
674 switch (InformationClass)
675 {
676 case AclRevisionInformation:
677 {
678 PACL_REVISION_INFORMATION Info = (PACL_REVISION_INFORMATION)Information;
679
680 if (InformationLength < sizeof(ACL_REVISION_INFORMATION))
681 {
682 return(STATUS_BUFFER_TOO_SMALL);
683 }
684
685 if (Acl->AclRevision >= Info->AclRevision)
686 {
687 return(STATUS_INVALID_PARAMETER);
688 }
689
690 Acl->AclRevision = Info->AclRevision;
691 }
692 break;
693
694 default:
695 return(STATUS_INVALID_INFO_CLASS);
696 }
697
698 return(STATUS_SUCCESS);
699 }
700
701
702 /*
703 * @implemented
704 */
705 BOOLEAN STDCALL
706 RtlValidAcl (PACL Acl)
707 {
708 PACE Ace;
709 USHORT Size;
710
711 PAGED_CODE_RTL();
712
713 Size = ROUND_UP(Acl->AclSize, 4);
714
715 if (Acl->AclRevision < MIN_ACL_REVISION ||
716 Acl->AclRevision > MAX_ACL_REVISION)
717 {
718 return(FALSE);
719 }
720
721 if (Size != Acl->AclSize)
722 {
723 return(FALSE);
724 }
725
726 return(RtlFirstFreeAce(Acl, &Ace));
727 }
728
729 /* EOF */