xref: /reactos/dll/win32/advapi32/wine/security.c (revision f4d29a74)
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     SetLastError(ERROR_SUCCESS);
763     return RtlIdentifierAuthoritySid(pSid);
764 }
765 
766 /*
767  * @implemented
768  */
769 PDWORD
770 WINAPI
771 GetSidSubAuthority(PSID pSid,
772                    DWORD nSubAuthority)
773 {
774     SetLastError(ERROR_SUCCESS);
775     return (PDWORD)RtlSubAuthoritySid(pSid, nSubAuthority);
776 }
777 
778 /*
779  * @implemented
780  */
781 PUCHAR
782 WINAPI
783 GetSidSubAuthorityCount(PSID pSid)
784 {
785     SetLastError(ERROR_SUCCESS);
786     return RtlSubAuthorityCountSid(pSid);
787 }
788 
789 /*
790  * @implemented
791  */
792 DWORD
793 WINAPI
794 GetLengthSid(PSID pSid)
795 {
796     return (DWORD)RtlLengthSid(pSid);
797 }
798 
799 /*
800  * @implemented
801  */
802 BOOL
803 WINAPI
804 InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor,
805                              DWORD dwRevision)
806 {
807     NTSTATUS Status;
808 
809     Status = RtlCreateSecurityDescriptor(pSecurityDescriptor,
810                                          dwRevision);
811     if (!NT_SUCCESS(Status))
812     {
813         SetLastError(RtlNtStatusToDosError(Status));
814         return FALSE;
815     }
816 
817     return TRUE;
818 }
819 
820 /*
821  * @implemented
822  */
823 BOOL
824 WINAPI
825 MakeAbsoluteSD(PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
826                PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,
827                LPDWORD lpdwAbsoluteSecurityDescriptorSize,
828                PACL pDacl,
829                LPDWORD lpdwDaclSize,
830                PACL pSacl,
831                LPDWORD lpdwSaclSize,
832                PSID pOwner,
833                LPDWORD lpdwOwnerSize,
834                PSID pPrimaryGroup,
835                LPDWORD lpdwPrimaryGroupSize)
836 {
837     NTSTATUS Status;
838 
839     Status = RtlSelfRelativeToAbsoluteSD(pSelfRelativeSecurityDescriptor,
840                                          pAbsoluteSecurityDescriptor,
841                                          lpdwAbsoluteSecurityDescriptorSize,
842                                          pDacl,
843                                          lpdwDaclSize,
844                                          pSacl,
845                                          lpdwSaclSize,
846                                          pOwner,
847                                          lpdwOwnerSize,
848                                          pPrimaryGroup,
849                                          lpdwPrimaryGroupSize);
850     if (!NT_SUCCESS(Status))
851     {
852         SetLastError(RtlNtStatusToDosError(Status));
853         return FALSE;
854     }
855 
856     return TRUE;
857 }
858 
859 /******************************************************************************
860  * GetKernelObjectSecurity [ADVAPI32.@]
861  */
862 BOOL WINAPI GetKernelObjectSecurity(
863         HANDLE Handle,
864         SECURITY_INFORMATION RequestedInformation,
865         PSECURITY_DESCRIPTOR pSecurityDescriptor,
866         DWORD nLength,
867         LPDWORD lpnLengthNeeded )
868 {
869     TRACE("(%p,0x%08x,%p,0x%08x,%p)\n", Handle, RequestedInformation,
870           pSecurityDescriptor, nLength, lpnLengthNeeded);
871 
872     return set_ntstatus( NtQuerySecurityObject(Handle, RequestedInformation, pSecurityDescriptor,
873                                                nLength, lpnLengthNeeded ));
874 }
875 
876 /*
877  * @implemented
878  */
879 BOOL
880 WINAPI
881 InitializeAcl(PACL pAcl,
882               DWORD nAclLength,
883               DWORD dwAclRevision)
884 {
885     NTSTATUS Status;
886 
887     Status = RtlCreateAcl(pAcl,
888                           nAclLength,
889                           dwAclRevision);
890     if (!NT_SUCCESS(Status))
891     {
892         SetLastError(RtlNtStatusToDosError(Status));
893         return FALSE;
894     }
895 
896     return TRUE;
897 }
898 
899 BOOL WINAPI ImpersonateNamedPipeClient( HANDLE hNamedPipe )
900 {
901     IO_STATUS_BLOCK io_block;
902 
903     TRACE("(%p)\n", hNamedPipe);
904 
905     return set_ntstatus( NtFsControlFile(hNamedPipe, NULL, NULL, NULL,
906                          &io_block, FSCTL_PIPE_IMPERSONATE, NULL, 0, NULL, 0) );
907 }
908 
909 /*
910  * @implemented
911  */
912 BOOL
913 WINAPI
914 AddAccessAllowedAce(PACL pAcl,
915                     DWORD dwAceRevision,
916                     DWORD AccessMask,
917                     PSID pSid)
918 {
919     NTSTATUS Status;
920 
921     Status = RtlAddAccessAllowedAce(pAcl,
922                                     dwAceRevision,
923                                     AccessMask,
924                                     pSid);
925     if (!NT_SUCCESS(Status))
926     {
927         SetLastError(RtlNtStatusToDosError(Status));
928         return FALSE;
929     }
930 
931     return TRUE;
932 }
933 
934 /*
935  * @implemented
936  */
937 BOOL WINAPI
938 AddAccessAllowedAceEx(PACL pAcl,
939                       DWORD dwAceRevision,
940                       DWORD AceFlags,
941                       DWORD AccessMask,
942                       PSID pSid)
943 {
944     NTSTATUS Status;
945 
946     Status = RtlAddAccessAllowedAceEx(pAcl,
947                                       dwAceRevision,
948                                       AceFlags,
949                                       AccessMask,
950                                       pSid);
951     if (!NT_SUCCESS(Status))
952     {
953         SetLastError(RtlNtStatusToDosError(Status));
954         return FALSE;
955     }
956 
957     return TRUE;
958 }
959 
960 /*
961  * @implemented
962  */
963 BOOL
964 WINAPI
965 AddAccessDeniedAce(PACL pAcl,
966                    DWORD dwAceRevision,
967                    DWORD AccessMask,
968                    PSID pSid)
969 {
970     NTSTATUS Status;
971 
972     Status = RtlAddAccessDeniedAce(pAcl,
973                                    dwAceRevision,
974                                    AccessMask,
975                                    pSid);
976     if (!NT_SUCCESS(Status))
977     {
978         SetLastError(RtlNtStatusToDosError(Status));
979         return FALSE;
980     }
981 
982     return TRUE;
983 }
984 
985 /*
986  * @implemented
987  */
988 BOOL WINAPI
989 AddAccessDeniedAceEx(PACL pAcl,
990                      DWORD dwAceRevision,
991                      DWORD AceFlags,
992                      DWORD AccessMask,
993                      PSID pSid)
994 {
995     NTSTATUS Status;
996 
997     Status = RtlAddAccessDeniedAceEx(pAcl,
998                                      dwAceRevision,
999                                      AceFlags,
1000                                      AccessMask,
1001                                      pSid);
1002     if (!NT_SUCCESS(Status))
1003     {
1004         SetLastError(RtlNtStatusToDosError(Status));
1005         return FALSE;
1006     }
1007 
1008     return TRUE;
1009 }
1010 
1011 /*
1012  * @implemented
1013  */
1014 BOOL
1015 WINAPI
1016 AddAce(PACL pAcl,
1017        DWORD dwAceRevision,
1018        DWORD dwStartingAceIndex,
1019        LPVOID pAceList,
1020        DWORD nAceListLength)
1021 {
1022     NTSTATUS Status;
1023 
1024     Status = RtlAddAce(pAcl,
1025                        dwAceRevision,
1026                        dwStartingAceIndex,
1027                        pAceList,
1028                        nAceListLength);
1029     if (!NT_SUCCESS(Status))
1030     {
1031         SetLastError(RtlNtStatusToDosError(Status));
1032         return FALSE;
1033     }
1034 
1035     return TRUE;
1036 }
1037 
1038 /******************************************************************************
1039  * DeleteAce [ADVAPI32.@]
1040  */
1041 BOOL WINAPI DeleteAce(PACL pAcl, DWORD dwAceIndex)
1042 {
1043     return set_ntstatus(RtlDeleteAce(pAcl, dwAceIndex));
1044 }
1045 
1046 /*
1047  * @implemented
1048  */
1049 BOOL
1050 WINAPI
1051 FindFirstFreeAce(PACL pAcl,
1052                  LPVOID *pAce)
1053 {
1054     return RtlFirstFreeAce(pAcl,
1055                            (PACE*)pAce);
1056 }
1057 
1058 /******************************************************************************
1059  * GetAce [ADVAPI32.@]
1060  */
1061 BOOL WINAPI GetAce(PACL pAcl,DWORD dwAceIndex,LPVOID *pAce )
1062 {
1063     return set_ntstatus(RtlGetAce(pAcl, dwAceIndex, pAce));
1064 }
1065 
1066 /******************************************************************************
1067  * GetAclInformation [ADVAPI32.@]
1068  */
1069 BOOL WINAPI GetAclInformation(
1070   PACL pAcl,
1071   LPVOID pAclInformation,
1072   DWORD nAclInformationLength,
1073   ACL_INFORMATION_CLASS dwAclInformationClass)
1074 {
1075     return set_ntstatus(RtlQueryInformationAcl(pAcl, pAclInformation,
1076                                                nAclInformationLength, dwAclInformationClass));
1077 }
1078 
1079 /*
1080  * @implemented
1081  */
1082 BOOL
1083 WINAPI
1084 IsValidAcl(PACL pAcl)
1085 {
1086     return RtlValidAcl (pAcl);
1087 }
1088 
1089 /*
1090  * @implemented
1091  */
1092 BOOL WINAPI
1093 AllocateLocallyUniqueId(PLUID Luid)
1094 {
1095     NTSTATUS Status;
1096 
1097     Status = NtAllocateLocallyUniqueId (Luid);
1098     if (!NT_SUCCESS (Status))
1099     {
1100         SetLastError(RtlNtStatusToDosError(Status));
1101         return FALSE;
1102     }
1103 
1104     return TRUE;
1105 }
1106 
1107 /**********************************************************************
1108  * LookupPrivilegeDisplayNameA			EXPORTED
1109  *
1110  * @unimplemented
1111  */
1112 BOOL
1113 WINAPI
1114 LookupPrivilegeDisplayNameA(LPCSTR lpSystemName,
1115                             LPCSTR lpName,
1116                             LPSTR lpDisplayName,
1117                             LPDWORD cchDisplayName,
1118                             LPDWORD lpLanguageId)
1119 {
1120     UNICODE_STRING lpSystemNameW;
1121     UNICODE_STRING lpNameW;
1122     BOOL ret;
1123     DWORD wLen = 0;
1124 
1125     TRACE("%s %s %p %p %p\n", debugstr_a(lpSystemName), debugstr_a(lpName), lpName, cchDisplayName, lpLanguageId);
1126 
1127     RtlCreateUnicodeStringFromAsciiz(&lpSystemNameW, lpSystemName);
1128     RtlCreateUnicodeStringFromAsciiz(&lpNameW, lpName);
1129     ret = LookupPrivilegeDisplayNameW(lpSystemNameW.Buffer, lpNameW.Buffer, NULL, &wLen, lpLanguageId);
1130     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1131     {
1132         LPWSTR lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, wLen * sizeof(WCHAR));
1133 
1134         ret = LookupPrivilegeDisplayNameW(lpSystemNameW.Buffer, lpNameW.Buffer, lpDisplayNameW,
1135                                           &wLen, lpLanguageId);
1136         if (ret)
1137         {
1138             unsigned int len = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, lpDisplayName,
1139                                                    *cchDisplayName, NULL, NULL);
1140 
1141             if (len == 0)
1142             {
1143                 /* WideCharToMultiByte failed */
1144                 ret = FALSE;
1145             }
1146             else if (len > *cchDisplayName)
1147             {
1148                 *cchDisplayName = len;
1149                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1150                 ret = FALSE;
1151             }
1152             else
1153             {
1154                 /* WideCharToMultiByte succeeded, output length needs to be
1155                  * length not including NULL terminator
1156                  */
1157                 *cchDisplayName = len - 1;
1158             }
1159         }
1160         HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1161     }
1162     RtlFreeUnicodeString(&lpSystemNameW);
1163     RtlFreeUnicodeString(&lpNameW);
1164     return ret;
1165 }
1166 
1167 /**********************************************************************
1168  * LookupPrivilegeNameA				EXPORTED
1169  *
1170  * @implemented
1171  */
1172 BOOL
1173 WINAPI
1174 LookupPrivilegeNameA(LPCSTR lpSystemName,
1175                      PLUID lpLuid,
1176                      LPSTR lpName,
1177                      LPDWORD cchName)
1178 {
1179     UNICODE_STRING lpSystemNameW;
1180     BOOL ret;
1181     DWORD wLen = 0;
1182 
1183     TRACE("%s %p %p %p\n", debugstr_a(lpSystemName), lpLuid, lpName, cchName);
1184 
1185     RtlCreateUnicodeStringFromAsciiz(&lpSystemNameW, lpSystemName);
1186     ret = LookupPrivilegeNameW(lpSystemNameW.Buffer, lpLuid, NULL, &wLen);
1187     if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1188     {
1189         LPWSTR lpNameW = HeapAlloc(GetProcessHeap(), 0, wLen * sizeof(WCHAR));
1190 
1191         ret = LookupPrivilegeNameW(lpSystemNameW.Buffer, lpLuid, lpNameW,
1192          &wLen);
1193         if (ret)
1194         {
1195             /* Windows crashes if cchName is NULL, so will I */
1196             unsigned int len = WideCharToMultiByte(CP_ACP, 0, lpNameW, -1, lpName,
1197              *cchName, NULL, NULL);
1198 
1199             if (len == 0)
1200             {
1201                 /* WideCharToMultiByte failed */
1202                 ret = FALSE;
1203             }
1204             else if (len > *cchName)
1205             {
1206                 *cchName = len;
1207                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1208                 ret = FALSE;
1209             }
1210             else
1211             {
1212                 /* WideCharToMultiByte succeeded, output length needs to be
1213                  * length not including NULL terminator
1214                  */
1215                 *cchName = len - 1;
1216             }
1217         }
1218         HeapFree(GetProcessHeap(), 0, lpNameW);
1219     }
1220     RtlFreeUnicodeString(&lpSystemNameW);
1221     return ret;
1222 }
1223 
1224 /******************************************************************************
1225  * GetFileSecurityA [ADVAPI32.@]
1226  *
1227  * Obtains Specified information about the security of a file or directory.
1228  *
1229  * PARAMS
1230  *  lpFileName           [I] Name of the file to get info for
1231  *  RequestedInformation [I] SE_ flags from "winnt.h"
1232  *  pSecurityDescriptor  [O] Destination for security information
1233  *  nLength              [I] Length of pSecurityDescriptor
1234  *  lpnLengthNeeded      [O] Destination for length of returned security information
1235  *
1236  * RETURNS
1237  *  Success: TRUE. pSecurityDescriptor contains the requested information.
1238  *  Failure: FALSE. lpnLengthNeeded contains the required space to return the info.
1239  *
1240  * NOTES
1241  *  The information returned is constrained by the callers access rights and
1242  *  privileges.
1243  *
1244  * @implemented
1245  */
1246 BOOL
1247 WINAPI
1248 GetFileSecurityA(LPCSTR lpFileName,
1249                  SECURITY_INFORMATION RequestedInformation,
1250                  PSECURITY_DESCRIPTOR pSecurityDescriptor,
1251                  DWORD nLength,
1252                  LPDWORD lpnLengthNeeded)
1253 {
1254     UNICODE_STRING FileName;
1255     BOOL bResult;
1256 
1257     if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFileName))
1258     {
1259         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1260         return FALSE;
1261     }
1262 
1263     bResult = GetFileSecurityW(FileName.Buffer,
1264                                RequestedInformation,
1265                                pSecurityDescriptor,
1266                                nLength,
1267                                lpnLengthNeeded);
1268 
1269     RtlFreeUnicodeString(&FileName);
1270 
1271     return bResult;
1272 }
1273 
1274 /*
1275  * @implemented
1276  */
1277 BOOL
1278 WINAPI
1279 GetFileSecurityW(LPCWSTR lpFileName,
1280                  SECURITY_INFORMATION RequestedInformation,
1281                  PSECURITY_DESCRIPTOR pSecurityDescriptor,
1282                  DWORD nLength,
1283                  LPDWORD lpnLengthNeeded)
1284 {
1285     OBJECT_ATTRIBUTES ObjectAttributes;
1286     IO_STATUS_BLOCK StatusBlock;
1287     UNICODE_STRING FileName;
1288     ULONG AccessMask = 0;
1289     HANDLE FileHandle;
1290     NTSTATUS Status;
1291 
1292     TRACE("GetFileSecurityW() called\n");
1293 
1294     QuerySecurityAccessMask(RequestedInformation, &AccessMask);
1295 
1296     if (!RtlDosPathNameToNtPathName_U(lpFileName,
1297                                       &FileName,
1298                                       NULL,
1299                                       NULL))
1300     {
1301         ERR("Invalid path\n");
1302         SetLastError(ERROR_INVALID_NAME);
1303         return FALSE;
1304     }
1305 
1306     InitializeObjectAttributes(&ObjectAttributes,
1307                                &FileName,
1308                                OBJ_CASE_INSENSITIVE,
1309                                NULL,
1310                                NULL);
1311 
1312     Status = NtOpenFile(&FileHandle,
1313                         AccessMask,
1314                         &ObjectAttributes,
1315                         &StatusBlock,
1316                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1317                         0);
1318 
1319     RtlFreeHeap(RtlGetProcessHeap(),
1320                 0,
1321                 FileName.Buffer);
1322 
1323     if (!NT_SUCCESS(Status))
1324     {
1325         ERR("NtOpenFile() failed (Status %lx)\n", Status);
1326         SetLastError(RtlNtStatusToDosError(Status));
1327         return FALSE;
1328     }
1329 
1330     Status = NtQuerySecurityObject(FileHandle,
1331                                    RequestedInformation,
1332                                    pSecurityDescriptor,
1333                                    nLength,
1334                                    lpnLengthNeeded);
1335     NtClose(FileHandle);
1336     if (!NT_SUCCESS(Status))
1337     {
1338         ERR("NtQuerySecurityObject() failed (Status %lx)\n", Status);
1339         SetLastError(RtlNtStatusToDosError(Status));
1340         return FALSE;
1341     }
1342 
1343     return TRUE;
1344 }
1345 
1346 /******************************************************************************
1347  * SetFileSecurityA [ADVAPI32.@]
1348  * Sets the security of a file or directory
1349  *
1350  * @implemented
1351  */
1352 BOOL
1353 WINAPI
1354 SetFileSecurityA(LPCSTR lpFileName,
1355                  SECURITY_INFORMATION SecurityInformation,
1356                  PSECURITY_DESCRIPTOR pSecurityDescriptor)
1357 {
1358     UNICODE_STRING FileName;
1359     BOOL bResult;
1360 
1361     if (!RtlCreateUnicodeStringFromAsciiz(&FileName, lpFileName))
1362     {
1363         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1364         return FALSE;
1365     }
1366 
1367     bResult = SetFileSecurityW(FileName.Buffer,
1368                                SecurityInformation,
1369                                pSecurityDescriptor);
1370 
1371     RtlFreeUnicodeString(&FileName);
1372 
1373     return bResult;
1374 }
1375 
1376 /******************************************************************************
1377  * SetFileSecurityW [ADVAPI32.@]
1378  * Sets the security of a file or directory
1379  *
1380  * @implemented
1381  */
1382 BOOL
1383 WINAPI
1384 SetFileSecurityW(LPCWSTR lpFileName,
1385                  SECURITY_INFORMATION SecurityInformation,
1386                  PSECURITY_DESCRIPTOR pSecurityDescriptor)
1387 {
1388     OBJECT_ATTRIBUTES ObjectAttributes;
1389     IO_STATUS_BLOCK StatusBlock;
1390     UNICODE_STRING FileName;
1391     ULONG AccessMask = 0;
1392     HANDLE FileHandle;
1393     NTSTATUS Status;
1394 
1395     TRACE("SetFileSecurityW() called\n");
1396 
1397     SetSecurityAccessMask(SecurityInformation, &AccessMask);
1398 
1399     if (!RtlDosPathNameToNtPathName_U(lpFileName,
1400                                       &FileName,
1401                                       NULL,
1402                                       NULL))
1403     {
1404         ERR("Invalid path\n");
1405         SetLastError(ERROR_INVALID_NAME);
1406         return FALSE;
1407     }
1408 
1409     InitializeObjectAttributes(&ObjectAttributes,
1410                                &FileName,
1411                                OBJ_CASE_INSENSITIVE,
1412                                NULL,
1413                                NULL);
1414 
1415     Status = NtOpenFile(&FileHandle,
1416                         AccessMask,
1417                         &ObjectAttributes,
1418                         &StatusBlock,
1419                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1420                         0);
1421 
1422     RtlFreeHeap(RtlGetProcessHeap(),
1423                 0,
1424                 FileName.Buffer);
1425 
1426     if (!NT_SUCCESS(Status))
1427     {
1428         ERR("NtOpenFile() failed (Status %lx)\n", Status);
1429         SetLastError(RtlNtStatusToDosError(Status));
1430         return FALSE;
1431     }
1432 
1433     Status = NtSetSecurityObject(FileHandle,
1434                                  SecurityInformation,
1435                                  pSecurityDescriptor);
1436     NtClose(FileHandle);
1437 
1438     if (!NT_SUCCESS(Status))
1439     {
1440         ERR("NtSetSecurityObject() failed (Status %lx)\n", Status);
1441         SetLastError(RtlNtStatusToDosError(Status));
1442         return FALSE;
1443     }
1444 
1445     return TRUE;
1446 }
1447 
1448 /******************************************************************************
1449  * QueryWindows31FilesMigration [ADVAPI32.@]
1450  *
1451  * PARAMS
1452  *   x1 []
1453  */
1454 BOOL WINAPI
1455 QueryWindows31FilesMigration( DWORD x1 )
1456 {
1457 	FIXME("(%d):stub\n",x1);
1458 	return TRUE;
1459 }
1460 
1461 /******************************************************************************
1462  * SynchronizeWindows31FilesAndWindowsNTRegistry [ADVAPI32.@]
1463  *
1464  * PARAMS
1465  *   x1 []
1466  *   x2 []
1467  *   x3 []
1468  *   x4 []
1469  */
1470 BOOL WINAPI
1471 SynchronizeWindows31FilesAndWindowsNTRegistry( DWORD x1, DWORD x2, DWORD x3,
1472                                                DWORD x4 )
1473 {
1474 	FIXME("(0x%08x,0x%08x,0x%08x,0x%08x):stub\n",x1,x2,x3,x4);
1475 	return TRUE;
1476 }
1477 
1478 /*
1479  * @implemented
1480  */
1481 BOOL
1482 WINAPI
1483 RevertToSelf(VOID)
1484 {
1485     NTSTATUS Status;
1486     HANDLE Token = NULL;
1487 
1488     Status = NtSetInformationThread(NtCurrentThread(),
1489                                     ThreadImpersonationToken,
1490                                     &Token,
1491                                     sizeof(HANDLE));
1492     if (!NT_SUCCESS(Status))
1493     {
1494         SetLastError(RtlNtStatusToDosError(Status));
1495         return FALSE;
1496     }
1497 
1498     return TRUE;
1499 }
1500 
1501 /*
1502  * @implemented
1503  */
1504 BOOL
1505 WINAPI
1506 ImpersonateSelf(SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
1507 {
1508     NTSTATUS Status;
1509 
1510     Status = RtlImpersonateSelf(ImpersonationLevel);
1511     if (!NT_SUCCESS(Status))
1512     {
1513         SetLastError(RtlNtStatusToDosError(Status));
1514         return FALSE;
1515     }
1516 
1517     return TRUE;
1518 }
1519 
1520 /*
1521  * @implemented
1522  */
1523 BOOL
1524 WINAPI
1525 AccessCheck(IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
1526             IN HANDLE ClientToken,
1527             IN DWORD DesiredAccess,
1528             IN PGENERIC_MAPPING GenericMapping,
1529             OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL,
1530             IN OUT LPDWORD PrivilegeSetLength,
1531             OUT LPDWORD GrantedAccess,
1532             OUT LPBOOL AccessStatus)
1533 {
1534     NTSTATUS Status;
1535     NTSTATUS NtAccessStatus;
1536 
1537     /* Do the access check */
1538     Status = NtAccessCheck(pSecurityDescriptor,
1539                            ClientToken,
1540                            DesiredAccess,
1541                            GenericMapping,
1542                            PrivilegeSet,
1543                            (PULONG)PrivilegeSetLength,
1544                            (PACCESS_MASK)GrantedAccess,
1545                            &NtAccessStatus);
1546 
1547     /* See if the access check operation succeeded */
1548     if (!NT_SUCCESS(Status))
1549     {
1550         /* Check failed */
1551         SetLastError(RtlNtStatusToDosError(Status));
1552         return FALSE;
1553     }
1554 
1555     /* Now check the access status  */
1556     if (!NT_SUCCESS(NtAccessStatus))
1557     {
1558         /* Access denied */
1559         SetLastError(RtlNtStatusToDosError(NtAccessStatus));
1560         *AccessStatus = FALSE;
1561     }
1562     else
1563     {
1564         /* Access granted */
1565         *AccessStatus = TRUE;
1566     }
1567 
1568     /* Check succeeded */
1569     return TRUE;
1570 }
1571 
1572 /*
1573  * @unimplemented
1574  */
1575 BOOL WINAPI AccessCheckByType(
1576     PSECURITY_DESCRIPTOR pSecurityDescriptor,
1577     PSID PrincipalSelfSid,
1578     HANDLE ClientToken,
1579     DWORD DesiredAccess,
1580     POBJECT_TYPE_LIST ObjectTypeList,
1581     DWORD ObjectTypeListLength,
1582     PGENERIC_MAPPING GenericMapping,
1583     PPRIVILEGE_SET PrivilegeSet,
1584     LPDWORD PrivilegeSetLength,
1585     LPDWORD GrantedAccess,
1586     LPBOOL AccessStatus)
1587 {
1588 	FIXME("stub\n");
1589 
1590 	*AccessStatus = TRUE;
1591 
1592 	return !*AccessStatus;
1593 }
1594 
1595 /*
1596  * @implemented
1597  */
1598 BOOL
1599 WINAPI
1600 SetKernelObjectSecurity(HANDLE Handle,
1601                         SECURITY_INFORMATION SecurityInformation,
1602                         PSECURITY_DESCRIPTOR SecurityDescriptor)
1603 {
1604     NTSTATUS Status;
1605 
1606     Status = NtSetSecurityObject(Handle,
1607                                  SecurityInformation,
1608                                  SecurityDescriptor);
1609     if (!NT_SUCCESS(Status))
1610     {
1611         SetLastError(RtlNtStatusToDosError(Status));
1612         return FALSE;
1613     }
1614 
1615     return TRUE;
1616 }
1617 
1618 /*
1619  * @implemented
1620  */
1621 BOOL
1622 WINAPI
1623 AddAuditAccessAce(PACL pAcl,
1624                   DWORD dwAceRevision,
1625                   DWORD dwAccessMask,
1626                   PSID pSid,
1627                   BOOL bAuditSuccess,
1628                   BOOL bAuditFailure)
1629 {
1630     NTSTATUS Status;
1631 
1632     Status = RtlAddAuditAccessAce(pAcl,
1633                                   dwAceRevision,
1634                                   dwAccessMask,
1635                                   pSid,
1636                                   bAuditSuccess,
1637                                   bAuditFailure);
1638     if (!NT_SUCCESS(Status))
1639     {
1640         SetLastError(RtlNtStatusToDosError(Status));
1641         return FALSE;
1642     }
1643 
1644     return TRUE;
1645 }
1646 
1647 /*
1648  * @implemented
1649  */
1650 BOOL WINAPI
1651 AddAuditAccessAceEx(PACL pAcl,
1652                     DWORD dwAceRevision,
1653                     DWORD AceFlags,
1654                     DWORD dwAccessMask,
1655                     PSID pSid,
1656                     BOOL bAuditSuccess,
1657                     BOOL bAuditFailure)
1658 {
1659     NTSTATUS Status;
1660 
1661     Status = RtlAddAuditAccessAceEx(pAcl,
1662                                     dwAceRevision,
1663                                     AceFlags,
1664                                     dwAccessMask,
1665                                     pSid,
1666                                     bAuditSuccess,
1667                                     bAuditFailure);
1668     if (!NT_SUCCESS(Status))
1669     {
1670         SetLastError(RtlNtStatusToDosError(Status));
1671         return FALSE;
1672     }
1673 
1674     return TRUE;
1675 }
1676 
1677 /******************************************************************************
1678  * LookupAccountNameA [ADVAPI32.@]
1679  *
1680  * @implemented
1681  */
1682 BOOL
1683 WINAPI
1684 LookupAccountNameA(LPCSTR SystemName,
1685                    LPCSTR AccountName,
1686                    PSID Sid,
1687                    LPDWORD SidLength,
1688                    LPSTR ReferencedDomainName,
1689                    LPDWORD hReferencedDomainNameLength,
1690                    PSID_NAME_USE SidNameUse)
1691 {
1692     BOOL ret;
1693     UNICODE_STRING lpSystemW;
1694     UNICODE_STRING lpAccountW;
1695     LPWSTR lpReferencedDomainNameW = NULL;
1696 
1697     RtlCreateUnicodeStringFromAsciiz(&lpSystemW, SystemName);
1698     RtlCreateUnicodeStringFromAsciiz(&lpAccountW, AccountName);
1699 
1700     if (ReferencedDomainName)
1701         lpReferencedDomainNameW = HeapAlloc(GetProcessHeap(),
1702                                             0,
1703                                             *hReferencedDomainNameLength * sizeof(WCHAR));
1704 
1705     ret = LookupAccountNameW(lpSystemW.Buffer,
1706                              lpAccountW.Buffer,
1707                              Sid,
1708                              SidLength,
1709                              lpReferencedDomainNameW,
1710                              hReferencedDomainNameLength,
1711                              SidNameUse);
1712 
1713     if (ret && lpReferencedDomainNameW)
1714     {
1715         WideCharToMultiByte(CP_ACP,
1716                             0,
1717                             lpReferencedDomainNameW,
1718                             *hReferencedDomainNameLength + 1,
1719                             ReferencedDomainName,
1720                             *hReferencedDomainNameLength + 1,
1721                             NULL,
1722                             NULL);
1723     }
1724 
1725     RtlFreeUnicodeString(&lpSystemW);
1726     RtlFreeUnicodeString(&lpAccountW);
1727     HeapFree(GetProcessHeap(), 0, lpReferencedDomainNameW);
1728 
1729     return ret;
1730 }
1731 
1732 /**********************************************************************
1733  *	PrivilegeCheck					EXPORTED
1734  *
1735  * @implemented
1736  */
1737 BOOL WINAPI
1738 PrivilegeCheck(HANDLE ClientToken,
1739                PPRIVILEGE_SET RequiredPrivileges,
1740                LPBOOL pfResult)
1741 {
1742     BOOLEAN Result;
1743     NTSTATUS Status;
1744 
1745     Status = NtPrivilegeCheck(ClientToken,
1746                               RequiredPrivileges,
1747                               &Result);
1748     if (!NT_SUCCESS(Status))
1749     {
1750         SetLastError(RtlNtStatusToDosError(Status));
1751         return FALSE;
1752     }
1753 
1754     *pfResult = (BOOL)Result;
1755 
1756     return TRUE;
1757 }
1758 
1759 /******************************************************************************
1760  * GetSecurityInfoExW         EXPORTED
1761  */
1762 DWORD
1763 WINAPI
1764 GetSecurityInfoExA(HANDLE hObject,
1765                    SE_OBJECT_TYPE ObjectType,
1766                    SECURITY_INFORMATION SecurityInfo,
1767                    LPCSTR lpProvider,
1768                    LPCSTR lpProperty,
1769                    PACTRL_ACCESSA *ppAccessList,
1770                    PACTRL_AUDITA *ppAuditList,
1771                    LPSTR *lppOwner,
1772                    LPSTR *lppGroup)
1773 {
1774     FIXME("%s() not implemented!\n", __FUNCTION__);
1775     return ERROR_BAD_PROVIDER;
1776 }
1777 
1778 
1779 /******************************************************************************
1780  * GetSecurityInfoExW         EXPORTED
1781  */
1782 DWORD
1783 WINAPI
1784 GetSecurityInfoExW(HANDLE hObject,
1785                    SE_OBJECT_TYPE ObjectType,
1786                    SECURITY_INFORMATION SecurityInfo,
1787                    LPCWSTR lpProvider,
1788                    LPCWSTR lpProperty,
1789                    PACTRL_ACCESSW *ppAccessList,
1790                    PACTRL_AUDITW *ppAuditList,
1791                    LPWSTR *lppOwner,
1792                    LPWSTR *lppGroup)
1793 {
1794     FIXME("%s() not implemented!\n", __FUNCTION__);
1795     return ERROR_BAD_PROVIDER;
1796 }
1797 
1798 /******************************************************************************
1799  * BuildExplicitAccessWithNameA [ADVAPI32.@]
1800  */
1801 VOID WINAPI
1802 BuildExplicitAccessWithNameA(PEXPLICIT_ACCESSA pExplicitAccess,
1803                              LPSTR pTrusteeName,
1804                              DWORD AccessPermissions,
1805                              ACCESS_MODE AccessMode,
1806                              DWORD Inheritance)
1807 {
1808     pExplicitAccess->grfAccessPermissions = AccessPermissions;
1809     pExplicitAccess->grfAccessMode = AccessMode;
1810     pExplicitAccess->grfInheritance = Inheritance;
1811 
1812     pExplicitAccess->Trustee.pMultipleTrustee = NULL;
1813     pExplicitAccess->Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1814     pExplicitAccess->Trustee.TrusteeForm = TRUSTEE_IS_NAME;
1815     pExplicitAccess->Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
1816     pExplicitAccess->Trustee.ptstrName = pTrusteeName;
1817 }
1818 
1819 
1820 /******************************************************************************
1821  * BuildExplicitAccessWithNameW [ADVAPI32.@]
1822  */
1823 VOID WINAPI
1824 BuildExplicitAccessWithNameW(PEXPLICIT_ACCESSW pExplicitAccess,
1825                              LPWSTR pTrusteeName,
1826                              DWORD AccessPermissions,
1827                              ACCESS_MODE AccessMode,
1828                              DWORD Inheritance)
1829 {
1830     pExplicitAccess->grfAccessPermissions = AccessPermissions;
1831     pExplicitAccess->grfAccessMode = AccessMode;
1832     pExplicitAccess->grfInheritance = Inheritance;
1833 
1834     pExplicitAccess->Trustee.pMultipleTrustee = NULL;
1835     pExplicitAccess->Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1836     pExplicitAccess->Trustee.TrusteeForm = TRUSTEE_IS_NAME;
1837     pExplicitAccess->Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
1838     pExplicitAccess->Trustee.ptstrName = pTrusteeName;
1839 }
1840 
1841 /******************************************************************************
1842  * BuildTrusteeWithObjectsAndNameA [ADVAPI32.@]
1843  */
1844 VOID WINAPI BuildTrusteeWithObjectsAndNameA( PTRUSTEEA pTrustee, POBJECTS_AND_NAME_A pObjName,
1845                                              SE_OBJECT_TYPE ObjectType, LPSTR ObjectTypeName,
1846                                              LPSTR InheritedObjectTypeName, LPSTR Name )
1847 {
1848     DWORD ObjectsPresent = 0;
1849 
1850     TRACE("%p %p 0x%08x %p %p %s\n", pTrustee, pObjName,
1851           ObjectType, ObjectTypeName, InheritedObjectTypeName, debugstr_a(Name));
1852 
1853     /* Fill the OBJECTS_AND_NAME structure */
1854     pObjName->ObjectType = ObjectType;
1855     if (ObjectTypeName != NULL)
1856     {
1857         ObjectsPresent |= ACE_OBJECT_TYPE_PRESENT;
1858     }
1859 
1860     pObjName->InheritedObjectTypeName = InheritedObjectTypeName;
1861     if (InheritedObjectTypeName != NULL)
1862     {
1863         ObjectsPresent |= ACE_INHERITED_OBJECT_TYPE_PRESENT;
1864     }
1865 
1866     pObjName->ObjectsPresent = ObjectsPresent;
1867     pObjName->ptstrName = Name;
1868 
1869     /* Fill the TRUSTEE structure */
1870     pTrustee->pMultipleTrustee = NULL;
1871     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1872     pTrustee->TrusteeForm = TRUSTEE_IS_OBJECTS_AND_NAME;
1873     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
1874     pTrustee->ptstrName = (LPSTR)pObjName;
1875 }
1876 
1877 /******************************************************************************
1878  * BuildTrusteeWithObjectsAndNameW [ADVAPI32.@]
1879  */
1880 VOID WINAPI BuildTrusteeWithObjectsAndNameW( PTRUSTEEW pTrustee, POBJECTS_AND_NAME_W pObjName,
1881                                              SE_OBJECT_TYPE ObjectType, LPWSTR ObjectTypeName,
1882                                              LPWSTR InheritedObjectTypeName, LPWSTR Name )
1883 {
1884     DWORD ObjectsPresent = 0;
1885 
1886     TRACE("%p %p 0x%08x %p %p %s\n", pTrustee, pObjName,
1887           ObjectType, ObjectTypeName, InheritedObjectTypeName, debugstr_w(Name));
1888 
1889     /* Fill the OBJECTS_AND_NAME structure */
1890     pObjName->ObjectType = ObjectType;
1891     if (ObjectTypeName != NULL)
1892     {
1893         ObjectsPresent |= ACE_OBJECT_TYPE_PRESENT;
1894     }
1895 
1896     pObjName->InheritedObjectTypeName = InheritedObjectTypeName;
1897     if (InheritedObjectTypeName != NULL)
1898     {
1899         ObjectsPresent |= ACE_INHERITED_OBJECT_TYPE_PRESENT;
1900     }
1901 
1902     pObjName->ObjectsPresent = ObjectsPresent;
1903     pObjName->ptstrName = Name;
1904 
1905     /* Fill the TRUSTEE structure */
1906     pTrustee->pMultipleTrustee = NULL;
1907     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1908     pTrustee->TrusteeForm = TRUSTEE_IS_OBJECTS_AND_NAME;
1909     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
1910     pTrustee->ptstrName = (LPWSTR)pObjName;
1911 }
1912 
1913 /******************************************************************************
1914  * BuildTrusteeWithObjectsAndSidA [ADVAPI32.@]
1915  */
1916 VOID WINAPI
1917 BuildTrusteeWithObjectsAndSidA(PTRUSTEEA pTrustee,
1918                                POBJECTS_AND_SID pObjSid,
1919                                GUID *pObjectGuid,
1920                                GUID *pInheritedObjectGuid,
1921                                PSID pSid)
1922 {
1923     DWORD ObjectsPresent = 0;
1924 
1925     TRACE("%p %p %p %p %p\n", pTrustee, pObjSid, pObjectGuid, pInheritedObjectGuid, pSid);
1926 
1927     /* Fill the OBJECTS_AND_SID structure */
1928     if (pObjectGuid != NULL)
1929     {
1930         pObjSid->ObjectTypeGuid = *pObjectGuid;
1931         ObjectsPresent |= ACE_OBJECT_TYPE_PRESENT;
1932     }
1933     else
1934     {
1935         ZeroMemory(&pObjSid->ObjectTypeGuid,
1936                    sizeof(GUID));
1937     }
1938 
1939     if (pInheritedObjectGuid != NULL)
1940     {
1941         pObjSid->InheritedObjectTypeGuid = *pInheritedObjectGuid;
1942         ObjectsPresent |= ACE_INHERITED_OBJECT_TYPE_PRESENT;
1943     }
1944     else
1945     {
1946         ZeroMemory(&pObjSid->InheritedObjectTypeGuid,
1947                    sizeof(GUID));
1948     }
1949 
1950     pObjSid->ObjectsPresent = ObjectsPresent;
1951     pObjSid->pSid = pSid;
1952 
1953     /* Fill the TRUSTEE structure */
1954     pTrustee->pMultipleTrustee = NULL;
1955     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1956     pTrustee->TrusteeForm = TRUSTEE_IS_OBJECTS_AND_SID;
1957     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
1958     pTrustee->ptstrName = (LPSTR) pObjSid;
1959 }
1960 
1961 
1962 /******************************************************************************
1963  * BuildTrusteeWithObjectsAndSidW [ADVAPI32.@]
1964  */
1965 VOID WINAPI
1966 BuildTrusteeWithObjectsAndSidW(PTRUSTEEW pTrustee,
1967                                POBJECTS_AND_SID pObjSid,
1968                                GUID *pObjectGuid,
1969                                GUID *pInheritedObjectGuid,
1970                                PSID pSid)
1971 {
1972     DWORD ObjectsPresent = 0;
1973 
1974     TRACE("%p %p %p %p %p\n", pTrustee, pObjSid, pObjectGuid, pInheritedObjectGuid, pSid);
1975 
1976     /* Fill the OBJECTS_AND_SID structure */
1977     if (pObjectGuid != NULL)
1978     {
1979         pObjSid->ObjectTypeGuid = *pObjectGuid;
1980         ObjectsPresent |= ACE_OBJECT_TYPE_PRESENT;
1981     }
1982     else
1983     {
1984         ZeroMemory(&pObjSid->ObjectTypeGuid,
1985                    sizeof(GUID));
1986     }
1987 
1988     if (pInheritedObjectGuid != NULL)
1989     {
1990         pObjSid->InheritedObjectTypeGuid = *pInheritedObjectGuid;
1991         ObjectsPresent |= ACE_INHERITED_OBJECT_TYPE_PRESENT;
1992     }
1993     else
1994     {
1995         ZeroMemory(&pObjSid->InheritedObjectTypeGuid,
1996                    sizeof(GUID));
1997     }
1998 
1999     pObjSid->ObjectsPresent = ObjectsPresent;
2000     pObjSid->pSid = pSid;
2001 
2002     /* Fill the TRUSTEE structure */
2003     pTrustee->pMultipleTrustee = NULL;
2004     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
2005     pTrustee->TrusteeForm = TRUSTEE_IS_OBJECTS_AND_SID;
2006     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
2007     pTrustee->ptstrName = (LPWSTR) pObjSid;
2008 }
2009 
2010 /******************************************************************************
2011  * BuildTrusteeWithSidA [ADVAPI32.@]
2012  */
2013 VOID WINAPI
2014 BuildTrusteeWithSidA(PTRUSTEE_A pTrustee,
2015                      PSID pSid)
2016 {
2017     TRACE("%p %p\n", pTrustee, pSid);
2018 
2019     pTrustee->pMultipleTrustee = NULL;
2020     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
2021     pTrustee->TrusteeForm = TRUSTEE_IS_SID;
2022     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
2023     pTrustee->ptstrName = (LPSTR) pSid;
2024 }
2025 
2026 
2027 /******************************************************************************
2028  * BuildTrusteeWithSidW [ADVAPI32.@]
2029  */
2030 VOID WINAPI
2031 BuildTrusteeWithSidW(PTRUSTEE_W pTrustee,
2032                      PSID pSid)
2033 {
2034     TRACE("%p %p\n", pTrustee, pSid);
2035 
2036     pTrustee->pMultipleTrustee = NULL;
2037     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
2038     pTrustee->TrusteeForm = TRUSTEE_IS_SID;
2039     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
2040     pTrustee->ptstrName = (LPWSTR) pSid;
2041 }
2042 
2043 /******************************************************************************
2044  * BuildTrusteeWithNameA [ADVAPI32.@]
2045  */
2046 VOID WINAPI
2047 BuildTrusteeWithNameA(PTRUSTEE_A pTrustee,
2048                       LPSTR name)
2049 {
2050     TRACE("%p %s\n", pTrustee, name);
2051 
2052     pTrustee->pMultipleTrustee = NULL;
2053     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
2054     pTrustee->TrusteeForm = TRUSTEE_IS_NAME;
2055     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
2056     pTrustee->ptstrName = name;
2057 }
2058 
2059 /******************************************************************************
2060  * BuildTrusteeWithNameW [ADVAPI32.@]
2061  */
2062 VOID WINAPI
2063 BuildTrusteeWithNameW(PTRUSTEE_W pTrustee,
2064                       LPWSTR name)
2065 {
2066     TRACE("%p %s\n", pTrustee, name);
2067 
2068     pTrustee->pMultipleTrustee = NULL;
2069     pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
2070     pTrustee->TrusteeForm = TRUSTEE_IS_NAME;
2071     pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN;
2072     pTrustee->ptstrName = name;
2073 }
2074 
2075 /******************************************************************************
2076  * GetTrusteeFormA [ADVAPI32.@]
2077  */
2078 TRUSTEE_FORM WINAPI GetTrusteeFormA(PTRUSTEEA pTrustee)
2079 {
2080     TRACE("(%p)\n", pTrustee);
2081 
2082     if (!pTrustee)
2083         return TRUSTEE_BAD_FORM;
2084 
2085     return pTrustee->TrusteeForm;
2086 }
2087 
2088 /******************************************************************************
2089  * GetTrusteeFormW [ADVAPI32.@]
2090  */
2091 TRUSTEE_FORM WINAPI GetTrusteeFormW(PTRUSTEEW pTrustee)
2092 {
2093     TRACE("(%p)\n", pTrustee);
2094 
2095     if (!pTrustee)
2096         return TRUSTEE_BAD_FORM;
2097 
2098     return pTrustee->TrusteeForm;
2099 }
2100 
2101 /******************************************************************************
2102  * GetTrusteeNameA [ADVAPI32.@]
2103  */
2104 LPSTR WINAPI
2105 GetTrusteeNameA(PTRUSTEE_A pTrustee)
2106 {
2107     return pTrustee->ptstrName;
2108 }
2109 
2110 
2111 /******************************************************************************
2112  * GetTrusteeNameW [ADVAPI32.@]
2113  */
2114 LPWSTR WINAPI
2115 GetTrusteeNameW(PTRUSTEE_W pTrustee)
2116 {
2117     return pTrustee->ptstrName;
2118 }
2119 
2120 /******************************************************************************
2121  * GetTrusteeTypeA [ADVAPI32.@]
2122  */
2123 TRUSTEE_TYPE WINAPI
2124 GetTrusteeTypeA(PTRUSTEE_A pTrustee)
2125 {
2126     return pTrustee->TrusteeType;
2127 }
2128 
2129 /******************************************************************************
2130  * GetTrusteeTypeW [ADVAPI32.@]
2131  */
2132 TRUSTEE_TYPE WINAPI
2133 GetTrusteeTypeW(PTRUSTEE_W pTrustee)
2134 {
2135     return pTrustee->TrusteeType;
2136 }
2137 
2138 /*
2139  * @implemented
2140  */
2141 BOOL
2142 WINAPI
2143 SetAclInformation(PACL pAcl,
2144                   LPVOID pAclInformation,
2145                   DWORD nAclInformationLength,
2146                   ACL_INFORMATION_CLASS dwAclInformationClass)
2147 {
2148     NTSTATUS Status;
2149 
2150     Status = RtlSetInformationAcl(pAcl,
2151                                   pAclInformation,
2152                                   nAclInformationLength,
2153                                   dwAclInformationClass);
2154     if (!NT_SUCCESS(Status))
2155     {
2156         SetLastError(RtlNtStatusToDosError(Status));
2157         return FALSE;
2158     }
2159 
2160     return TRUE;
2161 }
2162 
2163 /**********************************************************************
2164  * SetNamedSecurityInfoA			EXPORTED
2165  *
2166  * @implemented
2167  */
2168 DWORD
2169 WINAPI
2170 SetNamedSecurityInfoA(LPSTR pObjectName,
2171                       SE_OBJECT_TYPE ObjectType,
2172                       SECURITY_INFORMATION SecurityInfo,
2173                       PSID psidOwner,
2174                       PSID psidGroup,
2175                       PACL pDacl,
2176                       PACL pSacl)
2177 {
2178     UNICODE_STRING ObjectName;
2179     DWORD Ret;
2180 
2181     if (!RtlCreateUnicodeStringFromAsciiz(&ObjectName, pObjectName))
2182     {
2183         return ERROR_NOT_ENOUGH_MEMORY;
2184     }
2185 
2186     Ret = SetNamedSecurityInfoW(ObjectName.Buffer,
2187                                 ObjectType,
2188                                 SecurityInfo,
2189                                 psidOwner,
2190                                 psidGroup,
2191                                 pDacl,
2192                                 pSacl);
2193 
2194     RtlFreeUnicodeString(&ObjectName);
2195 
2196     return Ret;
2197 }
2198 
2199 /*
2200  * @implemented
2201  */
2202 BOOL
2203 WINAPI
2204 AreAllAccessesGranted(DWORD GrantedAccess,
2205                       DWORD DesiredAccess)
2206 {
2207     return (BOOL)RtlAreAllAccessesGranted(GrantedAccess,
2208                                           DesiredAccess);
2209 }
2210 
2211 /*
2212  * @implemented
2213  */
2214 BOOL
2215 WINAPI
2216 AreAnyAccessesGranted(DWORD GrantedAccess,
2217                       DWORD DesiredAccess)
2218 {
2219     return (BOOL)RtlAreAnyAccessesGranted(GrantedAccess,
2220                                           DesiredAccess);
2221 }
2222 
2223 /******************************************************************************
2224  * ParseAclStringFlags
2225  */
2226 static DWORD ParseAclStringFlags(LPCWSTR* StringAcl)
2227 {
2228     DWORD flags = 0;
2229     LPCWSTR szAcl = *StringAcl;
2230 
2231     while (*szAcl && *szAcl != '(')
2232     {
2233         if (*szAcl == 'P')
2234         {
2235             flags |= SE_DACL_PROTECTED;
2236         }
2237         else if (*szAcl == 'A')
2238         {
2239             szAcl++;
2240             if (*szAcl == 'R')
2241                 flags |= SE_DACL_AUTO_INHERIT_REQ;
2242             else if (*szAcl == 'I')
2243                 flags |= SE_DACL_AUTO_INHERITED;
2244         }
2245         szAcl++;
2246     }
2247 
2248     *StringAcl = szAcl;
2249     return flags;
2250 }
2251 
2252 /******************************************************************************
2253  * ParseAceStringType
2254  */
2255 static const ACEFLAG AceType[] =
2256 {
2257     { SDDL_ALARM,          SYSTEM_ALARM_ACE_TYPE },
2258     { SDDL_AUDIT,          SYSTEM_AUDIT_ACE_TYPE },
2259     { SDDL_ACCESS_ALLOWED, ACCESS_ALLOWED_ACE_TYPE },
2260     { SDDL_ACCESS_DENIED,  ACCESS_DENIED_ACE_TYPE },
2261     { SDDL_MANDATORY_LABEL,SYSTEM_MANDATORY_LABEL_ACE_TYPE },
2262     /*
2263     { SDDL_OBJECT_ACCESS_ALLOWED, ACCESS_ALLOWED_OBJECT_ACE_TYPE },
2264     { SDDL_OBJECT_ACCESS_DENIED,  ACCESS_DENIED_OBJECT_ACE_TYPE },
2265     { SDDL_OBJECT_ALARM,          SYSTEM_ALARM_OBJECT_ACE_TYPE },
2266     { SDDL_OBJECT_AUDIT,          SYSTEM_AUDIT_OBJECT_ACE_TYPE },
2267     */
2268     { NULL, 0 },
2269 };
2270 
2271 static BYTE ParseAceStringType(LPCWSTR* StringAcl)
2272 {
2273     UINT len = 0;
2274     LPCWSTR szAcl = *StringAcl;
2275     const ACEFLAG *lpaf = AceType;
2276 
2277     while (*szAcl == ' ')
2278         szAcl++;
2279 
2280     while (lpaf->wstr &&
2281         (len = strlenW(lpaf->wstr)) &&
2282         strncmpW(lpaf->wstr, szAcl, len))
2283         lpaf++;
2284 
2285     if (!lpaf->wstr)
2286         return 0;
2287 
2288     *StringAcl = szAcl + len;
2289     return lpaf->value;
2290 }
2291 
2292 
2293 /******************************************************************************
2294  * ParseAceStringFlags
2295  */
2296 static const ACEFLAG AceFlags[] =
2297 {
2298     { SDDL_CONTAINER_INHERIT, CONTAINER_INHERIT_ACE },
2299     { SDDL_AUDIT_FAILURE,     FAILED_ACCESS_ACE_FLAG },
2300     { SDDL_INHERITED,         INHERITED_ACE },
2301     { SDDL_INHERIT_ONLY,      INHERIT_ONLY_ACE },
2302     { SDDL_NO_PROPAGATE,      NO_PROPAGATE_INHERIT_ACE },
2303     { SDDL_OBJECT_INHERIT,    OBJECT_INHERIT_ACE },
2304     { SDDL_AUDIT_SUCCESS,     SUCCESSFUL_ACCESS_ACE_FLAG },
2305     { NULL, 0 },
2306 };
2307 
2308 static BYTE ParseAceStringFlags(LPCWSTR* StringAcl)
2309 {
2310     UINT len = 0;
2311     BYTE flags = 0;
2312     LPCWSTR szAcl = *StringAcl;
2313 
2314     while (*szAcl == ' ')
2315         szAcl++;
2316 
2317     while (*szAcl != ';')
2318     {
2319         const ACEFLAG *lpaf = AceFlags;
2320 
2321         while (lpaf->wstr &&
2322                (len = strlenW(lpaf->wstr)) &&
2323                strncmpW(lpaf->wstr, szAcl, len))
2324             lpaf++;
2325 
2326         if (!lpaf->wstr)
2327             return 0;
2328 
2329 	flags |= lpaf->value;
2330         szAcl += len;
2331     }
2332 
2333     *StringAcl = szAcl;
2334     return flags;
2335 }
2336 
2337 
2338 /******************************************************************************
2339  * ParseAceStringRights
2340  */
2341 static const ACEFLAG AceRights[] =
2342 {
2343     { SDDL_GENERIC_ALL,     GENERIC_ALL },
2344     { SDDL_GENERIC_READ,    GENERIC_READ },
2345     { SDDL_GENERIC_WRITE,   GENERIC_WRITE },
2346     { SDDL_GENERIC_EXECUTE, GENERIC_EXECUTE },
2347 
2348     { SDDL_READ_CONTROL,    READ_CONTROL },
2349     { SDDL_STANDARD_DELETE, DELETE },
2350     { SDDL_WRITE_DAC,       WRITE_DAC },
2351     { SDDL_WRITE_OWNER,     WRITE_OWNER },
2352 
2353     { SDDL_READ_PROPERTY,   ADS_RIGHT_DS_READ_PROP},
2354     { SDDL_WRITE_PROPERTY,  ADS_RIGHT_DS_WRITE_PROP},
2355     { SDDL_CREATE_CHILD,    ADS_RIGHT_DS_CREATE_CHILD},
2356     { SDDL_DELETE_CHILD,    ADS_RIGHT_DS_DELETE_CHILD},
2357     { SDDL_LIST_CHILDREN,   ADS_RIGHT_ACTRL_DS_LIST},
2358     { SDDL_SELF_WRITE,      ADS_RIGHT_DS_SELF},
2359     { SDDL_LIST_OBJECT,     ADS_RIGHT_DS_LIST_OBJECT},
2360     { SDDL_DELETE_TREE,     ADS_RIGHT_DS_DELETE_TREE},
2361     { SDDL_CONTROL_ACCESS,  ADS_RIGHT_DS_CONTROL_ACCESS},
2362 
2363     { SDDL_FILE_ALL,        FILE_ALL_ACCESS },
2364     { SDDL_FILE_READ,       FILE_GENERIC_READ },
2365     { SDDL_FILE_WRITE,      FILE_GENERIC_WRITE },
2366     { SDDL_FILE_EXECUTE,    FILE_GENERIC_EXECUTE },
2367 
2368     { SDDL_KEY_ALL,         KEY_ALL_ACCESS },
2369     { SDDL_KEY_READ,        KEY_READ },
2370     { SDDL_KEY_WRITE,       KEY_WRITE },
2371     { SDDL_KEY_EXECUTE,     KEY_EXECUTE },
2372 
2373     { SDDL_NO_READ_UP,      SYSTEM_MANDATORY_LABEL_NO_READ_UP },
2374     { SDDL_NO_WRITE_UP,     SYSTEM_MANDATORY_LABEL_NO_WRITE_UP },
2375     { SDDL_NO_EXECUTE_UP,   SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP },
2376     { NULL, 0 },
2377 };
2378 
2379 static DWORD ParseAceStringRights(LPCWSTR* StringAcl)
2380 {
2381     UINT len = 0;
2382     DWORD rights = 0;
2383     LPCWSTR szAcl = *StringAcl;
2384 
2385     while (*szAcl == ' ')
2386         szAcl++;
2387 
2388     if ((*szAcl == '0') && (*(szAcl + 1) == 'x'))
2389     {
2390         LPCWSTR p = szAcl;
2391 
2392 	while (*p && *p != ';')
2393             p++;
2394 
2395 	if (p - szAcl <= 10 /* 8 hex digits + "0x" */ )
2396 	{
2397 	    rights = strtoulW(szAcl, NULL, 16);
2398 	    szAcl = p;
2399 	}
2400 	else
2401             WARN("Invalid rights string format: %s\n", debugstr_wn(szAcl, p - szAcl));
2402     }
2403     else
2404     {
2405         while (*szAcl != ';')
2406         {
2407             const ACEFLAG *lpaf = AceRights;
2408 
2409             while (lpaf->wstr &&
2410                (len = strlenW(lpaf->wstr)) &&
2411                strncmpW(lpaf->wstr, szAcl, len))
2412 	    {
2413                lpaf++;
2414 	    }
2415 
2416             if (!lpaf->wstr)
2417                 return 0;
2418 
2419 	    rights |= lpaf->value;
2420             szAcl += len;
2421         }
2422     }
2423 
2424     *StringAcl = szAcl;
2425     return rights;
2426 }
2427 
2428 
2429 /******************************************************************************
2430  * ParseStringAclToAcl
2431  *
2432  * dacl_flags(string_ace1)(string_ace2)... (string_acen)
2433  */
2434 static BOOL ParseStringAclToAcl(LPCWSTR StringAcl, LPDWORD lpdwFlags,
2435     PACL pAcl, LPDWORD cBytes)
2436 {
2437     DWORD val;
2438     DWORD sidlen;
2439     DWORD length = sizeof(ACL);
2440     DWORD acesize = 0;
2441     DWORD acecount = 0;
2442     PACCESS_ALLOWED_ACE pAce = NULL; /* pointer to current ACE */
2443     DWORD error = ERROR_INVALID_ACL;
2444 
2445     TRACE("%s\n", debugstr_w(StringAcl));
2446 
2447     if (!StringAcl)
2448 	return FALSE;
2449 
2450     if (pAcl) /* pAce is only useful if we're setting values */
2451         pAce = (PACCESS_ALLOWED_ACE) (pAcl + 1);
2452 
2453     /* Parse ACL flags */
2454     *lpdwFlags = ParseAclStringFlags(&StringAcl);
2455 
2456     /* Parse ACE */
2457     while (*StringAcl == '(')
2458     {
2459         StringAcl++;
2460 
2461         /* Parse ACE type */
2462         val = ParseAceStringType(&StringAcl);
2463 	if (pAce)
2464             pAce->Header.AceType = (BYTE) val;
2465         if (*StringAcl != ';')
2466         {
2467             error = RPC_S_INVALID_STRING_UUID;
2468             goto lerr;
2469         }
2470         StringAcl++;
2471 
2472         /* Parse ACE flags */
2473 	val = ParseAceStringFlags(&StringAcl);
2474 	if (pAce)
2475             pAce->Header.AceFlags = (BYTE) val;
2476         if (*StringAcl != ';')
2477             goto lerr;
2478         StringAcl++;
2479 
2480         /* Parse ACE rights */
2481 	val = ParseAceStringRights(&StringAcl);
2482 	if (pAce)
2483             pAce->Mask = val;
2484         if (*StringAcl != ';')
2485             goto lerr;
2486         StringAcl++;
2487 
2488         /* Parse ACE object guid */
2489         while (*StringAcl == ' ')
2490             StringAcl++;
2491         if (*StringAcl != ';')
2492         {
2493             FIXME("Support for *_OBJECT_ACE_TYPE not implemented\n");
2494             goto lerr;
2495         }
2496         StringAcl++;
2497 
2498         /* Parse ACE inherit object guid */
2499         while (*StringAcl == ' ')
2500             StringAcl++;
2501         if (*StringAcl != ';')
2502         {
2503             FIXME("Support for *_OBJECT_ACE_TYPE not implemented\n");
2504             goto lerr;
2505         }
2506         StringAcl++;
2507 
2508         /* Parse ACE account sid */
2509         if (ParseStringSidToSid(StringAcl, pAce ? &pAce->SidStart : NULL, &sidlen))
2510 	{
2511             while (*StringAcl && *StringAcl != ')')
2512                 StringAcl++;
2513 	}
2514 
2515         if (*StringAcl != ')')
2516             goto lerr;
2517         StringAcl++;
2518 
2519         acesize = sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + sidlen;
2520         length += acesize;
2521         if (pAce)
2522         {
2523             pAce->Header.AceSize = acesize;
2524             pAce = (PACCESS_ALLOWED_ACE)((LPBYTE)pAce + acesize);
2525         }
2526         acecount++;
2527     }
2528 
2529     *cBytes = length;
2530 
2531     if (length > 0xffff)
2532     {
2533         ERR("ACL too large\n");
2534         goto lerr;
2535     }
2536 
2537     if (pAcl)
2538     {
2539         pAcl->AclRevision = ACL_REVISION;
2540         pAcl->Sbz1 = 0;
2541         pAcl->AclSize = length;
2542         pAcl->AceCount = acecount;
2543         pAcl->Sbz2 = 0;
2544     }
2545     return TRUE;
2546 
2547 lerr:
2548     SetLastError(error);
2549     WARN("Invalid ACE string format\n");
2550     return FALSE;
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_RELATIVE);
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