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