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