ntdll: Use build-time API detection instead of OS detection for finding the number...
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "ntstatus.h"
36 #define WIN32_NO_STATUS
37 #include "windef.h"
38 #include "ntdll_misc.h"
39 #include "wine/exception.h"
40 #include "wine/library.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
45
46 #define NT_SUCCESS(status) (status == STATUS_SUCCESS)
47
48 #define SELF_RELATIVE_FIELD(sd,field) ((BYTE *)(sd) + ((SECURITY_DESCRIPTOR_RELATIVE *)(sd))->field)
49
50 /* helper function to retrieve active length of an ACL */
51 static size_t acl_bytesInUse(PACL pAcl)
52 {
53     int i;
54     size_t bytesInUse = sizeof(ACL);
55     PACE_HEADER ace = (PACE_HEADER) (pAcl + 1);
56     for (i = 0; i < pAcl->AceCount; i++)
57     {
58         bytesInUse += ace->AceSize;
59         ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize);
60     }
61     return bytesInUse;
62 }
63
64 /* helper function to copy an ACL */
65 static BOOLEAN copy_acl(DWORD nDestinationAclLength, PACL pDestinationAcl, PACL pSourceAcl)
66 {
67     DWORD size;
68
69     if (!pSourceAcl || !RtlValidAcl(pSourceAcl))
70         return FALSE;
71
72     size = pSourceAcl->AclSize;
73     if (nDestinationAclLength < size)
74         return FALSE;
75
76     memmove(pDestinationAcl, pSourceAcl, size);
77     return TRUE;
78 }
79
80 /* generically adds an ACE to an ACL */
81 static NTSTATUS add_access_ace(PACL pAcl, DWORD dwAceRevision, DWORD dwAceFlags,
82                                DWORD dwAccessMask, PSID pSid, DWORD dwAceType)
83 {
84     ACE_HEADER *pAceHeader;
85     DWORD dwLengthSid;
86     DWORD dwAceSize;
87     DWORD *pAccessMask;
88     DWORD *pSidStart;
89
90     if (!RtlValidSid(pSid))
91         return STATUS_INVALID_SID;
92
93     if (pAcl->AclRevision > MAX_ACL_REVISION || dwAceRevision > MAX_ACL_REVISION)
94         return STATUS_REVISION_MISMATCH;
95
96     if (!RtlValidAcl(pAcl))
97         return STATUS_INVALID_ACL;
98
99     if (!RtlFirstFreeAce(pAcl, &pAceHeader))
100         return STATUS_INVALID_ACL;
101
102     if (!pAceHeader)
103         return STATUS_ALLOTTED_SPACE_EXCEEDED;
104
105     /* calculate generic size of the ACE */
106     dwLengthSid = RtlLengthSid(pSid);
107     dwAceSize = sizeof(ACE_HEADER) + sizeof(DWORD) + dwLengthSid;
108     if ((char *)pAceHeader + dwAceSize > (char *)pAcl + pAcl->AclSize)
109         return STATUS_ALLOTTED_SPACE_EXCEEDED;
110
111     /* fill the new ACE */
112     pAceHeader->AceType = dwAceType;
113     pAceHeader->AceFlags = dwAceFlags;
114     pAceHeader->AceSize = dwAceSize;
115
116     /* skip past the ACE_HEADER of the ACE */
117     pAccessMask = (DWORD *)(pAceHeader + 1);
118     *pAccessMask = dwAccessMask;
119
120     /* skip past ACE->Mask */
121     pSidStart = pAccessMask + 1;
122     RtlCopySid(dwLengthSid, pSidStart, pSid);
123
124     pAcl->AclRevision = max(pAcl->AclRevision, dwAceRevision);
125     pAcl->AceCount++;
126
127     return STATUS_SUCCESS;
128 }
129
130 /*
131  *      SID FUNCTIONS
132  */
133
134 /******************************************************************************
135  *  RtlAllocateAndInitializeSid         [NTDLL.@]
136  *
137  */
138 NTSTATUS WINAPI RtlAllocateAndInitializeSid (
139         PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
140         BYTE nSubAuthorityCount,
141         DWORD nSubAuthority0, DWORD nSubAuthority1,
142         DWORD nSubAuthority2, DWORD nSubAuthority3,
143         DWORD nSubAuthority4, DWORD nSubAuthority5,
144         DWORD nSubAuthority6, DWORD nSubAuthority7,
145         PSID *pSid )
146 {
147     SID *tmp_sid;
148
149     TRACE("(%p, 0x%04x,0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,%p)\n",
150                 pIdentifierAuthority,nSubAuthorityCount,
151                 nSubAuthority0, nSubAuthority1, nSubAuthority2, nSubAuthority3,
152                 nSubAuthority4, nSubAuthority5, nSubAuthority6, nSubAuthority7, pSid);
153
154     if (nSubAuthorityCount > 8) return STATUS_INVALID_SID;
155
156     if (!(tmp_sid= RtlAllocateHeap( GetProcessHeap(), 0,
157                                     RtlLengthRequiredSid(nSubAuthorityCount))))
158         return STATUS_NO_MEMORY;
159
160     tmp_sid->Revision = SID_REVISION;
161
162     if (pIdentifierAuthority)
163         tmp_sid->IdentifierAuthority = *pIdentifierAuthority;
164     tmp_sid->SubAuthorityCount = nSubAuthorityCount;
165
166     switch( nSubAuthorityCount )
167     {
168         case 8: tmp_sid->SubAuthority[7]= nSubAuthority7;
169             /* fall through */
170         case 7: tmp_sid->SubAuthority[6]= nSubAuthority6;
171             /* fall through */
172         case 6: tmp_sid->SubAuthority[5]= nSubAuthority5;
173             /* fall through */
174         case 5: tmp_sid->SubAuthority[4]= nSubAuthority4;
175             /* fall through */
176         case 4: tmp_sid->SubAuthority[3]= nSubAuthority3;
177             /* fall through */
178         case 3: tmp_sid->SubAuthority[2]= nSubAuthority2;
179             /* fall through */
180         case 2: tmp_sid->SubAuthority[1]= nSubAuthority1;
181             /* fall through */
182         case 1: tmp_sid->SubAuthority[0]= nSubAuthority0;
183         break;
184     }
185     *pSid = tmp_sid;
186     return STATUS_SUCCESS;
187 }
188
189 /******************************************************************************
190  *  RtlEqualSid         [NTDLL.@]
191  *
192  * Determine if two SIDs are equal.
193  *
194  * PARAMS
195  *  pSid1 [I] Source SID
196  *  pSid2 [I] SID to compare with
197  *
198  * RETURNS
199  *  TRUE, if pSid1 is equal to pSid2,
200  *  FALSE otherwise.
201  */
202 BOOL WINAPI RtlEqualSid( PSID pSid1, PSID pSid2 )
203 {
204     if (!RtlValidSid(pSid1) || !RtlValidSid(pSid2))
205         return FALSE;
206
207     if (*RtlSubAuthorityCountSid(pSid1) != *RtlSubAuthorityCountSid(pSid2))
208         return FALSE;
209
210     if (memcmp(pSid1, pSid2, RtlLengthSid(pSid1)) != 0)
211         return FALSE;
212
213     return TRUE;
214 }
215
216 /******************************************************************************
217  * RtlEqualPrefixSid    [NTDLL.@]
218  */
219 BOOL WINAPI RtlEqualPrefixSid (PSID pSid1, PSID pSid2)
220 {
221     if (!RtlValidSid(pSid1) || !RtlValidSid(pSid2))
222         return FALSE;
223
224     if (*RtlSubAuthorityCountSid(pSid1) != *RtlSubAuthorityCountSid(pSid2))
225         return FALSE;
226
227     if (memcmp(pSid1, pSid2, RtlLengthRequiredSid(((SID*)pSid1)->SubAuthorityCount - 1)) != 0)
228         return FALSE;
229
230     return TRUE;
231 }
232
233
234 /******************************************************************************
235  *  RtlFreeSid          [NTDLL.@]
236  *
237  * Free the resources used by a SID.
238  *
239  * PARAMS
240  *  pSid [I] SID to Free.
241  *
242  * RETURNS
243  *  STATUS_SUCCESS.
244  */
245 DWORD WINAPI RtlFreeSid(PSID pSid)
246 {
247         TRACE("(%p)\n", pSid);
248         RtlFreeHeap( GetProcessHeap(), 0, pSid );
249         return STATUS_SUCCESS;
250 }
251
252 /**************************************************************************
253  * RtlLengthRequiredSid [NTDLL.@]
254  *
255  * Determine the amount of memory a SID will use
256  *
257  * PARAMS
258  *   nrofsubauths [I] Number of Sub Authorities in the SID.
259  *
260  * RETURNS
261  *   The size, in bytes, of a SID with nrofsubauths Sub Authorities.
262  */
263 DWORD WINAPI RtlLengthRequiredSid(DWORD nrofsubauths)
264 {
265         return (nrofsubauths-1)*sizeof(DWORD) + sizeof(SID);
266 }
267
268 /**************************************************************************
269  *                 RtlLengthSid                         [NTDLL.@]
270  *
271  * Determine the amount of memory a SID is using
272  *
273  * PARAMS
274  *  pSid [I] SID to get the size of.
275  *
276  * RETURNS
277  *  The size, in bytes, of pSid.
278  */
279 DWORD WINAPI RtlLengthSid(PSID pSid)
280 {
281         TRACE("sid=%p\n",pSid);
282         if (!pSid) return 0;
283         return RtlLengthRequiredSid(*RtlSubAuthorityCountSid(pSid));
284 }
285
286 /**************************************************************************
287  *                 RtlInitializeSid                     [NTDLL.@]
288  *
289  * Initialise a SID.
290  *
291  * PARAMS
292  *  pSid                 [I] SID to initialise
293  *  pIdentifierAuthority [I] Identifier Authority
294  *  nSubAuthorityCount   [I] Number of Sub Authorities
295  *
296  * RETURNS
297  *  Success: TRUE. pSid is initialised with the details given.
298  *  Failure: FALSE, if nSubAuthorityCount is >= SID_MAX_SUB_AUTHORITIES.
299  */
300 BOOL WINAPI RtlInitializeSid(
301         PSID pSid,
302         PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
303         BYTE nSubAuthorityCount)
304 {
305         int i;
306         SID* pisid=pSid;
307
308         if (nSubAuthorityCount >= SID_MAX_SUB_AUTHORITIES)
309           return FALSE;
310
311         pisid->Revision = SID_REVISION;
312         pisid->SubAuthorityCount = nSubAuthorityCount;
313         if (pIdentifierAuthority)
314           pisid->IdentifierAuthority = *pIdentifierAuthority;
315
316         for (i = 0; i < nSubAuthorityCount; i++)
317           *RtlSubAuthoritySid(pSid, i) = 0;
318
319         return TRUE;
320 }
321
322 /**************************************************************************
323  *                 RtlSubAuthoritySid                   [NTDLL.@]
324  *
325  * Return the Sub Authority of a SID
326  *
327  * PARAMS
328  *   pSid          [I] SID to get the Sub Authority from.
329  *   nSubAuthority [I] Sub Authority number.
330  *
331  * RETURNS
332  *   A pointer to The Sub Authority value of pSid.
333  */
334 LPDWORD WINAPI RtlSubAuthoritySid( PSID pSid, DWORD nSubAuthority )
335 {
336     return &(((SID*)pSid)->SubAuthority[nSubAuthority]);
337 }
338
339 /**************************************************************************
340  * RtlIdentifierAuthoritySid    [NTDLL.@]
341  *
342  * Return the Identifier Authority of a SID.
343  *
344  * PARAMS
345  *   pSid [I] SID to get the Identifier Authority from.
346  *
347  * RETURNS
348  *   A pointer to the Identifier Authority value of pSid.
349  */
350 PSID_IDENTIFIER_AUTHORITY WINAPI RtlIdentifierAuthoritySid( PSID pSid )
351 {
352     return &(((SID*)pSid)->IdentifierAuthority);
353 }
354
355 /**************************************************************************
356  *                 RtlSubAuthorityCountSid              [NTDLL.@]
357  *
358  * Get the number of Sub Authorities in a SID.
359  *
360  * PARAMS
361  *   pSid [I] SID to get the count from.
362  *
363  * RETURNS
364  *  A pointer to the Sub Authority count of pSid.
365  */
366 LPBYTE WINAPI RtlSubAuthorityCountSid(PSID pSid)
367 {
368     return &(((SID*)pSid)->SubAuthorityCount);
369 }
370
371 /**************************************************************************
372  *                 RtlCopySid                           [NTDLL.@]
373  */
374 BOOLEAN WINAPI RtlCopySid( DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid )
375 {
376         if (!pSourceSid || !RtlValidSid(pSourceSid) ||
377             (nDestinationSidLength < RtlLengthSid(pSourceSid)))
378           return FALSE;
379
380         if (nDestinationSidLength < (((SID*)pSourceSid)->SubAuthorityCount*4+8))
381           return FALSE;
382
383         memmove(pDestinationSid, pSourceSid, ((SID*)pSourceSid)->SubAuthorityCount*4+8);
384         return TRUE;
385 }
386 /******************************************************************************
387  * RtlValidSid [NTDLL.@]
388  *
389  * Determine if a SID is valid.
390  *
391  * PARAMS
392  *   pSid [I] SID to check
393  *
394  * RETURNS
395  *   TRUE if pSid is valid,
396  *   FALSE otherwise.
397  */
398 BOOLEAN WINAPI RtlValidSid( PSID pSid )
399 {
400     BOOL ret;
401     __TRY
402     {
403         ret = TRUE;
404         if (!pSid || ((SID*)pSid)->Revision != SID_REVISION ||
405             ((SID*)pSid)->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES)
406         {
407             ret = FALSE;
408         }
409     }
410     __EXCEPT_PAGE_FAULT
411     {
412         WARN("(%p): invalid pointer!\n", pSid);
413         return FALSE;
414     }
415     __ENDTRY
416     return ret;
417 }
418
419
420 /*
421  *      security descriptor functions
422  */
423
424 /**************************************************************************
425  * RtlCreateSecurityDescriptor                  [NTDLL.@]
426  *
427  * Initialise a SECURITY_DESCRIPTOR.
428  *
429  * PARAMS
430  *  lpsd [O] Descriptor to initialise.
431  *  rev  [I] Revision, must be set to SECURITY_DESCRIPTOR_REVISION.
432  *
433  * RETURNS
434  *  Success: STATUS_SUCCESS.
435  *  Failure: STATUS_UNKNOWN_REVISION if rev is incorrect.
436  */
437 NTSTATUS WINAPI RtlCreateSecurityDescriptor(
438         PSECURITY_DESCRIPTOR lpsd,
439         DWORD rev)
440 {
441         if (rev!=SECURITY_DESCRIPTOR_REVISION)
442                 return STATUS_UNKNOWN_REVISION;
443         memset(lpsd,'\0',sizeof(SECURITY_DESCRIPTOR));
444         ((SECURITY_DESCRIPTOR*)lpsd)->Revision = SECURITY_DESCRIPTOR_REVISION;
445         return STATUS_SUCCESS;
446 }
447
448 /**************************************************************************
449  * RtlCopySecurityDescriptor            [NTDLL.@]
450  *
451  * Copies an absolute or sefl-relative SECURITY_DESCRIPTOR.
452  *
453  * PARAMS
454  *  pSourceSD      [O] SD to copy from.
455  *  pDestinationSD [I] Destination SD.
456  *
457  * RETURNS
458  *  Success: STATUS_SUCCESS.
459  *  Failure: STATUS_UNKNOWN_REVISION if rev is incorrect.
460  */
461 NTSTATUS WINAPI RtlCopySecurityDescriptor(PSECURITY_DESCRIPTOR pSourceSD, PSECURITY_DESCRIPTOR pDestinationSD)
462 {
463     PSID Owner, Group;
464     PACL Dacl, Sacl;
465     DWORD length;
466
467     if (((SECURITY_DESCRIPTOR *)pSourceSD)->Control & SE_SELF_RELATIVE)
468     {
469         SECURITY_DESCRIPTOR_RELATIVE *src = pSourceSD;
470         SECURITY_DESCRIPTOR_RELATIVE *dst = pDestinationSD;
471
472         if (src->Revision != SECURITY_DESCRIPTOR_REVISION)
473             return STATUS_UNKNOWN_REVISION;
474
475         *dst = *src;
476         if (src->Owner)
477         {
478             Owner = (PSID)SELF_RELATIVE_FIELD( src, Owner );
479             length = RtlLengthSid( Owner );
480             RtlCopySid(length, SELF_RELATIVE_FIELD( dst, Owner ), Owner);
481         }
482         if (src->Group)
483         {
484             Group = (PSID)SELF_RELATIVE_FIELD( src, Group );
485             length = RtlLengthSid( Group );
486             RtlCopySid(length, SELF_RELATIVE_FIELD( dst, Group ), Group);
487         }
488         if ((src->Control & SE_SACL_PRESENT) && src->Sacl)
489         {
490             Sacl = (PACL)SELF_RELATIVE_FIELD( src, Sacl );
491             copy_acl(Sacl->AclSize, (PACL)SELF_RELATIVE_FIELD( dst, Sacl ), Sacl);
492         }
493         if ((src->Control & SE_DACL_PRESENT) && src->Dacl)
494         {
495             Dacl = (PACL)SELF_RELATIVE_FIELD( src, Dacl );
496             copy_acl(Dacl->AclSize, (PACL)SELF_RELATIVE_FIELD( dst, Dacl ), Dacl);
497         }
498     }
499     else
500     {
501         SECURITY_DESCRIPTOR *src = pSourceSD;
502         SECURITY_DESCRIPTOR *dst = pDestinationSD;
503
504         if (src->Revision != SECURITY_DESCRIPTOR_REVISION)
505             return STATUS_UNKNOWN_REVISION;
506
507         *dst = *src;
508         if (src->Owner)
509         {
510             length = RtlLengthSid( src->Owner );
511             dst->Owner = RtlAllocateHeap(GetProcessHeap(), 0, length);
512             RtlCopySid(length, dst->Owner, src->Owner);
513         }
514         if (src->Group)
515         {
516             length = RtlLengthSid( src->Group );
517             dst->Group = RtlAllocateHeap(GetProcessHeap(), 0, length);
518             RtlCopySid(length, dst->Group, src->Group);
519         }
520         if (src->Control & SE_SACL_PRESENT)
521         {
522             length = src->Sacl->AclSize;
523             dst->Sacl = RtlAllocateHeap(GetProcessHeap(), 0, length);
524             copy_acl(length, dst->Sacl, src->Sacl);
525         }
526         if (src->Control & SE_DACL_PRESENT)
527         {
528             length = src->Dacl->AclSize;
529             dst->Dacl = RtlAllocateHeap(GetProcessHeap(), 0, length);
530             copy_acl(length, dst->Dacl, src->Dacl);
531         }
532     }
533
534     return STATUS_SUCCESS;
535 }
536
537 /**************************************************************************
538  * RtlValidSecurityDescriptor                   [NTDLL.@]
539  *
540  * Determine if a SECURITY_DESCRIPTOR is valid.
541  *
542  * PARAMS
543  *  SecurityDescriptor [I] Descriptor to check.
544  *
545  * RETURNS
546  *   Success: STATUS_SUCCESS.
547  *   Failure: STATUS_INVALID_SECURITY_DESCR or STATUS_UNKNOWN_REVISION.
548  */
549 NTSTATUS WINAPI RtlValidSecurityDescriptor(
550         PSECURITY_DESCRIPTOR SecurityDescriptor)
551 {
552         if ( ! SecurityDescriptor )
553                 return STATUS_INVALID_SECURITY_DESCR;
554         if ( ((SECURITY_DESCRIPTOR*)SecurityDescriptor)->Revision != SECURITY_DESCRIPTOR_REVISION )
555                 return STATUS_UNKNOWN_REVISION;
556
557         return STATUS_SUCCESS;
558 }
559
560 /**************************************************************************
561  *  RtlLengthSecurityDescriptor                 [NTDLL.@]
562  */
563 ULONG WINAPI RtlLengthSecurityDescriptor(
564         PSECURITY_DESCRIPTOR pSecurityDescriptor)
565 {
566         ULONG size;
567
568         if ( pSecurityDescriptor == NULL )
569                 return 0;
570
571         if (((SECURITY_DESCRIPTOR *)pSecurityDescriptor)->Control & SE_SELF_RELATIVE)
572         {
573             SECURITY_DESCRIPTOR_RELATIVE *sd = pSecurityDescriptor;
574             size = sizeof(*sd);
575             if (sd->Owner) size += RtlLengthSid((PSID)SELF_RELATIVE_FIELD(sd,Owner));
576             if (sd->Group) size += RtlLengthSid((PSID)SELF_RELATIVE_FIELD(sd,Group));
577             if ((sd->Control & SE_SACL_PRESENT) && sd->Sacl)
578                 size += ((PACL)SELF_RELATIVE_FIELD(sd,Sacl))->AclSize;
579             if ((sd->Control & SE_DACL_PRESENT) && sd->Dacl)
580                 size += ((PACL)SELF_RELATIVE_FIELD(sd,Dacl))->AclSize;
581         }
582         else
583         {
584             SECURITY_DESCRIPTOR *sd = pSecurityDescriptor;
585             size = sizeof(*sd);
586             if (sd->Owner) size += RtlLengthSid( sd->Owner );
587             if (sd->Group) size += RtlLengthSid( sd->Group );
588             if ((sd->Control & SE_SACL_PRESENT) && sd->Sacl) size += sd->Sacl->AclSize;
589             if ((sd->Control & SE_DACL_PRESENT) && sd->Dacl) size += sd->Dacl->AclSize;
590         }
591         return size;
592 }
593
594 /******************************************************************************
595  *  RtlGetDaclSecurityDescriptor                [NTDLL.@]
596  *
597  */
598 NTSTATUS WINAPI RtlGetDaclSecurityDescriptor(
599         IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
600         OUT PBOOLEAN lpbDaclPresent,
601         OUT PACL *pDacl,
602         OUT PBOOLEAN lpbDaclDefaulted)
603 {
604         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
605
606         TRACE("(%p,%p,%p,%p)\n",
607         pSecurityDescriptor, lpbDaclPresent, pDacl, lpbDaclDefaulted);
608
609         if (lpsd->Revision != SECURITY_DESCRIPTOR_REVISION)
610           return STATUS_UNKNOWN_REVISION ;
611
612         if ( (*lpbDaclPresent = (SE_DACL_PRESENT & lpsd->Control) ? 1 : 0) )
613         {
614             if (lpsd->Control & SE_SELF_RELATIVE)
615             {
616                 SECURITY_DESCRIPTOR_RELATIVE *sdr = pSecurityDescriptor;
617                 if (sdr->Dacl) *pDacl = (PACL)SELF_RELATIVE_FIELD( sdr, Dacl );
618                 else *pDacl = NULL;
619             }
620             else *pDacl = lpsd->Dacl;
621
622             *lpbDaclDefaulted = (lpsd->Control & SE_DACL_DEFAULTED) != 0;
623         }
624         else
625         {
626             *pDacl = NULL;
627             *lpbDaclDefaulted = 0;
628         }
629
630         return STATUS_SUCCESS;
631 }
632
633 /**************************************************************************
634  *  RtlSetDaclSecurityDescriptor                [NTDLL.@]
635  */
636 NTSTATUS WINAPI RtlSetDaclSecurityDescriptor (
637         PSECURITY_DESCRIPTOR pSecurityDescriptor,
638         BOOLEAN daclpresent,
639         PACL dacl,
640         BOOLEAN dacldefaulted )
641 {
642         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
643
644         if (lpsd->Revision!=SECURITY_DESCRIPTOR_REVISION)
645                 return STATUS_UNKNOWN_REVISION;
646         if (lpsd->Control & SE_SELF_RELATIVE)
647                 return STATUS_INVALID_SECURITY_DESCR;
648
649         if (!daclpresent)
650         {
651                 lpsd->Control &= ~SE_DACL_PRESENT;
652                 return STATUS_SUCCESS;
653         }
654
655         lpsd->Control |= SE_DACL_PRESENT;
656         lpsd->Dacl = dacl;
657
658         if (dacldefaulted)
659                 lpsd->Control |= SE_DACL_DEFAULTED;
660         else
661                 lpsd->Control &= ~SE_DACL_DEFAULTED;
662
663         return STATUS_SUCCESS;
664 }
665
666 /******************************************************************************
667  *  RtlGetSaclSecurityDescriptor                [NTDLL.@]
668  *
669  */
670 NTSTATUS WINAPI RtlGetSaclSecurityDescriptor(
671         IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
672         OUT PBOOLEAN lpbSaclPresent,
673         OUT PACL *pSacl,
674         OUT PBOOLEAN lpbSaclDefaulted)
675 {
676         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
677
678         TRACE("(%p,%p,%p,%p)\n",
679         pSecurityDescriptor, lpbSaclPresent, pSacl, lpbSaclDefaulted);
680
681         if (lpsd->Revision != SECURITY_DESCRIPTOR_REVISION)
682           return STATUS_UNKNOWN_REVISION;
683
684         if ( (*lpbSaclPresent = (SE_SACL_PRESENT & lpsd->Control) ? 1 : 0) )
685         {
686             if (lpsd->Control & SE_SELF_RELATIVE)
687             {
688                 SECURITY_DESCRIPTOR_RELATIVE *sdr = pSecurityDescriptor;
689                 if (sdr->Sacl) *pSacl = (PACL)SELF_RELATIVE_FIELD( sdr, Sacl );
690                 else *pSacl = NULL;
691             }
692             else *pSacl = lpsd->Sacl;
693
694             *lpbSaclDefaulted = (lpsd->Control & SE_SACL_DEFAULTED) != 0;
695         }
696         return STATUS_SUCCESS;
697 }
698
699 /**************************************************************************
700  * RtlSetSaclSecurityDescriptor                 [NTDLL.@]
701  */
702 NTSTATUS WINAPI RtlSetSaclSecurityDescriptor (
703         PSECURITY_DESCRIPTOR pSecurityDescriptor,
704         BOOLEAN saclpresent,
705         PACL sacl,
706         BOOLEAN sacldefaulted)
707 {
708         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
709
710         if (lpsd->Revision!=SECURITY_DESCRIPTOR_REVISION)
711                 return STATUS_UNKNOWN_REVISION;
712         if (lpsd->Control & SE_SELF_RELATIVE)
713                 return STATUS_INVALID_SECURITY_DESCR;
714         if (!saclpresent) {
715                 lpsd->Control &= ~SE_SACL_PRESENT;
716                 return 0;
717         }
718         lpsd->Control |= SE_SACL_PRESENT;
719         lpsd->Sacl = sacl;
720         if (sacldefaulted)
721                 lpsd->Control |= SE_SACL_DEFAULTED;
722         else
723                 lpsd->Control &= ~SE_SACL_DEFAULTED;
724         return STATUS_SUCCESS;
725 }
726
727 /**************************************************************************
728  * RtlGetOwnerSecurityDescriptor                [NTDLL.@]
729  */
730 NTSTATUS WINAPI RtlGetOwnerSecurityDescriptor(
731         PSECURITY_DESCRIPTOR pSecurityDescriptor,
732         PSID *Owner,
733         PBOOLEAN OwnerDefaulted)
734 {
735         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
736
737         if ( !lpsd  || !Owner || !OwnerDefaulted )
738                 return STATUS_INVALID_PARAMETER;
739
740         if ( lpsd->Control & SE_OWNER_DEFAULTED )
741             *OwnerDefaulted = TRUE;
742         else
743             *OwnerDefaulted = FALSE;
744
745         if (lpsd->Control & SE_SELF_RELATIVE)
746         {
747             SECURITY_DESCRIPTOR_RELATIVE *sd = pSecurityDescriptor;
748             if (sd->Owner) *Owner = (PSID)SELF_RELATIVE_FIELD( sd, Owner );
749             else *Owner = NULL;
750         }
751         else
752             *Owner = lpsd->Owner;
753
754         return STATUS_SUCCESS;
755 }
756
757 /**************************************************************************
758  *                 RtlSetOwnerSecurityDescriptor                [NTDLL.@]
759  */
760 NTSTATUS WINAPI RtlSetOwnerSecurityDescriptor(
761         PSECURITY_DESCRIPTOR pSecurityDescriptor,
762         PSID owner,
763         BOOLEAN ownerdefaulted)
764 {
765         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
766
767         if (lpsd->Revision!=SECURITY_DESCRIPTOR_REVISION)
768                 return STATUS_UNKNOWN_REVISION;
769         if (lpsd->Control & SE_SELF_RELATIVE)
770                 return STATUS_INVALID_SECURITY_DESCR;
771
772         lpsd->Owner = owner;
773         if (ownerdefaulted)
774                 lpsd->Control |= SE_OWNER_DEFAULTED;
775         else
776                 lpsd->Control &= ~SE_OWNER_DEFAULTED;
777         return STATUS_SUCCESS;
778 }
779
780 /**************************************************************************
781  *                 RtlSetGroupSecurityDescriptor                [NTDLL.@]
782  */
783 NTSTATUS WINAPI RtlSetGroupSecurityDescriptor (
784         PSECURITY_DESCRIPTOR pSecurityDescriptor,
785         PSID group,
786         BOOLEAN groupdefaulted)
787 {
788         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
789
790         if (lpsd->Revision!=SECURITY_DESCRIPTOR_REVISION)
791                 return STATUS_UNKNOWN_REVISION;
792         if (lpsd->Control & SE_SELF_RELATIVE)
793                 return STATUS_INVALID_SECURITY_DESCR;
794
795         lpsd->Group = group;
796         if (groupdefaulted)
797                 lpsd->Control |= SE_GROUP_DEFAULTED;
798         else
799                 lpsd->Control &= ~SE_GROUP_DEFAULTED;
800         return STATUS_SUCCESS;
801 }
802
803 /**************************************************************************
804  *                 RtlGetGroupSecurityDescriptor                [NTDLL.@]
805  */
806 NTSTATUS WINAPI RtlGetGroupSecurityDescriptor(
807         PSECURITY_DESCRIPTOR pSecurityDescriptor,
808         PSID *Group,
809         PBOOLEAN GroupDefaulted)
810 {
811         SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor;
812
813         if ( !lpsd || !Group || !GroupDefaulted )
814                 return STATUS_INVALID_PARAMETER;
815
816         if ( lpsd->Control & SE_GROUP_DEFAULTED )
817             *GroupDefaulted = TRUE;
818         else
819             *GroupDefaulted = FALSE;
820
821         if (lpsd->Control & SE_SELF_RELATIVE)
822         {
823             SECURITY_DESCRIPTOR_RELATIVE *sd = pSecurityDescriptor;
824             if (sd->Group) *Group = (PSID)SELF_RELATIVE_FIELD( sd, Group );
825             else *Group = NULL;
826         }
827         else
828             *Group = lpsd->Group;
829
830         return STATUS_SUCCESS;
831 }
832
833 /**************************************************************************
834  *                 RtlMakeSelfRelativeSD                [NTDLL.@]
835  */
836 NTSTATUS WINAPI RtlMakeSelfRelativeSD(
837         IN PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,
838         IN PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
839         IN OUT LPDWORD lpdwBufferLength)
840 {
841     DWORD offsetRel;
842     ULONG length;
843     SECURITY_DESCRIPTOR* pAbs = pAbsoluteSecurityDescriptor;
844     SECURITY_DESCRIPTOR_RELATIVE *pRel = pSelfRelativeSecurityDescriptor;
845
846     TRACE(" %p %p %p(%d)\n", pAbs, pRel, lpdwBufferLength,
847         lpdwBufferLength ? *lpdwBufferLength: -1);
848
849     if (!lpdwBufferLength || !pAbs)
850         return STATUS_INVALID_PARAMETER;
851
852     length = RtlLengthSecurityDescriptor(pAbs);
853     if (*lpdwBufferLength < length)
854     {
855         *lpdwBufferLength = length;
856         return STATUS_BUFFER_TOO_SMALL;
857     }
858
859     if (!pRel)
860         return STATUS_INVALID_PARAMETER;
861
862     if (pAbs->Control & SE_SELF_RELATIVE)
863     {
864         memcpy(pRel, pAbs, length);
865         return STATUS_SUCCESS;
866     }
867
868     pRel->Revision = pAbs->Revision;
869     pRel->Sbz1 = pAbs->Sbz1;
870     pRel->Control = pAbs->Control | SE_SELF_RELATIVE;
871
872     offsetRel = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
873     if (pAbs->Owner)
874     {
875         pRel->Owner = offsetRel;
876         length = RtlLengthSid(pAbs->Owner);
877         memcpy((LPBYTE)pRel + offsetRel, pAbs->Owner, length);
878         offsetRel += length;
879     }
880     else
881     {
882         pRel->Owner = 0;
883     }
884
885     if (pAbs->Group)
886     {
887         pRel->Group = offsetRel;
888         length = RtlLengthSid(pAbs->Group);
889         memcpy((LPBYTE)pRel + offsetRel, pAbs->Group, length);
890         offsetRel += length;
891     }
892     else
893     {
894         pRel->Group = 0;
895     }
896
897     if (pAbs->Sacl)
898     {
899         pRel->Sacl = offsetRel;
900         length = pAbs->Sacl->AclSize;
901         memcpy((LPBYTE)pRel + offsetRel, pAbs->Sacl, length);
902         offsetRel += length;
903     }
904     else
905     {
906         pRel->Sacl = 0;
907     }
908
909     if (pAbs->Dacl)
910     {
911         pRel->Dacl = offsetRel;
912         length = pAbs->Dacl->AclSize;
913         memcpy((LPBYTE)pRel + offsetRel, pAbs->Dacl, length);
914     }
915     else
916     {
917         pRel->Dacl = 0;
918     }
919
920     return STATUS_SUCCESS;
921 }
922
923
924 /**************************************************************************
925  *                 RtlSelfRelativeToAbsoluteSD [NTDLL.@]
926  */
927 NTSTATUS WINAPI RtlSelfRelativeToAbsoluteSD(
928         IN PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
929         OUT PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,
930         OUT LPDWORD lpdwAbsoluteSecurityDescriptorSize,
931         OUT PACL pDacl,
932         OUT LPDWORD lpdwDaclSize,
933         OUT PACL pSacl,
934         OUT LPDWORD lpdwSaclSize,
935         OUT PSID pOwner,
936         OUT LPDWORD lpdwOwnerSize,
937         OUT PSID pPrimaryGroup,
938         OUT LPDWORD lpdwPrimaryGroupSize)
939 {
940     NTSTATUS status = STATUS_SUCCESS;
941     SECURITY_DESCRIPTOR* pAbs = pAbsoluteSecurityDescriptor;
942     SECURITY_DESCRIPTOR_RELATIVE* pRel = pSelfRelativeSecurityDescriptor;
943
944     if (!pRel ||
945         !lpdwAbsoluteSecurityDescriptorSize ||
946         !lpdwDaclSize ||
947         !lpdwSaclSize ||
948         !lpdwOwnerSize ||
949         !lpdwPrimaryGroupSize ||
950         ~pRel->Control & SE_SELF_RELATIVE)
951         return STATUS_INVALID_PARAMETER;
952
953     /* Confirm buffers are sufficiently large */
954     if (*lpdwAbsoluteSecurityDescriptorSize < sizeof(SECURITY_DESCRIPTOR))
955     {
956         *lpdwAbsoluteSecurityDescriptorSize = sizeof(SECURITY_DESCRIPTOR);
957         status = STATUS_BUFFER_TOO_SMALL;
958     }
959
960     if ((pRel->Control & SE_DACL_PRESENT) && pRel->Dacl &&
961         *lpdwDaclSize  < ((PACL)SELF_RELATIVE_FIELD(pRel,Dacl))->AclSize)
962     {
963         *lpdwDaclSize = ((PACL)SELF_RELATIVE_FIELD(pRel,Dacl))->AclSize;
964         status = STATUS_BUFFER_TOO_SMALL;
965     }
966
967     if ((pRel->Control & SE_SACL_PRESENT) && pRel->Sacl &&
968         *lpdwSaclSize  < ((PACL)SELF_RELATIVE_FIELD(pRel,Sacl))->AclSize)
969     {
970         *lpdwSaclSize = ((PACL)SELF_RELATIVE_FIELD(pRel,Sacl))->AclSize;
971         status = STATUS_BUFFER_TOO_SMALL;
972     }
973
974     if (pRel->Owner &&
975         *lpdwOwnerSize < RtlLengthSid((PSID)SELF_RELATIVE_FIELD(pRel,Owner)))
976     {
977         *lpdwOwnerSize = RtlLengthSid((PSID)SELF_RELATIVE_FIELD(pRel,Owner));
978         status = STATUS_BUFFER_TOO_SMALL;
979     }
980
981     if (pRel->Group &&
982         *lpdwPrimaryGroupSize < RtlLengthSid((PSID)SELF_RELATIVE_FIELD(pRel,Group)))
983     {
984         *lpdwPrimaryGroupSize = RtlLengthSid((PSID)SELF_RELATIVE_FIELD(pRel,Group));
985         status = STATUS_BUFFER_TOO_SMALL;
986     }
987
988     if (status != STATUS_SUCCESS)
989         return status;
990
991     /* Copy structures, and clear the ones we don't set */
992     pAbs->Revision = pRel->Revision;
993     pAbs->Control = pRel->Control & ~SE_SELF_RELATIVE;
994     pAbs->Sacl = NULL;
995     pAbs->Dacl = NULL;
996     pAbs->Owner = NULL;
997     pAbs->Group = NULL;
998
999     if ((pRel->Control & SE_SACL_PRESENT) && pRel->Sacl)
1000     {
1001         PACL pAcl = (PACL)SELF_RELATIVE_FIELD( pRel, Sacl );
1002
1003         memcpy(pSacl, pAcl, pAcl->AclSize);
1004         pAbs->Sacl = pSacl;
1005     }
1006
1007     if ((pRel->Control & SE_DACL_PRESENT) && pRel->Dacl)
1008     {
1009         PACL pAcl = (PACL)SELF_RELATIVE_FIELD( pRel, Dacl );
1010         memcpy(pDacl, pAcl, pAcl->AclSize);
1011         pAbs->Dacl = pDacl;
1012     }
1013
1014     if (pRel->Owner)
1015     {
1016         PSID psid = (PSID)SELF_RELATIVE_FIELD( pRel, Owner );
1017         memcpy(pOwner, psid, RtlLengthSid(psid));
1018         pAbs->Owner = pOwner;
1019     }
1020
1021     if (pRel->Group)
1022     {
1023         PSID psid = (PSID)SELF_RELATIVE_FIELD( pRel, Group );
1024         memcpy(pPrimaryGroup, psid, RtlLengthSid(psid));
1025         pAbs->Group = pPrimaryGroup;
1026     }
1027
1028     return status;
1029 }
1030
1031 /******************************************************************************
1032  * RtlGetControlSecurityDescriptor (NTDLL.@)
1033  */
1034 NTSTATUS WINAPI RtlGetControlSecurityDescriptor(
1035     PSECURITY_DESCRIPTOR pSecurityDescriptor,
1036     PSECURITY_DESCRIPTOR_CONTROL pControl,
1037     LPDWORD lpdwRevision)
1038 {
1039     SECURITY_DESCRIPTOR *lpsd = pSecurityDescriptor;
1040
1041     TRACE("(%p,%p,%p)\n",pSecurityDescriptor,pControl,lpdwRevision);
1042
1043     *lpdwRevision = lpsd->Revision;
1044
1045     if (*lpdwRevision != SECURITY_DESCRIPTOR_REVISION)
1046         return STATUS_UNKNOWN_REVISION;
1047
1048     *pControl = lpsd->Control;
1049
1050     return STATUS_SUCCESS;
1051 }
1052
1053 /******************************************************************************
1054  * RtlSetControlSecurityDescriptor (NTDLL.@)
1055  */
1056 NTSTATUS WINAPI RtlSetControlSecurityDescriptor(
1057     PSECURITY_DESCRIPTOR SecurityDescriptor,
1058     SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
1059     SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet)
1060 {
1061     SECURITY_DESCRIPTOR_CONTROL const immutable
1062        = SE_OWNER_DEFAULTED  | SE_GROUP_DEFAULTED
1063        | SE_DACL_PRESENT     | SE_DACL_DEFAULTED
1064        | SE_SACL_PRESENT     | SE_SACL_DEFAULTED
1065        | SE_RM_CONTROL_VALID | SE_SELF_RELATIVE
1066        ;
1067
1068     SECURITY_DESCRIPTOR *lpsd = SecurityDescriptor;
1069
1070     TRACE("(%p 0x%04x 0x%04x)\n", SecurityDescriptor,
1071           ControlBitsOfInterest, ControlBitsToSet);
1072
1073     if ((ControlBitsOfInterest | ControlBitsToSet) & immutable)
1074         return STATUS_INVALID_PARAMETER;
1075
1076     lpsd->Control |=  (ControlBitsOfInterest &  ControlBitsToSet);
1077     lpsd->Control &= ~(ControlBitsOfInterest & ~ControlBitsToSet);
1078
1079     return STATUS_SUCCESS;
1080 }
1081
1082
1083 /**************************************************************************
1084  *                 RtlAbsoluteToSelfRelativeSD [NTDLL.@]
1085  */
1086 NTSTATUS WINAPI RtlAbsoluteToSelfRelativeSD(
1087     PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor,
1088     PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor,
1089     PULONG BufferLength)
1090 {
1091     SECURITY_DESCRIPTOR *abs = AbsoluteSecurityDescriptor;
1092
1093     TRACE("%p %p %p\n", AbsoluteSecurityDescriptor,
1094           SelfRelativeSecurityDescriptor, BufferLength);
1095
1096     if (abs->Control & SE_SELF_RELATIVE)
1097         return STATUS_BAD_DESCRIPTOR_FORMAT;
1098
1099     return RtlMakeSelfRelativeSD(AbsoluteSecurityDescriptor, 
1100         SelfRelativeSecurityDescriptor, BufferLength);
1101 }
1102
1103
1104 /*
1105  *      access control list's
1106  */
1107
1108 /**************************************************************************
1109  *                 RtlCreateAcl                         [NTDLL.@]
1110  *
1111  * NOTES
1112  *    This should return NTSTATUS
1113  */
1114 NTSTATUS WINAPI RtlCreateAcl(PACL acl,DWORD size,DWORD rev)
1115 {
1116         TRACE("%p 0x%08x 0x%08x\n", acl, size, rev);
1117
1118         if (rev < MIN_ACL_REVISION || rev > MAX_ACL_REVISION)
1119                 return STATUS_INVALID_PARAMETER;
1120         if (size<sizeof(ACL))
1121                 return STATUS_BUFFER_TOO_SMALL;
1122         if (size>0xFFFF)
1123                 return STATUS_INVALID_PARAMETER;
1124
1125         memset(acl,'\0',sizeof(ACL));
1126         acl->AclRevision        = rev;
1127         acl->AclSize            = size;
1128         acl->AceCount           = 0;
1129         return STATUS_SUCCESS;
1130 }
1131
1132 /**************************************************************************
1133  *                 RtlFirstFreeAce                      [NTDLL.@]
1134  * looks for the AceCount+1 ACE, and if it is still within the alloced
1135  * ACL, return a pointer to it
1136  */
1137 BOOLEAN WINAPI RtlFirstFreeAce(
1138         PACL acl,
1139         PACE_HEADER *x)
1140 {
1141         PACE_HEADER     ace;
1142         int             i;
1143
1144         *x = 0;
1145         ace = (PACE_HEADER)(acl+1);
1146         for (i=0;i<acl->AceCount;i++) {
1147                 if ((BYTE *)ace >= (BYTE *)acl + acl->AclSize)
1148                         return 0;
1149                 ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize);
1150         }
1151         if ((BYTE *)ace >= (BYTE *)acl + acl->AclSize)
1152                 return 0;
1153         *x = ace;
1154         return 1;
1155 }
1156
1157 /**************************************************************************
1158  *                 RtlAddAce                            [NTDLL.@]
1159  */
1160 NTSTATUS WINAPI RtlAddAce(
1161         PACL acl,
1162         DWORD rev,
1163         DWORD xnrofaces,
1164         PACE_HEADER acestart,
1165         DWORD acelen)
1166 {
1167         PACE_HEADER     ace,targetace;
1168         int             nrofaces;
1169
1170         if (acl->AclRevision != ACL_REVISION)
1171                 return STATUS_INVALID_PARAMETER;
1172         if (!RtlFirstFreeAce(acl,&targetace))
1173                 return STATUS_INVALID_PARAMETER;
1174         nrofaces=0;ace=acestart;
1175         while (((BYTE *)ace - (BYTE *)acestart) < acelen) {
1176                 nrofaces++;
1177                 ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize);
1178         }
1179         if ((BYTE *)targetace + acelen > (BYTE *)acl + acl->AclSize) /* too much aces */
1180                 return STATUS_INVALID_PARAMETER;
1181         memcpy(targetace,acestart,acelen);
1182         acl->AceCount+=nrofaces;
1183         return STATUS_SUCCESS;
1184 }
1185
1186 /**************************************************************************
1187  *                 RtlDeleteAce                         [NTDLL.@]
1188  */
1189 NTSTATUS  WINAPI RtlDeleteAce(PACL pAcl, DWORD dwAceIndex)
1190 {
1191         NTSTATUS status;
1192         PACE_HEADER pAce;
1193
1194         status = RtlGetAce(pAcl,dwAceIndex,(LPVOID*)&pAce);
1195
1196         if (STATUS_SUCCESS == status)
1197         {
1198                 PACE_HEADER pcAce;
1199                 DWORD len = 0;
1200
1201                 /* skip over the ACE we are deleting */
1202                 pcAce = (PACE_HEADER)(((BYTE*)pAce)+pAce->AceSize);
1203                 dwAceIndex++;
1204
1205                 /* calculate the length of the rest */
1206                 for (; dwAceIndex < pAcl->AceCount; dwAceIndex++)
1207                 {
1208                         len += pcAce->AceSize;
1209                         pcAce = (PACE_HEADER)(((BYTE*)pcAce) + pcAce->AceSize);
1210                 }
1211
1212                 /* slide them all backwards */
1213                 memmove(pAce, ((BYTE*)pAce)+pAce->AceSize, len);
1214                 pAcl->AceCount--;
1215         }
1216
1217         TRACE("pAcl=%p dwAceIndex=%d status=0x%08x\n", pAcl, dwAceIndex, status);
1218
1219         return status;
1220 }
1221
1222 /******************************************************************************
1223  *  RtlAddAccessAllowedAce              [NTDLL.@]
1224  */
1225 NTSTATUS WINAPI RtlAddAccessAllowedAce(
1226         IN OUT PACL pAcl,
1227         IN DWORD dwAceRevision,
1228         IN DWORD AccessMask,
1229         IN PSID pSid)
1230 {
1231         return RtlAddAccessAllowedAceEx( pAcl, dwAceRevision, 0, AccessMask, pSid);
1232 }
1233  
1234 /******************************************************************************
1235  *  RtlAddAccessAllowedAceEx            [NTDLL.@]
1236  */
1237 NTSTATUS WINAPI RtlAddAccessAllowedAceEx(
1238         IN OUT PACL pAcl,
1239         IN DWORD dwAceRevision,
1240         IN DWORD AceFlags,
1241         IN DWORD AccessMask,
1242         IN PSID pSid)
1243 {
1244    TRACE("(%p,0x%08x,0x%08x,%p)\n", pAcl, dwAceRevision, AccessMask, pSid);
1245
1246     return add_access_ace(pAcl, dwAceRevision, AceFlags,
1247                           AccessMask, pSid, ACCESS_ALLOWED_ACE_TYPE);
1248 }
1249
1250 /******************************************************************************
1251  *  RtlAddAccessDeniedAce               [NTDLL.@]
1252  */
1253 NTSTATUS WINAPI RtlAddAccessDeniedAce(
1254         IN OUT PACL pAcl,
1255         IN DWORD dwAceRevision,
1256         IN DWORD AccessMask,
1257         IN PSID pSid)
1258 {
1259         return RtlAddAccessDeniedAceEx( pAcl, dwAceRevision, 0, AccessMask, pSid);
1260 }
1261
1262 /******************************************************************************
1263  *  RtlAddAccessDeniedAceEx             [NTDLL.@]
1264  */
1265 NTSTATUS WINAPI RtlAddAccessDeniedAceEx(
1266         IN OUT PACL pAcl,
1267         IN DWORD dwAceRevision,
1268         IN DWORD AceFlags,
1269         IN DWORD AccessMask,
1270         IN PSID pSid)
1271 {
1272    TRACE("(%p,0x%08x,0x%08x,%p)\n", pAcl, dwAceRevision, AccessMask, pSid);
1273
1274     return add_access_ace(pAcl, dwAceRevision, AceFlags,
1275                           AccessMask, pSid, ACCESS_DENIED_ACE_TYPE);
1276 }
1277
1278 /************************************************************************** 
1279  *  RtlAddAuditAccessAce     [NTDLL.@] 
1280  */ 
1281 NTSTATUS WINAPI RtlAddAuditAccessAceEx(
1282     IN OUT PACL pAcl, 
1283     IN DWORD dwAceRevision, 
1284     IN DWORD dwAceFlags,
1285     IN DWORD dwAccessMask, 
1286     IN PSID pSid, 
1287     IN BOOL bAuditSuccess, 
1288     IN BOOL bAuditFailure) 
1289
1290     TRACE("(%p,%d,0x%08x,0x%08x,%p,%u,%u)\n",pAcl,dwAceRevision,dwAceFlags,dwAccessMask,
1291           pSid,bAuditSuccess,bAuditFailure);
1292
1293     if (bAuditSuccess)
1294         dwAceFlags |= SUCCESSFUL_ACCESS_ACE_FLAG;
1295
1296     if (bAuditFailure)
1297         dwAceFlags |= FAILED_ACCESS_ACE_FLAG;
1298
1299     return add_access_ace(pAcl, dwAceRevision, dwAceFlags,
1300                           dwAccessMask, pSid, SYSTEM_AUDIT_ACE_TYPE);
1301
1302
1303 /**************************************************************************
1304  *  RtlAddAuditAccessAce     [NTDLL.@]
1305  */
1306 NTSTATUS WINAPI RtlAddAuditAccessAce(
1307     IN OUT PACL pAcl,
1308     IN DWORD dwAceRevision,
1309     IN DWORD dwAccessMask,
1310     IN PSID pSid,
1311     IN BOOL bAuditSuccess,
1312     IN BOOL bAuditFailure)
1313 {
1314     return RtlAddAuditAccessAceEx(pAcl, dwAceRevision, 0, dwAccessMask, pSid, bAuditSuccess, bAuditFailure);
1315 }
1316  
1317 /******************************************************************************
1318  *  RtlValidAcl         [NTDLL.@]
1319  */
1320 BOOLEAN WINAPI RtlValidAcl(PACL pAcl)
1321 {
1322         BOOLEAN ret;
1323         TRACE("(%p)\n", pAcl);
1324
1325         __TRY
1326         {
1327                 PACE_HEADER     ace;
1328                 int             i;
1329
1330                 if (pAcl->AclRevision < MIN_ACL_REVISION ||
1331                     pAcl->AclRevision > MAX_ACL_REVISION)
1332                     ret = FALSE;
1333                 else
1334                 {
1335                     ace = (PACE_HEADER)(pAcl+1);
1336                     ret = TRUE;
1337                     for (i=0;i<=pAcl->AceCount;i++)
1338                     {
1339                         if ((char *)ace > (char *)pAcl + pAcl->AclSize)
1340                         {
1341                             ret = FALSE;
1342                             break;
1343                         }
1344                         if (i != pAcl->AceCount)
1345                             ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize);
1346                     }
1347                 }
1348         }
1349         __EXCEPT_PAGE_FAULT
1350         {
1351                 WARN("(%p): invalid pointer!\n", pAcl);
1352                 return 0;
1353         }
1354         __ENDTRY
1355         return ret;
1356 }
1357
1358 /******************************************************************************
1359  *  RtlGetAce           [NTDLL.@]
1360  */
1361 NTSTATUS WINAPI RtlGetAce(PACL pAcl,DWORD dwAceIndex,LPVOID *pAce )
1362 {
1363         PACE_HEADER ace;
1364
1365         TRACE("(%p,%d,%p)\n",pAcl,dwAceIndex,pAce);
1366
1367         if (dwAceIndex >= pAcl->AceCount)
1368                 return STATUS_INVALID_PARAMETER;
1369
1370         ace = (PACE_HEADER)(pAcl + 1);
1371         for (;dwAceIndex;dwAceIndex--)
1372                 ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize);
1373
1374         *pAce = ace;
1375
1376         return STATUS_SUCCESS;
1377 }
1378
1379 /*
1380  *      misc
1381  */
1382
1383 /******************************************************************************
1384  *  RtlAdjustPrivilege          [NTDLL.@]
1385  *
1386  * Enables or disables a privilege from the calling thread or process.
1387  *
1388  * PARAMS
1389  *  Privilege     [I] Privilege index to change.
1390  *  Enable        [I] If TRUE, then enable the privilege otherwise disable.
1391  *  CurrentThread [I] If TRUE, then enable in calling thread, otherwise process.
1392  *  Enabled       [O] Whether privilege was previously enabled or disabled.
1393  *
1394  * RETURNS
1395  *  Success: STATUS_SUCCESS.
1396  *  Failure: NTSTATUS code.
1397  *
1398  * SEE ALSO
1399  *  NtAdjustPrivilegesToken, NtOpenThreadToken, NtOpenProcessToken.
1400  *
1401  */
1402 NTSTATUS WINAPI
1403 RtlAdjustPrivilege(ULONG Privilege,
1404                    BOOLEAN Enable,
1405                    BOOLEAN CurrentThread,
1406                    PBOOLEAN Enabled)
1407 {
1408     TOKEN_PRIVILEGES NewState;
1409     TOKEN_PRIVILEGES OldState;
1410     ULONG ReturnLength;
1411     HANDLE TokenHandle;
1412     NTSTATUS Status;
1413
1414     TRACE("(%d, %s, %s, %p)\n", Privilege, Enable ? "TRUE" : "FALSE",
1415         CurrentThread ? "TRUE" : "FALSE", Enabled);
1416
1417     if (CurrentThread)
1418     {
1419         Status = NtOpenThreadToken(GetCurrentThread(),
1420                                    TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
1421                                    FALSE,
1422                                    &TokenHandle);
1423     }
1424     else
1425     {
1426         Status = NtOpenProcessToken(GetCurrentProcess(),
1427                                     TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
1428                                     &TokenHandle);
1429     }
1430
1431     if (!NT_SUCCESS(Status))
1432     {
1433         WARN("Retrieving token handle failed (Status %x)\n", Status);
1434         return Status;
1435     }
1436
1437     OldState.PrivilegeCount = 1;
1438
1439     NewState.PrivilegeCount = 1;
1440     NewState.Privileges[0].Luid.LowPart = Privilege;
1441     NewState.Privileges[0].Luid.HighPart = 0;
1442     NewState.Privileges[0].Attributes = (Enable) ? SE_PRIVILEGE_ENABLED : 0;
1443
1444     Status = NtAdjustPrivilegesToken(TokenHandle,
1445                                      FALSE,
1446                                      &NewState,
1447                                      sizeof(TOKEN_PRIVILEGES),
1448                                      &OldState,
1449                                      &ReturnLength);
1450     NtClose (TokenHandle);
1451     if (Status == STATUS_NOT_ALL_ASSIGNED)
1452     {
1453         TRACE("Failed to assign all privileges\n");
1454         return STATUS_PRIVILEGE_NOT_HELD;
1455     }
1456     if (!NT_SUCCESS(Status))
1457     {
1458         WARN("NtAdjustPrivilegesToken() failed (Status %x)\n", Status);
1459         return Status;
1460     }
1461
1462     if (OldState.PrivilegeCount == 0)
1463         *Enabled = Enable;
1464     else
1465         *Enabled = (OldState.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED);
1466
1467     return STATUS_SUCCESS;
1468 }
1469
1470 /******************************************************************************
1471  *  RtlImpersonateSelf          [NTDLL.@]
1472  *
1473  * Makes an impersonation token that represents the process user and assigns
1474  * to the current thread.
1475  *
1476  * PARAMS
1477  *  ImpersonationLevel [I] Level at which to impersonate.
1478  *
1479  * RETURNS
1480  *  Success: STATUS_SUCCESS.
1481  *  Failure: NTSTATUS code.
1482  */
1483 NTSTATUS WINAPI
1484 RtlImpersonateSelf(SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
1485 {
1486     NTSTATUS Status;
1487     OBJECT_ATTRIBUTES ObjectAttributes;
1488     HANDLE ProcessToken;
1489     HANDLE ImpersonationToken;
1490
1491     TRACE("(%08x)\n", ImpersonationLevel);
1492
1493     Status = NtOpenProcessToken( NtCurrentProcess(), TOKEN_DUPLICATE,
1494                                  &ProcessToken);
1495     if (Status != STATUS_SUCCESS)
1496         return Status;
1497
1498     InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
1499
1500     Status = NtDuplicateToken( ProcessToken,
1501                                TOKEN_IMPERSONATE,
1502                                &ObjectAttributes,
1503                                ImpersonationLevel,
1504                                TokenImpersonation,
1505                                &ImpersonationToken );
1506     if (Status != STATUS_SUCCESS)
1507     {
1508         NtClose( ProcessToken );
1509         return Status;
1510     }
1511
1512     Status = NtSetInformationThread( GetCurrentThread(),
1513                                      ThreadImpersonationToken,
1514                                      &ImpersonationToken,
1515                                      sizeof(ImpersonationToken) );
1516
1517     NtClose( ImpersonationToken );
1518     NtClose( ProcessToken );
1519
1520     return Status;
1521 }
1522
1523 /******************************************************************************
1524  *  NtAccessCheck               [NTDLL.@]
1525  *  ZwAccessCheck               [NTDLL.@]
1526  *
1527  * Checks that a user represented by a token is allowed to access an object
1528  * represented by a security descriptor.
1529  *
1530  * PARAMS
1531  *  SecurityDescriptor [I] The security descriptor of the object to check.
1532  *  ClientToken        [I] Token of the user accessing the object.
1533  *  DesiredAccess      [I] The desired access to the object.
1534  *  GenericMapping     [I] Mapping used to transform access rights in the SD to their specific forms.
1535  *  PrivilegeSet       [I/O] Privileges used during the access check.
1536  *  ReturnLength       [O] Number of bytes stored into PrivilegeSet.
1537  *  GrantedAccess      [O] The actual access rights granted.
1538  *  AccessStatus       [O] The status of the access check.
1539  *
1540  * RETURNS
1541  *  NTSTATUS code.
1542  *
1543  * NOTES
1544  *  DesiredAccess may be MAXIMUM_ALLOWED, in which case the function determines
1545  *  the maximum access rights allowed by the SD and returns them in
1546  *  GrantedAccess.
1547  *  The SecurityDescriptor must have a valid owner and groups present,
1548  *  otherwise the function will fail.
1549  */
1550 NTSTATUS WINAPI
1551 NtAccessCheck(
1552     PSECURITY_DESCRIPTOR SecurityDescriptor,
1553     HANDLE ClientToken,
1554     ACCESS_MASK DesiredAccess,
1555     PGENERIC_MAPPING GenericMapping,
1556     PPRIVILEGE_SET PrivilegeSet,
1557     PULONG ReturnLength,
1558     PULONG GrantedAccess,
1559     NTSTATUS *AccessStatus)
1560 {
1561     NTSTATUS status;
1562
1563     TRACE("(%p, %p, %08x, %p, %p, %p, %p, %p)\n",
1564         SecurityDescriptor, ClientToken, DesiredAccess, GenericMapping,
1565         PrivilegeSet, ReturnLength, GrantedAccess, AccessStatus);
1566
1567     if (!PrivilegeSet || !ReturnLength)
1568         return STATUS_ACCESS_VIOLATION;
1569
1570     SERVER_START_REQ( access_check )
1571     {
1572         struct security_descriptor sd;
1573         PSID owner;
1574         PSID group;
1575         PACL sacl;
1576         PACL dacl;
1577         BOOLEAN defaulted, present;
1578         DWORD revision;
1579         SECURITY_DESCRIPTOR_CONTROL control;
1580
1581         req->handle = wine_server_obj_handle( ClientToken );
1582         req->desired_access = DesiredAccess;
1583         req->mapping_read = GenericMapping->GenericRead;
1584         req->mapping_write = GenericMapping->GenericWrite;
1585         req->mapping_execute = GenericMapping->GenericExecute;
1586         req->mapping_all = GenericMapping->GenericAll;
1587
1588         /* marshal security descriptor */
1589         RtlGetControlSecurityDescriptor( SecurityDescriptor, &control, &revision );
1590         sd.control = control & ~SE_SELF_RELATIVE;
1591         RtlGetOwnerSecurityDescriptor( SecurityDescriptor, &owner, &defaulted );
1592         sd.owner_len = RtlLengthSid( owner );
1593         RtlGetGroupSecurityDescriptor( SecurityDescriptor, &group, &defaulted );
1594         sd.group_len = RtlLengthSid( group );
1595         RtlGetSaclSecurityDescriptor( SecurityDescriptor, &present, &sacl, &defaulted );
1596         sd.sacl_len = ((present && sacl) ? acl_bytesInUse(sacl) : 0);
1597         RtlGetDaclSecurityDescriptor( SecurityDescriptor, &present, &dacl, &defaulted );
1598         sd.dacl_len = ((present && dacl) ? acl_bytesInUse(dacl) : 0);
1599
1600         wine_server_add_data( req, &sd, sizeof(sd) );
1601         wine_server_add_data( req, owner, sd.owner_len );
1602         wine_server_add_data( req, group, sd.group_len );
1603         wine_server_add_data( req, sacl, sd.sacl_len );
1604         wine_server_add_data( req, dacl, sd.dacl_len );
1605
1606         wine_server_set_reply( req, PrivilegeSet->Privilege, *ReturnLength - FIELD_OFFSET( PRIVILEGE_SET, Privilege ) );
1607
1608         status = wine_server_call( req );
1609
1610         *ReturnLength = FIELD_OFFSET( PRIVILEGE_SET, Privilege ) + reply->privileges_len;
1611         PrivilegeSet->PrivilegeCount = reply->privileges_len / sizeof(LUID_AND_ATTRIBUTES);
1612
1613         if (status == STATUS_SUCCESS)
1614         {
1615             *AccessStatus = reply->access_status;
1616             *GrantedAccess = reply->access_granted;
1617         }
1618     }
1619     SERVER_END_REQ;
1620
1621     return status;
1622 }
1623
1624 /******************************************************************************
1625  *  NtSetSecurityObject         [NTDLL.@]
1626  *  ZwSetSecurityObject         [NTDLL.@]
1627  *
1628  * Sets specified parts of the object's security descriptor.
1629  *
1630  * PARAMS
1631  *  Handle              [I] Handle to the object to change security descriptor of.
1632  *  SecurityInformation [I] Specifies which parts of the security descriptor to set.
1633  *  SecurityDescriptor  [I] New parts of a security descriptor for the object.
1634  *
1635  * RETURNS
1636  *  NTSTATUS code.
1637  *
1638  */
1639 NTSTATUS WINAPI NtSetSecurityObject(HANDLE Handle,
1640         SECURITY_INFORMATION SecurityInformation,
1641         PSECURITY_DESCRIPTOR SecurityDescriptor)
1642 {
1643     NTSTATUS status;
1644     struct security_descriptor sd;
1645     PACL dacl = NULL, sacl = NULL;
1646     PSID owner = NULL, group = NULL;
1647     BOOLEAN defaulted, present;
1648     DWORD revision;
1649     SECURITY_DESCRIPTOR_CONTROL control;
1650
1651     TRACE("%p 0x%08x %p\n", Handle, SecurityInformation, SecurityDescriptor);
1652
1653     if (!SecurityDescriptor) return STATUS_ACCESS_VIOLATION;
1654
1655     memset( &sd, 0, sizeof(sd) );
1656     status = RtlGetControlSecurityDescriptor( SecurityDescriptor, &control, &revision );
1657     if (status != STATUS_SUCCESS) return status;
1658     sd.control = control & ~SE_SELF_RELATIVE;
1659
1660     if (SecurityInformation & OWNER_SECURITY_INFORMATION)
1661     {
1662         status = RtlGetOwnerSecurityDescriptor( SecurityDescriptor, &owner, &defaulted );
1663         if (status != STATUS_SUCCESS) return status;
1664         if (!(sd.owner_len = RtlLengthSid( owner )))
1665             return STATUS_INVALID_SECURITY_DESCR;
1666     }
1667
1668     if (SecurityInformation & GROUP_SECURITY_INFORMATION)
1669     {
1670         status = RtlGetGroupSecurityDescriptor( SecurityDescriptor, &group, &defaulted );
1671         if (status != STATUS_SUCCESS) return status;
1672         if (!(sd.group_len = RtlLengthSid( group )))
1673             return STATUS_INVALID_SECURITY_DESCR;
1674     }
1675
1676     if (SecurityInformation & SACL_SECURITY_INFORMATION)
1677     {
1678         status = RtlGetSaclSecurityDescriptor( SecurityDescriptor, &present, &sacl, &defaulted );
1679         if (status != STATUS_SUCCESS) return status;
1680         sd.sacl_len = (sacl && present) ? acl_bytesInUse(sacl) : 0;
1681         sd.control |= SE_SACL_PRESENT;
1682     }
1683
1684     if (SecurityInformation & DACL_SECURITY_INFORMATION)
1685     {
1686         status = RtlGetDaclSecurityDescriptor( SecurityDescriptor, &present, &dacl, &defaulted );
1687         if (status != STATUS_SUCCESS) return status;
1688         sd.dacl_len = (dacl && present) ? acl_bytesInUse(dacl) : 0;
1689         sd.control |= SE_DACL_PRESENT;
1690     }
1691
1692     SERVER_START_REQ( set_security_object )
1693     {
1694         req->handle = wine_server_obj_handle( Handle );
1695         req->security_info = SecurityInformation;
1696
1697         wine_server_add_data( req, &sd, sizeof(sd) );
1698         wine_server_add_data( req, owner, sd.owner_len );
1699         wine_server_add_data( req, group, sd.group_len );
1700         wine_server_add_data( req, sacl, sd.sacl_len );
1701         wine_server_add_data( req, dacl, sd.dacl_len );
1702         status = wine_server_call( req );
1703     }
1704     SERVER_END_REQ;
1705
1706     return status;
1707 }
1708
1709 /******************************************************************************
1710  * RtlConvertSidToUnicodeString (NTDLL.@)
1711  *
1712  * The returned SID is used to access the USER registry hive usually
1713  *
1714  * the native function returns something like
1715  * "S-1-5-21-0000000000-000000000-0000000000-500";
1716  */
1717 NTSTATUS WINAPI RtlConvertSidToUnicodeString(
1718        PUNICODE_STRING String,
1719        PSID pSid,
1720        BOOLEAN AllocateString)
1721 {
1722     static const WCHAR formatW[] = {'-','%','u',0};
1723     WCHAR buffer[2 + 10 + 10 + 10 * SID_MAX_SUB_AUTHORITIES];
1724     WCHAR *p = buffer;
1725     const SID *sid = pSid;
1726     DWORD i, len;
1727
1728     *p++ = 'S';
1729     p += sprintfW( p, formatW, sid->Revision );
1730     p += sprintfW( p, formatW, MAKELONG( MAKEWORD( sid->IdentifierAuthority.Value[5],
1731                                                    sid->IdentifierAuthority.Value[4] ),
1732                                          MAKEWORD( sid->IdentifierAuthority.Value[3],
1733                                                    sid->IdentifierAuthority.Value[2] )));
1734     for (i = 0; i < sid->SubAuthorityCount; i++)
1735         p += sprintfW( p, formatW, sid->SubAuthority[i] );
1736
1737     len = (p + 1 - buffer) * sizeof(WCHAR);
1738
1739     String->Length = len - sizeof(WCHAR);
1740     if (AllocateString)
1741     {
1742         String->MaximumLength = len;
1743         if (!(String->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len )))
1744             return STATUS_NO_MEMORY;
1745     }
1746     else if (len > String->MaximumLength) return STATUS_BUFFER_OVERFLOW;
1747
1748     memcpy( String->Buffer, buffer, len );
1749     return STATUS_SUCCESS;
1750 }
1751
1752 /******************************************************************************
1753  * RtlQueryInformationAcl (NTDLL.@)
1754  */
1755 NTSTATUS WINAPI RtlQueryInformationAcl(
1756     PACL pAcl,
1757     LPVOID pAclInformation,
1758     DWORD nAclInformationLength,
1759     ACL_INFORMATION_CLASS dwAclInformationClass)
1760 {
1761     NTSTATUS status = STATUS_SUCCESS;
1762
1763     TRACE("pAcl=%p pAclInfo=%p len=%d, class=%d\n", 
1764         pAcl, pAclInformation, nAclInformationLength, dwAclInformationClass);
1765
1766     switch (dwAclInformationClass)
1767     {
1768         case AclRevisionInformation:
1769         {
1770             PACL_REVISION_INFORMATION paclrev = pAclInformation;
1771
1772             if (nAclInformationLength < sizeof(ACL_REVISION_INFORMATION))
1773                 status = STATUS_INVALID_PARAMETER;
1774             else
1775                 paclrev->AclRevision = pAcl->AclRevision;
1776
1777             break;
1778         }
1779
1780         case AclSizeInformation:
1781         {
1782             PACL_SIZE_INFORMATION paclsize = pAclInformation;
1783
1784             if (nAclInformationLength < sizeof(ACL_SIZE_INFORMATION))
1785                 status = STATUS_INVALID_PARAMETER;
1786             else
1787             {
1788                 paclsize->AceCount = pAcl->AceCount;
1789                 paclsize->AclBytesInUse = acl_bytesInUse(pAcl);
1790                 if (pAcl->AclSize < paclsize->AclBytesInUse)
1791                 {
1792                     WARN("Acl uses %d bytes, but only has %d allocated!  Returning smaller of the two values.\n", pAcl->AclSize, paclsize->AclBytesInUse);
1793                     paclsize->AclBytesFree = 0;
1794                     paclsize->AclBytesInUse = pAcl->AclSize;
1795                 }
1796                 else
1797                     paclsize->AclBytesFree = pAcl->AclSize - paclsize->AclBytesInUse;
1798             }
1799
1800             break;
1801         }
1802
1803         default:
1804             WARN("Unknown AclInformationClass value: %d\n", dwAclInformationClass);
1805             status = STATUS_INVALID_PARAMETER;
1806     }
1807
1808     return status;
1809 }