xref: /reactos/dll/win32/advapi32/wine/security.c (revision ba3f0743)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * WINE COPYRIGHT:
4  * Copyright 1999, 2000 Juergen Schmied <juergen.schmied@debitel.net>
5  * Copyright 2003 CodeWeavers Inc. (Ulrich Czekalla)
6  * Copyright 2006 Robert Reif
7  * Copyright 2006 Herv� Poussineau
8  *
9  * PROJECT:         ReactOS system libraries
10  * FILE:            dll/win32/advapi32/wine/security.c
11  */
12 
13 #include <advapi32.h>
14 
15 #include <sddl.h>
16 
17 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
18 
19 static BOOL ParseStringSidToSid(LPCWSTR StringSid, PSID pSid, LPDWORD cBytes);
20 
21 typedef struct _ACEFLAG
22 {
23    LPCWSTR wstr;
24    DWORD value;
25 } ACEFLAG, *LPACEFLAG;
26 
27 typedef struct _MAX_SID
28 {
29     /* same fields as struct _SID */
30     BYTE Revision;
31     BYTE SubAuthorityCount;
32     SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
33     DWORD SubAuthority[SID_MAX_SUB_AUTHORITIES];
34 } MAX_SID;
35 
36 typedef struct WELLKNOWNSID
37 {
38     WCHAR wstr[2];
39     WELL_KNOWN_SID_TYPE Type;
40     MAX_SID Sid;
41 } WELLKNOWNSID;
42 
43 static const WELLKNOWNSID WellKnownSids[] =
44 {
45     { {0,0}, WinNullSid, { SID_REVISION, 1, { SECURITY_NULL_SID_AUTHORITY }, { SECURITY_NULL_RID } } },
46     { {'W','D'}, WinWorldSid, { SID_REVISION, 1, { SECURITY_WORLD_SID_AUTHORITY }, { SECURITY_WORLD_RID } } },
47     { {0,0}, WinLocalSid, { SID_REVISION, 1, { SECURITY_LOCAL_SID_AUTHORITY }, { SECURITY_LOCAL_RID } } },
48     { {'C','O'}, WinCreatorOwnerSid, { SID_REVISION, 1, { SECURITY_CREATOR_SID_AUTHORITY }, { SECURITY_CREATOR_OWNER_RID } } },
49     { {'C','G'}, WinCreatorGroupSid, { SID_REVISION, 1, { SECURITY_CREATOR_SID_AUTHORITY }, { SECURITY_CREATOR_GROUP_RID } } },
50     { {0,0}, WinCreatorOwnerServerSid, { SID_REVISION, 1, { SECURITY_CREATOR_SID_AUTHORITY }, { SECURITY_CREATOR_OWNER_SERVER_RID } } },
51     { {0,0}, WinCreatorGroupServerSid, { SID_REVISION, 1, { SECURITY_CREATOR_SID_AUTHORITY }, { SECURITY_CREATOR_GROUP_SERVER_RID } } },
52     { {0,0}, WinNtAuthoritySid, { SID_REVISION, 0, { SECURITY_NT_AUTHORITY }, { SECURITY_NULL_RID } } },
53     { {0,0}, WinDialupSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_DIALUP_RID } } },
54     { {'N','U'}, WinNetworkSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_NETWORK_RID } } },
55     { {0,0}, WinBatchSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_BATCH_RID } } },
56     { {'I','U'}, WinInteractiveSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_INTERACTIVE_RID } } },
57     { {'S','U'}, WinServiceSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_SERVICE_RID } } },
58     { {'A','N'}, WinAnonymousSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_ANONYMOUS_LOGON_RID } } },
59     { {0,0}, WinProxySid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_PROXY_RID } } },
60     { {'E','D'}, WinEnterpriseControllersSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_ENTERPRISE_CONTROLLERS_RID } } },
61     { {'P','S'}, WinSelfSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_PRINCIPAL_SELF_RID } } },
62     { {'A','U'}, WinAuthenticatedUserSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_AUTHENTICATED_USER_RID } } },
63     { {'R','C'}, WinRestrictedCodeSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_RESTRICTED_CODE_RID } } },
64     { {0,0}, WinTerminalServerSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_TERMINAL_SERVER_RID } } },
65     { {0,0}, WinRemoteLogonIdSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_REMOTE_LOGON_RID } } },
66     { {'S','Y'}, WinLocalSystemSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_LOCAL_SYSTEM_RID } } },
67     { {'L','S'}, WinLocalServiceSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_LOCAL_SERVICE_RID } } },
68     { {'N','S'}, WinNetworkServiceSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_NETWORK_SERVICE_RID } } },
69     { {0,0}, WinBuiltinDomainSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID } } },
70     { {'B','A'}, WinBuiltinAdministratorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS } } },
71     { {'B','U'}, WinBuiltinUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS } } },
72     { {'B','G'}, WinBuiltinGuestsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS } } },
73     { {'P','U'}, WinBuiltinPowerUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS } } },
74     { {'A','O'}, WinBuiltinAccountOperatorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ACCOUNT_OPS } } },
75     { {'S','O'}, WinBuiltinSystemOperatorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_SYSTEM_OPS } } },
76     { {'P','O'}, WinBuiltinPrintOperatorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_PRINT_OPS } } },
77     { {'B','O'}, WinBuiltinBackupOperatorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_BACKUP_OPS } } },
78     { {'R','E'}, WinBuiltinReplicatorSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_REPLICATOR } } },
79     { {'R','U'}, WinBuiltinPreWindows2000CompatibleAccessSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_PREW2KCOMPACCESS } } },
80     { {'R','D'}, WinBuiltinRemoteDesktopUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS } } },
81     { {'N','O'}, WinBuiltinNetworkConfigurationOperatorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS } } },
82     { {0,0}, WinNTLMAuthenticationSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_PACKAGE_BASE_RID, SECURITY_PACKAGE_NTLM_RID } } },
83     { {0,0}, WinDigestAuthenticationSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_PACKAGE_BASE_RID, SECURITY_PACKAGE_DIGEST_RID } } },
84     { {0,0}, WinSChannelAuthenticationSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_PACKAGE_BASE_RID, SECURITY_PACKAGE_SCHANNEL_RID } } },
85     { {0,0}, WinThisOrganizationSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_THIS_ORGANIZATION_RID } } },
86     { {0,0}, WinOtherOrganizationSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_OTHER_ORGANIZATION_RID } } },
87     { {0,0}, WinBuiltinIncomingForestTrustBuildersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS  } } },
88     { {0,0}, WinBuiltinPerfMonitoringUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_MONITORING_USERS } } },
89     { {0,0}, WinBuiltinPerfLoggingUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_LOGGING_USERS } } },
90     { {0,0}, WinBuiltinAuthorizationAccessSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS } } },
91     { {0,0}, WinBuiltinTerminalServerLicenseServersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS } } },
92     { {0,0}, WinBuiltinDCOMUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_DCOM_USERS } } },
93     { {'L','W'}, WinLowLabelSid, { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY}, { SECURITY_MANDATORY_LOW_RID} } },
94     { {'M','E'}, WinMediumLabelSid, { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY}, { SECURITY_MANDATORY_MEDIUM_RID } } },
95     { {'H','I'}, WinHighLabelSid, { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY}, { SECURITY_MANDATORY_HIGH_RID } } },
96     { {'S','I'}, WinSystemLabelSid, { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY}, { SECURITY_MANDATORY_SYSTEM_RID } } },
97 };
98 
99 /* these SIDs must be constructed as relative to some domain - only the RID is well-known */
100 typedef struct WELLKNOWNRID
101 {
102     WCHAR wstr[2];
103     WELL_KNOWN_SID_TYPE Type;
104     DWORD Rid;
105 } WELLKNOWNRID;
106 
107 static const WELLKNOWNRID WellKnownRids[] = {
108     { {'L','A'}, WinAccountAdministratorSid,    DOMAIN_USER_RID_ADMIN },
109     { {'L','G'}, WinAccountGuestSid,            DOMAIN_USER_RID_GUEST },
110     { {0,0}, WinAccountKrbtgtSid,           DOMAIN_USER_RID_KRBTGT },
111     { {'D','A'}, WinAccountDomainAdminsSid,     DOMAIN_GROUP_RID_ADMINS },
112     { {'D','U'}, WinAccountDomainUsersSid,      DOMAIN_GROUP_RID_USERS },
113     { {'D','G'}, WinAccountDomainGuestsSid,     DOMAIN_GROUP_RID_GUESTS },
114     { {'D','C'}, WinAccountComputersSid,        DOMAIN_GROUP_RID_COMPUTERS },
115     { {'D','D'}, WinAccountControllersSid,      DOMAIN_GROUP_RID_CONTROLLERS },
116     { {'C','A'}, WinAccountCertAdminsSid,       DOMAIN_GROUP_RID_CERT_ADMINS },
117     { {'S','A'}, WinAccountSchemaAdminsSid,     DOMAIN_GROUP_RID_SCHEMA_ADMINS },
118     { {'E','A'}, WinAccountEnterpriseAdminsSid, DOMAIN_GROUP_RID_ENTERPRISE_ADMINS },
119     { {'P','A'}, WinAccountPolicyAdminsSid,     DOMAIN_GROUP_RID_POLICY_ADMINS },
120     { {'R','S'}, WinAccountRasAndIasServersSid, DOMAIN_ALIAS_RID_RAS_SERVERS },
121 };
122 
123 #ifndef __REACTOS__
124 static const SID sidWorld = { SID_REVISION, 1, { SECURITY_WORLD_SID_AUTHORITY} , { SECURITY_WORLD_RID } };
125 #endif
126 
127 static const WCHAR SDDL_NO_READ_UP[]       = {'N','R',0};
128 static const WCHAR SDDL_NO_WRITE_UP[]      = {'N','W',0};
129 static const WCHAR SDDL_NO_EXECUTE_UP[]    = {'N','X',0};
130 
131 /*
132  * ACE types
133  */
134 static const WCHAR SDDL_ACCESS_ALLOWED[]        = {'A',0};
135 static const WCHAR SDDL_ACCESS_DENIED[]         = {'D',0};
136 #ifndef __REACTOS__
137 static const WCHAR SDDL_OBJECT_ACCESS_ALLOWED[] = {'O','A',0};
138 static const WCHAR SDDL_OBJECT_ACCESS_DENIED[]  = {'O','D',0};
139 #endif
140 static const WCHAR SDDL_AUDIT[]                 = {'A','U',0};
141 static const WCHAR SDDL_ALARM[]                 = {'A','L',0};
142 static const WCHAR SDDL_MANDATORY_LABEL[]       = {'M','L',0};
143 #ifndef __REACTOS__
144 static const WCHAR SDDL_OBJECT_AUDIT[]          = {'O','U',0};
145 static const WCHAR SDDL_OBJECT_ALARM[]          = {'O','L',0};
146 #endif
147 
148 /*
149  * SDDL ADS Rights
150  */
151 #define ADS_RIGHT_DS_CREATE_CHILD   0x0001
152 #define ADS_RIGHT_DS_DELETE_CHILD   0x0002
153 #define ADS_RIGHT_ACTRL_DS_LIST     0x0004
154 #define ADS_RIGHT_DS_SELF           0x0008
155 #define ADS_RIGHT_DS_READ_PROP      0x0010
156 #define ADS_RIGHT_DS_WRITE_PROP     0x0020
157 #define ADS_RIGHT_DS_DELETE_TREE    0x0040
158 #define ADS_RIGHT_DS_LIST_OBJECT    0x0080
159 #define ADS_RIGHT_DS_CONTROL_ACCESS 0x0100
160 
161 /*
162  * ACE flags
163  */
164 static const WCHAR SDDL_CONTAINER_INHERIT[]  = {'C','I',0};
165 static const WCHAR SDDL_OBJECT_INHERIT[]     = {'O','I',0};
166 static const WCHAR SDDL_NO_PROPAGATE[]       = {'N','P',0};
167 static const WCHAR SDDL_INHERIT_ONLY[]       = {'I','O',0};
168 static const WCHAR SDDL_INHERITED[]          = {'I','D',0};
169 static const WCHAR SDDL_AUDIT_SUCCESS[]      = {'S','A',0};
170 static const WCHAR SDDL_AUDIT_FAILURE[]      = {'F','A',0};
171 
172 static const char * debugstr_sid(PSID sid)
173 {
174     int auth = 0;
175     SID * psid = (SID *)sid;
176 
177     if (psid == NULL)
178         return "(null)";
179 
180     auth = psid->IdentifierAuthority.Value[5] +
181            (psid->IdentifierAuthority.Value[4] << 8) +
182            (psid->IdentifierAuthority.Value[3] << 16) +
183            (psid->IdentifierAuthority.Value[2] << 24);
184 
185     switch (psid->SubAuthorityCount) {
186     case 0:
187         return wine_dbg_sprintf("S-%d-%d", psid->Revision, auth);
188     case 1:
189         return wine_dbg_sprintf("S-%d-%d-%lu", psid->Revision, auth,
190             psid->SubAuthority[0]);
191     case 2:
192         return wine_dbg_sprintf("S-%d-%d-%lu-%lu", psid->Revision, auth,
193             psid->SubAuthority[0], psid->SubAuthority[1]);
194     case 3:
195         return wine_dbg_sprintf("S-%d-%d-%lu-%lu-%lu", psid->Revision, auth,
196             psid->SubAuthority[0], psid->SubAuthority[1], psid->SubAuthority[2]);
197     case 4:
198         return wine_dbg_sprintf("S-%d-%d-%lu-%lu-%lu-%lu", psid->Revision, auth,
199             psid->SubAuthority[0], psid->SubAuthority[1], psid->SubAuthority[2],
200             psid->SubAuthority[3]);
201     case 5:
202         return wine_dbg_sprintf("S-%d-%d-%lu-%lu-%lu-%lu-%lu", psid->Revision, auth,
203             psid->SubAuthority[0], psid->SubAuthority[1], psid->SubAuthority[2],
204             psid->SubAuthority[3], psid->SubAuthority[4]);
205     case 6:
206         return wine_dbg_sprintf("S-%d-%d-%lu-%lu-%lu-%lu-%lu-%lu", psid->Revision, auth,
207             psid->SubAuthority[3], psid->SubAuthority[1], psid->SubAuthority[2],
208             psid->SubAuthority[0], psid->SubAuthority[4], psid->SubAuthority[5]);
209     case 7:
210         return wine_dbg_sprintf("S-%d-%d-%lu-%lu-%lu-%lu-%lu-%lu-%lu", psid->Revision, auth,
211             psid->SubAuthority[0], psid->SubAuthority[1], psid->SubAuthority[2],
212             psid->SubAuthority[3], psid->SubAuthority[4], psid->SubAuthority[5],
213             psid->SubAuthority[6]);
214     case 8:
215         return wine_dbg_sprintf("S-%d-%d-%lu-%lu-%lu-%lu-%lu-%lu-%lu-%lu", psid->Revision, auth,
216             psid->SubAuthority[0], psid->SubAuthority[1], psid->SubAuthority[2],
217             psid->SubAuthority[3], psid->SubAuthority[4], psid->SubAuthority[5],
218             psid->SubAuthority[6], psid->SubAuthority[7]);
219     }
220     return "(too-big)";
221 }
222 
223 /* set last error code from NT status and get the proper boolean return value */
224 /* used for functions that are a simple wrapper around the corresponding ntdll API */
225 static __inline BOOL set_ntstatus( NTSTATUS status )
226 {
227     if (!NT_SUCCESS(status)) SetLastError( RtlNtStatusToDosError( status ));
228     return NT_SUCCESS(status);
229 }
230 
231 static LPWSTR SERV_dup( LPCSTR str )
232 {
233     UINT len;
234     LPWSTR wstr;
235 
236     if( !str )
237         return NULL;
238     len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
239     wstr = heap_alloc( len*sizeof (WCHAR) );
240     MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
241     return wstr;
242 }
243 
244 /************************************************************
245  *                ADVAPI_IsLocalComputer
246  *
247  * Checks whether the server name indicates local machine.
248  */
249 BOOL ADVAPI_IsLocalComputer(LPCWSTR ServerName)
250 {
251     DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
252     BOOL Result;
253     LPWSTR buf;
254 
255     if (!ServerName || !ServerName[0])
256         return TRUE;
257 
258     buf = heap_alloc(dwSize * sizeof(WCHAR));
259     Result = GetComputerNameW(buf,  &dwSize);
260     if (Result && (ServerName[0] == '\\') && (ServerName[1] == '\\'))
261         ServerName += 2;
262     Result = Result && !lstrcmpW(ServerName, buf);
263     heap_free(buf);
264 
265     return Result;
266 }
267 
268 /************************************************************
269  *                ADVAPI_GetComputerSid
270  */
271 BOOL ADVAPI_GetComputerSid(PSID sid)
272 {
273     static const struct /* same fields as struct SID */
274     {
275         BYTE Revision;
276         BYTE SubAuthorityCount;
277         SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
278         DWORD SubAuthority[4];
279     } computer_sid =
280     { SID_REVISION, 4, { SECURITY_NT_AUTHORITY }, { SECURITY_NT_NON_UNIQUE, 0, 0, 0 } };
281 
282     memcpy( sid, &computer_sid, sizeof(computer_sid) );
283     return TRUE;
284 }
285 
286 /* Exported functions */
287 
288 /*
289  * @implemented
290  */
291 BOOL WINAPI
292 OpenProcessToken(HANDLE ProcessHandle,
293                  DWORD DesiredAccess,
294                  PHANDLE TokenHandle)
295 {
296     NTSTATUS Status;
297 
298     TRACE("%p, %x, %p.\n", ProcessHandle, DesiredAccess, TokenHandle);
299 
300     Status = NtOpenProcessToken(ProcessHandle,
301                                 DesiredAccess,
302                                 TokenHandle);
303     if (!NT_SUCCESS(Status))
304     {
305         ERR("NtOpenProcessToken failed! Status %08x.\n", Status);
306         SetLastError(RtlNtStatusToDosError(Status));
307         return FALSE;
308     }
309 
310     TRACE("Returning token %p.\n", *TokenHandle);
311 
312     return TRUE;
313 }
314 
315 /******************************************************************************
316  * OpenThreadToken [ADVAPI32.@]
317  *
318  * Opens the access token associated with a thread handle.
319  *
320  * PARAMS
321  *   ThreadHandle  [I] Handle to process
322  *   DesiredAccess [I] Desired access to the thread
323  *   OpenAsSelf    [I] ???
324  *   TokenHandle   [O] Destination for the token handle
325  *
326  * RETURNS
327  *  Success: TRUE. TokenHandle contains the access token.
328  *  Failure: FALSE.
329  *
330  * NOTES
331  *  See NtOpenThreadToken.
332  */
333 BOOL WINAPI
334 OpenThreadToken( HANDLE ThreadHandle, DWORD DesiredAccess,
335 		 BOOL OpenAsSelf, HANDLE *TokenHandle)
336 {
337 	return set_ntstatus( NtOpenThreadToken(ThreadHandle, DesiredAccess, OpenAsSelf, TokenHandle));
338 }
339 
340 /*
341  * @implemented
342  */
343 BOOL WINAPI
344 AdjustTokenGroups(HANDLE TokenHandle,
345                   BOOL ResetToDefault,
346                   PTOKEN_GROUPS NewState,
347                   DWORD BufferLength,
348                   PTOKEN_GROUPS PreviousState,
349                   PDWORD ReturnLength)
350 {
351     NTSTATUS Status;
352 
353     Status = NtAdjustGroupsToken(TokenHandle,
354                                  ResetToDefault,
355                                  NewState,
356                                  BufferLength,
357                                  PreviousState,
358                                  (PULONG)ReturnLength);
359     if (!NT_SUCCESS(Status))
360     {
361        SetLastError(RtlNtStatusToDosError(Status));
362        return FALSE;
363     }
364 
365     return TRUE;
366 }
367 
368 /*
369  * @implemented
370  */
371 BOOL WINAPI
372 AdjustTokenPrivileges(HANDLE TokenHandle,
373                       BOOL DisableAllPrivileges,
374                       PTOKEN_PRIVILEGES NewState,
375                       DWORD BufferLength,
376                       PTOKEN_PRIVILEGES PreviousState,
377                       PDWORD ReturnLength)
378 {
379     NTSTATUS Status;
380 
381     Status = NtAdjustPrivilegesToken(TokenHandle,
382                                      DisableAllPrivileges,
383                                      NewState,
384                                      BufferLength,
385                                      PreviousState,
386                                      (PULONG)ReturnLength);
387     if (STATUS_NOT_ALL_ASSIGNED == Status)
388     {
389         SetLastError(ERROR_NOT_ALL_ASSIGNED);
390         return TRUE;
391     }
392 
393     if (!NT_SUCCESS(Status))
394     {
395         SetLastError(RtlNtStatusToDosError(Status));
396         return FALSE;
397     }
398 
399     /* AdjustTokenPrivileges is documented to do this */
400     SetLastError(ERROR_SUCCESS);
401 
402     return TRUE;
403 }
404 
405 /*
406  * @implemented
407  */
408 BOOL WINAPI
409 GetTokenInformation(HANDLE TokenHandle,
410                     TOKEN_INFORMATION_CLASS TokenInformationClass,
411                     LPVOID TokenInformation,
412                     DWORD TokenInformationLength,
413                     PDWORD ReturnLength)
414 {
415     NTSTATUS Status;
416 
417     Status = NtQueryInformationToken(TokenHandle,
418                                      TokenInformationClass,
419                                      TokenInformation,
420                                      TokenInformationLength,
421                                      (PULONG)ReturnLength);
422     if (!NT_SUCCESS(Status))
423     {
424         SetLastError(RtlNtStatusToDosError(Status));
425         return FALSE;
426     }
427 
428   return TRUE;
429 }
430 
431 /*
432  * @implemented
433  */
434 BOOL WINAPI
435 SetTokenInformation(HANDLE TokenHandle,
436                     TOKEN_INFORMATION_CLASS TokenInformationClass,
437                     LPVOID TokenInformation,
438                     DWORD TokenInformationLength)
439 {
440     NTSTATUS Status;
441 
442     Status = NtSetInformationToken(TokenHandle,
443                                    TokenInformationClass,
444                                    TokenInformation,
445                                    TokenInformationLength);
446     if (!NT_SUCCESS(Status))
447     {
448         SetLastError(RtlNtStatusToDosError(Status));
449         return FALSE;
450     }
451 
452     return TRUE;
453 }
454 
455 /*
456  * @implemented
457  */
458 BOOL WINAPI
459 SetThreadToken(IN PHANDLE ThreadHandle  OPTIONAL,
460                IN HANDLE TokenHandle)
461 {
462     NTSTATUS Status;
463     HANDLE hThread;
464 
465     hThread = (ThreadHandle != NULL) ? *ThreadHandle : NtCurrentThread();
466 
467     Status = NtSetInformationThread(hThread,
468                                     ThreadImpersonationToken,
469                                     &TokenHandle,
470                                     sizeof(HANDLE));
471     if (!NT_SUCCESS(Status))
472     {
473         SetLastError(RtlNtStatusToDosError(Status));
474         return FALSE;
475     }
476 
477     return TRUE;
478 }
479 
480 /*************************************************************************
481  * CreateRestrictedToken [ADVAPI32.@]
482  *
483  * Create a new more restricted token from an existing token.
484  *
485  * PARAMS
486  *   baseToken       [I] Token to base the new restricted token on
487  *   flags           [I] Options
488  *   nDisableSids    [I] Length of disableSids array
489  *   disableSids     [I] Array of SIDs to disable in the new token
490  *   nDeletePrivs    [I] Length of deletePrivs array
491  *   deletePrivs     [I] Array of privileges to delete in the new token
492  *   nRestrictSids   [I] Length of restrictSids array
493  *   restrictSids    [I] Array of SIDs to restrict in the new token
494  *   newToken        [O] Address where the new token is stored
495  *
496  * RETURNS
497  *  Success: TRUE
498  *  Failure: FALSE
499  */
500 BOOL WINAPI CreateRestrictedToken(
501     HANDLE baseToken,
502     DWORD flags,
503     DWORD nDisableSids,
504     PSID_AND_ATTRIBUTES disableSids,
505     DWORD nDeletePrivs,
506     PLUID_AND_ATTRIBUTES deletePrivs,
507     DWORD nRestrictSids,
508     PSID_AND_ATTRIBUTES restrictSids,
509     PHANDLE newToken)
510 {
511     TOKEN_TYPE type;
512     SECURITY_IMPERSONATION_LEVEL level = SecurityAnonymous;
513     DWORD size;
514 
515     FIXME("(%p, 0x%x, %u, %p, %u, %p, %u, %p, %p): stub\n",
516           baseToken, flags, nDisableSids, disableSids,
517           nDeletePrivs, deletePrivs,
518           nRestrictSids, restrictSids,
519           newToken);
520 
521     size = sizeof(type);
522     if (!GetTokenInformation( baseToken, TokenType, &type, size, &size )) return FALSE;
523     if (type == TokenImpersonation)
524     {
525         size = sizeof(level);
526         if (!GetTokenInformation( baseToken, TokenImpersonationLevel, &level, size, &size ))
527             return FALSE;
528     }
529     return DuplicateTokenEx( baseToken, MAXIMUM_ALLOWED, NULL, level, type, newToken );
530 }
531 
532 /******************************************************************************
533  * AllocateAndInitializeSid [ADVAPI32.@]
534  *
535  * PARAMS
536  *   pIdentifierAuthority []
537  *   nSubAuthorityCount   []
538  *   nSubAuthority0       []
539  *   nSubAuthority1       []
540  *   nSubAuthority2       []
541  *   nSubAuthority3       []
542  *   nSubAuthority4       []
543  *   nSubAuthority5       []
544  *   nSubAuthority6       []
545  *   nSubAuthority7       []
546  *   pSid                 []
547  */
548 BOOL WINAPI
549 AllocateAndInitializeSid( PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
550                           BYTE nSubAuthorityCount,
551                           DWORD nSubAuthority0, DWORD nSubAuthority1,
552                           DWORD nSubAuthority2, DWORD nSubAuthority3,
553                           DWORD nSubAuthority4, DWORD nSubAuthority5,
554                           DWORD nSubAuthority6, DWORD nSubAuthority7,
555                           PSID *pSid )
556 {
557     return set_ntstatus( RtlAllocateAndInitializeSid(
558                              pIdentifierAuthority, nSubAuthorityCount,
559                              nSubAuthority0, nSubAuthority1, nSubAuthority2, nSubAuthority3,
560                              nSubAuthority4, nSubAuthority5, nSubAuthority6, nSubAuthority7,
561                              pSid ));
562 }
563 
564 /*
565  * @implemented
566  *
567  * RETURNS
568  *  Docs says this function does NOT return a value
569  *  even thou it's defined to return a PVOID...
570  */
571 PVOID
572 WINAPI
573 FreeSid(PSID pSid)
574 {
575     return RtlFreeSid(pSid);
576 }
577 
578 /******************************************************************************
579  * CopySid [ADVAPI32.@]
580  *
581  * PARAMS
582  *   nDestinationSidLength []
583  *   pDestinationSid       []
584  *   pSourceSid            []
585  */
586 BOOL WINAPI
587 CopySid( DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid )
588 {
589 	return set_ntstatus(RtlCopySid(nDestinationSidLength, pDestinationSid, pSourceSid));
590 }
591 
592 /*
593  * @unimplemented
594  */
595 BOOL
596 WINAPI
597 CreateWellKnownSid(IN WELL_KNOWN_SID_TYPE WellKnownSidType,
598                    IN PSID DomainSid  OPTIONAL,
599                    OUT PSID pSid,
600                    IN OUT DWORD* cbSid)
601 {
602     unsigned int i;
603     TRACE("(%d, %s, %p, %p)\n", WellKnownSidType, debugstr_sid(DomainSid), pSid, cbSid);
604 
605     if (cbSid == NULL || (DomainSid && !IsValidSid(DomainSid)))
606     {
607         SetLastError(ERROR_INVALID_PARAMETER);
608         return FALSE;
609     }
610 
611     for (i = 0; i < sizeof(WellKnownSids)/sizeof(WellKnownSids[0]); i++) {
612         if (WellKnownSids[i].Type == WellKnownSidType) {
613             DWORD length = GetSidLengthRequired(WellKnownSids[i].Sid.SubAuthorityCount);
614 
615             if (*cbSid < length)
616             {
617                 *cbSid = length;
618                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
619                 return FALSE;
620             }
621             if (!pSid)
622             {
623                 SetLastError(ERROR_INVALID_PARAMETER);
624                 return FALSE;
625             }
626             CopyMemory(pSid, &WellKnownSids[i].Sid.Revision, length);
627             *cbSid = length;
628             return TRUE;
629         }
630     }
631 
632     if (DomainSid == NULL || *GetSidSubAuthorityCount(DomainSid) == SID_MAX_SUB_AUTHORITIES)
633     {
634         SetLastError(ERROR_INVALID_PARAMETER);
635         return FALSE;
636     }
637 
638     for (i = 0; i < sizeof(WellKnownRids)/sizeof(WellKnownRids[0]); i++)
639         if (WellKnownRids[i].Type == WellKnownSidType) {
640             UCHAR domain_subauth = *GetSidSubAuthorityCount(DomainSid);
641             DWORD domain_sid_length = GetSidLengthRequired(domain_subauth);
642             DWORD output_sid_length = GetSidLengthRequired(domain_subauth + 1);
643 
644             if (*cbSid < output_sid_length)
645             {
646                 *cbSid = output_sid_length;
647                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
648                 return FALSE;
649             }
650             if (!pSid)
651             {
652                 SetLastError(ERROR_INVALID_PARAMETER);
653                 return FALSE;
654             }
655             CopyMemory(pSid, DomainSid, domain_sid_length);
656             (*GetSidSubAuthorityCount(pSid))++;
657             (*GetSidSubAuthority(pSid, domain_subauth)) = WellKnownRids[i].Rid;
658             *cbSid = output_sid_length;
659             return TRUE;
660         }
661 
662     SetLastError(ERROR_INVALID_PARAMETER);
663     return FALSE;
664 }
665 
666 /*
667  * @unimplemented
668  */
669 BOOL
670 WINAPI
671 IsWellKnownSid(IN PSID pSid,
672                IN WELL_KNOWN_SID_TYPE WellKnownSidType)
673 {
674     unsigned int i;
675     TRACE("(%s, %d)\n", debugstr_sid(pSid), WellKnownSidType);
676 
677     for (i = 0; i < sizeof(WellKnownSids) / sizeof(WellKnownSids[0]); i++)
678     {
679         if (WellKnownSids[i].Type == WellKnownSidType)
680         {
681             if (EqualSid(pSid, (PSID)(&WellKnownSids[i].Sid.Revision)))
682                 return TRUE;
683         }
684     }
685 
686     return FALSE;
687 }
688 
689 /*
690  * @implemented
691  */
692 BOOL
693 WINAPI
694 IsValidSid(PSID pSid)
695 {
696     return (BOOL)RtlValidSid(pSid);
697 }
698 
699 /*
700  * @implemented
701  */
702 BOOL
703 WINAPI
704 EqualSid(PSID pSid1,
705          PSID pSid2)
706 {
707     SetLastError(ERROR_SUCCESS);
708     return RtlEqualSid (pSid1, pSid2);
709 }
710 
711 /*
712  * @implemented
713  */
714 BOOL
715 WINAPI
716 EqualPrefixSid(PSID pSid1,
717                PSID pSid2)
718 {
719     return RtlEqualPrefixSid (pSid1, pSid2);
720 }
721 
722 /*
723  * @implemented
724  */
725 DWORD
726 WINAPI
727 GetSidLengthRequired(UCHAR nSubAuthorityCount)
728 {
729     return (DWORD)RtlLengthRequiredSid(nSubAuthorityCount);
730 }
731 
732 /*
733  * @implemented
734  */
735 BOOL
736 WINAPI
737 InitializeSid(PSID Sid,
738               PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
739               BYTE nSubAuthorityCount)
740 {
741     NTSTATUS Status;
742 
743     Status = RtlInitializeSid(Sid,
744                               pIdentifierAuthority,
745                               nSubAuthorityCount);
746     if (!NT_SUCCESS(Status))
747     {
748         SetLastError(RtlNtStatusToDosError(Status));
749         return FALSE;
750     }
751 
752     return TRUE;
753 }
754 
755 /*
756  * @implemented
757  */
758 PSID_IDENTIFIER_AUTHORITY
759 WINAPI
760 GetSidIdentifierAuthority(PSID pSid)
761 {
762     return RtlIdentifierAuthoritySid(pSid);
763 }
764 
765 /*
766  * @implemented
767  */
768 PDWORD
769 WINAPI
770 GetSidSubAuthority(PSID pSid,
771                    DWORD nSubAuthority)
772 {
773     SetLastError(ERROR_SUCCESS);
774     return (PDWORD)RtlSubAuthoritySid(pSid, nSubAuthority);
775 }
776 
777 /*
778  * @implemented
779  */
780 PUCHAR
781 WINAPI
782 GetSidSubAuthorityCount(PSID pSid)
783 {
784     SetLastError(ERROR_SUCCESS);
785     return RtlSubAuthorityCountSid(pSid);
786 }
787 
788 /*
789  * @implemented
790  */
791 DWORD
792 WINAPI
793 GetLengthSid(PSID pSid)
794 {
795     return (DWORD)RtlLengthSid(pSid);
796 }
797 
798 /*
799  * @implemented
800  */
801 BOOL
802 WINAPI
803 InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor,
804                              DWORD dwRevision)
805 {
806     NTSTATUS Status;
807 
808     Status = RtlCreateSecurityDescriptor(pSecurityDescriptor,
809                                          dwRevision);
810     if (!NT_SUCCESS(Status))
811     {
812         SetLastError(RtlNtStatusToDosError(Status));
813         return FALSE;
814     }
815 
816     return TRUE;
817 }
818 
819 /*
820  * @implemented
821  */
822 BOOL
823 WINAPI
824 MakeAbsoluteSD(PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
825                PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,
826                LPDWORD lpdwAbsoluteSecurityDescriptorSize,
827                PACL pDacl,
828                LPDWORD lpdwDaclSize,
829                PACL pSacl,
830                LPDWORD lpdwSaclSize,
831                PSID pOwner,
832                LPDWORD lpdwOwnerSize,
833                PSID pPrimaryGroup,
834                LPDWORD lpdwPrimaryGroupSize)
835 {
836     NTSTATUS Status;
837 
838     Status = RtlSelfRelativeToAbsoluteSD(pSelfRelativeSecurityDescriptor,
839                                          pAbsoluteSecurityDescriptor,
840                                          lpdwAbsoluteSecurityDescriptorSize,
841                                          pDacl,
842                                          lpdwDaclSize,
843                                          pSacl,
844                                          lpdwSaclSize,
845                                          pOwner,
846                                          lpdwOwnerSize,
847                                          pPrimaryGroup,
848                                          lpdwPrimaryGroupSize);
849     if (!NT_SUCCESS(Status))
850     {
851         SetLastError(RtlNtStatusToDosError(Status));
852         return FALSE;
853     }
854 
855     return TRUE;
856 }
857 
858 /******************************************************************************
859  * GetKernelObjectSecurity [ADVAPI32.@]
860  */
861 BOOL WINAPI GetKernelObjectSecurity(
862         HANDLE Handle,
863         SECURITY_INFORMATION RequestedInformation,
864         PSECURITY_DESCRIPTOR pSecurityDescriptor,
865         DWORD nLength,
866         LPDWORD lpnLengthNeeded )
867 {
868     TRACE("(%p,0x%08x,%p,0x%08x,%p)\n", Handle, RequestedInformation,
869           pSecurityDescriptor, nLength, lpnLengthNeeded);
870 
871     return set_ntstatus( NtQuerySecurityObject(Handle, RequestedInformation, pSecurityDescriptor,
872                                                nLength, lpnLengthNeeded ));
873 }
874 
875 /*
876  * @implemented
877  */
878 BOOL
879 WINAPI
880 InitializeAcl(PACL pAcl,
881               DWORD nAclLength,
882               DWORD dwAclRevision)
883 {
884     NTSTATUS Status;
885 
886     Status = RtlCreateAcl(pAcl,
887                           nAclLength,
888                           dwAclRevision);
889     if (!NT_SUCCESS(Status))
890     {
891         SetLastError(RtlNtStatusToDosError(Status));
892         return FALSE;
893     }
894 
895     return TRUE;
896 }
897 
898 BOOL WINAPI ImpersonateNamedPipeClient( HANDLE hNamedPipe )
899 {
900     IO_STATUS_BLOCK io_block;
901 
902     TRACE("(%p)\n", hNamedPipe);
903 
904     return set_ntstatus( NtFsControlFile(hNamedPipe, NULL, NULL, NULL,
905                          &io_block, FSCTL_PIPE_IMPERSONATE, NULL, 0, NULL, 0) );
906 }
907 
908 /*
909  * @implemented
910  */
911 BOOL
912 WINAPI
913 AddAccessAllowedAce(PACL pAcl,
914                     DWORD dwAceRevision,
915                     DWORD AccessMask,
916                     PSID pSid)
917 {
918     NTSTATUS Status;
919 
920     Status = RtlAddAccessAllowedAce(pAcl,
921                                     dwAceRevision,
922                                     AccessMask,
923                                     pSid);
924     if (!NT_SUCCESS(Status))
925     {
926         SetLastError(RtlNtStatusToDosError(Status));
927         return FALSE;
928     }
929 
930     return TRUE;
931 }
932 
933 /*
934  * @implemented
935  */
936 BOOL WINAPI
937 AddAccessAllowedAceEx(PACL pAcl,
938                       DWORD dwAceRevision,
939                       DWORD AceFlags,
940                       DWORD AccessMask,
941                       PSID pSid)
942 {
943     NTSTATUS Status;
944 
945     Status = RtlAddAccessAllowedAceEx(pAcl,
946                                       dwAceRevision,
947                                       AceFlags,
948                                       AccessMask,
949                                       pSid);
950     if (!NT_SUCCESS(Status))
951     {
952         SetLastError(RtlNtStatusToDosError(Status));
953         return FALSE;
954     }
955 
956     return TRUE;
957 }
958 
959 /*
960  * @implemented
961  */
962 BOOL
963 WINAPI
964 AddAccessDeniedAce(PACL pAcl,
965                    DWORD dwAceRevision,
966                    DWORD AccessMask,
967                    PSID pSid)
968 {
969     NTSTATUS Status;
970 
971     Status = RtlAddAccessDeniedAce(pAcl,
972                                    dwAceRevision,
973                                    AccessMask,
974                                    pSid);
975     if (!NT_SUCCESS(Status))
976     {
977         SetLastError(RtlNtStatusToDosError(Status));
978         return FALSE;
979     }
980 
981     return TRUE;
982 }
983 
984 /*
985  * @implemented
986  */
987 BOOL WINAPI
988 AddAccessDeniedAceEx(PACL pAcl,
989                      DWORD dwAceRevision,
990                      DWORD AceFlags,
991                      DWORD AccessMask,
992                      PSID pSid)
993 {
994     NTSTATUS Status;
995 
996     Status = RtlAddAccessDeniedAceEx(pAcl,
997                                      dwAceRevision,
998                                      AceFlags,
999                                      AccessMask,
1000                                      pSid);
1001     if (!NT_SUCCESS(Status))
1002     {
1003         SetLastError(RtlNtStatusToDosError(Status));
1004         return FALSE;
1005     }
1006 
1007     return TRUE;
1008 }
1009 
1010 /*
1011  * @implemented
1012  */
1013 BOOL
1014 WINAPI
1015 AddAce(PACL pAcl,
1016        DWORD dwAceRevision,
1017        DWORD dwStartingAceIndex,
1018        LPVOID pAceList,
1019        DWORD nAceListLength)
1020 {
1021     NTSTATUS Status;
1022 
1023     Status = RtlAddAce(pAcl,
1024                        dwAceRevision,
1025                        dwStartingAceIndex,
1026                        pAceList,
1027                        nAceListLength);
1028     if (!NT_SUCCESS(Status))
1029     {
1030         SetLastError(RtlNtStatusToDosError(Status));
1031         return FALSE;
1032     }
1033 
1034     return TRUE;
1035 }
1036 
1037 /******************************************************************************
1038  * DeleteAce [ADVAPI32.@]
1039  */
1040 BOOL WINAPI DeleteAce(PACL pAcl, DWORD dwAceIndex)
1041 {
1042     return set_ntstatus(RtlDeleteAce(pAcl, dwAceIndex));
1043 }
1044 
1045 /*
1046  * @implemented
1047  */
1048 BOOL
1049 WINAPI
1050 FindFirstFreeAce(PACL pAcl,
1051                  LPVOID *pAce)
1052 {
1053     return RtlFirstFreeAce(pAcl,
1054                            (PACE*)pAce);
1055 }
1056 
1057 /******************************************************************************
1058  * GetAce [ADVAPI32.@]
1059  */
1060 BOOL WINAPI GetAce(PACL pAcl,DWORD dwAceIndex,LPVOID *pAce )
1061 {
1062     return set_ntstatus(RtlGetAce(pAcl, dwAceIndex, pAce));
1063 }
1064 
1065 /******************************************************************************
1066  * GetAclInformation [ADVAPI32.@]
1067  */
1068 BOOL WINAPI GetAclInformation(
1069   PACL pAcl,
1070   LPVOID pAclInformation,
1071   DWORD nAclInformationLength,
1072   ACL_INFORMATION_CLASS dwAclInformationClass)
1073 {
1074     return set_ntstatus(RtlQueryInformationAcl(pAcl, pAclInformation,
1075                                                nAclInformationLength, dwAclInformationClass));
1076 }
1077 
1078 /*
1079  * @implemented
1080  */
1081 BOOL
1082 WINAPI
1083 IsValidAcl(PACL pAcl)
1084 {
1085     return RtlValidAcl (pAcl);
1086 }
1087 
1088 /*
1089  * @implemented
1090  */
1091 BOOL WINAPI
1092 AllocateLocallyUniqueId(PLUID Luid)
1093 {
1094     NTSTATUS Status;
1095 
1096     Status = NtAllocateLocallyUniqueId (Luid);
1097     if (!NT_SUCCESS (Status))
1098     {
1099         SetLastError(RtlNtStatusToDosError(Status));
1100         return FALSE;
1101     }
1102 
1103     return TRUE;
1104 }
1105 
1106 /**********************************************************************
1107  * LookupPrivilegeDisplayNameA			EXPORTED
1108  *
1109  * @unimplemented
1110  */
1111 BOOL
1112 WINAPI
1113 LookupPrivilegeDisplayNameA(LPCSTR lpSystemName,
1114                             LPCSTR lpName,
1115                             LPSTR lpDisplayName,
1116                             LPDWORD cchDisplayName,
1117                             LPDWORD lpLanguageId)
1118 {
1119     UNICODE_STRING lpSystemNameW;
1120     UNICODE_STRING lpNameW;
1121     BOOL ret;
1122     DWORD wLen = 0;
1123 
1124     TRACE("%s %s %p %p %p\n", debugstr_a(lpSystemName), debugstr_a(lpName), lpName, cchDisplayName, lpLanguageId);
1125 
1126     RtlCreateUnicodeStringFromAsciiz(&lpSystemNameW, lpSystemName);
1127     RtlCreateUnicodeStringFromAsciiz(&lpNameW, lpName);
1128     ret = LookupPrivilegeDisplayNameW(lpSystemNameW.Buffer, lpNameW.Buffer, NULL, &wLen, lpLanguageId);
1129     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1130     {
1131         LPWSTR lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, wLen * sizeof(WCHAR));
1132 
1133         ret = LookupPrivilegeDisplayNameW(lpSystemNameW.Buffer, lpNameW.Buffer, lpDisplayNameW,
1134                                           &wLen, lpLanguageId);
1135         if (ret)
1136         {
1137             unsigned int len = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, lpDisplayName,
1138                                                    *cchDisplayName, NULL, NULL);
1139 
1140             if (len == 0)
1141             {
1142                 /* WideCharToMultiByte failed */
1143                 ret = FALSE;
1144             }
1145             else if (len > *cchDisplayName)
1146             {
1147                 *cchDisplayName = len;
1148                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1149                 ret = FALSE;
1150             }
1151             else
1152             {
1153                 /* WideCharToMultiByte succeeded, output length needs to be
1154                  * length not including NULL terminator
1155                  */
1156                 *cchDisplayName = len - 1;
1157             }
1158         }
1159         HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1160     }
1161     RtlFreeUnicodeString(&lpSystemNameW);
1162     RtlFreeUnicodeString(&lpNameW);
1163     return ret;
1164 }
1165 
1166 /**********************************************************************
1167  * LookupPrivilegeNameA				EXPORTED
1168  *
1169  * @implemented
1170  */
1171 BOOL
1172 WINAPI
1173 LookupPrivilegeNameA(LPCSTR lpSystemName,
1174                      PLUID lpLuid,
1175                      LPSTR lpName,
1176                      LPDWORD cchName)
1177 {
1178     UNICODE_STRING lpSystemNameW;
1179     BOOL ret;
1180     DWORD wLen = 0;
1181 
1182     TRACE("%s %p %p %p\n", debugstr_a(lpSystemName), lpLuid, lpName, cchName);
1183 
1184     RtlCreateUnicodeStringFromAsciiz(&lpSystemNameW, lpSystemName);
1185     ret = LookupPrivilegeNameW(lpSystemNameW.Buffer, lpLuid, NULL, &wLen);
1186     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1187     {
1188         LPWSTR lpNameW = HeapAlloc(GetProcessHeap(), 0, wLen * sizeof(WCHAR));
1189 
1190         ret = LookupPrivilegeNameW(lpSystemNameW.Buffer, lpLuid, lpNameW,
1191          &wLen);
1192         if (ret)
1193         {
1194             /* Windows crashes if cchName is NULL, so will I */
1195             unsigned int len = WideCharToMultiByte(CP_ACP, 0, lpNameW, -1, lpName,
1196              *cchName, NULL, NULL);
1197 
1198             if (len == 0)
1199             {
1200                 /* WideCharToMultiByte failed */
1201                 ret = FALSE;
1202             }
1203             else if (len > *cchName)
1204             {
1205                 *cchName = len;
1206                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1207                 ret = FALSE;
1208             }
1209             else
1210             {
1211                 /* WideCharToMultiByte succeeded, output length needs to be
1212                  * length not including NULL terminator
1213                  */
1214                 *cchName = len - 1;
1215             }
1216         }
1217         HeapFree(GetProcessHeap(), 0, lpNameW);
1218     }
1219     RtlFreeUnicodeString(&lpSystemNameW);
1220     return ret;
1221 }
1222 
1223 /******************************************************************************
1224  * GetFileSecurityA [ADVAPI32.@]
1225  *
1226  * Obtains Specified information about the security of a file or directory.
1227  *
1228  * PARAMS
1229  *  lpFileName           [I] Name of the file to get info for
1230  *  RequestedInformation [I] SE_ flags from "winnt.h"
1231  *  pSecurityDescriptor  [O] Destination for security information
1232  *  nLength              [I] Length of pSecurityDescriptor
1233  *  lpnLengthNeeded      [O] Destination for length of returned security information
1234  *
1235  * RETURNS
1236  *  Success: TRUE. pSecurityDescriptor contains the requested information.
1237  *  Failure: FALSE. lpnLengthNeeded contains the required space to return the info.
1238  *
1239  * NOTES
1240  *  The information returned is constrained by the callers access rights and
1241  *  privileges.
1242  *
1243  * @implemented
1244  */
1245 BOOL
1246 WINAPI
1247 GetFileSecurityA(LPCSTR lpFileName,
1248                  SECURITY_INFORMATION RequestedInformation,
1249                  PSECURITY_DESCRIPTOR pSecurityDescriptor,
1250                  DWORD nLength,
1251                  LPDWORD lpnLengthNeeded)
1252 {
1253     UNICODE_STRING FileName;
1254     BOOL bResult;
1255 
1256     if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFileName))
1257     {
1258         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1259         return FALSE;
1260     }
1261 
1262     bResult = GetFileSecurityW(FileName.Buffer,
1263                                RequestedInformation,
1264                                pSecurityDescriptor,
1265                                nLength,
1266                                lpnLengthNeeded);
1267 
1268     RtlFreeUnicodeString(&FileName);
1269 
1270     return bResult;
1271 }
1272 
1273 /*
1274  * @implemented
1275  */
1276 BOOL
1277 WINAPI
1278 GetFileSecurityW(LPCWSTR lpFileName,
1279                  SECURITY_INFORMATION RequestedInformation,
1280                  PSECURITY_DESCRIPTOR pSecurityDescriptor,
1281                  DWORD nLength,
1282                  LPDWORD lpnLengthNeeded)
1283 {
1284     OBJECT_ATTRIBUTES ObjectAttributes;
1285     IO_STATUS_BLOCK StatusBlock;
1286     UNICODE_STRING FileName;
1287     ULONG AccessMask = 0;
1288     HANDLE FileHandle;
1289     NTSTATUS Status;
1290 
1291     TRACE("GetFileSecurityW() called\n");
1292 
1293     QuerySecurityAccessMask(RequestedInformation, &AccessMask);
1294 
1295     if (!RtlDosPathNameToNtPathName_U(lpFileName,
1296                                       &FileName,
1297                                       NULL,
1298                                       NULL))
1299     {
1300         ERR("Invalid path\n");
1301         SetLastError(ERROR_INVALID_NAME);
1302         return FALSE;
1303     }
1304 
1305     InitializeObjectAttributes(&ObjectAttributes,
1306                                &FileName,
1307                                OBJ_CASE_INSENSITIVE,
1308                                NULL,
1309                                NULL);
1310 
1311     Status = NtOpenFile(&FileHandle,
1312                         AccessMask,
1313                         &ObjectAttributes,
1314                         &StatusBlock,
1315                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1316                         0);
1317 
1318     RtlFreeHeap(RtlGetProcessHeap(),
1319                 0,
1320                 FileName.Buffer);
1321 
1322     if (!NT_SUCCESS(Status))
1323     {
1324         ERR("NtOpenFile() failed (Status %lx)\n", Status);
1325         SetLastError(RtlNtStatusToDosError(Status));
1326         return FALSE;
1327     }
1328 
1329     Status = NtQuerySecurityObject(FileHandle,
1330                                    RequestedInformation,
1331                                    pSecurityDescriptor,
1332                                    nLength,
1333                                    lpnLengthNeeded);
1334     NtClose(FileHandle);
1335     if (!NT_SUCCESS(Status))
1336     {
1337         ERR("NtQuerySecurityObject() failed (Status %lx)\n", Status);
1338         SetLastError(RtlNtStatusToDosError(Status));
1339         return FALSE;
1340     }
1341 
1342     return TRUE;
1343 }
1344 
1345 /******************************************************************************
1346  * SetFileSecurityA [ADVAPI32.@]
1347  * Sets the security of a file or directory
1348  *
1349  * @implemented
1350  */
1351 BOOL
1352 WINAPI
1353 SetFileSecurityA(LPCSTR lpFileName,
1354                  SECURITY_INFORMATION SecurityInformation,
1355                  PSECURITY_DESCRIPTOR pSecurityDescriptor)
1356 {
1357     UNICODE_STRING FileName;
1358     BOOL bResult;
1359 
1360     if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFileName))
1361     {
1362         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1363         return FALSE;
1364     }
1365 
1366     bResult = SetFileSecurityW(FileName.Buffer,
1367                                SecurityInformation,
1368                                pSecurityDescriptor);
1369 
1370     RtlFreeUnicodeString(&FileName);
1371 
1372     return bResult;
1373 }
1374 
1375 /******************************************************************************
1376  * SetFileSecurityW [ADVAPI32.@]
1377  * Sets the security of a file or directory
1378  *
1379  * @implemented
1380  */
1381 BOOL
1382 WINAPI
1383 SetFileSecurityW(LPCWSTR lpFileName,
1384                  SECURITY_INFORMATION SecurityInformation,
1385                  PSECURITY_DESCRIPTOR pSecurityDescriptor)
1386 {
1387     OBJECT_ATTRIBUTES ObjectAttributes;
1388     IO_STATUS_BLOCK StatusBlock;
1389     UNICODE_STRING FileName;
1390     ULONG AccessMask = 0;
1391     HANDLE FileHandle;
1392     NTSTATUS Status;
1393 
1394     TRACE("SetFileSecurityW() called\n");
1395 
1396     SetSecurityAccessMask(SecurityInformation, &AccessMask);
1397 
1398     if (!RtlDosPathNameToNtPathName_U(lpFileName,
1399                                       &FileName,
1400                                       NULL,
1401                                       NULL))
1402     {
1403         ERR("Invalid path\n");
1404         SetLastError(ERROR_INVALID_NAME);
1405         return FALSE;
1406     }
1407 
1408     InitializeObjectAttributes(&ObjectAttributes,
1409                                &FileName,
1410                                OBJ_CASE_INSENSITIVE,
1411                                NULL,
1412                                NULL);
1413 
1414     Status = NtOpenFile(&FileHandle,
1415                         AccessMask,
1416                         &ObjectAttributes,
1417                         &StatusBlock,
1418                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1419                         0);
1420 
1421     RtlFreeHeap(RtlGetProcessHeap(),
1422                 0,
1423                 FileName.Buffer);
1424 
1425     if (!NT_SUCCESS(Status))
1426     {
1427         ERR("NtOpenFile() failed (Status %lx)\n", Status);
1428         SetLastError(RtlNtStatusToDosError(Status));
1429         return FALSE;
1430     }
1431 
1432     Status = NtSetSecurityObject(FileHandle,
1433                                  SecurityInformation,
1434                                  pSecurityDescriptor);
1435     NtClose(FileHandle);
1436 
1437     if (!NT_SUCCESS(Status))
1438     {
1439         ERR("NtSetSecurityObject() failed (Status %lx)\n", Status);
1440         SetLastError(RtlNtStatusToDosError(Status));
1441         return FALSE;
1442     }
1443 
1444     return TRUE;
1445 }
1446 
1447 /******************************************************************************
1448  * QueryWindows31FilesMigration [ADVAPI32.@]
1449  *
1450  * PARAMS
1451  *   x1 []
1452  */
1453 BOOL WINAPI
1454 QueryWindows31FilesMigration( DWORD x1 )
1455 {
1456 	FIXME("(%d):stub\n",x1);
1457 	return TRUE;
1458 }
1459 
1460 /******************************************************************************
1461  * SynchronizeWindows31FilesAndWindowsNTRegistry [ADVAPI32.@]
1462  *
1463  * PARAMS
1464  *   x1 []
1465  *   x2 []
1466  *   x3 []
1467  *   x4 []
1468  */
1469 BOOL WINAPI
1470 SynchronizeWindows31FilesAndWindowsNTRegistry( DWORD x1, DWORD x2, DWORD x3,
1471                                                DWORD x4 )
1472 {
1473 	FIXME("(0x%08x,0x%08x,0x%08x,0x%08x):stub\n",x1,x2,x3,x4);
1474 	return TRUE;
1475 }
1476 
1477 /*
1478  * @implemented
1479  */
1480 BOOL
1481 WINAPI
1482 RevertToSelf(VOID)
1483 {
1484     NTSTATUS Status;
1485     HANDLE Token = NULL;
1486 
1487     Status = NtSetInformationThread(NtCurrentThread(),
1488                                     ThreadImpersonationToken,
1489                                     &Token,
1490                                     sizeof(HANDLE));
1491     if (!NT_SUCCESS(Status))
1492     {
1493         SetLastError(RtlNtStatusToDosError(Status));
1494         return FALSE;
1495     }
1496 
1497     return TRUE;
1498 }
1499 
1500 /*
1501  * @implemented
1502  */
1503 BOOL
1504 WINAPI
1505 ImpersonateSelf(SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
1506 {
1507     NTSTATUS Status;
1508 
1509     Status = RtlImpersonateSelf(ImpersonationLevel);
1510     if (!NT_SUCCESS(Status))
1511     {
1512         SetLastError(RtlNtStatusToDosError(Status));
1513         return FALSE;
1514     }
1515 
1516     return TRUE;
1517 }
1518 
1519 /*
1520  * @implemented
1521  */
1522 BOOL
1523 WINAPI
1524 AccessCheck(IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
1525             IN HANDLE ClientToken,
1526             IN DWORD DesiredAccess,
1527             IN PGENERIC_MAPPING GenericMapping,
1528             OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL,
1529             IN OUT LPDWORD PrivilegeSetLength,
1530             OUT LPDWORD GrantedAccess,
1531             OUT LPBOOL AccessStatus)
1532 {
1533     NTSTATUS Status;
1534     NTSTATUS NtAccessStatus;
1535 
1536     /* Do the access check */
1537     Status = NtAccessCheck(pSecurityDescriptor,
1538                            ClientToken,
1539                            DesiredAccess,
1540                            GenericMapping,
1541                            PrivilegeSet,
1542                            (PULONG)PrivilegeSetLength,
1543                            (PACCESS_MASK)GrantedAccess,
1544                            &NtAccessStatus);
1545 
1546     /* See if the access check operation succeeded */
1547     if (!NT_SUCCESS(Status))
1548     {
1549         /* Check failed */
1550         SetLastError(RtlNtStatusToDosError(Status));
1551         return FALSE;
1552     }
1553 
1554     /* Now check the access status  */
1555     if (!NT_SUCCESS(NtAccessStatus))
1556     {
1557         /* Access denied */
1558         SetLastError(RtlNtStatusToDosError(NtAccessStatus));
1559         *AccessStatus = FALSE;
1560     }
1561     else
1562     {
1563         /* Access granted */
1564         *AccessStatus = TRUE;
1565     }
1566 
1567     /* Check succeeded */
1568     return TRUE;
1569 }
1570 
1571 /*
1572  * @unimplemented
1573  */
1574 BOOL WINAPI AccessCheckByType(
1575     PSECURITY_DESCRIPTOR pSecurityDescriptor,
1576     PSID PrincipalSelfSid,
1577     HANDLE ClientToken,
1578     DWORD DesiredAccess,
1579     POBJECT_TYPE_LIST ObjectTypeList,
1580     DWORD ObjectTypeListLength,
1581     PGENERIC_MAPPING GenericMapping,
1582     PPRIVILEGE_SET PrivilegeSet,
1583     LPDWORD PrivilegeSetLength,
1584     LPDWORD GrantedAccess,
1585     LPBOOL AccessStatus)
1586 {
1587 	FIXME("stub\n");
1588 
1589 	*AccessStatus = TRUE;
1590 
1591 	return !*AccessStatus;
1592 }
1593 
1594 /*
1595  * @implemented
1596  */
1597 BOOL
1598 WINAPI
1599 SetKernelObjectSecurity(HANDLE Handle,
1600                         SECURITY_INFORMATION SecurityInformation,
1601                         PSECURITY_DESCRIPTOR SecurityDescriptor)
1602 {
1603     NTSTATUS Status;
1604 
1605     Status = NtSetSecurityObject(Handle,
1606                                  SecurityInformation,
1607                                  SecurityDescriptor);
1608     if (!NT_SUCCESS(Status))
1609     {
1610         SetLastError(RtlNtStatusToDosError(Status));
1611         return FALSE;
1612     }
1613 
1614     return TRUE;
1615 }
1616 
1617 /*
1618  * @implemented
1619  */
1620 BOOL
1621 WINAPI
1622 AddAuditAccessAce(PACL pAcl,
1623                   DWORD dwAceRevision,
1624                   DWORD dwAccessMask,
1625                   PSID pSid,
1626                   BOOL bAuditSuccess,
1627                   BOOL bAuditFailure)
1628 {
1629     NTSTATUS Status;
1630 
1631     Status = RtlAddAuditAccessAce(pAcl,
1632                                   dwAceRevision,
1633                                   dwAccessMask,
1634                                   pSid,
1635                                   bAuditSuccess,
1636                                   bAuditFailure);
1637     if (!NT_SUCCESS(Status))
1638     {
1639         SetLastError(RtlNtStatusToDosError(Status));
1640         return FALSE;
1641     }
1642 
1643     return TRUE;
1644 }
1645 
1646 /*
1647  * @implemented
1648  */
1649 BOOL WINAPI
1650 AddAuditAccessAceEx(PACL pAcl,
1651                     DWORD dwAceRevision,
1652                     DWORD AceFlags,
1653                     DWORD dwAccessMask,
1654                     PSID pSid,
1655                     BOOL bAuditSuccess,
1656                     BOOL bAuditFailure)
1657 {
1658     NTSTATUS Status;
1659 
1660     Status = RtlAddAuditAccessAceEx(pAcl,
1661                                     dwAceRevision,
1662                                     AceFlags,
1663                                     dwAccessMask,
1664                                     pSid,
1665                                     bAuditSuccess,
1666                                     bAuditFailure);
1667     if (!NT_SUCCESS(Status))
1668     {
1669         SetLastError(RtlNtStatusToDosError(Status));
1670         return FALSE;
1671     }
1672 
1673     return TRUE;
1674 }
1675 
1676 /******************************************************************************
1677  * LookupAccountNameA [ADVAPI32.@]
1678  *
1679  * @implemented
1680  */
1681 BOOL
1682 WINAPI
1683 LookupAccountNameA(LPCSTR SystemName,
1684                    LPCSTR AccountName,
1685                    PSID Sid,
1686                    LPDWORD SidLength,
1687                    LPSTR ReferencedDomainName,
1688                    LPDWORD hReferencedDomainNameLength,
1689                    PSID_NAME_USE SidNameUse)
1690 {
1691     BOOL ret;
1692     UNICODE_STRING lpSystemW;
1693     UNICODE_STRING lpAccountW;
1694     LPWSTR lpReferencedDomainNameW = NULL;
1695 
1696     RtlCreateUnicodeStringFromAsciiz(&lpSystemW, SystemName);
1697     RtlCreateUnicodeStringFromAsciiz(&lpAccountW, AccountName);
1698 
1699     if (ReferencedDomainName)
1700         lpReferencedDomainNameW = HeapAlloc(GetProcessHeap(),
1701                                             0,
1702                                             *hReferencedDomainNameLength * sizeof(WCHAR));
1703 
1704     ret = LookupAccountNameW(lpSystemW.Buffer,
1705                              lpAccountW.Buffer,
1706                              Sid,
1707                              SidLength,
1708                              lpReferencedDomainNameW,
1709                              hReferencedDomainNameLength,
1710                              SidNameUse);
1711 
1712     if (ret && lpReferencedDomainNameW)
1713     {
1714         WideCharToMultiByte(CP_ACP,
1715                             0,
1716                             lpReferencedDomainNameW,
1717                             *hReferencedDomainNameLength + 1,
1718                             ReferencedDomainName,
1719                             *hReferencedDomainNameLength + 1,
1720                             NULL,
1721                             NULL);
1722     }
1723 
1724     RtlFreeUnicodeString(&lpSystemW);
1725     RtlFreeUnicodeString(&lpAccountW);
1726     HeapFree(GetProcessHeap(), 0, lpReferencedDomainNameW);
1727 
1728     return ret;
1729 }
1730 
1731 /**********************************************************************
1732  *	PrivilegeCheck					EXPORTED
1733  *
1734  * @implemented
1735  */
1736 BOOL WINAPI
1737 PrivilegeCheck(HANDLE ClientToken,
1738                PPRIVILEGE_SET RequiredPrivileges,
1739                LPBOOL pfResult)
1740 {
1741     BOOLEAN Result;
1742     NTSTATUS Status;
1743 
1744     Status = NtPrivilegeCheck(ClientToken,
1745                               RequiredPrivileges,
1746                               &Result);
1747     if (!NT_SUCCESS(Status))
1748     {
1749         SetLastError(RtlNtStatusToDosError(Status));
1750         return FALSE;
1751     }
1752 
1753     *pfResult = (BOOL)Result;
1754 
1755     return TRUE;
1756 }
1757 
1758 /******************************************************************************
1759  * GetSecurityInfoExW         EXPORTED
1760  */
1761 DWORD
1762 WINAPI
1763 GetSecurityInfoExA(HANDLE hObject,
1764                    SE_OBJECT_TYPE ObjectType,
1765                    SECURITY_INFORMATION SecurityInfo,
1766                    LPCSTR lpProvider,
1767                    LPCSTR lpProperty,
1768                    PACTRL_ACCESSA *ppAccessList,
1769                    PACTRL_AUDITA *ppAuditList,
1770                    LPSTR *lppOwner,
1771                    LPSTR *lppGroup)
1772 {
1773     FIXME("%s() not implemented!\n", __FUNCTION__);
1774     return ERROR_BAD_PROVIDER;
1775 }
1776 
1777 
1778 /******************************************************************************
1779  * GetSecurityInfoExW         EXPORTED
1780  */
1781 DWORD
1782 WINAPI
1783 GetSecurityInfoExW(HANDLE hObject,
1784                    SE_OBJECT_TYPE ObjectType,
1785                    SECURITY_INFORMATION SecurityInfo,
1786                    LPCWSTR lpProvider,
1787                    LPCWSTR lpProperty,
1788                    PACTRL_ACCESSW *ppAccessList,
1789                    PACTRL_AUDITW *ppAuditList,
1790                    LPWSTR *lppOwner,
1791                    LPWSTR *lppGroup)
1792 {
1793     FIXME("%s() not implemented!\n", __FUNCTION__);
1794     return ERROR_BAD_PROVIDER;
1795 }
1796 
1797 /******************************************************************************
1798  * BuildExplicitAccessWithNameA [ADVAPI32.@]
1799  */
1800 VOID WINAPI
1801 BuildExplicitAccessWithNameA(PEXPLICIT_ACCESSA pExplicitAccess,
1802                              LPSTR pTrusteeName,
1803                              DWORD AccessPermissions,
1804                              ACCESS_MODE AccessMode,
1805                              DWORD Inheritance)
1806 {
1807     pExplicitAccess->grfAccessPermissions = AccessPermissions;
1808     pExplicitAccess->grfAccessMode = AccessMode;
1809     pExplicitAccess->grfInheritance = Inheritance;
1810 
1811     pExplicitAccess->Trustee.pMultipleTrustee = NULL;
1812     pExplicitAccess->Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1813     pExplicitAccess->Trustee.TrusteeForm = TRUSTEE_IS_NAME;
1814     pExplicitAccess->Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
1815     pExplicitAccess->Trustee.ptstrName = pTrusteeName;
1816 }
1817 
1818 
1819 /******************************************************************************
1820  * BuildExplicitAccessWithNameW [ADVAPI32.@]
1821  */
1822 VOID WINAPI
1823 BuildExplicitAccessWithNameW(PEXPLICIT_ACCESSW pExplicitAccess,
1824                              LPWSTR pTrusteeName,
1825                              DWORD AccessPermissions,
1826                              ACCESS_MODE AccessMode,
1827                              DWORD Inheritance)
1828 {
1829     pExplicitAccess->grfAccessPermissions = AccessPermissions;
1830     pExplicitAccess->grfAccessMode = AccessMode;
1831     pExplicitAccess->grfInheritance = Inheritance;
1832 
1833     pExplicitAccess->Trustee.pMultipleTrustee = NULL;
1834     pExplicitAccess->Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1835     pExplicitAccess->Trustee.TrusteeForm = TRUSTEE_IS_NAME;
1836     pExplicitAccess->Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
1837     pExplicitAccess->Trustee.ptstrName = pTrusteeName;
1838 }
1839 
1840 /******************************************************************************
1841  * BuildTrusteeWithObjectsAndNameA [ADVAPI32.@]
1842  */
1843 VOID WINAPI BuildTrusteeWithObjectsAndNameA( PTRUSTEEA pTrustee, POBJECTS_AND_NAME_A pObjName,
1844                                              SE_OBJECT_TYPE ObjectType, LPSTR ObjectTypeName,
1845                                              LPSTR InheritedObjectTypeName, LPSTR Name )
1846 {
1847     DWORD ObjectsPresent = 0;
1848 
1849     TRACE("%p %p 0x%08x %p %p %s\n", pTrustee, pObjName,
1850           ObjectType, ObjectTypeName, InheritedObjectTypeName, debugstr_a(Name));
1851 
1852     /* Fill the OBJECTS_AND_NAME structure */
1853     pObjName->ObjectType = ObjectType;
1854     if (ObjectTypeName != NULL)
1855     {
1856         ObjectsPresent |= ACE_OBJECT_TYPE_PRESENT;
1857     }
1858 
1859     pObjName->InheritedObjectTypeName = InheritedObjectTypeName;
1860     if (InheritedObjectTypeName != NULL)
1861     {
1862         ObjectsPresent |= ACE_INHERITED_OBJECT_TYPE_PRESENT;
1863     }
1864 
1865     pObjName->ObjectsPresent = ObjectsPresent;
1866     pObjName->ptstrName = Name;
1867 
1868     /* Fill the TRUSTEE structure */
1869     pTrustee->pMultipleTrustee = NULL;
1870     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1871     pTrustee->TrusteeForm = TRUSTEE_IS_OBJECTS_AND_NAME;
1872     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
1873     pTrustee->ptstrName = (LPSTR)pObjName;
1874 }
1875 
1876 /******************************************************************************
1877  * BuildTrusteeWithObjectsAndNameW [ADVAPI32.@]
1878  */
1879 VOID WINAPI BuildTrusteeWithObjectsAndNameW( PTRUSTEEW pTrustee, POBJECTS_AND_NAME_W pObjName,
1880                                              SE_OBJECT_TYPE ObjectType, LPWSTR ObjectTypeName,
1881                                              LPWSTR InheritedObjectTypeName, LPWSTR Name )
1882 {
1883     DWORD ObjectsPresent = 0;
1884 
1885     TRACE("%p %p 0x%08x %p %p %s\n", pTrustee, pObjName,
1886           ObjectType, ObjectTypeName, InheritedObjectTypeName, debugstr_w(Name));
1887 
1888     /* Fill the OBJECTS_AND_NAME structure */
1889     pObjName->ObjectType = ObjectType;
1890     if (ObjectTypeName != NULL)
1891     {
1892         ObjectsPresent |= ACE_OBJECT_TYPE_PRESENT;
1893     }
1894 
1895     pObjName->InheritedObjectTypeName = InheritedObjectTypeName;
1896     if (InheritedObjectTypeName != NULL)
1897     {
1898         ObjectsPresent |= ACE_INHERITED_OBJECT_TYPE_PRESENT;
1899     }
1900 
1901     pObjName->ObjectsPresent = ObjectsPresent;
1902     pObjName->ptstrName = Name;
1903 
1904     /* Fill the TRUSTEE structure */
1905     pTrustee->pMultipleTrustee = NULL;
1906     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1907     pTrustee->TrusteeForm = TRUSTEE_IS_OBJECTS_AND_NAME;
1908     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
1909     pTrustee->ptstrName = (LPWSTR)pObjName;
1910 }
1911 
1912 /******************************************************************************
1913  * BuildTrusteeWithObjectsAndSidA [ADVAPI32.@]
1914  */
1915 VOID WINAPI
1916 BuildTrusteeWithObjectsAndSidA(PTRUSTEEA pTrustee,
1917                                POBJECTS_AND_SID pObjSid,
1918                                GUID *pObjectGuid,
1919                                GUID *pInheritedObjectGuid,
1920                                PSID pSid)
1921 {
1922     DWORD ObjectsPresent = 0;
1923 
1924     TRACE("%p %p %p %p %p\n", pTrustee, pObjSid, pObjectGuid, pInheritedObjectGuid, pSid);
1925 
1926     /* Fill the OBJECTS_AND_SID structure */
1927     if (pObjectGuid != NULL)
1928     {
1929         pObjSid->ObjectTypeGuid = *pObjectGuid;
1930         ObjectsPresent |= ACE_OBJECT_TYPE_PRESENT;
1931     }
1932     else
1933     {
1934         ZeroMemory(&pObjSid->ObjectTypeGuid,
1935                    sizeof(GUID));
1936     }
1937 
1938     if (pInheritedObjectGuid != NULL)
1939     {
1940         pObjSid->InheritedObjectTypeGuid = *pInheritedObjectGuid;
1941         ObjectsPresent |= ACE_INHERITED_OBJECT_TYPE_PRESENT;
1942     }
1943     else
1944     {
1945         ZeroMemory(&pObjSid->InheritedObjectTypeGuid,
1946                    sizeof(GUID));
1947     }
1948 
1949     pObjSid->ObjectsPresent = ObjectsPresent;
1950     pObjSid->pSid = pSid;
1951 
1952     /* Fill the TRUSTEE structure */
1953     pTrustee->pMultipleTrustee = NULL;
1954     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1955     pTrustee->TrusteeForm = TRUSTEE_IS_OBJECTS_AND_SID;
1956     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
1957     pTrustee->ptstrName = (LPSTR) pObjSid;
1958 }
1959 
1960 
1961 /******************************************************************************
1962  * BuildTrusteeWithObjectsAndSidW [ADVAPI32.@]
1963  */
1964 VOID WINAPI
1965 BuildTrusteeWithObjectsAndSidW(PTRUSTEEW pTrustee,
1966                                POBJECTS_AND_SID pObjSid,
1967                                GUID *pObjectGuid,
1968                                GUID *pInheritedObjectGuid,
1969                                PSID pSid)
1970 {
1971     DWORD ObjectsPresent = 0;
1972 
1973     TRACE("%p %p %p %p %p\n", pTrustee, pObjSid, pObjectGuid, pInheritedObjectGuid, pSid);
1974 
1975     /* Fill the OBJECTS_AND_SID structure */
1976     if (pObjectGuid != NULL)
1977     {
1978         pObjSid->ObjectTypeGuid = *pObjectGuid;
1979         ObjectsPresent |= ACE_OBJECT_TYPE_PRESENT;
1980     }
1981     else
1982     {
1983         ZeroMemory(&pObjSid->ObjectTypeGuid,
1984                    sizeof(GUID));
1985     }
1986 
1987     if (pInheritedObjectGuid != NULL)
1988     {
1989         pObjSid->InheritedObjectTypeGuid = *pInheritedObjectGuid;
1990         ObjectsPresent |= ACE_INHERITED_OBJECT_TYPE_PRESENT;
1991     }
1992     else
1993     {
1994         ZeroMemory(&pObjSid->InheritedObjectTypeGuid,
1995                    sizeof(GUID));
1996     }
1997 
1998     pObjSid->ObjectsPresent = ObjectsPresent;
1999     pObjSid->pSid = pSid;
2000 
2001     /* Fill the TRUSTEE structure */
2002     pTrustee->pMultipleTrustee = NULL;
2003     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
2004     pTrustee->TrusteeForm = TRUSTEE_IS_OBJECTS_AND_SID;
2005     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
2006     pTrustee->ptstrName = (LPWSTR) pObjSid;
2007 }
2008 
2009 /******************************************************************************
2010  * BuildTrusteeWithSidA [ADVAPI32.@]
2011  */
2012 VOID WINAPI
2013 BuildTrusteeWithSidA(PTRUSTEE_A pTrustee,
2014                      PSID pSid)
2015 {
2016     TRACE("%p %p\n", pTrustee, pSid);
2017 
2018     pTrustee->pMultipleTrustee = NULL;
2019     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
2020     pTrustee->TrusteeForm = TRUSTEE_IS_SID;
2021     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
2022     pTrustee->ptstrName = (LPSTR) pSid;
2023 }
2024 
2025 
2026 /******************************************************************************
2027  * BuildTrusteeWithSidW [ADVAPI32.@]
2028  */
2029 VOID WINAPI
2030 BuildTrusteeWithSidW(PTRUSTEE_W pTrustee,
2031                      PSID pSid)
2032 {
2033     TRACE("%p %p\n", pTrustee, pSid);
2034 
2035     pTrustee->pMultipleTrustee = NULL;
2036     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
2037     pTrustee->TrusteeForm = TRUSTEE_IS_SID;
2038     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
2039     pTrustee->ptstrName = (LPWSTR) pSid;
2040 }
2041 
2042 /******************************************************************************
2043  * BuildTrusteeWithNameA [ADVAPI32.@]
2044  */
2045 VOID WINAPI
2046 BuildTrusteeWithNameA(PTRUSTEE_A pTrustee,
2047                       LPSTR name)
2048 {
2049     TRACE("%p %s\n", pTrustee, name);
2050 
2051     pTrustee->pMultipleTrustee = NULL;
2052     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
2053     pTrustee->TrusteeForm = TRUSTEE_IS_NAME;
2054     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
2055     pTrustee->ptstrName = name;
2056 }
2057 
2058 /******************************************************************************
2059  * BuildTrusteeWithNameW [ADVAPI32.@]
2060  */
2061 VOID WINAPI
2062 BuildTrusteeWithNameW(PTRUSTEE_W pTrustee,
2063                       LPWSTR name)
2064 {
2065     TRACE("%p %s\n", pTrustee, name);
2066 
2067     pTrustee->pMultipleTrustee = NULL;
2068     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
2069     pTrustee->TrusteeForm = TRUSTEE_IS_NAME;
2070     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
2071     pTrustee->ptstrName = name;
2072 }
2073 
2074 /******************************************************************************
2075  * GetTrusteeFormA [ADVAPI32.@]
2076  */
2077 TRUSTEE_FORM WINAPI GetTrusteeFormA(PTRUSTEEA pTrustee)
2078 {
2079     TRACE("(%p)\n", pTrustee);
2080 
2081     if (!pTrustee)
2082         return TRUSTEE_BAD_FORM;
2083 
2084     return pTrustee->TrusteeForm;
2085 }
2086 
2087 /******************************************************************************
2088  * GetTrusteeFormW [ADVAPI32.@]
2089  */
2090 TRUSTEE_FORM WINAPI GetTrusteeFormW(PTRUSTEEW pTrustee)
2091 {
2092     TRACE("(%p)\n", pTrustee);
2093 
2094     if (!pTrustee)
2095         return TRUSTEE_BAD_FORM;
2096 
2097     return pTrustee->TrusteeForm;
2098 }
2099 
2100 /******************************************************************************
2101  * GetTrusteeNameA [ADVAPI32.@]
2102  */
2103 LPSTR WINAPI
2104 GetTrusteeNameA(PTRUSTEE_A pTrustee)
2105 {
2106     return pTrustee->ptstrName;
2107 }
2108 
2109 
2110 /******************************************************************************
2111  * GetTrusteeNameW [ADVAPI32.@]
2112  */
2113 LPWSTR WINAPI
2114 GetTrusteeNameW(PTRUSTEE_W pTrustee)
2115 {
2116     return pTrustee->ptstrName;
2117 }
2118 
2119 /******************************************************************************
2120  * GetTrusteeTypeA [ADVAPI32.@]
2121  */
2122 TRUSTEE_TYPE WINAPI
2123 GetTrusteeTypeA(PTRUSTEE_A pTrustee)
2124 {
2125     return pTrustee->TrusteeType;
2126 }
2127 
2128 /******************************************************************************
2129  * GetTrusteeTypeW [ADVAPI32.@]
2130  */
2131 TRUSTEE_TYPE WINAPI
2132 GetTrusteeTypeW(PTRUSTEE_W pTrustee)
2133 {
2134     return pTrustee->TrusteeType;
2135 }
2136 
2137 /*
2138  * @implemented
2139  */
2140 BOOL
2141 WINAPI
2142 SetAclInformation(PACL pAcl,
2143                   LPVOID pAclInformation,
2144                   DWORD nAclInformationLength,
2145                   ACL_INFORMATION_CLASS dwAclInformationClass)
2146 {
2147     NTSTATUS Status;
2148 
2149     Status = RtlSetInformationAcl(pAcl,
2150                                   pAclInformation,
2151                                   nAclInformationLength,
2152                                   dwAclInformationClass);
2153     if (!NT_SUCCESS(Status))
2154     {
2155         SetLastError(RtlNtStatusToDosError(Status));
2156         return FALSE;
2157     }
2158 
2159     return TRUE;
2160 }
2161 
2162 /**********************************************************************
2163  * SetNamedSecurityInfoA			EXPORTED
2164  *
2165  * @implemented
2166  */
2167 DWORD
2168 WINAPI
2169 SetNamedSecurityInfoA(LPSTR pObjectName,
2170                       SE_OBJECT_TYPE ObjectType,
2171                       SECURITY_INFORMATION SecurityInfo,
2172                       PSID psidOwner,
2173                       PSID psidGroup,
2174                       PACL pDacl,
2175                       PACL pSacl)
2176 {
2177     UNICODE_STRING ObjectName;
2178     DWORD Ret;
2179 
2180     if (!RtlCreateUnicodeStringFromAsciiz(&ObjectName, pObjectName))
2181     {
2182         return ERROR_NOT_ENOUGH_MEMORY;
2183     }
2184 
2185     Ret = SetNamedSecurityInfoW(ObjectName.Buffer,
2186                                 ObjectType,
2187                                 SecurityInfo,
2188                                 psidOwner,
2189                                 psidGroup,
2190                                 pDacl,
2191                                 pSacl);
2192 
2193     RtlFreeUnicodeString(&ObjectName);
2194 
2195     return Ret;
2196 }
2197 
2198 /*
2199  * @implemented
2200  */
2201 BOOL
2202 WINAPI
2203 AreAllAccessesGranted(DWORD GrantedAccess,
2204                       DWORD DesiredAccess)
2205 {
2206     return (BOOL)RtlAreAllAccessesGranted(GrantedAccess,
2207                                           DesiredAccess);
2208 }
2209 
2210 /*
2211  * @implemented
2212  */
2213 BOOL
2214 WINAPI
2215 AreAnyAccessesGranted(DWORD GrantedAccess,
2216                       DWORD DesiredAccess)
2217 {
2218     return (BOOL)RtlAreAnyAccessesGranted(GrantedAccess,
2219                                           DesiredAccess);
2220 }
2221 
2222 /******************************************************************************
2223  * ParseAclStringFlags
2224  */
2225 static DWORD ParseAclStringFlags(LPCWSTR* StringAcl)
2226 {
2227     DWORD flags = 0;
2228     LPCWSTR szAcl = *StringAcl;
2229 
2230     while (*szAcl != '(')
2231     {
2232         if (*szAcl == 'P')
2233         {
2234             flags |= SE_DACL_PROTECTED;
2235         }
2236         else if (*szAcl == 'A')
2237         {
2238             szAcl++;
2239             if (*szAcl == 'R')
2240                 flags |= SE_DACL_AUTO_INHERIT_REQ;
2241             else if (*szAcl == 'I')
2242                 flags |= SE_DACL_AUTO_INHERITED;
2243         }
2244         szAcl++;
2245     }
2246 
2247     *StringAcl = szAcl;
2248     return flags;
2249 }
2250 
2251 /******************************************************************************
2252  * ParseAceStringType
2253  */
2254 static const ACEFLAG AceType[] =
2255 {
2256     { SDDL_ALARM,          SYSTEM_ALARM_ACE_TYPE },
2257     { SDDL_AUDIT,          SYSTEM_AUDIT_ACE_TYPE },
2258     { SDDL_ACCESS_ALLOWED, ACCESS_ALLOWED_ACE_TYPE },
2259     { SDDL_ACCESS_DENIED,  ACCESS_DENIED_ACE_TYPE },
2260     { SDDL_MANDATORY_LABEL,SYSTEM_MANDATORY_LABEL_ACE_TYPE },
2261     /*
2262     { SDDL_OBJECT_ACCESS_ALLOWED, ACCESS_ALLOWED_OBJECT_ACE_TYPE },
2263     { SDDL_OBJECT_ACCESS_DENIED,  ACCESS_DENIED_OBJECT_ACE_TYPE },
2264     { SDDL_OBJECT_ALARM,          SYSTEM_ALARM_OBJECT_ACE_TYPE },
2265     { SDDL_OBJECT_AUDIT,          SYSTEM_AUDIT_OBJECT_ACE_TYPE },
2266     */
2267     { NULL, 0 },
2268 };
2269 
2270 static BYTE ParseAceStringType(LPCWSTR* StringAcl)
2271 {
2272     UINT len = 0;
2273     LPCWSTR szAcl = *StringAcl;
2274     const ACEFLAG *lpaf = AceType;
2275 
2276     while (*szAcl == ' ')
2277         szAcl++;
2278 
2279     while (lpaf->wstr &&
2280         (len = strlenW(lpaf->wstr)) &&
2281         strncmpW(lpaf->wstr, szAcl, len))
2282         lpaf++;
2283 
2284     if (!lpaf->wstr)
2285         return 0;
2286 
2287     *StringAcl = szAcl + len;
2288     return lpaf->value;
2289 }
2290 
2291 
2292 /******************************************************************************
2293  * ParseAceStringFlags
2294  */
2295 static const ACEFLAG AceFlags[] =
2296 {
2297     { SDDL_CONTAINER_INHERIT, CONTAINER_INHERIT_ACE },
2298     { SDDL_AUDIT_FAILURE,     FAILED_ACCESS_ACE_FLAG },
2299     { SDDL_INHERITED,         INHERITED_ACE },
2300     { SDDL_INHERIT_ONLY,      INHERIT_ONLY_ACE },
2301     { SDDL_NO_PROPAGATE,      NO_PROPAGATE_INHERIT_ACE },
2302     { SDDL_OBJECT_INHERIT,    OBJECT_INHERIT_ACE },
2303     { SDDL_AUDIT_SUCCESS,     SUCCESSFUL_ACCESS_ACE_FLAG },
2304     { NULL, 0 },
2305 };
2306 
2307 static BYTE ParseAceStringFlags(LPCWSTR* StringAcl)
2308 {
2309     UINT len = 0;
2310     BYTE flags = 0;
2311     LPCWSTR szAcl = *StringAcl;
2312 
2313     while (*szAcl == ' ')
2314         szAcl++;
2315 
2316     while (*szAcl != ';')
2317     {
2318         const ACEFLAG *lpaf = AceFlags;
2319 
2320         while (lpaf->wstr &&
2321                (len = strlenW(lpaf->wstr)) &&
2322                strncmpW(lpaf->wstr, szAcl, len))
2323             lpaf++;
2324 
2325         if (!lpaf->wstr)
2326             return 0;
2327 
2328 	flags |= lpaf->value;
2329         szAcl += len;
2330     }
2331 
2332     *StringAcl = szAcl;
2333     return flags;
2334 }
2335 
2336 
2337 /******************************************************************************
2338  * ParseAceStringRights
2339  */
2340 static const ACEFLAG AceRights[] =
2341 {
2342     { SDDL_GENERIC_ALL,     GENERIC_ALL },
2343     { SDDL_GENERIC_READ,    GENERIC_READ },
2344     { SDDL_GENERIC_WRITE,   GENERIC_WRITE },
2345     { SDDL_GENERIC_EXECUTE, GENERIC_EXECUTE },
2346 
2347     { SDDL_READ_CONTROL,    READ_CONTROL },
2348     { SDDL_STANDARD_DELETE, DELETE },
2349     { SDDL_WRITE_DAC,       WRITE_DAC },
2350     { SDDL_WRITE_OWNER,     WRITE_OWNER },
2351 
2352     { SDDL_READ_PROPERTY,   ADS_RIGHT_DS_READ_PROP},
2353     { SDDL_WRITE_PROPERTY,  ADS_RIGHT_DS_WRITE_PROP},
2354     { SDDL_CREATE_CHILD,    ADS_RIGHT_DS_CREATE_CHILD},
2355     { SDDL_DELETE_CHILD,    ADS_RIGHT_DS_DELETE_CHILD},
2356     { SDDL_LIST_CHILDREN,   ADS_RIGHT_ACTRL_DS_LIST},
2357     { SDDL_SELF_WRITE,      ADS_RIGHT_DS_SELF},
2358     { SDDL_LIST_OBJECT,     ADS_RIGHT_DS_LIST_OBJECT},
2359     { SDDL_DELETE_TREE,     ADS_RIGHT_DS_DELETE_TREE},
2360     { SDDL_CONTROL_ACCESS,  ADS_RIGHT_DS_CONTROL_ACCESS},
2361 
2362     { SDDL_FILE_ALL,        FILE_ALL_ACCESS },
2363     { SDDL_FILE_READ,       FILE_GENERIC_READ },
2364     { SDDL_FILE_WRITE,      FILE_GENERIC_WRITE },
2365     { SDDL_FILE_EXECUTE,    FILE_GENERIC_EXECUTE },
2366 
2367     { SDDL_KEY_ALL,         KEY_ALL_ACCESS },
2368     { SDDL_KEY_READ,        KEY_READ },
2369     { SDDL_KEY_WRITE,       KEY_WRITE },
2370     { SDDL_KEY_EXECUTE,     KEY_EXECUTE },
2371 
2372     { SDDL_NO_READ_UP,      SYSTEM_MANDATORY_LABEL_NO_READ_UP },
2373     { SDDL_NO_WRITE_UP,     SYSTEM_MANDATORY_LABEL_NO_WRITE_UP },
2374     { SDDL_NO_EXECUTE_UP,   SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP },
2375     { NULL, 0 },
2376 };
2377 
2378 static DWORD ParseAceStringRights(LPCWSTR* StringAcl)
2379 {
2380     UINT len = 0;
2381     DWORD rights = 0;
2382     LPCWSTR szAcl = *StringAcl;
2383 
2384     while (*szAcl == ' ')
2385         szAcl++;
2386 
2387     if ((*szAcl == '0') && (*(szAcl + 1) == 'x'))
2388     {
2389         LPCWSTR p = szAcl;
2390 
2391 	while (*p && *p != ';')
2392             p++;
2393 
2394 	if (p - szAcl <= 10 /* 8 hex digits + "0x" */ )
2395 	{
2396 	    rights = strtoulW(szAcl, NULL, 16);
2397 	    szAcl = p;
2398 	}
2399 	else
2400             WARN("Invalid rights string format: %s\n", debugstr_wn(szAcl, p - szAcl));
2401     }
2402     else
2403     {
2404         while (*szAcl != ';')
2405         {
2406             const ACEFLAG *lpaf = AceRights;
2407 
2408             while (lpaf->wstr &&
2409                (len = strlenW(lpaf->wstr)) &&
2410                strncmpW(lpaf->wstr, szAcl, len))
2411 	    {
2412                lpaf++;
2413 	    }
2414 
2415             if (!lpaf->wstr)
2416                 return 0;
2417 
2418 	    rights |= lpaf->value;
2419             szAcl += len;
2420         }
2421     }
2422 
2423     *StringAcl = szAcl;
2424     return rights;
2425 }
2426 
2427 
2428 /******************************************************************************
2429  * ParseStringAclToAcl
2430  *
2431  * dacl_flags(string_ace1)(string_ace2)... (string_acen)
2432  */
2433 static BOOL ParseStringAclToAcl(LPCWSTR StringAcl, LPDWORD lpdwFlags,
2434     PACL pAcl, LPDWORD cBytes)
2435 {
2436     DWORD val;
2437     DWORD sidlen;
2438     DWORD length = sizeof(ACL);
2439     DWORD acesize = 0;
2440     DWORD acecount = 0;
2441     PACCESS_ALLOWED_ACE pAce = NULL; /* pointer to current ACE */
2442     DWORD error = ERROR_INVALID_ACL;
2443 
2444     TRACE("%s\n", debugstr_w(StringAcl));
2445 
2446     if (!StringAcl)
2447 	return FALSE;
2448 
2449     if (pAcl) /* pAce is only useful if we're setting values */
2450         pAce = (PACCESS_ALLOWED_ACE) (pAcl + 1);
2451 
2452     /* Parse ACL flags */
2453     *lpdwFlags = ParseAclStringFlags(&StringAcl);
2454 
2455     /* Parse ACE */
2456     while (*StringAcl == '(')
2457     {
2458         StringAcl++;
2459 
2460         /* Parse ACE type */
2461         val = ParseAceStringType(&StringAcl);
2462 	if (pAce)
2463             pAce->Header.AceType = (BYTE) val;
2464         if (*StringAcl != ';')
2465         {
2466             error = RPC_S_INVALID_STRING_UUID;
2467             goto lerr;
2468         }
2469         StringAcl++;
2470 
2471         /* Parse ACE flags */
2472 	val = ParseAceStringFlags(&StringAcl);
2473 	if (pAce)
2474             pAce->Header.AceFlags = (BYTE) val;
2475         if (*StringAcl != ';')
2476             goto lerr;
2477         StringAcl++;
2478 
2479         /* Parse ACE rights */
2480 	val = ParseAceStringRights(&StringAcl);
2481 	if (pAce)
2482             pAce->Mask = val;
2483         if (*StringAcl != ';')
2484             goto lerr;
2485         StringAcl++;
2486 
2487         /* Parse ACE object guid */
2488         while (*StringAcl == ' ')
2489             StringAcl++;
2490         if (*StringAcl != ';')
2491         {
2492             FIXME("Support for *_OBJECT_ACE_TYPE not implemented\n");
2493             goto lerr;
2494         }
2495         StringAcl++;
2496 
2497         /* Parse ACE inherit object guid */
2498         while (*StringAcl == ' ')
2499             StringAcl++;
2500         if (*StringAcl != ';')
2501         {
2502             FIXME("Support for *_OBJECT_ACE_TYPE not implemented\n");
2503             goto lerr;
2504         }
2505         StringAcl++;
2506 
2507         /* Parse ACE account sid */
2508         if (ParseStringSidToSid(StringAcl, pAce ? &pAce->SidStart : NULL, &sidlen))
2509 	{
2510             while (*StringAcl && *StringAcl != ')')
2511                 StringAcl++;
2512 	}
2513 
2514         if (*StringAcl != ')')
2515             goto lerr;
2516         StringAcl++;
2517 
2518         acesize = sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + sidlen;
2519         length += acesize;
2520         if (pAce)
2521         {
2522             pAce->Header.AceSize = acesize;
2523             pAce = (PACCESS_ALLOWED_ACE)((LPBYTE)pAce + acesize);
2524         }
2525         acecount++;
2526     }
2527 
2528     *cBytes = length;
2529 
2530     if (length > 0xffff)
2531     {
2532         ERR("ACL too large\n");
2533         goto lerr;
2534     }
2535 
2536     if (pAcl)
2537     {
2538         pAcl->AclRevision = ACL_REVISION;
2539         pAcl->Sbz1 = 0;
2540         pAcl->AclSize = length;
2541         pAcl->AceCount = acecount++;
2542         pAcl->Sbz2 = 0;
2543     }
2544     return TRUE;
2545 
2546 lerr:
2547     SetLastError(error);
2548     WARN("Invalid ACE string format\n");
2549     return FALSE;
2550 }
2551 
2552 
2553 /******************************************************************************
2554  * ParseStringSecurityDescriptorToSecurityDescriptor
2555  */
2556 static BOOL ParseStringSecurityDescriptorToSecurityDescriptor(
2557     LPCWSTR StringSecurityDescriptor,
2558     SECURITY_DESCRIPTOR_RELATIVE* SecurityDescriptor,
2559     LPDWORD cBytes)
2560 {
2561     BOOL bret = FALSE;
2562     WCHAR toktype;
2563     WCHAR *tok;
2564     LPCWSTR lptoken;
2565     LPBYTE lpNext = NULL;
2566     DWORD len;
2567 
2568     *cBytes = sizeof(SECURITY_DESCRIPTOR);
2569 
2570     tok = heap_alloc( (lstrlenW(StringSecurityDescriptor) + 1) * sizeof(WCHAR));
2571 
2572     if (SecurityDescriptor)
2573         lpNext = (LPBYTE)(SecurityDescriptor + 1);
2574 
2575     while (*StringSecurityDescriptor == ' ')
2576         StringSecurityDescriptor++;
2577 
2578     while (*StringSecurityDescriptor)
2579     {
2580         toktype = *StringSecurityDescriptor;
2581 
2582 	/* Expect char identifier followed by ':' */
2583 	StringSecurityDescriptor++;
2584         if (*StringSecurityDescriptor != ':')
2585         {
2586             SetLastError(ERROR_INVALID_PARAMETER);
2587             goto lend;
2588         }
2589 	StringSecurityDescriptor++;
2590 
2591 	/* Extract token */
2592 	lptoken = StringSecurityDescriptor;
2593 	while (*lptoken && *lptoken != ':')
2594             lptoken++;
2595 
2596 	if (*lptoken)
2597             lptoken--;
2598 
2599         len = lptoken - StringSecurityDescriptor;
2600         memcpy( tok, StringSecurityDescriptor, len * sizeof(WCHAR) );
2601         tok[len] = 0;
2602 
2603         switch (toktype)
2604 	{
2605             case 'O':
2606             {
2607                 DWORD bytes;
2608 
2609                 if (!ParseStringSidToSid(tok, lpNext, &bytes))
2610                     goto lend;
2611 
2612                 if (SecurityDescriptor)
2613                 {
2614                     SecurityDescriptor->Owner = lpNext - (LPBYTE)SecurityDescriptor;
2615                     lpNext += bytes; /* Advance to next token */
2616                 }
2617 
2618 		*cBytes += bytes;
2619 
2620                 break;
2621             }
2622 
2623             case 'G':
2624             {
2625                 DWORD bytes;
2626 
2627                 if (!ParseStringSidToSid(tok, lpNext, &bytes))
2628                     goto lend;
2629 
2630                 if (SecurityDescriptor)
2631                 {
2632                     SecurityDescriptor->Group = lpNext - (LPBYTE)SecurityDescriptor;
2633                     lpNext += bytes; /* Advance to next token */
2634                 }
2635 
2636 		*cBytes += bytes;
2637 
2638                 break;
2639             }
2640 
2641             case 'D':
2642 	    {
2643                 DWORD flags;
2644                 DWORD bytes;
2645 
2646                 if (!ParseStringAclToAcl(tok, &flags, (PACL)lpNext, &bytes))
2647                     goto lend;
2648 
2649                 if (SecurityDescriptor)
2650                 {
2651                     SecurityDescriptor->Control |= SE_DACL_PRESENT | flags;
2652                     SecurityDescriptor->Dacl = lpNext - (LPBYTE)SecurityDescriptor;
2653                     lpNext += bytes; /* Advance to next token */
2654 		}
2655 
2656 		*cBytes += bytes;
2657 
2658 		break;
2659             }
2660 
2661             case 'S':
2662             {
2663                 DWORD flags;
2664                 DWORD bytes;
2665 
2666                 if (!ParseStringAclToAcl(tok, &flags, (PACL)lpNext, &bytes))
2667                     goto lend;
2668 
2669                 if (SecurityDescriptor)
2670                 {
2671                     SecurityDescriptor->Control |= SE_SACL_PRESENT | flags;
2672                     SecurityDescriptor->Sacl = lpNext - (LPBYTE)SecurityDescriptor;
2673                     lpNext += bytes; /* Advance to next token */
2674 		}
2675 
2676 		*cBytes += bytes;
2677 
2678 		break;
2679             }
2680 
2681             default:
2682                 FIXME("Unknown token\n");
2683                 SetLastError(ERROR_INVALID_PARAMETER);
2684 		goto lend;
2685 	}
2686 
2687         StringSecurityDescriptor = lptoken;
2688     }
2689 
2690     bret = TRUE;
2691 
2692 lend:
2693     heap_free(tok);
2694     return bret;
2695 }
2696 
2697 /* Winehq cvs 20050916 */
2698 /******************************************************************************
2699  * ConvertStringSecurityDescriptorToSecurityDescriptorA [ADVAPI32.@]
2700  * @implemented
2701  */
2702 BOOL
2703 WINAPI
2704 ConvertStringSecurityDescriptorToSecurityDescriptorA(LPCSTR StringSecurityDescriptor,
2705                                                      DWORD StringSDRevision,
2706                                                      PSECURITY_DESCRIPTOR* SecurityDescriptor,
2707                                                      PULONG SecurityDescriptorSize)
2708 {
2709     UINT len;
2710     BOOL ret = FALSE;
2711     LPWSTR StringSecurityDescriptorW;
2712 
2713     len = MultiByteToWideChar(CP_ACP, 0, StringSecurityDescriptor, -1, NULL, 0);
2714     StringSecurityDescriptorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2715 
2716     if (StringSecurityDescriptorW)
2717     {
2718         MultiByteToWideChar(CP_ACP, 0, StringSecurityDescriptor, -1, StringSecurityDescriptorW, len);
2719 
2720         ret = ConvertStringSecurityDescriptorToSecurityDescriptorW(StringSecurityDescriptorW,
2721                                                                    StringSDRevision, SecurityDescriptor,
2722                                                                    SecurityDescriptorSize);
2723         HeapFree(GetProcessHeap(), 0, StringSecurityDescriptorW);
2724     }
2725 
2726     return ret;
2727 }
2728 
2729 /******************************************************************************
2730  * ConvertStringSecurityDescriptorToSecurityDescriptorW [ADVAPI32.@]
2731  * @implemented
2732  */
2733 BOOL WINAPI
2734 ConvertStringSecurityDescriptorToSecurityDescriptorW(LPCWSTR StringSecurityDescriptor,
2735                                                      DWORD StringSDRevision,
2736                                                      PSECURITY_DESCRIPTOR* SecurityDescriptor,
2737                                                      PULONG SecurityDescriptorSize)
2738 {
2739     DWORD cBytes;
2740     SECURITY_DESCRIPTOR* psd;
2741     BOOL bret = FALSE;
2742 
2743     TRACE("%s\n", debugstr_w(StringSecurityDescriptor));
2744 
2745     if (GetVersion() & 0x80000000)
2746     {
2747         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2748         goto lend;
2749     }
2750     else if (!StringSecurityDescriptor || !SecurityDescriptor)
2751     {
2752         SetLastError(ERROR_INVALID_PARAMETER);
2753         goto lend;
2754     }
2755     else if (StringSDRevision != SID_REVISION)
2756     {
2757         SetLastError(ERROR_UNKNOWN_REVISION);
2758         goto lend;
2759     }
2760 
2761     /* Compute security descriptor length */
2762     if (!ParseStringSecurityDescriptorToSecurityDescriptor(StringSecurityDescriptor,
2763         NULL, &cBytes))
2764         goto lend;
2765 
2766     psd = *SecurityDescriptor = LocalAlloc(GMEM_ZEROINIT, cBytes);
2767     if (!psd) goto lend;
2768 
2769     psd->Revision = SID_REVISION;
2770     psd->Control |= SE_SELF_RELATIVE;
2771 
2772     if (!ParseStringSecurityDescriptorToSecurityDescriptor(StringSecurityDescriptor,
2773              (SECURITY_DESCRIPTOR_RELATIVE *)psd, &cBytes))
2774     {
2775         LocalFree(psd);
2776         goto lend;
2777     }
2778 
2779     if (SecurityDescriptorSize)
2780         *SecurityDescriptorSize = cBytes;
2781 
2782     bret = TRUE;
2783 
2784 lend:
2785     TRACE(" ret=%d\n", bret);
2786     return bret;
2787 }
2788 
2789 static void DumpString(LPCWSTR string, int cch, WCHAR **pwptr, ULONG *plen)
2790 {
2791     if (cch == -1)
2792         cch = strlenW(string);
2793 
2794     if (plen)
2795         *plen += cch;
2796 
2797     if (pwptr)
2798     {
2799         memcpy(*pwptr, string, sizeof(WCHAR)*cch);
2800         *pwptr += cch;
2801     }
2802 }
2803 
2804 static BOOL DumpSidNumeric(PSID psid, WCHAR **pwptr, ULONG *plen)
2805 {
2806     DWORD i;
2807     WCHAR fmt[] = { 'S','-','%','u','-','%','d',0 };
2808     WCHAR subauthfmt[] = { '-','%','u',0 };
2809     WCHAR buf[26];
2810     SID *pisid = psid;
2811 
2812     if( !IsValidSid( psid ) || pisid->Revision != SDDL_REVISION)
2813     {
2814         SetLastError(ERROR_INVALID_SID);
2815         return FALSE;
2816     }
2817 
2818     if (pisid->IdentifierAuthority.Value[0] ||
2819      pisid->IdentifierAuthority.Value[1])
2820     {
2821         FIXME("not matching MS' bugs\n");
2822         SetLastError(ERROR_INVALID_SID);
2823         return FALSE;
2824     }
2825 
2826     sprintfW( buf, fmt, pisid->Revision,
2827         MAKELONG(
2828             MAKEWORD( pisid->IdentifierAuthority.Value[5],
2829                     pisid->IdentifierAuthority.Value[4] ),
2830             MAKEWORD( pisid->IdentifierAuthority.Value[3],
2831                     pisid->IdentifierAuthority.Value[2] )
2832         ) );
2833     DumpString(buf, -1, pwptr, plen);
2834 
2835     for( i=0; i<pisid->SubAuthorityCount; i++ )
2836     {
2837         sprintfW( buf, subauthfmt, pisid->SubAuthority[i] );
2838         DumpString(buf, -1, pwptr, plen);
2839     }
2840     return TRUE;
2841 }
2842 
2843 static BOOL DumpSid(PSID psid, WCHAR **pwptr, ULONG *plen)
2844 {
2845     size_t i;
2846     for (i = 0; i < sizeof(WellKnownSids) / sizeof(WellKnownSids[0]); i++)
2847     {
2848         if (WellKnownSids[i].wstr[0] && EqualSid(psid, (PSID)&(WellKnownSids[i].Sid.Revision)))
2849         {
2850             DumpString(WellKnownSids[i].wstr, 2, pwptr, plen);
2851             return TRUE;
2852         }
2853     }
2854 
2855     return DumpSidNumeric(psid, pwptr, plen);
2856 }
2857 
2858 static const LPCWSTR AceRightBitNames[32] = {
2859         SDDL_CREATE_CHILD,        /*  0 */
2860         SDDL_DELETE_CHILD,
2861         SDDL_LIST_CHILDREN,
2862         SDDL_SELF_WRITE,
2863         SDDL_READ_PROPERTY,       /*  4 */
2864         SDDL_WRITE_PROPERTY,
2865         SDDL_DELETE_TREE,
2866         SDDL_LIST_OBJECT,
2867         SDDL_CONTROL_ACCESS,      /*  8 */
2868         NULL,
2869         NULL,
2870         NULL,
2871         NULL,                     /* 12 */
2872         NULL,
2873         NULL,
2874         NULL,
2875         SDDL_STANDARD_DELETE,     /* 16 */
2876         SDDL_READ_CONTROL,
2877         SDDL_WRITE_DAC,
2878         SDDL_WRITE_OWNER,
2879         NULL,                     /* 20 */
2880         NULL,
2881         NULL,
2882         NULL,
2883         NULL,                     /* 24 */
2884         NULL,
2885         NULL,
2886         NULL,
2887         SDDL_GENERIC_ALL,         /* 28 */
2888         SDDL_GENERIC_EXECUTE,
2889         SDDL_GENERIC_WRITE,
2890         SDDL_GENERIC_READ
2891 };
2892 
2893 static void DumpRights(DWORD mask, WCHAR **pwptr, ULONG *plen)
2894 {
2895     static const WCHAR fmtW[] = {'0','x','%','x',0};
2896     WCHAR buf[15];
2897     size_t i;
2898 
2899     if (mask == 0)
2900         return;
2901 
2902     /* first check if the right have name */
2903     for (i = 0; i < sizeof(AceRights)/sizeof(AceRights[0]); i++)
2904     {
2905         if (AceRights[i].wstr == NULL)
2906             break;
2907         if (mask == AceRights[i].value)
2908         {
2909             DumpString(AceRights[i].wstr, -1, pwptr, plen);
2910             return;
2911         }
2912     }
2913 
2914     /* then check if it can be built from bit names */
2915     for (i = 0; i < 32; i++)
2916     {
2917         if ((mask & (1 << i)) && (AceRightBitNames[i] == NULL))
2918         {
2919             /* can't be built from bit names */
2920             sprintfW(buf, fmtW, mask);
2921             DumpString(buf, -1, pwptr, plen);
2922             return;
2923         }
2924     }
2925 
2926     /* build from bit names */
2927     for (i = 0; i < 32; i++)
2928         if (mask & (1 << i))
2929             DumpString(AceRightBitNames[i], -1, pwptr, plen);
2930 }
2931 
2932 static BOOL DumpAce(LPVOID pace, WCHAR **pwptr, ULONG *plen)
2933 {
2934     ACCESS_ALLOWED_ACE *piace; /* all the supported ACEs have the same memory layout */
2935     static const WCHAR openbr = '(';
2936     static const WCHAR closebr = ')';
2937     static const WCHAR semicolon = ';';
2938 
2939     if (((PACE_HEADER)pace)->AceType > SYSTEM_ALARM_ACE_TYPE || ((PACE_HEADER)pace)->AceSize < sizeof(ACCESS_ALLOWED_ACE))
2940     {
2941         SetLastError(ERROR_INVALID_ACL);
2942         return FALSE;
2943     }
2944 
2945     piace = pace;
2946     DumpString(&openbr, 1, pwptr, plen);
2947     switch (piace->Header.AceType)
2948     {
2949         case ACCESS_ALLOWED_ACE_TYPE:
2950             DumpString(SDDL_ACCESS_ALLOWED, -1, pwptr, plen);
2951             break;
2952         case ACCESS_DENIED_ACE_TYPE:
2953             DumpString(SDDL_ACCESS_DENIED, -1, pwptr, plen);
2954             break;
2955         case SYSTEM_AUDIT_ACE_TYPE:
2956             DumpString(SDDL_AUDIT, -1, pwptr, plen);
2957             break;
2958         case SYSTEM_ALARM_ACE_TYPE:
2959             DumpString(SDDL_ALARM, -1, pwptr, plen);
2960             break;
2961     }
2962     DumpString(&semicolon, 1, pwptr, plen);
2963 
2964     if (piace->Header.AceFlags & OBJECT_INHERIT_ACE)
2965         DumpString(SDDL_OBJECT_INHERIT, -1, pwptr, plen);
2966     if (piace->Header.AceFlags & CONTAINER_INHERIT_ACE)
2967         DumpString(SDDL_CONTAINER_INHERIT, -1, pwptr, plen);
2968     if (piace->Header.AceFlags & NO_PROPAGATE_INHERIT_ACE)
2969         DumpString(SDDL_NO_PROPAGATE, -1, pwptr, plen);
2970     if (piace->Header.AceFlags & INHERIT_ONLY_ACE)
2971         DumpString(SDDL_INHERIT_ONLY, -1, pwptr, plen);
2972     if (piace->Header.AceFlags & INHERITED_ACE)
2973         DumpString(SDDL_INHERITED, -1, pwptr, plen);
2974     if (piace->Header.AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG)
2975         DumpString(SDDL_AUDIT_SUCCESS, -1, pwptr, plen);
2976     if (piace->Header.AceFlags & FAILED_ACCESS_ACE_FLAG)
2977         DumpString(SDDL_AUDIT_FAILURE, -1, pwptr, plen);
2978     DumpString(&semicolon, 1, pwptr, plen);
2979     DumpRights(piace->Mask, pwptr, plen);
2980     DumpString(&semicolon, 1, pwptr, plen);
2981     /* objects not supported */
2982     DumpString(&semicolon, 1, pwptr, plen);
2983     /* objects not supported */
2984     DumpString(&semicolon, 1, pwptr, plen);
2985     if (!DumpSid((PSID)&piace->SidStart, pwptr, plen))
2986         return FALSE;
2987     DumpString(&closebr, 1, pwptr, plen);
2988     return TRUE;
2989 }
2990 
2991 static BOOL DumpAcl(PACL pacl, WCHAR **pwptr, ULONG *plen, BOOL protected, BOOL autoInheritReq, BOOL autoInherited)
2992 {
2993     WORD count;
2994     int i;
2995 
2996     if (protected)
2997         DumpString(SDDL_PROTECTED, -1, pwptr, plen);
2998     if (autoInheritReq)
2999         DumpString(SDDL_AUTO_INHERIT_REQ, -1, pwptr, plen);
3000     if (autoInherited)
3001         DumpString(SDDL_AUTO_INHERITED, -1, pwptr, plen);
3002 
3003     if (pacl == NULL)
3004         return TRUE;
3005 
3006     if (!IsValidAcl(pacl))
3007         return FALSE;
3008 
3009     count = pacl->AceCount;
3010     for (i = 0; i < count; i++)
3011     {
3012         LPVOID ace;
3013         if (!GetAce(pacl, i, &ace))
3014             return FALSE;
3015         if (!DumpAce(ace, pwptr, plen))
3016             return FALSE;
3017     }
3018 
3019     return TRUE;
3020 }
3021 
3022 static BOOL DumpOwner(PSECURITY_DESCRIPTOR SecurityDescriptor, WCHAR **pwptr, ULONG *plen)
3023 {
3024     static const WCHAR prefix[] = {'O',':',0};
3025     BOOL bDefaulted;
3026     PSID psid;
3027 
3028     if (!GetSecurityDescriptorOwner(SecurityDescriptor, &psid, &bDefaulted))
3029         return FALSE;
3030 
3031     if (psid == NULL)
3032         return TRUE;
3033 
3034     DumpString(prefix, -1, pwptr, plen);
3035     if (!DumpSid(psid, pwptr, plen))
3036         return FALSE;
3037     return TRUE;
3038 }
3039 
3040 static BOOL DumpGroup(PSECURITY_DESCRIPTOR SecurityDescriptor, WCHAR **pwptr, ULONG *plen)
3041 {
3042     static const WCHAR prefix[] = {'G',':',0};
3043     BOOL bDefaulted;
3044     PSID psid;
3045 
3046     if (!GetSecurityDescriptorGroup(SecurityDescriptor, &psid, &bDefaulted))
3047         return FALSE;
3048 
3049     if (psid == NULL)
3050         return TRUE;
3051 
3052     DumpString(prefix, -1, pwptr, plen);
3053     if (!DumpSid(psid, pwptr, plen))
3054         return FALSE;
3055     return TRUE;
3056 }
3057 
3058 static BOOL DumpDacl(PSECURITY_DESCRIPTOR SecurityDescriptor, WCHAR **pwptr, ULONG *plen)
3059 {
3060     static const WCHAR dacl[] = {'D',':',0};
3061     SECURITY_DESCRIPTOR_CONTROL control;
3062     BOOL present, defaulted;
3063     DWORD revision;
3064     PACL pacl;
3065 
3066     if (!GetSecurityDescriptorDacl(SecurityDescriptor, &present, &pacl, &defaulted))
3067         return FALSE;
3068 
3069     if (!GetSecurityDescriptorControl(SecurityDescriptor, &control, &revision))
3070         return FALSE;
3071 
3072     if (!present)
3073         return TRUE;
3074 
3075     DumpString(dacl, 2, pwptr, plen);
3076     if (!DumpAcl(pacl, pwptr, plen, control & SE_DACL_PROTECTED, control & SE_DACL_AUTO_INHERIT_REQ, control & SE_DACL_AUTO_INHERITED))
3077         return FALSE;
3078     return TRUE;
3079 }
3080 
3081 static BOOL DumpSacl(PSECURITY_DESCRIPTOR SecurityDescriptor, WCHAR **pwptr, ULONG *plen)
3082 {
3083     static const WCHAR sacl[] = {'S',':',0};
3084     SECURITY_DESCRIPTOR_CONTROL control;
3085     BOOL present, defaulted;
3086     DWORD revision;
3087     PACL pacl;
3088 
3089     if (!GetSecurityDescriptorSacl(SecurityDescriptor, &present, &pacl, &defaulted))
3090         return FALSE;
3091 
3092     if (!GetSecurityDescriptorControl(SecurityDescriptor, &control, &revision))
3093         return FALSE;
3094 
3095     if (!present)
3096         return TRUE;
3097 
3098     DumpString(sacl, 2, pwptr, plen);
3099     if (!DumpAcl(pacl, pwptr, plen, control & SE_SACL_PROTECTED, control & SE_SACL_AUTO_INHERIT_REQ, control & SE_SACL_AUTO_INHERITED))
3100         return FALSE;
3101     return TRUE;
3102 }
3103 
3104 /******************************************************************************
3105  * ConvertSecurityDescriptorToStringSecurityDescriptorW [ADVAPI32.@]
3106  */
3107 BOOL WINAPI ConvertSecurityDescriptorToStringSecurityDescriptorW(PSECURITY_DESCRIPTOR SecurityDescriptor, DWORD SDRevision, SECURITY_INFORMATION RequestedInformation, LPWSTR *OutputString, PULONG OutputLen)
3108 {
3109     ULONG len;
3110     WCHAR *wptr, *wstr;
3111 
3112     if (SDRevision != SDDL_REVISION_1)
3113     {
3114         ERR("Program requested unknown SDDL revision %d\n", SDRevision);
3115         SetLastError(ERROR_UNKNOWN_REVISION);
3116         return FALSE;
3117     }
3118 
3119     len = 0;
3120     if (RequestedInformation & OWNER_SECURITY_INFORMATION)
3121         if (!DumpOwner(SecurityDescriptor, NULL, &len))
3122             return FALSE;
3123     if (RequestedInformation & GROUP_SECURITY_INFORMATION)
3124         if (!DumpGroup(SecurityDescriptor, NULL, &len))
3125             return FALSE;
3126     if (RequestedInformation & DACL_SECURITY_INFORMATION)
3127         if (!DumpDacl(SecurityDescriptor, NULL, &len))
3128             return FALSE;
3129     if (RequestedInformation & SACL_SECURITY_INFORMATION)
3130         if (!DumpSacl(SecurityDescriptor, NULL, &len))
3131             return FALSE;
3132 
3133     wstr = wptr = LocalAlloc(0, (len + 1)*sizeof(WCHAR));
3134 #ifdef __REACTOS__
3135     if (wstr == NULL)
3136         return FALSE;
3137 #endif
3138 
3139     if (RequestedInformation & OWNER_SECURITY_INFORMATION)
3140         if (!DumpOwner(SecurityDescriptor, &wptr, NULL)) {
3141             LocalFree (wstr);
3142             return FALSE;
3143         }
3144     if (RequestedInformation & GROUP_SECURITY_INFORMATION)
3145         if (!DumpGroup(SecurityDescriptor, &wptr, NULL)) {
3146             LocalFree (wstr);
3147             return FALSE;
3148         }
3149     if (RequestedInformation & DACL_SECURITY_INFORMATION)
3150         if (!DumpDacl(SecurityDescriptor, &wptr, NULL)) {
3151             LocalFree (wstr);
3152             return FALSE;
3153         }
3154     if (RequestedInformation & SACL_SECURITY_INFORMATION)
3155         if (!DumpSacl(SecurityDescriptor, &wptr, NULL)) {
3156             LocalFree (wstr);
3157             return FALSE;
3158         }
3159     *wptr = 0;
3160 
3161     TRACE("ret: %s, %d\n", wine_dbgstr_w(wstr), len);
3162     *OutputString = wstr;
3163     if (OutputLen)
3164         *OutputLen = strlenW(*OutputString)+1;
3165     return TRUE;
3166 }
3167 
3168 /******************************************************************************
3169  * ConvertSecurityDescriptorToStringSecurityDescriptorA [ADVAPI32.@]
3170  */
3171 BOOL WINAPI ConvertSecurityDescriptorToStringSecurityDescriptorA(PSECURITY_DESCRIPTOR SecurityDescriptor, DWORD SDRevision, SECURITY_INFORMATION Information, LPSTR *OutputString, PULONG OutputLen)
3172 {
3173     LPWSTR wstr;
3174     ULONG len;
3175     if (ConvertSecurityDescriptorToStringSecurityDescriptorW(SecurityDescriptor, SDRevision, Information, &wstr, &len))
3176     {
3177         int lenA;
3178 
3179         lenA = WideCharToMultiByte(CP_ACP, 0, wstr, len, NULL, 0, NULL, NULL);
3180         *OutputString = heap_alloc(lenA);
3181 #ifdef __REACTOS__
3182         if (*OutputString == NULL)
3183         {
3184             LocalFree(wstr);
3185             *OutputLen = 0;
3186             return FALSE;
3187         }
3188 #endif
3189         WideCharToMultiByte(CP_ACP, 0, wstr, len, *OutputString, lenA, NULL, NULL);
3190         LocalFree(wstr);
3191 
3192         if (OutputLen != NULL)
3193             *OutputLen = lenA;
3194         return TRUE;
3195     }
3196     else
3197     {
3198         *OutputString = NULL;
3199         if (OutputLen)
3200             *OutputLen = 0;
3201         return FALSE;
3202     }
3203 }
3204 
3205 /******************************************************************************
3206  * ConvertStringSidToSidW [ADVAPI32.@]
3207  */
3208 BOOL WINAPI ConvertStringSidToSidW(LPCWSTR StringSid, PSID* Sid)
3209 {
3210     BOOL bret = FALSE;
3211     DWORD cBytes;
3212 
3213     TRACE("%s, %p\n", debugstr_w(StringSid), Sid);
3214     if (GetVersion() & 0x80000000)
3215         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3216     else if (!StringSid || !Sid)
3217         SetLastError(ERROR_INVALID_PARAMETER);
3218     else if (ParseStringSidToSid(StringSid, NULL, &cBytes))
3219     {
3220         PSID pSid = *Sid = LocalAlloc(0, cBytes);
3221 
3222         bret = ParseStringSidToSid(StringSid, pSid, &cBytes);
3223         if (!bret)
3224             LocalFree(*Sid);
3225     }
3226     return bret;
3227 }
3228 
3229 /******************************************************************************
3230  * ConvertStringSidToSidA [ADVAPI32.@]
3231  */
3232 BOOL WINAPI ConvertStringSidToSidA(LPCSTR StringSid, PSID* Sid)
3233 {
3234     BOOL bret = FALSE;
3235 
3236     TRACE("%s, %p\n", debugstr_a(StringSid), Sid);
3237     if (GetVersion() & 0x80000000)
3238         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3239     else if (!StringSid || !Sid)
3240         SetLastError(ERROR_INVALID_PARAMETER);
3241     else
3242     {
3243         WCHAR *wStringSid = SERV_dup(StringSid);
3244         bret = ConvertStringSidToSidW(wStringSid, Sid);
3245         heap_free(wStringSid);
3246     }
3247     return bret;
3248 }
3249 
3250 /*
3251  * @implemented
3252  */
3253 BOOL
3254 WINAPI
3255 ConvertSidToStringSidW(PSID Sid,
3256                        LPWSTR *StringSid)
3257 {
3258     NTSTATUS Status;
3259     UNICODE_STRING UnicodeString;
3260     WCHAR FixedBuffer[64];
3261 
3262     if (!RtlValidSid(Sid))
3263     {
3264         SetLastError(ERROR_INVALID_SID);
3265         return FALSE;
3266     }
3267 
3268     UnicodeString.Length = 0;
3269     UnicodeString.MaximumLength = sizeof(FixedBuffer);
3270     UnicodeString.Buffer = FixedBuffer;
3271     Status = RtlConvertSidToUnicodeString(&UnicodeString, Sid, FALSE);
3272     if (STATUS_BUFFER_TOO_SMALL == Status)
3273     {
3274         Status = RtlConvertSidToUnicodeString(&UnicodeString, Sid, TRUE);
3275     }
3276 
3277     if (!NT_SUCCESS(Status))
3278     {
3279         SetLastError(RtlNtStatusToDosError(Status));
3280         return FALSE;
3281     }
3282 
3283     *StringSid = LocalAlloc(LMEM_FIXED, UnicodeString.Length + sizeof(WCHAR));
3284     if (NULL == *StringSid)
3285     {
3286         if (UnicodeString.Buffer != FixedBuffer)
3287         {
3288             RtlFreeUnicodeString(&UnicodeString);
3289         }
3290       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3291       return FALSE;
3292     }
3293 
3294     MoveMemory(*StringSid, UnicodeString.Buffer, UnicodeString.Length);
3295     ZeroMemory((PCHAR) *StringSid + UnicodeString.Length, sizeof(WCHAR));
3296     if (UnicodeString.Buffer != FixedBuffer)
3297     {
3298         RtlFreeUnicodeString(&UnicodeString);
3299     }
3300 
3301     return TRUE;
3302 }
3303 
3304 /*
3305  * @implemented
3306  */
3307 BOOL
3308 WINAPI
3309 ConvertSidToStringSidA(PSID Sid,
3310                        LPSTR *StringSid)
3311 {
3312     LPWSTR StringSidW;
3313     int Len;
3314 
3315     if (!ConvertSidToStringSidW(Sid, &StringSidW))
3316     {
3317         return FALSE;
3318     }
3319 
3320     Len = WideCharToMultiByte(CP_ACP, 0, StringSidW, -1, NULL, 0, NULL, NULL);
3321     if (Len <= 0)
3322     {
3323         LocalFree(StringSidW);
3324         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3325         return FALSE;
3326     }
3327 
3328     *StringSid = LocalAlloc(LMEM_FIXED, Len);
3329     if (NULL == *StringSid)
3330     {
3331         LocalFree(StringSidW);
3332         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3333         return FALSE;
3334     }
3335 
3336     if (!WideCharToMultiByte(CP_ACP, 0, StringSidW, -1, *StringSid, Len, NULL, NULL))
3337     {
3338         LocalFree(StringSid);
3339         LocalFree(StringSidW);
3340         return FALSE;
3341     }
3342 
3343     LocalFree(StringSidW);
3344 
3345     return TRUE;
3346 }
3347 
3348 /*
3349  * @unimplemented
3350  */
3351 BOOL WINAPI
3352 CreateProcessWithLogonW(LPCWSTR lpUsername,
3353                         LPCWSTR lpDomain,
3354                         LPCWSTR lpPassword,
3355                         DWORD dwLogonFlags,
3356                         LPCWSTR lpApplicationName,
3357                         LPWSTR lpCommandLine,
3358                         DWORD dwCreationFlags,
3359                         LPVOID lpEnvironment,
3360                         LPCWSTR lpCurrentDirectory,
3361                         LPSTARTUPINFOW lpStartupInfo,
3362                         LPPROCESS_INFORMATION lpProcessInformation)
3363 {
3364     FIXME("%s %s %s 0x%08x %s %s 0x%08x %p %s %p %p stub\n", debugstr_w(lpUsername), debugstr_w(lpDomain),
3365     debugstr_w(lpPassword), dwLogonFlags, debugstr_w(lpApplicationName),
3366     debugstr_w(lpCommandLine), dwCreationFlags, lpEnvironment, debugstr_w(lpCurrentDirectory),
3367     lpStartupInfo, lpProcessInformation);
3368 
3369     return FALSE;
3370 }
3371 
3372 BOOL WINAPI CreateProcessWithTokenW(HANDLE token, DWORD logon_flags, LPCWSTR application_name, LPWSTR command_line,
3373         DWORD creation_flags, void *environment, LPCWSTR current_directory, STARTUPINFOW *startup_info,
3374         PROCESS_INFORMATION *process_information )
3375 {
3376     FIXME("%p 0x%08x %s %s 0x%08x %p %s %p %p - semi-stub\n", token,
3377           logon_flags, debugstr_w(application_name), debugstr_w(command_line),
3378           creation_flags, environment, debugstr_w(current_directory),
3379           startup_info, process_information);
3380 
3381     /* FIXME: check if handles should be inherited */
3382     return CreateProcessW( application_name, command_line, NULL, NULL, FALSE, creation_flags, environment,
3383                            current_directory, startup_info, process_information );
3384 }
3385 
3386 /*
3387  * @implemented
3388  */
3389 BOOL WINAPI
3390 DuplicateTokenEx(IN HANDLE ExistingTokenHandle,
3391                  IN DWORD dwDesiredAccess,
3392                  IN LPSECURITY_ATTRIBUTES lpTokenAttributes  OPTIONAL,
3393                  IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
3394                  IN TOKEN_TYPE TokenType,
3395                  OUT PHANDLE DuplicateTokenHandle)
3396 {
3397     OBJECT_ATTRIBUTES ObjectAttributes;
3398     NTSTATUS Status;
3399     SECURITY_QUALITY_OF_SERVICE Sqos;
3400 
3401     TRACE("%p 0x%08x 0x%08x 0x%08x %p\n", ExistingTokenHandle, dwDesiredAccess,
3402         ImpersonationLevel, TokenType, DuplicateTokenHandle);
3403 
3404     Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
3405     Sqos.ImpersonationLevel = ImpersonationLevel;
3406     Sqos.ContextTrackingMode = 0;
3407     Sqos.EffectiveOnly = FALSE;
3408 
3409     if (lpTokenAttributes != NULL)
3410     {
3411         InitializeObjectAttributes(&ObjectAttributes,
3412                                    NULL,
3413                                    lpTokenAttributes->bInheritHandle ? OBJ_INHERIT : 0,
3414                                    NULL,
3415                                    lpTokenAttributes->lpSecurityDescriptor);
3416     }
3417     else
3418     {
3419         InitializeObjectAttributes(&ObjectAttributes,
3420                                    NULL,
3421                                    0,
3422                                    NULL,
3423                                    NULL);
3424     }
3425 
3426     ObjectAttributes.SecurityQualityOfService = &Sqos;
3427 
3428     Status = NtDuplicateToken(ExistingTokenHandle,
3429                               dwDesiredAccess,
3430                               &ObjectAttributes,
3431                               FALSE,
3432                               TokenType,
3433                               DuplicateTokenHandle);
3434     if (!NT_SUCCESS(Status))
3435     {
3436         ERR("NtDuplicateToken failed: Status %08x\n", Status);
3437         SetLastError(RtlNtStatusToDosError(Status));
3438         return FALSE;
3439     }
3440 
3441     TRACE("Returning token %p.\n", *DuplicateTokenHandle);
3442 
3443     return TRUE;
3444 }
3445 
3446 /*
3447  * @implemented
3448  */
3449 BOOL WINAPI
3450 DuplicateToken(IN HANDLE ExistingTokenHandle,
3451                IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
3452                OUT PHANDLE DuplicateTokenHandle)
3453 {
3454     return DuplicateTokenEx(ExistingTokenHandle,
3455                             TOKEN_IMPERSONATE | TOKEN_QUERY,
3456                             NULL,
3457                             ImpersonationLevel,
3458                             TokenImpersonation,
3459                             DuplicateTokenHandle);
3460 }
3461 
3462 /******************************************************************************
3463  * ComputeStringSidSize
3464  */
3465 static DWORD ComputeStringSidSize(LPCWSTR StringSid)
3466 {
3467     if (StringSid[0] == 'S' && StringSid[1] == '-') /* S-R-I(-S)+ */
3468     {
3469         int ctok = 0;
3470         while (*StringSid)
3471         {
3472             if (*StringSid == '-')
3473                 ctok++;
3474             StringSid++;
3475         }
3476 
3477         if (ctok >= 3)
3478             return GetSidLengthRequired(ctok - 2);
3479     }
3480     else /* String constant format  - Only available in winxp and above */
3481     {
3482         unsigned int i;
3483 
3484         for (i = 0; i < sizeof(WellKnownSids)/sizeof(WellKnownSids[0]); i++)
3485             if (!strncmpW(WellKnownSids[i].wstr, StringSid, 2))
3486                 return GetSidLengthRequired(WellKnownSids[i].Sid.SubAuthorityCount);
3487 
3488         for (i = 0; i < sizeof(WellKnownRids)/sizeof(WellKnownRids[0]); i++)
3489             if (!strncmpW(WellKnownRids[i].wstr, StringSid, 2))
3490             {
3491                 MAX_SID local;
3492                 ADVAPI_GetComputerSid(&local);
3493                 return GetSidLengthRequired(*GetSidSubAuthorityCount(&local) + 1);
3494             }
3495 
3496     }
3497 
3498     return GetSidLengthRequired(0);
3499 }
3500 
3501 /******************************************************************************
3502  * ParseStringSidToSid
3503  */
3504 static BOOL ParseStringSidToSid(LPCWSTR StringSid, PSID pSid, LPDWORD cBytes)
3505 {
3506     BOOL bret = FALSE;
3507     SID* pisid=pSid;
3508 
3509     TRACE("%s, %p, %p\n", debugstr_w(StringSid), pSid, cBytes);
3510     if (!StringSid)
3511     {
3512         SetLastError(ERROR_INVALID_PARAMETER);
3513         TRACE("StringSid is NULL, returning FALSE\n");
3514         return FALSE;
3515     }
3516 
3517     while (*StringSid == ' ')
3518         StringSid++;
3519 
3520     if (!*StringSid)
3521         goto lend; /* ERROR_INVALID_SID */
3522 
3523     *cBytes = ComputeStringSidSize(StringSid);
3524     if (!pisid) /* Simply compute the size */
3525     {
3526         TRACE("only size requested, returning TRUE with %d\n", *cBytes);
3527         return TRUE;
3528     }
3529 
3530     if (StringSid[0] == 'S' && StringSid[1] == '-') /* S-R-I-S-S */
3531     {
3532         DWORD i = 0, identAuth;
3533         DWORD csubauth = ((*cBytes - GetSidLengthRequired(0)) / sizeof(DWORD));
3534 
3535         StringSid += 2; /* Advance to Revision */
3536         pisid->Revision = atoiW(StringSid);
3537 
3538         if (pisid->Revision != SDDL_REVISION)
3539         {
3540             TRACE("Revision %d is unknown\n", pisid->Revision);
3541             goto lend; /* ERROR_INVALID_SID */
3542         }
3543         if (csubauth == 0)
3544         {
3545             TRACE("SubAuthorityCount is 0\n");
3546             goto lend; /* ERROR_INVALID_SID */
3547         }
3548 
3549         pisid->SubAuthorityCount = csubauth;
3550 
3551         /* Advance to identifier authority */
3552         while (*StringSid && *StringSid != '-')
3553             StringSid++;
3554         if (*StringSid == '-')
3555             StringSid++;
3556 
3557         /* MS' implementation can't handle values greater than 2^32 - 1, so
3558          * we don't either; assume most significant bytes are always 0
3559          */
3560         pisid->IdentifierAuthority.Value[0] = 0;
3561         pisid->IdentifierAuthority.Value[1] = 0;
3562         identAuth = atoiW(StringSid);
3563         pisid->IdentifierAuthority.Value[5] = identAuth & 0xff;
3564         pisid->IdentifierAuthority.Value[4] = (identAuth & 0xff00) >> 8;
3565         pisid->IdentifierAuthority.Value[3] = (identAuth & 0xff0000) >> 16;
3566         pisid->IdentifierAuthority.Value[2] = (identAuth & 0xff000000) >> 24;
3567 
3568         /* Advance to first sub authority */
3569         while (*StringSid && *StringSid != '-')
3570             StringSid++;
3571         if (*StringSid == '-')
3572             StringSid++;
3573 
3574         while (*StringSid)
3575         {
3576             pisid->SubAuthority[i++] = atoiW(StringSid);
3577 
3578             while (*StringSid && *StringSid != '-')
3579                 StringSid++;
3580             if (*StringSid == '-')
3581                 StringSid++;
3582         }
3583 
3584         if (i != pisid->SubAuthorityCount)
3585             goto lend; /* ERROR_INVALID_SID */
3586 
3587         bret = TRUE;
3588     }
3589     else /* String constant format  - Only available in winxp and above */
3590     {
3591         unsigned int i;
3592         pisid->Revision = SDDL_REVISION;
3593 
3594         for (i = 0; i < sizeof(WellKnownSids)/sizeof(WellKnownSids[0]); i++)
3595             if (!strncmpW(WellKnownSids[i].wstr, StringSid, 2))
3596             {
3597                 DWORD j;
3598                 pisid->SubAuthorityCount = WellKnownSids[i].Sid.SubAuthorityCount;
3599                 pisid->IdentifierAuthority = WellKnownSids[i].Sid.IdentifierAuthority;
3600                 for (j = 0; j < WellKnownSids[i].Sid.SubAuthorityCount; j++)
3601                     pisid->SubAuthority[j] = WellKnownSids[i].Sid.SubAuthority[j];
3602                 bret = TRUE;
3603             }
3604 
3605         for (i = 0; i < sizeof(WellKnownRids)/sizeof(WellKnownRids[0]); i++)
3606             if (!strncmpW(WellKnownRids[i].wstr, StringSid, 2))
3607             {
3608                 ADVAPI_GetComputerSid(pisid);
3609                 pisid->SubAuthority[pisid->SubAuthorityCount] = WellKnownRids[i].Rid;
3610                 pisid->SubAuthorityCount++;
3611                 bret = TRUE;
3612             }
3613 
3614         if (!bret)
3615             FIXME("String constant not supported: %s\n", debugstr_wn(StringSid, 2));
3616     }
3617 
3618 lend:
3619     if (!bret)
3620         SetLastError(ERROR_INVALID_SID);
3621 
3622     TRACE("returning %s\n", bret ? "TRUE" : "FALSE");
3623     return bret;
3624 }
3625 
3626 /**********************************************************************
3627  * GetNamedSecurityInfoA			EXPORTED
3628  *
3629  * @implemented
3630  */
3631 DWORD
3632 WINAPI
3633 GetNamedSecurityInfoA(LPSTR pObjectName,
3634                       SE_OBJECT_TYPE ObjectType,
3635                       SECURITY_INFORMATION SecurityInfo,
3636                       PSID *ppsidOwner,
3637                       PSID *ppsidGroup,
3638                       PACL *ppDacl,
3639                       PACL *ppSacl,
3640                       PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
3641 {
3642     DWORD len;
3643     LPWSTR wstr = NULL;
3644     DWORD r;
3645 
3646     TRACE("%s %d %d %p %p %p %p %p\n", pObjectName, ObjectType, SecurityInfo,
3647         ppsidOwner, ppsidGroup, ppDacl, ppSacl, ppSecurityDescriptor);
3648 
3649     if( pObjectName )
3650     {
3651         len = MultiByteToWideChar( CP_ACP, 0, pObjectName, -1, NULL, 0 );
3652         wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR));
3653         MultiByteToWideChar( CP_ACP, 0, pObjectName, -1, wstr, len );
3654     }
3655 
3656     r = GetNamedSecurityInfoW( wstr, ObjectType, SecurityInfo, ppsidOwner,
3657                            ppsidGroup, ppDacl, ppSacl, ppSecurityDescriptor );
3658 
3659     HeapFree( GetProcessHeap(), 0, wstr );
3660 
3661     return r;
3662 }
3663 
3664 /******************************************************************************
3665  * GetWindowsAccountDomainSid         [ADVAPI32.@]
3666  */
3667 BOOL WINAPI GetWindowsAccountDomainSid( PSID sid, PSID domain_sid, DWORD *size )
3668 {
3669     SID_IDENTIFIER_AUTHORITY domain_ident = { SECURITY_NT_AUTHORITY };
3670     DWORD required_size;
3671     int i;
3672 
3673     FIXME( "(%p %p %p): semi-stub\n", sid, domain_sid, size );
3674 
3675     if (!sid || !IsValidSid( sid ))
3676     {
3677         SetLastError( ERROR_INVALID_SID );
3678         return FALSE;
3679     }
3680 
3681     if (!size)
3682     {
3683         SetLastError( ERROR_INVALID_PARAMETER );
3684         return FALSE;
3685     }
3686 
3687     if (*GetSidSubAuthorityCount( sid ) < 4)
3688     {
3689         SetLastError( ERROR_INVALID_SID );
3690         return FALSE;
3691     }
3692 
3693     required_size = GetSidLengthRequired( 4 );
3694     if (*size < required_size || !domain_sid)
3695     {
3696         *size = required_size;
3697         SetLastError( domain_sid ? ERROR_INSUFFICIENT_BUFFER :
3698                                    ERROR_INVALID_PARAMETER );
3699         return FALSE;
3700     }
3701 
3702     InitializeSid( domain_sid, &domain_ident, 4 );
3703     for (i = 0; i < 4; i++)
3704         *GetSidSubAuthority( domain_sid, i ) = *GetSidSubAuthority( sid, i );
3705 
3706     *size = required_size;
3707     return TRUE;
3708 }
3709 
3710 /*
3711  * @unimplemented
3712  */
3713 BOOL
3714 WINAPI
3715 EqualDomainSid(IN PSID pSid1,
3716                IN PSID pSid2,
3717                OUT BOOL* pfEqual)
3718 {
3719     UNIMPLEMENTED;
3720     return FALSE;
3721 }
3722 
3723 /* EOF */
3724