:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / lib / ntdll / 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:              kernel/se/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
16 #include <ntdll/ntdll.h>
17
18 /* FUNCTIONS ***************************************************************/
19
20 BOOLEAN STDCALL
21 RtlFirstFreeAce(PACL Acl,
22                 PACE* Ace)
23 {
24   PACE Current;
25   PVOID AclEnd;
26   ULONG i;
27
28   Current = (PACE)(Acl + 1);
29   *Ace = NULL;
30   i = 0;
31   if (Acl->AceCount == 0)
32     {
33       *Ace = Current;
34       return(TRUE);
35     }
36   AclEnd = Acl->AclSize + (PVOID)Acl;
37   do
38     {
39       if ((PVOID)Current >= AclEnd)
40         {
41           return(FALSE);
42         }
43       if (Current->Header.AceType == 4)
44         {
45           if (Acl->AclRevision < 3)
46             {
47               return(FALSE);
48             }
49         }
50       Current = (PACE)((PVOID)Current + (ULONG)Current->Header.AceSize);
51       i++;
52     }
53   while (i < Acl->AceCount);
54
55   if ((PVOID)Current < AclEnd)
56     {
57       *Ace = Current;
58     }
59
60   return(TRUE);
61 }
62
63
64 NTSTATUS STDCALL
65 RtlGetAce(PACL Acl,
66           ULONG AceIndex,
67           PACE *Ace)
68 {
69   ULONG i;
70
71   *Ace = (PACE)(Acl + 1);
72
73   if (Acl->AclRevision != 2 &&
74       Acl->AclRevision != 3)
75     {
76       return(STATUS_INVALID_PARAMETER);
77     }
78
79   if (AceIndex >= Acl->AceCount)
80     {
81       return(STATUS_INVALID_PARAMETER);
82     }
83
84   for (i = 0; i < AceIndex; i++)
85     {
86       if ((PVOID)*Ace >= (PVOID)Acl + Acl->AclSize)
87         {
88           return(STATUS_INVALID_PARAMETER);
89         }
90       *Ace = (PACE)((PVOID)(*Ace) + (ULONG)(*Ace)->Header.AceSize);
91     }
92
93   if ((PVOID)*Ace >= (PVOID)Acl + Acl->AclSize)
94     {
95       return(STATUS_INVALID_PARAMETER);
96     }
97
98   return(STATUS_SUCCESS);
99 }
100
101
102 static NTSTATUS
103 RtlpAddKnownAce(PACL Acl,
104                 ULONG Revision,
105                 ACCESS_MASK AccessMask,
106                 PSID Sid,
107                 ULONG Type)
108 {
109   PACE Ace;
110
111   if (!RtlValidSid(Sid))
112     {
113       return(STATUS_INVALID_SID);
114     }
115   if (Acl->AclRevision > 3 ||
116       Revision > 3)
117     {
118       return(STATUS_UNKNOWN_REVISION);
119     }
120   if (Revision < Acl->AclRevision)
121     {
122       Revision = Acl->AclRevision;
123     }
124   if (!RtlFirstFreeAce(Acl, &Ace))
125     {
126       return(STATUS_INVALID_ACL);
127     }
128   if (Ace == NULL)
129     {
130       return(STATUS_ALLOTTED_SPACE_EXCEEDED);
131     }
132   if (((PVOID)Ace + RtlLengthSid(Sid) + sizeof(ACE)) >=
133       ((PVOID)Acl + Acl->AclSize))
134     {
135       return(STATUS_ALLOTTED_SPACE_EXCEEDED);
136     }
137   Ace->Header.AceFlags = 0;
138   Ace->Header.AceType = Type;
139   Ace->Header.AceSize = RtlLengthSid(Sid) + sizeof(ACE);
140   Ace->AccessMask = AccessMask;
141   RtlCopySid(RtlLengthSid(Sid), (PSID)(Ace + 1), Sid);
142   Acl->AceCount++;
143   Acl->AclRevision = Revision;
144   return(STATUS_SUCCESS);
145 }
146
147
148 NTSTATUS STDCALL
149 RtlAddAccessAllowedAce(PACL Acl,
150                        ULONG Revision,
151                        ACCESS_MASK AccessMask,
152                        PSID Sid)
153 {
154   return(RtlpAddKnownAce(Acl, Revision, AccessMask, Sid, 0));
155 }
156
157
158 NTSTATUS STDCALL
159 RtlAddAccessDeniedAce(PACL Acl,
160                       ULONG Revision,
161                       ACCESS_MASK AccessMask,
162                       PSID Sid)
163 {
164   return(RtlpAddKnownAce(Acl, Revision, AccessMask, Sid, 1));
165 }
166
167
168 static VOID
169 RtlpAddData(PVOID AceList,
170             ULONG AceListLength,
171             PVOID Ace,
172             ULONG Offset)
173 {
174   if (Offset > 0)
175     {
176       memcpy((PUCHAR)Ace + AceListLength,
177              Ace,
178              Offset);
179     }
180
181   if (AceListLength != 0)
182     {
183       memcpy(Ace,
184              AceList,
185              AceListLength);
186     }
187 }
188
189
190 NTSTATUS STDCALL
191 RtlAddAce(PACL Acl,
192           ULONG AclRevision,
193           ULONG StartingIndex,
194           PACE AceList,
195           ULONG AceListLength)
196 {
197   PACE Ace;
198   ULONG i;
199   PACE Current;
200   ULONG j;
201
202   if (Acl->AclRevision != 2 &&
203       Acl->AclRevision != 3)
204     {
205       return(STATUS_INVALID_PARAMETER);
206     }
207
208   if (!RtlFirstFreeAce(Acl,&Ace))
209     {
210       return(STATUS_INVALID_PARAMETER);
211     }
212
213   if (Acl->AclRevision <= AclRevision)
214     {
215       AclRevision = Acl->AclRevision;
216     }
217
218   if (((PVOID)AceList + AceListLength) <= (PVOID)AceList)
219     {
220       return(STATUS_INVALID_PARAMETER);
221     }
222
223   i = 0;
224   Current = (PACE)(Acl + 1);
225   while ((PVOID)Current < ((PVOID)AceList + AceListLength))
226     {
227       if (AceList->Header.AceType == 4 &&
228           AclRevision < 3)
229         {
230           return(STATUS_INVALID_PARAMETER);
231         }
232       Current = (PACE)((PVOID)Current + Current->Header.AceSize);
233     }
234
235   if (Ace == NULL)
236     {
237       return(STATUS_BUFFER_TOO_SMALL);
238     }
239
240   if (((PVOID)Ace + AceListLength) >= ((PVOID)Acl + Acl->AclSize))
241     {
242       return(STATUS_BUFFER_TOO_SMALL);
243     }
244
245   if (StartingIndex != 0)
246     {
247       if (Acl->AceCount > 0)
248         {
249           Current = (PACE)(Acl + 1);
250           for (j = 0; j < StartingIndex; j++)
251             {
252               Current = (PACE)((PVOID)Current + Current->Header.AceSize);
253             }
254         }
255     }
256
257   RtlpAddData(AceList,
258               AceListLength,
259               Current,
260               (ULONG)Ace - (ULONG)Current);
261   Acl->AceCount = Acl->AceCount + i;
262   Acl->AclRevision = AclRevision;
263
264   return(STATUS_SUCCESS);
265 }
266
267
268 NTSTATUS STDCALL
269 RtlAddAuditAccessAce(PACL Acl,
270                      ULONG Revision,
271                      ACCESS_MASK AccessMask,
272                      PSID Sid,
273                      BOOLEAN Success,
274                      BOOLEAN Failure)
275 {
276   PACE Ace;
277   ULONG Flags = 0;
278
279   if (Success != FALSE)
280     {
281       Flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
282     }
283
284   if (Failure != FALSE)
285     {
286       Flags |= FAILED_ACCESS_ACE_FLAG;
287     }
288
289   if (!RtlValidSid(Sid))
290     {
291       return(STATUS_INVALID_SID);
292     }
293
294   if (Acl->AclRevision > 3 ||
295       Revision > 3)
296     {
297       return(STATUS_REVISION_MISMATCH);
298     }
299
300   if (Revision < Acl->AclRevision)
301     {
302       Revision = Acl->AclRevision;
303     }
304
305   if (!RtlFirstFreeAce(Acl, &Ace))
306     {
307       return(STATUS_INVALID_ACL);
308     }
309
310   if (Ace == NULL)
311     {
312       return(STATUS_ALLOTTED_SPACE_EXCEEDED);
313     }
314
315   if (((PVOID)Ace + RtlLengthSid(Sid) + sizeof(ACE)) >= ((PVOID)Acl + Acl->AclSize))
316     {
317       return(STATUS_ALLOTTED_SPACE_EXCEEDED);
318     }
319
320   Ace->Header.AceFlags = Flags;
321   Ace->Header.AceType = 2;
322   Ace->Header.AceSize = RtlLengthSid(Sid) + sizeof(ACE);
323   Ace->AccessMask = AccessMask;
324   RtlCopySid(RtlLengthSid(Sid),
325              (PSID)(Ace + 1),
326              Sid);
327   Acl->AceCount++;
328   Acl->AclRevision = Revision;
329
330   return(STATUS_SUCCESS);
331 }
332
333
334 static VOID
335 RtlpDeleteData(PVOID Ace,
336                ULONG AceSize,
337                ULONG Offset)
338 {
339   if (AceSize < Offset)
340     {
341       memcpy(Ace,
342              (PUCHAR)Ace + AceSize,
343              Offset - AceSize);
344     }
345
346   if (Offset - AceSize < Offset)
347     {
348       memset((PUCHAR)Ace + Offset - AceSize,
349              0,
350              AceSize);
351     }
352 }
353
354
355 NTSTATUS STDCALL
356 RtlDeleteAce(PACL Acl,
357              ULONG AceIndex)
358 {
359   PACE Ace;
360   PACE Current;
361
362   if (Acl->AclRevision != 2 &&
363       Acl->AclRevision != 3)
364     {
365       return(STATUS_INVALID_PARAMETER);
366     }
367
368   if (Acl->AceCount <= AceIndex)
369     {
370       return(STATUS_INVALID_PARAMETER);
371     }
372
373   if (!RtlFirstFreeAce(Acl, &Ace))
374     {
375       return(STATUS_INVALID_PARAMETER);
376     }
377
378   Current = (PACE)(Acl + 1);
379
380   while(AceIndex--)
381     {
382       Current = (PACE)((PVOID)Current + Current->Header.AceSize);
383     }
384
385   RtlpDeleteData(Current,
386                  Current->Header.AceSize,
387                  Ace - Current);
388   Acl->AceCount++;
389
390   return(STATUS_SUCCESS);
391 }
392
393
394 NTSTATUS STDCALL
395 RtlCreateAcl(PACL Acl,
396              ULONG AclSize,
397              ULONG AclRevision)
398 {
399   if (AclSize < 8)
400     {
401       return(STATUS_BUFFER_TOO_SMALL);
402     }
403
404   if (AclRevision != 2 &&
405       AclRevision != 3)
406     {
407       return(STATUS_INVALID_PARAMETER);
408     }
409
410   if (AclSize > 0xffff)
411     {
412       return(STATUS_INVALID_PARAMETER);
413     }
414
415   AclSize = AclSize & ~(0x3);
416   Acl->AclSize = AclSize;
417   Acl->AclRevision = AclRevision;
418   Acl->AceCount = 0;
419   Acl->Sbz1 = 0;
420   Acl->Sbz2 = 0;
421
422   return(STATUS_SUCCESS);
423 }
424
425
426 NTSTATUS STDCALL
427 RtlQueryInformationAcl(PACL Acl,
428                        PVOID Information,
429                        ULONG InformationLength,
430                        ACL_INFORMATION_CLASS InformationClass)
431 {
432   PACE Ace;
433
434   if (Acl->AclRevision != 2 &&
435       Acl->AclRevision != 3)
436     {
437       return(STATUS_INVALID_PARAMETER);
438     }
439
440   switch (InformationClass)
441     {
442       case AclRevisionInformation:
443         {
444           PACL_REVISION_INFORMATION Info = (PACL_REVISION_INFORMATION)Information;
445
446           if (InformationLength < sizeof(ACL_REVISION_INFORMATION))
447             {
448               return(STATUS_BUFFER_TOO_SMALL);
449             }
450           Info->AclRevision = Acl->AclRevision;
451         }
452         break;
453
454       case AclSizeInformation:
455         {
456           PACL_SIZE_INFORMATION Info = (PACL_SIZE_INFORMATION)Information;
457
458           if (InformationLength < sizeof(ACL_SIZE_INFORMATION))
459             {
460               return(STATUS_BUFFER_TOO_SMALL);
461             }
462
463           if (!RtlFirstFreeAce(Acl, &Ace))
464             {
465               return(STATUS_INVALID_PARAMETER);
466             }
467
468           Info->AceCount = Acl->AceCount;
469           if (Ace != NULL)
470             {
471               Info->AclBytesInUse = (PVOID)Ace - (PVOID)Acl;
472               Info->AclBytesFree  = Acl->AclSize - Info->AclBytesInUse;
473             }
474           else
475             {
476               Info->AclBytesInUse = Acl->AclSize;
477               Info->AclBytesFree  = 0;
478             }
479         }
480         break;
481
482       default:
483         return(STATUS_INVALID_INFO_CLASS);
484     }
485
486   return(STATUS_SUCCESS);
487 }
488
489
490 NTSTATUS STDCALL
491 RtlSetInformationAcl(PACL Acl,
492                      PVOID Information,
493                      ULONG InformationLength,
494                      ACL_INFORMATION_CLASS InformationClass)
495 {
496   if (Acl->AclRevision != 2 &&
497       Acl->AclRevision != 3)
498     {
499       return(STATUS_INVALID_PARAMETER);
500     }
501
502   switch (InformationClass)
503     {
504       case AclRevisionInformation:
505         {
506           PACL_REVISION_INFORMATION Info = (PACL_REVISION_INFORMATION)Information;
507
508           if (InformationLength < sizeof(ACL_REVISION_INFORMATION))
509             {
510               return(STATUS_BUFFER_TOO_SMALL);
511             }
512
513           if (Acl->AclRevision >= Info->AclRevision)
514             {
515               return(STATUS_INVALID_PARAMETER);
516             }
517
518           Acl->AclRevision = Info->AclRevision;
519         }
520         break;
521
522       default:
523         return(STATUS_INVALID_INFO_CLASS);
524     }
525
526   return(STATUS_SUCCESS);
527 }
528
529
530 BOOLEAN STDCALL
531 RtlValidAcl(PACL Acl)
532 {
533   PACE Ace;
534   USHORT Size;
535
536   Size = (Acl->AclSize + 3) & ~3;
537
538   if (Acl->AclRevision != 2 &&
539       Acl->AclRevision != 3)
540     {
541       return(FALSE);
542     }
543
544   if (Size != Acl->AclSize)
545     {
546       return(FALSE);
547     }
548
549   return(RtlFirstFreeAce(Acl, &Ace));
550 }
551
552 /* EOF */