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