Correct the calculation of the year for the 31'st of December of 2000
[wine] / dlls / ntdll / sec.c
1 /*
2  *      Security functions
3  *
4  *      Copyright 1996-1998 Marcus Meissner
5  *      Copyright 2003 CodeWeavers Inc. (Ulrich Czekalla)
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29 #include <ctype.h>
30 #include <math.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34
35 #include "windef.h"
36 #include "winbase.h"
37 #include "wine/exception.h"
38 #include "winnls.h"
39 #include "winerror.h"
40 #include "winreg.h"
41 #include "winternl.h"
42 #include "ntdll_misc.h"
43 #include "excpt.h"
44 #include "wine/library.h"
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
48
49 #define NT_SUCCESS(status) (status == STATUS_SUCCESS)
50
51 /* filter for page-fault exceptions */
52 static WINE_EXCEPTION_FILTER(page_fault)
53 {
54     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
55         return EXCEPTION_EXECUTE_HANDLER;
56     return EXCEPTION_CONTINUE_SEARCH;
57 }
58
59 /*
60  *      SID FUNCTIONS
61  */
62
63 /******************************************************************************
64  *  RtlAllocateAndInitializeSid         [NTDLL.@]
65  *
66  */
67 BOOLEAN WINAPI RtlAllocateAndInitializeSid (
68         PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
69         BYTE nSubAuthorityCount,
70         DWORD nSubAuthority0, DWORD nSubAuthority1,
71         DWORD nSubAuthority2, DWORD nSubAuthority3,
72         DWORD nSubAuthority4, DWORD nSubAuthority5,
73         DWORD nSubAuthority6, DWORD nSubAuthority7,
74         PSID *pSid )
75 {
76
77         TRACE("(%p, 0x%04x,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,%p)\n",
78                 pIdentifierAuthority,nSubAuthorityCount,
79                 nSubAuthority0, nSubAuthority1, nSubAuthority2, nSubAuthority3,
80                 nSubAuthority4, nSubAuthority5, nSubAuthority6, nSubAuthority7, pSid);
81
82         if (!(*pSid = RtlAllocateHeap( GetProcessHeap(), 0,
83                                        RtlLengthRequiredSid(nSubAuthorityCount))))
84           return FALSE;
85
86         ((SID*)*pSid)->Revision = SID_REVISION;
87
88         if (pIdentifierAuthority)
89           memcpy(&((SID*)*pSid)->IdentifierAuthority, pIdentifierAuthority, sizeof (SID_IDENTIFIER_AUTHORITY));
90         *RtlSubAuthorityCountSid(*pSid) = nSubAuthorityCount;
91
92         if (nSubAuthorityCount > 0)
93           *RtlSubAuthoritySid(*pSid, 0) = nSubAuthority0;
94         if (nSubAuthorityCount > 1)
95           *RtlSubAuthoritySid(*pSid, 1) = nSubAuthority1;
96         if (nSubAuthorityCount > 2)
97           *RtlSubAuthoritySid(*pSid, 2) = nSubAuthority2;
98         if (nSubAuthorityCount > 3)
99           *RtlSubAuthoritySid(*pSid, 3) = nSubAuthority3;
100         if (nSubAuthorityCount > 4)
101           *RtlSubAuthoritySid(*pSid, 4) = nSubAuthority4;
102         if (nSubAuthorityCount > 5)
103           *RtlSubAuthoritySid(*pSid, 5) = nSubAuthority5;
104         if (nSubAuthorityCount > 6)
105           *RtlSubAuthoritySid(*pSid, 6) = nSubAuthority6;
106         if (nSubAuthorityCount > 7)
107           *RtlSubAuthoritySid(*pSid, 7) = nSubAuthority7;
108
109         return STATUS_SUCCESS;
110 }
111 /******************************************************************************
112  *  RtlEqualSid         [NTDLL.@]
113  *
114  * Determine if two SIDs are equal.
115  *
116  * PARAMS
117  *  pSid1 [I] Source SID
118  *  pSid2 [I] SID to compare with
119  *
120  * RETURNS
121  *  TRUE, if pSid1 is equal to pSid2,
122  *  FALSE otherwise.
123  */
124 BOOL WINAPI RtlEqualSid( PSID pSid1, PSID pSid2 )
125 {
126     if (!RtlValidSid(pSid1) || !RtlValidSid(pSid2))
127         return FALSE;
128
129     if (*RtlSubAuthorityCountSid(pSid1) != *RtlSubAuthorityCountSid(pSid2))
130         return FALSE;
131
132     if (memcmp(pSid1, pSid2, RtlLengthSid(pSid1)) != 0)
133         return FALSE;
134
135     return TRUE;
136 }
137
138 /******************************************************************************
139  * RtlEqualPrefixSid    [NTDLL.@]
140  */
141 BOOL WINAPI RtlEqualPrefixSid (PSID pSid1, PSID pSid2)
142 {
143     if (!RtlValidSid(pSid1) || !RtlValidSid(pSid2))
144         return FALSE;
145
146     if (*RtlSubAuthorityCountSid(pSid1) != *RtlSubAuthorityCountSid(pSid2))
147         return FALSE;
148
149     if (memcmp(pSid1, pSid2, RtlLengthRequiredSid(((SID*)pSid1)->SubAuthorityCount - 1)) != 0)
150         return FALSE;
151
152     return TRUE;
153 }
154
155
156 /******************************************************************************
157  *  RtlFreeSid          [NTDLL.@]
158  *
159  * Free the resources used by a SID.
160  *
161  * PARAMS
162  *  pSid [I] SID to Free.
163  *
164  * RETURNS
165  *  STATUS_SUCCESS.
166  */
167 DWORD WINAPI RtlFreeSid(PSID pSid)
168 {
169         TRACE("(%p)\n", pSid);
170         RtlFreeHeap( GetProcessHeap(), 0, pSid );
171         return STATUS_SUCCESS;
172 }
173
174 /**************************************************************************
175  * RtlLengthRequiredSid [NTDLL.@]
176  *
177  * Determine the amount of memory a SID will use
178  *
179  * PARAMS
180  *   nrofsubauths [I] Number of Sub Authorities in the SID.
181  *
182  * RETURNS
183  *   The size, in bytes, of a SID with nrofsubauths Sub Authorities.
184  */
185 DWORD WINAPI RtlLengthRequiredSid(DWORD nrofsubauths)
186 {
187         return (nrofsubauths-1)*sizeof(DWORD) + sizeof(SID);
188 }
189
190 /**************************************************************************
191  *                 RtlLengthSid                         [NTDLL.@]
192  *
193  * Determine the amount of memory a SID is using
194  *
195  * PARAMS
196  *  pSid [I] SID to ge the size of.
197  *
198  * RETURNS
199  *  The size, in bytes, of pSid.
200  */
201 DWORD WINAPI RtlLengthSid(PSID pSid)
202 {
203         TRACE("sid=%p\n",pSid);
204         if (!pSid) return 0;
205         return RtlLengthRequiredSid(*RtlSubAuthorityCountSid(pSid));
206 }
207
208 /**************************************************************************
209  *                 RtlInitializeSid                     [NTDLL.@]
210  *
211  * Initialise a SID.
212  *
213  * PARAMS
214  *  pSid                 [I] SID to initialise
215  *  pIdentifierAuthority [I] Identifier Authority
216  *  nSubAuthorityCount   [I] Number of Sub Authorities
217  *
218  * RETURNS
219  *  Success: TRUE. pSid is initialised withe the details given.
220  *  Failure: FALSE, if nSubAuthorityCount is >= SID_MAX_SUB_AUTHORITIES.
221  */
222 BOOL WINAPI RtlInitializeSid(
223         PSID pSid,
224         PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
225         BYTE nSubAuthorityCount)
226 {
227         int i;
228         SID* pisid=pSid;
229
230         if (nSubAuthorityCount >= SID_MAX_SUB_AUTHORITIES)
231           return FALSE;
232
233         pisid->Revision = SID_REVISION;
234         pisid->SubAuthorityCount = nSubAuthorityCount;
235         if (pIdentifierAuthority)
236           memcpy(&pisid->IdentifierAuthority, pIdentifierAuthority, sizeof (SID_IDENTIFIER_AUTHORITY));
237
238         for (i = 0; i < nSubAuthorityCount; i++)
239           *RtlSubAuthoritySid(pSid, i) = 0;
240
241         return TRUE;
242 }
243
244 /**************************************************************************
245  *                 RtlSubAuthoritySid                   [NTDLL.@]
246  *
247  * Return the Sub Authority of a SID
248  *
249  * PARAMS
250  *   pSid          [I] SID to get the Sub Authority from.
251  *   nSubAuthority [I] Sub Authority number.
252  *
253  * RETURNS
254  *   A pointer to The Sub Authority value of pSid.
255  */
256 LPDWORD WINAPI RtlSubAuthoritySid( PSID pSid, DWORD nSubAuthority )
257 {
258     return &(((SID*)pSid)->SubAuthority[nSubAuthority]);
259 }
260
261 /**************************************************************************
262  * RtlIdentifierAuthoritySid    [NTDLL.@]
263  *
264  * Return the Identifier Authority of a SID.
265  *
266  * PARAMS
267  *   pSid [I] SID to get the Identifier Authority from.
268  *
269  * RETURNS
270  *   A pointer to the Identifier Authority value of pSid.
271  */
272 PSID_IDENTIFIER_AUTHORITY WINAPI RtlIdentifierAuthoritySid( PSID pSid )
273 {
274     return &(((SID*)pSid)->IdentifierAuthority);
275 }
276
277 /**************************************************************************
278  *                 RtlSubAuthorityCountSid              [NTDLL.@]
279  *
280  * Get the number of Sub Authorities in a SID.
281  *
282  * PARAMS
283  *   pSid [I] SID to get the count from.
284  *
285  * RETURNS
286  *  A pointer to the Sub Authority count of pSid.
287  */
288 LPBYTE WINAPI RtlSubAuthorityCountSid(PSID pSid)
289 {
290     return &(((SID*)pSid)->SubAuthorityCount);
291 }
292
293 /**************************************************************************
294  *                 RtlCopySid                           [NTDLL.@]
295  */
296 DWORD WINAPI RtlCopySid( DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid )
297 {
298         if (!pSourceSid || !RtlValidSid(pSourceSid) ||
299             (nDestinationSidLength < RtlLengthSid(pSourceSid)))
300           return FALSE;
301
302         if (nDestinationSidLength < (((SID*)pSourceSid)->SubAuthorityCount*4+8))
303           return FALSE;
304
305         memmove(pDestinationSid, pSourceSid, ((SID*)pSourceSid)->SubAuthorityCount*4+8);
306         return TRUE;
307 }
308 /******************************************************************************
309  * RtlValidSid [NTDLL.@]
310  *
311  * Determine if a SID is valid.
312  *
313  * PARAMS
314  *   pSid [I] SID to check
315  *
316  * RETURNS
317  *   TRUE if pSid is valid,
318  *   FALSE otherwise.
319  */
320 BOOLEAN WINAPI RtlValidSid( PSID pSid )
321 {
322     BOOL ret;
323     __TRY
324     {
325         ret = TRUE;
326         if (!pSid || ((SID*)pSid)->Revision != SID_REVISION ||
327             ((SID*)pSid)->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES)
328         {
329             ret = FALSE;
330         }
331     }
332     __EXCEPT(page_fault)
333     {
334         WARN("(%p): invalid pointer!\n", pSid);
335         return FALSE;
336     }
337     __ENDTRY
338     return ret;
339 }
340
341
342 /*
343  *      security descriptor functions
344  */
345
346 /**************************************************************************
347  * RtlCreateSecurityDescriptor                  [NTDLL.@]
348  *
349  * Initialise a SECURITY_DESCRIPTOR.
350  *
351  * PARAMS
352  *  lpsd [O] Descriptor to initialise.
353  *  rev  [I] Revision, must be set to SECURITY_DESCRIPTOR_REVISION.
354  *
355  * RETURNS:
356  *  Success: STATUS_SUCCESS.
357  *  Failure: STATUS_UNKNOWN_REVISION if rev is incorrect.
358  */
359 NTSTATUS WINAPI RtlCreateSecurityDescriptor(
360         PSECURITY_DESCRIPTOR lpsd,
361         DWORD rev)
362 {
363         if (rev!=SECURITY_DESCRIPTOR_REVISION)
364                 return STATUS_UNKNOWN_REVISION;
365         memset(lpsd,'\0',sizeof(SECURITY_DESCRIPTOR));
366         ((SECURITY_DESCRIPTOR*)lpsd)->Revision = SECURITY_DESCRIPTOR_REVISION;
367         return STATUS_SUCCESS;
368 }
369 /**************************************************************************
370  * RtlValidSecurityDescriptor                   [NTDLL.@]
371  *
372  * Determine if a SECURITY_DESCRIPTOR is valid.
373  *
374  * PARAMS
375  *  SecurityDescriptor [I] Descriptor to check.
376  *
377  * RETURNS
378  *   Success: STATUS_SUCCESS.
379  *   Failure: STATUS_INVALID_SECURITY_DESCR or STATUS_UNKNOWN_REVISION.
380  */
381 NTSTATUS WINAPI RtlValidSecurityDescriptor(
382         PSECURITY_DESCRIPTOR SecurityDescriptor)
383 {
384         if ( ! SecurityDescriptor )
385                 return STATUS_INVALID_SECURITY_DESCR;
386         if ( ((SECURITY_DESCRIPTOR*)SecurityDescriptor)->Revision != SECURITY_DESCRIPTOR_REVISION )
387                 return STATUS_UNKNOWN_REVISION;
388
389         return STATUS_SUCCESS;
390 }
391
392 /**************************************************************************
393  *  RtlLengthSecurityDescriptor                 [NTDLL.@]
394  */
395 ULONG WINAPI RtlLengthSecurityDescriptor(
396         PSECURITY_DESCRIPTOR pSecurityDescriptor)
397 {
398         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
399         ULONG offset = 0;
400         ULONG Size = SECURITY_DESCRIPTOR_MIN_LENGTH;
401
402         if ( lpsd == NULL )
403                 return 0;
404
405         if ( lpsd->Control & SE_SELF_RELATIVE)
406                 offset = (ULONG) lpsd;
407
408         if ( lpsd->Owner != NULL )
409                 Size += RtlLengthSid((PSID)((LPBYTE)lpsd->Owner + offset));
410
411         if ( lpsd->Group != NULL )
412                 Size += RtlLengthSid((PSID)((LPBYTE)lpsd->Group + offset));
413
414         if ( lpsd->Sacl != NULL )
415                 Size += ((PACL)((LPBYTE)lpsd->Sacl + offset))->AclSize;
416
417         if ( lpsd->Dacl != NULL )
418                 Size += ((PACL)((LPBYTE)lpsd->Dacl + offset))->AclSize;
419
420         return Size;
421 }
422
423 /******************************************************************************
424  *  RtlGetDaclSecurityDescriptor                [NTDLL.@]
425  *
426  */
427 NTSTATUS WINAPI RtlGetDaclSecurityDescriptor(
428         IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
429         OUT PBOOLEAN lpbDaclPresent,
430         OUT PACL *pDacl,
431         OUT PBOOLEAN lpbDaclDefaulted)
432 {
433         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
434
435         TRACE("(%p,%p,%p,%p)\n",
436         pSecurityDescriptor, lpbDaclPresent, *pDacl, lpbDaclDefaulted);
437
438         if (lpsd->Revision != SECURITY_DESCRIPTOR_REVISION)
439           return STATUS_UNKNOWN_REVISION ;
440
441         if ( (*lpbDaclPresent = (SE_DACL_PRESENT & lpsd->Control) ? 1 : 0) )
442         {
443           if ( SE_SELF_RELATIVE & lpsd->Control)
444           { *pDacl = (PACL) ((LPBYTE)lpsd + (DWORD)lpsd->Dacl);
445           }
446           else
447           { *pDacl = lpsd->Dacl;
448           }
449         }
450
451         *lpbDaclDefaulted = (( SE_DACL_DEFAULTED & lpsd->Control ) ? 1 : 0);
452
453         return STATUS_SUCCESS;
454 }
455
456 /**************************************************************************
457  *  RtlSetDaclSecurityDescriptor                [NTDLL.@]
458  */
459 NTSTATUS WINAPI RtlSetDaclSecurityDescriptor (
460         PSECURITY_DESCRIPTOR pSecurityDescriptor,
461         BOOLEAN daclpresent,
462         PACL dacl,
463         BOOLEAN dacldefaulted )
464 {
465         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
466
467         if (lpsd->Revision!=SECURITY_DESCRIPTOR_REVISION)
468                 return STATUS_UNKNOWN_REVISION;
469         if (lpsd->Control & SE_SELF_RELATIVE)
470                 return STATUS_INVALID_SECURITY_DESCR;
471
472         if (!daclpresent)
473         {       lpsd->Control &= ~SE_DACL_PRESENT;
474                 return TRUE;
475         }
476
477         lpsd->Control |= SE_DACL_PRESENT;
478         lpsd->Dacl = dacl;
479
480         if (dacldefaulted)
481                 lpsd->Control |= SE_DACL_DEFAULTED;
482         else
483                 lpsd->Control &= ~SE_DACL_DEFAULTED;
484
485         return STATUS_SUCCESS;
486 }
487
488 /******************************************************************************
489  *  RtlGetSaclSecurityDescriptor                [NTDLL.@]
490  *
491  */
492 NTSTATUS WINAPI RtlGetSaclSecurityDescriptor(
493         IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
494         OUT PBOOLEAN lpbSaclPresent,
495         OUT PACL *pSacl,
496         OUT PBOOLEAN lpbSaclDefaulted)
497 {
498         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
499
500         TRACE("(%p,%p,%p,%p)\n",
501         pSecurityDescriptor, lpbSaclPresent, *pSacl, lpbSaclDefaulted);
502
503         if (lpsd->Revision != SECURITY_DESCRIPTOR_REVISION)
504           return STATUS_UNKNOWN_REVISION ;
505
506         if ( (*lpbSaclPresent = (SE_SACL_PRESENT & lpsd->Control) ? 1 : 0) )
507         {
508           if ( SE_SELF_RELATIVE & lpsd->Control)
509           { *pSacl = (PACL) ((LPBYTE)lpsd + (DWORD)lpsd->Sacl);
510           }
511           else
512           { *pSacl = lpsd->Sacl;
513           }
514         }
515
516         *lpbSaclDefaulted = (( SE_SACL_DEFAULTED & lpsd->Control ) ? 1 : 0);
517
518         return STATUS_SUCCESS;
519 }
520
521 /**************************************************************************
522  * RtlSetSaclSecurityDescriptor                 [NTDLL.@]
523  */
524 NTSTATUS WINAPI RtlSetSaclSecurityDescriptor (
525         PSECURITY_DESCRIPTOR pSecurityDescriptor,
526         BOOLEAN saclpresent,
527         PACL sacl,
528         BOOLEAN sacldefaulted)
529 {
530         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
531
532         if (lpsd->Revision!=SECURITY_DESCRIPTOR_REVISION)
533                 return STATUS_UNKNOWN_REVISION;
534         if (lpsd->Control & SE_SELF_RELATIVE)
535                 return STATUS_INVALID_SECURITY_DESCR;
536         if (!saclpresent) {
537                 lpsd->Control &= ~SE_SACL_PRESENT;
538                 return 0;
539         }
540         lpsd->Control |= SE_SACL_PRESENT;
541         lpsd->Sacl = sacl;
542         if (sacldefaulted)
543                 lpsd->Control |= SE_SACL_DEFAULTED;
544         else
545                 lpsd->Control &= ~SE_SACL_DEFAULTED;
546         return STATUS_SUCCESS;
547 }
548
549 /**************************************************************************
550  * RtlGetOwnerSecurityDescriptor                [NTDLL.@]
551  */
552 NTSTATUS WINAPI RtlGetOwnerSecurityDescriptor(
553         PSECURITY_DESCRIPTOR pSecurityDescriptor,
554         PSID *Owner,
555         PBOOLEAN OwnerDefaulted)
556 {
557         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
558
559         if ( !lpsd  || !Owner || !OwnerDefaulted )
560                 return STATUS_INVALID_PARAMETER;
561
562         if (lpsd->Owner != NULL)
563         {
564             if (lpsd->Control & SE_SELF_RELATIVE)
565                 *Owner = (PSID)((LPBYTE)lpsd +
566                                 (ULONG)lpsd->Owner);
567             else
568                 *Owner = lpsd->Owner;
569
570             if ( lpsd->Control & SE_OWNER_DEFAULTED )
571                 *OwnerDefaulted = TRUE;
572             else
573                 *OwnerDefaulted = FALSE;
574         }
575         else
576             *Owner = NULL;
577
578         return STATUS_SUCCESS;
579 }
580
581 /**************************************************************************
582  *                 RtlSetOwnerSecurityDescriptor                [NTDLL.@]
583  */
584 NTSTATUS WINAPI RtlSetOwnerSecurityDescriptor(
585         PSECURITY_DESCRIPTOR pSecurityDescriptor,
586         PSID owner,
587         BOOLEAN ownerdefaulted)
588 {
589         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
590
591         if (lpsd->Revision!=SECURITY_DESCRIPTOR_REVISION)
592                 return STATUS_UNKNOWN_REVISION;
593         if (lpsd->Control & SE_SELF_RELATIVE)
594                 return STATUS_INVALID_SECURITY_DESCR;
595
596         lpsd->Owner = owner;
597         if (ownerdefaulted)
598                 lpsd->Control |= SE_OWNER_DEFAULTED;
599         else
600                 lpsd->Control &= ~SE_OWNER_DEFAULTED;
601         return STATUS_SUCCESS;
602 }
603
604 /**************************************************************************
605  *                 RtlSetGroupSecurityDescriptor                [NTDLL.@]
606  */
607 NTSTATUS WINAPI RtlSetGroupSecurityDescriptor (
608         PSECURITY_DESCRIPTOR pSecurityDescriptor,
609         PSID group,
610         BOOLEAN groupdefaulted)
611 {
612         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
613
614         if (lpsd->Revision!=SECURITY_DESCRIPTOR_REVISION)
615                 return STATUS_UNKNOWN_REVISION;
616         if (lpsd->Control & SE_SELF_RELATIVE)
617                 return STATUS_INVALID_SECURITY_DESCR;
618
619         lpsd->Group = group;
620         if (groupdefaulted)
621                 lpsd->Control |= SE_GROUP_DEFAULTED;
622         else
623                 lpsd->Control &= ~SE_GROUP_DEFAULTED;
624         return STATUS_SUCCESS;
625 }
626 /**************************************************************************
627  *                 RtlGetGroupSecurityDescriptor                [NTDLL.@]
628  */
629 NTSTATUS WINAPI RtlGetGroupSecurityDescriptor(
630         PSECURITY_DESCRIPTOR pSecurityDescriptor,
631         PSID *Group,
632         PBOOLEAN GroupDefaulted)
633 {
634         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
635
636         if ( !lpsd || !Group || !GroupDefaulted )
637                 return STATUS_INVALID_PARAMETER;
638
639         if (lpsd->Group != NULL)
640         {
641             if (lpsd->Control & SE_SELF_RELATIVE)
642                 *Group = (PSID)((LPBYTE)lpsd +
643                                 (ULONG)lpsd->Group);
644             else
645                 *Group = lpsd->Group;
646
647             if ( lpsd->Control & SE_GROUP_DEFAULTED )
648                 *GroupDefaulted = TRUE;
649             else
650                 *GroupDefaulted = FALSE;
651         }
652         else
653             *Group = NULL;
654
655         return STATUS_SUCCESS;
656 }
657
658 /**************************************************************************
659  *                 RtlMakeSelfRelativeSD                [NTDLL.@]
660  */
661 NTSTATUS WINAPI RtlMakeSelfRelativeSD(
662         IN PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,
663         IN PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
664         IN OUT LPDWORD lpdwBufferLength)
665 {
666     ULONG offsetRel;
667     ULONG length;
668     SECURITY_DESCRIPTOR* pAbs = pAbsoluteSecurityDescriptor;
669     SECURITY_DESCRIPTOR* pRel = pSelfRelativeSecurityDescriptor;
670
671     TRACE(" %p %p %p(%ld)\n", pAbs, pRel, lpdwBufferLength,
672         lpdwBufferLength ? *lpdwBufferLength: -1);
673
674     if (!lpdwBufferLength || !pAbs)
675         return STATUS_INVALID_PARAMETER;
676
677     length = RtlLengthSecurityDescriptor(pAbs);
678     if (*lpdwBufferLength < length)
679     {
680         *lpdwBufferLength = length;
681         return STATUS_BUFFER_TOO_SMALL;
682     }
683
684     if (!pRel)
685         return STATUS_INVALID_PARAMETER;
686
687     if (pAbs->Control & SE_SELF_RELATIVE)
688     {
689         memcpy(pRel, pAbs, length);
690         return STATUS_SUCCESS;
691     }
692
693     pRel->Revision = pAbs->Revision;
694     pRel->Sbz1 = pAbs->Sbz1;
695     pRel->Control = pAbs->Control | SE_SELF_RELATIVE;
696
697     offsetRel = sizeof(SECURITY_DESCRIPTOR);
698     pRel->Owner = (PSID) offsetRel;
699     length = RtlLengthSid(pAbs->Owner);
700     memcpy((LPBYTE)pRel + offsetRel, pAbs->Owner, length);
701
702     offsetRel += length;
703     pRel->Group = (PSID) offsetRel;
704     length = RtlLengthSid(pAbs->Group);
705     memcpy((LPBYTE)pRel + offsetRel, pAbs->Group, length);
706
707     if (pRel->Control & SE_SACL_PRESENT)
708     {
709         offsetRel += length;
710         pRel->Sacl = (PACL) offsetRel;
711         length = pAbs->Sacl->AclSize;
712         memcpy((LPBYTE)pRel + offsetRel, pAbs->Sacl, length);
713     }
714     else
715     {
716         pRel->Sacl = NULL;
717     }
718
719     if (pRel->Control & SE_DACL_PRESENT)
720     {
721         offsetRel += length;
722         pRel->Dacl = (PACL) offsetRel;
723         length = pAbs->Dacl->AclSize;
724         memcpy((LPBYTE)pRel + offsetRel, pAbs->Dacl, length);
725     }
726     else
727     {
728         pRel->Dacl = NULL;
729     }
730
731     return STATUS_SUCCESS;
732 }
733
734
735 /**************************************************************************
736 + *                 RtlSelfRelativeToAbsoluteSD [NTDLL.@]
737 + */
738 NTSTATUS WINAPI RtlSelfRelativeToAbsoluteSD(
739         IN PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
740         OUT PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,
741         OUT LPDWORD lpdwAbsoluteSecurityDescriptorSize,
742         OUT PACL pDacl,
743         OUT LPDWORD lpdwDaclSize,
744         OUT PACL pSacl,
745         OUT LPDWORD lpdwSaclSize,
746         OUT PSID pOwner,
747         OUT LPDWORD lpdwOwnerSize,
748         OUT PSID pPrimaryGroup,
749         OUT LPDWORD lpdwPrimaryGroupSize)
750 {
751     NTSTATUS status = STATUS_SUCCESS;
752     SECURITY_DESCRIPTOR* pAbs = pAbsoluteSecurityDescriptor;
753     SECURITY_DESCRIPTOR* pRel = pSelfRelativeSecurityDescriptor;
754
755     if (!pRel ||
756         !lpdwAbsoluteSecurityDescriptorSize ||
757         !lpdwDaclSize ||
758         !lpdwSaclSize ||
759         !lpdwOwnerSize ||
760         !lpdwPrimaryGroupSize ||
761         ~pRel->Control & SE_SELF_RELATIVE)
762         return STATUS_INVALID_PARAMETER;
763
764     /* Confirm buffers are sufficiently large */
765     if (*lpdwAbsoluteSecurityDescriptorSize < sizeof(SECURITY_DESCRIPTOR))
766     {
767         *lpdwAbsoluteSecurityDescriptorSize = sizeof(SECURITY_DESCRIPTOR);
768         status = STATUS_BUFFER_TOO_SMALL;
769     }
770
771     if (pRel->Control & SE_DACL_PRESENT &&
772         *lpdwDaclSize  < ((PACL)((LPBYTE)pRel->Dacl + (ULONG)pRel))->AclSize)
773     {
774         *lpdwDaclSize = ((PACL)((LPBYTE)pRel->Dacl + (ULONG)pRel))->AclSize;
775         status = STATUS_BUFFER_TOO_SMALL;
776     }
777
778     if (pRel->Control & SE_SACL_PRESENT &&
779         *lpdwSaclSize  < ((PACL)((LPBYTE)pRel->Sacl + (ULONG)pRel))->AclSize)
780     {
781         *lpdwSaclSize = ((PACL)((LPBYTE)pRel->Sacl + (ULONG)pRel))->AclSize;
782         status = STATUS_BUFFER_TOO_SMALL;
783     }
784
785     if (pRel->Owner &&
786         *lpdwOwnerSize < RtlLengthSid((PSID)((LPBYTE)pRel->Owner + (ULONG)pRel)))
787     {
788         *lpdwOwnerSize = RtlLengthSid((PSID)((LPBYTE)pRel->Owner + (ULONG)pRel));
789         status = STATUS_BUFFER_TOO_SMALL;
790     }
791
792     if (pRel->Group &&
793         *lpdwPrimaryGroupSize < RtlLengthSid((PSID)((LPBYTE)pRel->Group + (ULONG)pRel)))
794     {
795         *lpdwPrimaryGroupSize = RtlLengthSid((PSID)((LPBYTE)pRel->Group + (ULONG)pRel));
796         status = STATUS_BUFFER_TOO_SMALL;
797     }
798
799     if (status != STATUS_SUCCESS)
800         return status;
801
802     /* Copy structures */
803     pAbs->Revision = pRel->Revision;
804     pAbs->Control = pRel->Control & ~SE_SELF_RELATIVE;
805
806     if (pRel->Control & SE_SACL_PRESENT)
807     {
808         PACL pAcl = (PACL)((LPBYTE)pRel->Sacl + (ULONG)pRel);
809
810         memcpy(pSacl, pAcl, pAcl->AclSize);
811         pAbs->Sacl = pSacl;
812     }
813
814     if (pRel->Control & SE_DACL_PRESENT)
815     {
816         PACL pAcl = (PACL)((LPBYTE)pRel->Dacl + (ULONG)pRel);
817         memcpy(pDacl, pAcl, pAcl->AclSize);
818         pAbs->Dacl = pDacl;
819     }
820
821     if (pRel->Owner)
822     {
823         PSID psid = (PSID)((LPBYTE)pRel->Owner + (ULONG)pRel);
824         memcpy(pOwner, psid, RtlLengthSid(psid));
825         pAbs->Owner = pOwner;
826     }
827
828     if (pRel->Group)
829     {
830         PSID psid = (PSID)((LPBYTE)pRel->Group + (ULONG)pRel);
831         memcpy(pPrimaryGroup, psid, RtlLengthSid(psid));
832         pAbs->Group = pPrimaryGroup;
833     }
834
835     return status;
836 }
837
838 /*
839  *      access control list's
840  */
841
842 /**************************************************************************
843  *                 RtlCreateAcl                         [NTDLL.@]
844  *
845  * NOTES
846  *    This should return NTSTATUS
847  */
848 NTSTATUS WINAPI RtlCreateAcl(PACL acl,DWORD size,DWORD rev)
849 {
850         TRACE("%p 0x%08lx 0x%08lx\n", acl, size, rev);
851
852         if (rev!=ACL_REVISION)
853                 return STATUS_INVALID_PARAMETER;
854         if (size<sizeof(ACL))
855                 return STATUS_BUFFER_TOO_SMALL;
856         if (size>0xFFFF)
857                 return STATUS_INVALID_PARAMETER;
858
859         memset(acl,'\0',sizeof(ACL));
860         acl->AclRevision        = rev;
861         acl->AclSize            = size;
862         acl->AceCount           = 0;
863         return STATUS_SUCCESS;
864 }
865
866 /**************************************************************************
867  *                 RtlFirstFreeAce                      [NTDLL.@]
868  * looks for the AceCount+1 ACE, and if it is still within the alloced
869  * ACL, return a pointer to it
870  */
871 BOOLEAN WINAPI RtlFirstFreeAce(
872         PACL acl,
873         PACE_HEADER *x)
874 {
875         PACE_HEADER     ace;
876         int             i;
877
878         *x = 0;
879         ace = (PACE_HEADER)(acl+1);
880         for (i=0;i<acl->AceCount;i++) {
881                 if ((DWORD)ace>=(((DWORD)acl)+acl->AclSize))
882                         return 0;
883                 ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize);
884         }
885         if ((DWORD)ace>=(((DWORD)acl)+acl->AclSize))
886                 return 0;
887         *x = ace;
888         return 1;
889 }
890
891 /**************************************************************************
892  *                 RtlAddAce                            [NTDLL.@]
893  */
894 NTSTATUS WINAPI RtlAddAce(
895         PACL acl,
896         DWORD rev,
897         DWORD xnrofaces,
898         PACE_HEADER acestart,
899         DWORD acelen)
900 {
901         PACE_HEADER     ace,targetace;
902         int             nrofaces;
903
904         if (acl->AclRevision != ACL_REVISION)
905                 return STATUS_INVALID_PARAMETER;
906         if (!RtlFirstFreeAce(acl,&targetace))
907                 return STATUS_INVALID_PARAMETER;
908         nrofaces=0;ace=acestart;
909         while (((DWORD)ace-(DWORD)acestart)<acelen) {
910                 nrofaces++;
911                 ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize);
912         }
913         if ((DWORD)targetace+acelen>(DWORD)acl+acl->AclSize) /* too much aces */
914                 return STATUS_INVALID_PARAMETER;
915         memcpy((LPBYTE)targetace,acestart,acelen);
916         acl->AceCount+=nrofaces;
917         return STATUS_SUCCESS;
918 }
919
920 /**************************************************************************
921  *                 RtlDeleteAce                         [NTDLL.@]
922  */
923 NTSTATUS  WINAPI RtlDeleteAce(PACL pAcl, DWORD dwAceIndex)
924 {
925         NTSTATUS status;
926         PACE_HEADER pAce;
927
928         status = RtlGetAce(pAcl,dwAceIndex,(LPVOID*)&pAce);
929
930         if (STATUS_SUCCESS == status)
931         {
932                 PACE_HEADER pcAce;
933                 DWORD len = 0;
934
935                 pcAce = (PACE_HEADER)(((BYTE*)pAce)+pAce->AceSize);
936                 for (; dwAceIndex < pAcl->AceCount; dwAceIndex++)
937                 {
938                         len += pcAce->AceSize;
939                         pcAce = (PACE_HEADER)(((BYTE*)pcAce) + pcAce->AceSize);
940                 }
941
942                 memcpy(pAce, ((BYTE*)pAce)+pAce->AceSize, len);
943                 pAcl->AceCount--;
944         }
945
946         return status;
947 }
948
949 /******************************************************************************
950  *  RtlAddAccessAllowedAce              [NTDLL.@]
951  */
952 NTSTATUS WINAPI RtlAddAccessAllowedAce(
953         IN OUT PACL pAcl,
954         IN DWORD dwAceRevision,
955         IN DWORD AccessMask,
956         IN PSID pSid)
957 {
958         return RtlAddAccessAllowedAceEx( pAcl, dwAceRevision, 0, AccessMask, pSid);
959 }
960  
961 /******************************************************************************
962  *  RtlAddAccessAllowedAceEx            [NTDLL.@]
963  */
964 NTSTATUS WINAPI RtlAddAccessAllowedAceEx(
965         IN OUT PACL pAcl,
966         IN DWORD dwAceRevision,
967         IN DWORD AceFlags,
968         IN DWORD AccessMask,
969         IN PSID pSid)
970 {
971         DWORD dwLengthSid;
972         ACCESS_ALLOWED_ACE * pAaAce;
973         DWORD dwSpaceLeft;
974
975         TRACE("(%p,0x%08lx,0x%08lx,%p)\n",
976                 pAcl, dwAceRevision, AccessMask, pSid);
977
978         if (!RtlValidSid(pSid))
979                 return STATUS_INVALID_SID;
980         if (!RtlValidAcl(pAcl))
981                 return STATUS_INVALID_ACL;
982
983         dwLengthSid = RtlLengthSid(pSid);
984         if (!RtlFirstFreeAce(pAcl, (PACE_HEADER *) &pAaAce))
985                 return STATUS_INVALID_ACL;
986
987         if (!pAaAce)
988                 return STATUS_ALLOTTED_SPACE_EXCEEDED;
989
990         dwSpaceLeft = (DWORD)pAcl + pAcl->AclSize - (DWORD)pAaAce;
991         if (dwSpaceLeft < sizeof(*pAaAce) - sizeof(pAaAce->SidStart) + dwLengthSid)
992                 return STATUS_ALLOTTED_SPACE_EXCEEDED;
993
994         pAaAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
995         pAaAce->Header.AceFlags = AceFlags;
996         pAaAce->Header.AceSize = sizeof(*pAaAce) - sizeof(pAaAce->SidStart) + dwLengthSid;
997         pAaAce->Mask = AccessMask;
998         pAcl->AceCount++;
999         RtlCopySid(dwLengthSid, (PSID)&pAaAce->SidStart, pSid);
1000         return STATUS_SUCCESS;
1001 }
1002
1003 /******************************************************************************
1004  *  RtlAddAccessDeniedAce               [NTDLL.@]
1005  */
1006 NTSTATUS WINAPI RtlAddAccessDeniedAce(
1007         IN OUT PACL pAcl,
1008         IN DWORD dwAceRevision,
1009         IN DWORD AccessMask,
1010         IN PSID pSid)
1011 {
1012         return RtlAddAccessDeniedAceEx( pAcl, dwAceRevision, 0, AccessMask, pSid);
1013 }
1014
1015 /******************************************************************************
1016  *  RtlAddAccessDeniedAceEx             [NTDLL.@]
1017  */
1018 NTSTATUS WINAPI RtlAddAccessDeniedAceEx(
1019         IN OUT PACL pAcl,
1020         IN DWORD dwAceRevision,
1021         IN DWORD AceFlags,
1022         IN DWORD AccessMask,
1023         IN PSID pSid)
1024 {
1025         DWORD dwLengthSid;
1026         DWORD dwSpaceLeft;
1027         ACCESS_DENIED_ACE * pAdAce;
1028
1029         TRACE("(%p,0x%08lx,0x%08lx,%p)\n",
1030                 pAcl, dwAceRevision, AccessMask, pSid);
1031
1032         if (!RtlValidSid(pSid))
1033                 return STATUS_INVALID_SID;
1034         if (!RtlValidAcl(pAcl))
1035                 return STATUS_INVALID_ACL;
1036
1037         dwLengthSid = RtlLengthSid(pSid);
1038         if (!RtlFirstFreeAce(pAcl, (PACE_HEADER *) &pAdAce))
1039                 return STATUS_INVALID_ACL;
1040
1041         if (!pAdAce)
1042                 return STATUS_ALLOTTED_SPACE_EXCEEDED;
1043
1044         dwSpaceLeft = (DWORD)pAcl + pAcl->AclSize - (DWORD)pAdAce;
1045         if (dwSpaceLeft < sizeof(*pAdAce) - sizeof(pAdAce->SidStart) + dwLengthSid)
1046                 return STATUS_ALLOTTED_SPACE_EXCEEDED;
1047
1048         pAdAce->Header.AceType = ACCESS_DENIED_ACE_TYPE;
1049         pAdAce->Header.AceFlags = AceFlags;
1050         pAdAce->Header.AceSize = sizeof(*pAdAce) - sizeof(pAdAce->SidStart) + dwLengthSid;
1051         pAdAce->Mask = AccessMask;
1052         pAcl->AceCount++;
1053         RtlCopySid(dwLengthSid, (PSID)&pAdAce->SidStart, pSid);
1054         return STATUS_SUCCESS;
1055 }
1056
1057 /******************************************************************************
1058  *  RtlValidAcl         [NTDLL.@]
1059  */
1060 BOOLEAN WINAPI RtlValidAcl(PACL pAcl)
1061 {
1062         BOOLEAN ret;
1063         TRACE("(%p)\n", pAcl);
1064
1065         __TRY
1066         {
1067                 PACE_HEADER     ace;
1068                 int             i;
1069
1070                 if (pAcl->AclRevision != ACL_REVISION)
1071                     ret = FALSE;
1072                 else
1073                 {
1074                     ace = (PACE_HEADER)(pAcl+1);
1075                     ret = TRUE;
1076                     for (i=0;i<=pAcl->AceCount;i++)
1077                     {
1078                         if ((char *)ace > (char *)pAcl + pAcl->AclSize)
1079                         {
1080                             ret = FALSE;
1081                             break;
1082                         }
1083                         ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize);
1084                     }
1085                 }
1086         }
1087         __EXCEPT(page_fault)
1088         {
1089                 WARN("(%p): invalid pointer!\n", pAcl);
1090                 return 0;
1091         }
1092         __ENDTRY
1093         return ret;
1094 }
1095
1096 /******************************************************************************
1097  *  RtlGetAce           [NTDLL.@]
1098  */
1099 DWORD WINAPI RtlGetAce(PACL pAcl,DWORD dwAceIndex,LPVOID *pAce )
1100 {
1101         PACE_HEADER ace;
1102
1103         TRACE("(%p,%ld,%p)\n",pAcl,dwAceIndex,pAce);
1104
1105         if ((dwAceIndex < 0) || (dwAceIndex > pAcl->AceCount))
1106                 return STATUS_INVALID_PARAMETER;
1107
1108         ace = (PACE_HEADER)(pAcl + 1);
1109         for (;dwAceIndex;dwAceIndex--)
1110                 ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize);
1111
1112         *pAce = (LPVOID) ace;
1113
1114         return STATUS_SUCCESS;
1115 }
1116
1117 /*
1118  *      misc
1119  */
1120
1121 /******************************************************************************
1122  *  RtlAdjustPrivilege          [NTDLL.@]
1123  */
1124 DWORD WINAPI RtlAdjustPrivilege(DWORD x1,DWORD x2,DWORD x3,DWORD x4)
1125 {
1126         FIXME("(0x%08lx,0x%08lx,0x%08lx,0x%08lx),stub!\n",x1,x2,x3,x4);
1127         return 0;
1128 }
1129
1130 /******************************************************************************
1131  *  RtlImpersonateSelf          [NTDLL.@]
1132  */
1133 BOOL WINAPI
1134 RtlImpersonateSelf(SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
1135 {
1136         FIXME("(%08x), stub\n", ImpersonationLevel);
1137         return TRUE;
1138 }
1139
1140 /******************************************************************************
1141  *  NtAccessCheck               [NTDLL.@]
1142  *  ZwAccessCheck               [NTDLL.@]
1143  */
1144 NTSTATUS WINAPI
1145 NtAccessCheck(
1146         IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1147         IN HANDLE ClientToken,
1148         IN ACCESS_MASK DesiredAccess,
1149         IN PGENERIC_MAPPING GenericMapping,
1150         OUT PPRIVILEGE_SET PrivilegeSet,
1151         OUT PULONG ReturnLength,
1152         OUT PULONG GrantedAccess,
1153         OUT PBOOLEAN AccessStatus)
1154 {
1155         FIXME("(%p, %p, %08lx, %p, %p, %p, %p, %p), stub\n",
1156           SecurityDescriptor, ClientToken, DesiredAccess, GenericMapping,
1157           PrivilegeSet, ReturnLength, GrantedAccess, AccessStatus);
1158         *AccessStatus = TRUE;
1159         return STATUS_SUCCESS;
1160 }
1161
1162 /******************************************************************************
1163  *  NtSetSecurityObject         [NTDLL.@]
1164  */
1165 NTSTATUS WINAPI
1166 NtSetSecurityObject(
1167         IN HANDLE Handle,
1168         IN SECURITY_INFORMATION SecurityInformation,
1169         IN PSECURITY_DESCRIPTOR SecurityDescriptor)
1170 {
1171         FIXME("%p 0x%08lx %p\n", Handle, SecurityInformation, SecurityDescriptor);
1172         return STATUS_SUCCESS;
1173 }
1174
1175 /******************************************************************************
1176  * RtlGetControlSecurityDescriptor (NTDLL.@)
1177  */
1178
1179 NTSTATUS WINAPI RtlGetControlSecurityDescriptor(
1180         PSECURITY_DESCRIPTOR  pSecurityDescriptor,
1181         PSECURITY_DESCRIPTOR_CONTROL pControl,
1182         LPDWORD lpdwRevision)
1183 {
1184         FIXME("(%p,%p,%p),stub!\n",pSecurityDescriptor,pControl,lpdwRevision);
1185         return STATUS_SUCCESS;
1186 }
1187
1188 /******************************************************************************
1189  * RtlConvertSidToUnicodeString (NTDLL.@)
1190  *
1191  * The returned SID is used to access the USER registry hive usually
1192  *
1193  * the native function returns something like
1194  * "S-1-5-21-0000000000-000000000-0000000000-500";
1195  */
1196 NTSTATUS WINAPI RtlConvertSidToUnicodeString(
1197        PUNICODE_STRING String,
1198        PSID Sid,
1199        BOOLEAN AllocateString)
1200 {
1201     const char *user = wine_get_user_name();
1202     int len = ntdll_umbstowcs( 0, user, strlen(user)+1, NULL, 0 ) * sizeof(WCHAR);
1203
1204     FIXME("(%p %p %u)\n", String, Sid, AllocateString);
1205
1206     String->Length = len - sizeof(WCHAR);
1207     if (AllocateString)
1208     {
1209         String->MaximumLength = len;
1210         if (!(String->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len )))
1211             return STATUS_NO_MEMORY;
1212     }
1213     else if (len > String->MaximumLength) return STATUS_BUFFER_OVERFLOW;
1214
1215     ntdll_umbstowcs( 0, user, strlen(user)+1, String->Buffer, len/sizeof(WCHAR) );
1216     return STATUS_SUCCESS;
1217 }
1218
1219 /******************************************************************************
1220  * RtlQueryInformationAcl (NTDLL.@)
1221  */
1222 NTSTATUS WINAPI RtlQueryInformationAcl(
1223     PACL pAcl,
1224     LPVOID pAclInformation,
1225     DWORD nAclInformationLength,
1226     ACL_INFORMATION_CLASS dwAclInformationClass)
1227 {
1228     NTSTATUS status = STATUS_SUCCESS;
1229
1230     TRACE("pAcl=%p pAclInfo=%p len=%ld, class=%d\n", 
1231         pAcl, pAclInformation, nAclInformationLength, dwAclInformationClass);
1232
1233     switch (dwAclInformationClass)
1234     {
1235         case AclRevisionInformation:
1236         {
1237             PACL_REVISION_INFORMATION paclrev = (PACL_REVISION_INFORMATION) pAclInformation;
1238
1239             if (nAclInformationLength < sizeof(ACL_REVISION_INFORMATION))
1240                 status = STATUS_INVALID_PARAMETER;
1241             else
1242                 paclrev->AclRevision = pAcl->AclRevision;
1243
1244             break;
1245         }
1246
1247         case AclSizeInformation:
1248         {
1249             PACL_SIZE_INFORMATION paclsize = (PACL_SIZE_INFORMATION) pAclInformation;
1250
1251             if (nAclInformationLength < sizeof(ACL_SIZE_INFORMATION))
1252                 status = STATUS_INVALID_PARAMETER;
1253             else
1254             {
1255                 INT i;
1256                 PACE_HEADER ace;
1257
1258                 paclsize->AceCount = pAcl->AceCount;
1259
1260                 paclsize->AclBytesInUse = 0;
1261                 ace = (PACE_HEADER) (pAcl + 1);
1262
1263                 for (i = 0; i < pAcl->AceCount; i++)
1264                 {
1265                     paclsize->AclBytesInUse += ace->AceSize;
1266                     ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize);
1267                 }
1268
1269                 if (pAcl->AclSize < paclsize->AclBytesInUse)
1270                 {
1271                     WARN("Acl has %ld bytes free\n", pAcl->AclSize - paclsize->AclBytesInUse);
1272                     paclsize->AclBytesFree = 0;
1273                     paclsize->AclBytesInUse = pAcl->AclSize;
1274                 }
1275                 else
1276                     paclsize->AclBytesFree = pAcl->AclSize - paclsize->AclBytesInUse;
1277             }
1278
1279             break;
1280         }
1281
1282         default:
1283             WARN("Unknown AclInformationClass value: %d\n", dwAclInformationClass);
1284             status = STATUS_INVALID_PARAMETER;
1285     }
1286
1287     return status;
1288 }