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