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