wusa: Fix double free on error path in read_update_package (scan-build).
[wine.git] / dlls / sechost / security.c
blob88f5aa7f5ae647304f7553722b94969df75df66f
1 /*
2 * Security API
4 * Copyright 2003 CodeWeavers Inc. (Ulrich Czekalla)
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <assert.h>
22 #include <stdarg.h>
24 #define WINADVAPI
25 #include "windef.h"
26 #include "winbase.h"
27 #include "sddl.h"
28 #include "iads.h"
30 #include "wine/debug.h"
31 #include "wine/heap.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(security);
35 static const struct
37 WCHAR str[3];
38 DWORD value;
40 ace_rights[] =
42 { L"GA", GENERIC_ALL },
43 { L"GR", GENERIC_READ },
44 { L"GW", GENERIC_WRITE },
45 { L"GX", GENERIC_EXECUTE },
47 { L"RC", READ_CONTROL },
48 { L"SD", DELETE },
49 { L"WD", WRITE_DAC },
50 { L"WO", WRITE_OWNER },
52 { L"RP", ADS_RIGHT_DS_READ_PROP },
53 { L"WP", ADS_RIGHT_DS_WRITE_PROP },
54 { L"CC", ADS_RIGHT_DS_CREATE_CHILD },
55 { L"DC", ADS_RIGHT_DS_DELETE_CHILD },
56 { L"LC", ADS_RIGHT_ACTRL_DS_LIST },
57 { L"SW", ADS_RIGHT_DS_SELF },
58 { L"LO", ADS_RIGHT_DS_LIST_OBJECT },
59 { L"DT", ADS_RIGHT_DS_DELETE_TREE },
60 { L"CR", ADS_RIGHT_DS_CONTROL_ACCESS },
62 { L"FA", FILE_ALL_ACCESS },
63 { L"FR", FILE_GENERIC_READ },
64 { L"FW", FILE_GENERIC_WRITE },
65 { L"FX", FILE_GENERIC_EXECUTE },
67 { L"KA", KEY_ALL_ACCESS },
68 { L"KR", KEY_READ },
69 { L"KW", KEY_WRITE },
70 { L"KX", KEY_EXECUTE },
72 { L"NR", SYSTEM_MANDATORY_LABEL_NO_READ_UP },
73 { L"NW", SYSTEM_MANDATORY_LABEL_NO_WRITE_UP },
74 { L"NX", SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP },
77 struct max_sid
79 /* same fields as struct _SID */
80 BYTE Revision;
81 BYTE SubAuthorityCount;
82 SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
83 DWORD SubAuthority[SID_MAX_SUB_AUTHORITIES];
86 static const struct
88 WCHAR str[2];
89 WELL_KNOWN_SID_TYPE Type;
90 struct max_sid sid;
92 well_known_sids[] =
94 { {0,0}, WinNullSid, { SID_REVISION, 1, { SECURITY_NULL_SID_AUTHORITY }, { SECURITY_NULL_RID } } },
95 { {'W','D'}, WinWorldSid, { SID_REVISION, 1, { SECURITY_WORLD_SID_AUTHORITY }, { SECURITY_WORLD_RID } } },
96 { {0,0}, WinLocalSid, { SID_REVISION, 1, { SECURITY_LOCAL_SID_AUTHORITY }, { SECURITY_LOCAL_RID } } },
97 { {'C','O'}, WinCreatorOwnerSid, { SID_REVISION, 1, { SECURITY_CREATOR_SID_AUTHORITY }, { SECURITY_CREATOR_OWNER_RID } } },
98 { {'C','G'}, WinCreatorGroupSid, { SID_REVISION, 1, { SECURITY_CREATOR_SID_AUTHORITY }, { SECURITY_CREATOR_GROUP_RID } } },
99 { {'O','W'}, WinCreatorOwnerRightsSid, { SID_REVISION, 1, { SECURITY_CREATOR_SID_AUTHORITY }, { SECURITY_CREATOR_OWNER_RIGHTS_RID } } },
100 { {0,0}, WinCreatorOwnerServerSid, { SID_REVISION, 1, { SECURITY_CREATOR_SID_AUTHORITY }, { SECURITY_CREATOR_OWNER_SERVER_RID } } },
101 { {0,0}, WinCreatorGroupServerSid, { SID_REVISION, 1, { SECURITY_CREATOR_SID_AUTHORITY }, { SECURITY_CREATOR_GROUP_SERVER_RID } } },
102 { {0,0}, WinNtAuthoritySid, { SID_REVISION, 0, { SECURITY_NT_AUTHORITY }, { SECURITY_NULL_RID } } },
103 { {0,0}, WinDialupSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_DIALUP_RID } } },
104 { {'N','U'}, WinNetworkSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_NETWORK_RID } } },
105 { {0,0}, WinBatchSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_BATCH_RID } } },
106 { {'I','U'}, WinInteractiveSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_INTERACTIVE_RID } } },
107 { {'S','U'}, WinServiceSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_SERVICE_RID } } },
108 { {'A','N'}, WinAnonymousSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_ANONYMOUS_LOGON_RID } } },
109 { {0,0}, WinProxySid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_PROXY_RID } } },
110 { {'E','D'}, WinEnterpriseControllersSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_ENTERPRISE_CONTROLLERS_RID } } },
111 { {'P','S'}, WinSelfSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_PRINCIPAL_SELF_RID } } },
112 { {'A','U'}, WinAuthenticatedUserSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_AUTHENTICATED_USER_RID } } },
113 { {'R','C'}, WinRestrictedCodeSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_RESTRICTED_CODE_RID } } },
114 { {0,0}, WinTerminalServerSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_TERMINAL_SERVER_RID } } },
115 { {0,0}, WinRemoteLogonIdSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_REMOTE_LOGON_RID } } },
116 { {0,0}, WinLogonIdsSid, { SID_REVISION, SECURITY_LOGON_IDS_RID_COUNT, { SECURITY_NT_AUTHORITY }, { SECURITY_LOGON_IDS_RID } } },
117 { {'S','Y'}, WinLocalSystemSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_LOCAL_SYSTEM_RID } } },
118 { {'L','S'}, WinLocalServiceSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_LOCAL_SERVICE_RID } } },
119 { {'N','S'}, WinNetworkServiceSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_NETWORK_SERVICE_RID } } },
120 { {0,0}, WinBuiltinDomainSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID } } },
121 { {'B','A'}, WinBuiltinAdministratorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS } } },
122 { {'B','U'}, WinBuiltinUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS } } },
123 { {'B','G'}, WinBuiltinGuestsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS } } },
124 { {'P','U'}, WinBuiltinPowerUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS } } },
125 { {'A','O'}, WinBuiltinAccountOperatorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ACCOUNT_OPS } } },
126 { {'S','O'}, WinBuiltinSystemOperatorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_SYSTEM_OPS } } },
127 { {'P','O'}, WinBuiltinPrintOperatorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_PRINT_OPS } } },
128 { {'B','O'}, WinBuiltinBackupOperatorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_BACKUP_OPS } } },
129 { {'R','E'}, WinBuiltinReplicatorSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_REPLICATOR } } },
130 { {'R','U'}, WinBuiltinPreWindows2000CompatibleAccessSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_PREW2KCOMPACCESS } } },
131 { {'R','D'}, WinBuiltinRemoteDesktopUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS } } },
132 { {'N','O'}, WinBuiltinNetworkConfigurationOperatorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS } } },
133 { {0,0}, WinNTLMAuthenticationSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_PACKAGE_BASE_RID, SECURITY_PACKAGE_NTLM_RID } } },
134 { {0,0}, WinDigestAuthenticationSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_PACKAGE_BASE_RID, SECURITY_PACKAGE_DIGEST_RID } } },
135 { {0,0}, WinSChannelAuthenticationSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_PACKAGE_BASE_RID, SECURITY_PACKAGE_SCHANNEL_RID } } },
136 { {0,0}, WinThisOrganizationSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_THIS_ORGANIZATION_RID } } },
137 { {0,0}, WinOtherOrganizationSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_OTHER_ORGANIZATION_RID } } },
138 { {0,0}, WinBuiltinIncomingForestTrustBuildersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS } } },
139 { {0,0}, WinBuiltinPerfMonitoringUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_MONITORING_USERS } } },
140 { {0,0}, WinBuiltinPerfLoggingUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_LOGGING_USERS } } },
141 { {0,0}, WinBuiltinAuthorizationAccessSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS } } },
142 { {0,0}, WinBuiltinTerminalServerLicenseServersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS } } },
143 { {0,0}, WinBuiltinDCOMUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_DCOM_USERS } } },
144 { {'L','W'}, WinLowLabelSid, { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY}, { SECURITY_MANDATORY_LOW_RID} } },
145 { {'M','E'}, WinMediumLabelSid, { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY}, { SECURITY_MANDATORY_MEDIUM_RID } } },
146 { {'H','I'}, WinHighLabelSid, { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY}, { SECURITY_MANDATORY_HIGH_RID } } },
147 { {'S','I'}, WinSystemLabelSid, { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY}, { SECURITY_MANDATORY_SYSTEM_RID } } },
148 { {'A','C'}, WinBuiltinAnyPackageSid, { SID_REVISION, 2, { SECURITY_APP_PACKAGE_AUTHORITY }, { SECURITY_APP_PACKAGE_BASE_RID, SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE } } },
151 /* these SIDs must be constructed as relative to some domain - only the RID is well-known */
152 static const struct
154 WCHAR str[2];
155 WELL_KNOWN_SID_TYPE type;
156 DWORD rid;
158 well_known_rids[] =
160 { {'L','A'}, WinAccountAdministratorSid, DOMAIN_USER_RID_ADMIN },
161 { {'L','G'}, WinAccountGuestSid, DOMAIN_USER_RID_GUEST },
162 { {0,0}, WinAccountKrbtgtSid, DOMAIN_USER_RID_KRBTGT },
163 { {'D','A'}, WinAccountDomainAdminsSid, DOMAIN_GROUP_RID_ADMINS },
164 { {'D','U'}, WinAccountDomainUsersSid, DOMAIN_GROUP_RID_USERS },
165 { {'D','G'}, WinAccountDomainGuestsSid, DOMAIN_GROUP_RID_GUESTS },
166 { {'D','C'}, WinAccountComputersSid, DOMAIN_GROUP_RID_COMPUTERS },
167 { {'D','D'}, WinAccountControllersSid, DOMAIN_GROUP_RID_CONTROLLERS },
168 { {'C','A'}, WinAccountCertAdminsSid, DOMAIN_GROUP_RID_CERT_ADMINS },
169 { {'S','A'}, WinAccountSchemaAdminsSid, DOMAIN_GROUP_RID_SCHEMA_ADMINS },
170 { {'E','A'}, WinAccountEnterpriseAdminsSid, DOMAIN_GROUP_RID_ENTERPRISE_ADMINS },
171 { {'P','A'}, WinAccountPolicyAdminsSid, DOMAIN_GROUP_RID_POLICY_ADMINS },
172 { {'R','S'}, WinAccountRasAndIasServersSid, DOMAIN_ALIAS_RID_RAS_SERVERS },
176 static void print_string(const WCHAR *string, int cch, WCHAR **pwptr, ULONG *plen)
178 if (cch == -1)
179 cch = wcslen(string);
181 if (plen)
182 *plen += cch;
184 if (pwptr)
186 memcpy(*pwptr, string, sizeof(WCHAR)*cch);
187 *pwptr += cch;
191 static BOOL print_sid_numeric(PSID psid, WCHAR **pwptr, ULONG *plen)
193 DWORD i;
194 WCHAR buf[26];
195 SID *pisid = psid;
197 if( !IsValidSid( psid ) || pisid->Revision != SDDL_REVISION)
199 SetLastError(ERROR_INVALID_SID);
200 return FALSE;
203 if (pisid->IdentifierAuthority.Value[0] ||
204 pisid->IdentifierAuthority.Value[1])
206 FIXME("not matching MS' bugs\n");
207 SetLastError(ERROR_INVALID_SID);
208 return FALSE;
211 swprintf( buf, ARRAY_SIZE(buf), L"S-%u-%d", pisid->Revision, MAKELONG(
212 MAKEWORD( pisid->IdentifierAuthority.Value[5], pisid->IdentifierAuthority.Value[4] ),
213 MAKEWORD( pisid->IdentifierAuthority.Value[3], pisid->IdentifierAuthority.Value[2] )
214 ) );
215 print_string(buf, -1, pwptr, plen);
217 for( i=0; i<pisid->SubAuthorityCount; i++ )
219 swprintf( buf, ARRAY_SIZE(buf), L"-%u", pisid->SubAuthority[i] );
220 print_string(buf, -1, pwptr, plen);
222 return TRUE;
225 /******************************************************************************
226 * ConvertSidToStringSidW (sechost.@)
228 BOOL WINAPI DECLSPEC_HOTPATCH ConvertSidToStringSidW( PSID sid, WCHAR **pstr )
230 DWORD len = 0;
231 WCHAR *wstr, *wptr;
233 TRACE("%p %p\n", sid, pstr );
235 len = 0;
236 if (!print_sid_numeric( sid, NULL, &len ))
237 return FALSE;
238 wstr = wptr = LocalAlloc( 0, (len + 1) * sizeof(WCHAR) );
239 print_sid_numeric( sid, &wptr, NULL );
240 *wptr = 0;
242 *pstr = wstr;
243 return TRUE;
246 static BOOL print_sid(PSID psid, WCHAR **pwptr, ULONG *plen)
248 size_t i;
249 for (i = 0; i < ARRAY_SIZE(well_known_sids); i++)
251 if (well_known_sids[i].str[0] && EqualSid(psid, (PSID)&well_known_sids[i].sid.Revision))
253 print_string(well_known_sids[i].str, 2, pwptr, plen);
254 return TRUE;
258 return print_sid_numeric(psid, pwptr, plen);
261 static void print_rights(DWORD mask, WCHAR **pwptr, ULONG *plen)
263 static const WCHAR *bit_names[32] =
265 L"CC", /* 0 */
266 L"DC",
267 L"LC",
268 L"SW",
269 L"RP", /* 4 */
270 L"WP",
271 L"DT",
272 L"LO",
273 L"CR", /* 8 */
274 NULL,
275 NULL,
276 NULL,
277 NULL, /* 12 */
278 NULL,
279 NULL,
280 NULL,
281 L"SD", /* 16 */
282 L"RC",
283 L"WD",
284 L"WO",
285 NULL, /* 20 */
286 NULL,
287 NULL,
288 NULL,
289 NULL, /* 24 */
290 NULL,
291 NULL,
292 NULL,
293 L"GA", /* 28 */
294 L"GX",
295 L"GW",
296 L"GR",
299 WCHAR buf[15];
300 size_t i;
302 if (mask == 0)
303 return;
305 /* first check if the right have name */
306 for (i = 0; i < ARRAY_SIZE(ace_rights); i++)
308 if (mask == ace_rights[i].value)
310 print_string(ace_rights[i].str, -1, pwptr, plen);
311 return;
315 /* then check if it can be built from bit names */
316 for (i = 0; i < 32; i++)
318 if ((mask & (1 << i)) && !bit_names[i])
320 /* can't be built from bit names */
321 swprintf(buf, ARRAY_SIZE(buf), L"0x%x", mask);
322 print_string(buf, -1, pwptr, plen);
323 return;
327 /* build from bit names */
328 for (i = 0; i < 32; i++)
329 if (mask & (1 << i))
330 print_string(bit_names[i], -1, pwptr, plen);
333 static inline BOOL is_object_ace(BYTE type)
335 switch (type)
337 case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
338 case ACCESS_DENIED_OBJECT_ACE_TYPE:
339 case ACCESS_AUDIT_OBJECT_ACE_TYPE:
340 case ACCESS_ALARM_OBJECT_ACE_TYPE:
341 case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
342 case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
343 case SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
344 case SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE:
345 return TRUE;
347 default:
348 return FALSE;
352 static BOOL print_ace(void *pace, WCHAR **pwptr, ULONG *plen)
354 ACCESS_ALLOWED_ACE *piace; /* all the supported ACEs have the same memory layout */
355 DWORD *sid_start;
357 piace = pace;
359 if (piace->Header.AceType > ACCESS_MAX_MS_V5_ACE_TYPE || piace->Header.AceSize < sizeof(ACCESS_ALLOWED_ACE))
361 SetLastError(ERROR_INVALID_ACL);
362 return FALSE;
365 print_string(L"(", -1, pwptr, plen);
366 switch (piace->Header.AceType)
368 case ACCESS_ALLOWED_ACE_TYPE:
369 print_string(L"A", -1, pwptr, plen);
370 break;
371 case ACCESS_DENIED_ACE_TYPE:
372 print_string(L"D", -1, pwptr, plen);
373 break;
374 case SYSTEM_AUDIT_ACE_TYPE:
375 print_string(L"AU", -1, pwptr, plen);
376 break;
377 case SYSTEM_ALARM_ACE_TYPE:
378 print_string(L"AL", -1, pwptr, plen);
379 break;
381 print_string(L";", -1, pwptr, plen);
383 if (piace->Header.AceFlags & OBJECT_INHERIT_ACE)
384 print_string(L"OI", -1, pwptr, plen);
385 if (piace->Header.AceFlags & CONTAINER_INHERIT_ACE)
386 print_string(L"CI", -1, pwptr, plen);
387 if (piace->Header.AceFlags & NO_PROPAGATE_INHERIT_ACE)
388 print_string(L"NP", -1, pwptr, plen);
389 if (piace->Header.AceFlags & INHERIT_ONLY_ACE)
390 print_string(L"IO", -1, pwptr, plen);
391 if (piace->Header.AceFlags & INHERITED_ACE)
392 print_string(L"ID", -1, pwptr, plen);
393 if (piace->Header.AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG)
394 print_string(L"SA", -1, pwptr, plen);
395 if (piace->Header.AceFlags & FAILED_ACCESS_ACE_FLAG)
396 print_string(L"FA", -1, pwptr, plen);
397 print_string(L";", -1, pwptr, plen);
398 print_rights(piace->Mask, pwptr, plen);
399 print_string(L";", -1, pwptr, plen);
400 sid_start = &piace->SidStart;
401 if (is_object_ace(piace->Header.AceType))
403 ACCESS_ALLOWED_OBJECT_ACE *objace = pace;
405 sid_start++; /* Flags */
406 if (objace->Flags & ACE_OBJECT_TYPE_PRESENT)
407 sid_start += sizeof(GUID) / sizeof(*sid_start); /* ObjectType */
408 if (objace->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
409 sid_start += sizeof(GUID) / sizeof(*sid_start); /* InheritedObjectType */
411 /* objects not supported */
412 print_string(L";", -1, pwptr, plen);
413 /* objects not supported */
414 print_string(L";", -1, pwptr, plen);
415 if (!print_sid(sid_start, pwptr, plen))
416 return FALSE;
417 print_string(L")", -1, pwptr, plen);
418 return TRUE;
421 static BOOL print_acl(ACL *pacl, WCHAR **pwptr, ULONG *plen, SECURITY_DESCRIPTOR_CONTROL control)
423 WORD count;
424 UINT i;
426 if (control & SE_DACL_PROTECTED)
427 print_string(L"P", -1, pwptr, plen);
428 if (control & SE_DACL_AUTO_INHERIT_REQ)
429 print_string(L"AR", -1, pwptr, plen);
430 if (control & SE_DACL_AUTO_INHERITED)
431 print_string(L"AI", -1, pwptr, plen);
433 if (pacl == NULL)
434 return TRUE;
436 if (!IsValidAcl(pacl))
437 return FALSE;
439 count = pacl->AceCount;
440 for (i = 0; i < count; i++)
442 void *ace;
443 if (!GetAce(pacl, i, &ace))
444 return FALSE;
445 if (!print_ace(ace, pwptr, plen))
446 return FALSE;
449 return TRUE;
452 static BOOL print_owner(PSECURITY_DESCRIPTOR sd, WCHAR **pwptr, ULONG *plen)
454 BOOL defaulted;
455 PSID psid;
457 if (!GetSecurityDescriptorOwner(sd, &psid, &defaulted))
458 return FALSE;
460 if (psid == NULL)
461 return TRUE;
463 print_string(L"O:", -1, pwptr, plen);
464 if (!print_sid(psid, pwptr, plen))
465 return FALSE;
466 return TRUE;
469 static BOOL print_group(PSECURITY_DESCRIPTOR sd, WCHAR **pwptr, ULONG *plen)
471 BOOL defaulted;
472 PSID psid;
474 if (!GetSecurityDescriptorGroup(sd, &psid, &defaulted))
475 return FALSE;
477 if (psid == NULL)
478 return TRUE;
480 print_string(L"G:", -1, pwptr, plen);
481 if (!print_sid(psid, pwptr, plen))
482 return FALSE;
483 return TRUE;
486 static BOOL print_dacl(PSECURITY_DESCRIPTOR sd, WCHAR **pwptr, ULONG *plen)
488 SECURITY_DESCRIPTOR_CONTROL control;
489 BOOL present, defaulted;
490 DWORD revision;
491 ACL *pacl;
493 if (!GetSecurityDescriptorDacl(sd, &present, &pacl, &defaulted))
494 return FALSE;
496 if (!GetSecurityDescriptorControl(sd, &control, &revision))
497 return FALSE;
499 if (!present)
500 return TRUE;
502 print_string(L"D:", -1, pwptr, plen);
503 if (!print_acl(pacl, pwptr, plen, control))
504 return FALSE;
505 return TRUE;
508 static BOOL print_sacl(PSECURITY_DESCRIPTOR sd, WCHAR **pwptr, ULONG *plen)
510 SECURITY_DESCRIPTOR_CONTROL control;
511 BOOL present, defaulted;
512 DWORD revision;
513 ACL *pacl;
515 if (!GetSecurityDescriptorSacl(sd, &present, &pacl, &defaulted))
516 return FALSE;
518 if (!GetSecurityDescriptorControl(sd, &control, &revision))
519 return FALSE;
521 if (!present)
522 return TRUE;
524 print_string(L"S:", -1, pwptr, plen);
525 if (!print_acl(pacl, pwptr, plen, control))
526 return FALSE;
527 return TRUE;
530 /******************************************************************************
531 * ConvertSecurityDescriptorToStringSecurityDescriptorW (sechost.@)
533 BOOL WINAPI DECLSPEC_HOTPATCH ConvertSecurityDescriptorToStringSecurityDescriptorW( PSECURITY_DESCRIPTOR sd,
534 DWORD revision, SECURITY_INFORMATION flags, WCHAR **string, ULONG *ret_len )
536 ULONG len = 0;
537 WCHAR *wptr, *wstr;
539 if (revision != SDDL_REVISION_1)
541 ERR("Unhandled SDDL revision %ld\n", revision);
542 SetLastError( ERROR_UNKNOWN_REVISION );
543 return FALSE;
546 if ((flags & OWNER_SECURITY_INFORMATION) && !print_owner(sd, NULL, &len))
547 return FALSE;
548 if ((flags & GROUP_SECURITY_INFORMATION) && !print_group(sd, NULL, &len))
549 return FALSE;
550 if ((flags & DACL_SECURITY_INFORMATION) && !print_dacl(sd, NULL, &len))
551 return FALSE;
552 if ((flags & SACL_SECURITY_INFORMATION) && !print_sacl(sd, NULL, &len))
553 return FALSE;
555 wstr = wptr = LocalAlloc( 0, (len + 1) * sizeof(WCHAR) );
556 if ((flags & OWNER_SECURITY_INFORMATION) && !print_owner(sd, &wptr, NULL))
558 LocalFree(wstr);
559 return FALSE;
561 if ((flags & GROUP_SECURITY_INFORMATION) && !print_group(sd, &wptr, NULL))
563 LocalFree(wstr);
564 return FALSE;
566 if ((flags & DACL_SECURITY_INFORMATION) && !print_dacl(sd, &wptr, NULL))
568 LocalFree(wstr);
569 return FALSE;
571 if ((flags & SACL_SECURITY_INFORMATION) && !print_sacl(sd, &wptr, NULL))
573 LocalFree(wstr);
574 return FALSE;
576 *wptr = 0;
578 TRACE("ret: %s, %ld\n", wine_dbgstr_w(wstr), len);
579 *string = wstr;
580 if (ret_len) *ret_len = wcslen(*string) + 1;
581 return TRUE;
584 static BOOL get_computer_sid( PSID sid )
586 static const struct /* same fields as struct SID */
588 BYTE Revision;
589 BYTE SubAuthorityCount;
590 SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
591 DWORD SubAuthority[4];
592 } computer_sid =
593 { SID_REVISION, 4, { SECURITY_NT_AUTHORITY }, { SECURITY_NT_NON_UNIQUE, 0, 0, 0 } };
595 memcpy( sid, &computer_sid, sizeof(computer_sid) );
596 return TRUE;
599 static BOOL parse_token( const WCHAR *string, const WCHAR **end, DWORD *result )
601 if (string[0] == '0' && (string[1] == 'X' || string[1] == 'x'))
603 /* hexadecimal */
604 *result = wcstoul( string + 2, (WCHAR**)&string, 16 );
605 if (*string == '-')
606 string++;
607 *end = string;
608 return TRUE;
610 else if (iswdigit(string[0]) || string[0] == '-')
612 *result = wcstoul( string, (WCHAR**)&string, 10 );
613 if (*string == '-')
614 string++;
615 *end = string;
616 return TRUE;
619 *result = 0;
620 *end = string;
621 return FALSE;
624 static DWORD get_sid_size( const WCHAR *string, const WCHAR **end )
626 if ((string[0] == 'S' || string[0] == 's') && string[1] == '-') /* S-R-I(-S)+ */
628 int token_count = 0;
629 DWORD value;
631 string += 2;
633 while (parse_token( string, &string, &value ))
634 token_count++;
636 if (end)
637 *end = string;
639 if (token_count >= 3)
640 return GetSidLengthRequired( token_count - 2 );
642 else /* String constant format - Only available in winxp and above */
644 unsigned int i;
646 if (end)
647 *end = string + 2;
649 for (i = 0; i < ARRAY_SIZE(well_known_sids); i++)
651 if (!wcsnicmp( well_known_sids[i].str, string, 2 ))
652 return GetSidLengthRequired( well_known_sids[i].sid.SubAuthorityCount );
655 for (i = 0; i < ARRAY_SIZE(well_known_rids); i++)
657 if (!wcsnicmp( well_known_rids[i].str, string, 2 ))
659 struct max_sid local;
660 get_computer_sid(&local);
661 return GetSidLengthRequired( *GetSidSubAuthorityCount(&local) + 1 );
666 return GetSidLengthRequired( 0 );
669 static BOOL parse_sid( const WCHAR *string, const WCHAR **end, SID *pisid, DWORD *size )
671 while (*string == ' ')
672 string++;
674 *size = get_sid_size( string, end );
675 if (!pisid) /* Simply compute the size */
676 return TRUE;
678 if ((string[0] == 'S' || string[0] == 's') && string[1] == '-') /* S-R-I-S-S */
680 DWORD i = 0, identAuth;
681 DWORD csubauth = ((*size - GetSidLengthRequired(0)) / sizeof(DWORD));
682 DWORD token;
684 string += 2; /* Advance to Revision */
685 parse_token( string, &string, &token );
686 pisid->Revision = token;
688 if (pisid->Revision != SDDL_REVISION)
690 TRACE("Revision %d is unknown\n", pisid->Revision);
691 SetLastError( ERROR_INVALID_SID );
692 return FALSE;
694 if (csubauth == 0)
696 TRACE("SubAuthorityCount is 0\n");
697 SetLastError( ERROR_INVALID_SID );
698 return FALSE;
701 pisid->SubAuthorityCount = csubauth;
703 /* MS' implementation can't handle values greater than 2^32 - 1, so
704 * we don't either; assume most significant bytes are always 0
706 pisid->IdentifierAuthority.Value[0] = 0;
707 pisid->IdentifierAuthority.Value[1] = 0;
708 parse_token( string, &string, &identAuth );
709 pisid->IdentifierAuthority.Value[5] = identAuth & 0xff;
710 pisid->IdentifierAuthority.Value[4] = (identAuth & 0xff00) >> 8;
711 pisid->IdentifierAuthority.Value[3] = (identAuth & 0xff0000) >> 16;
712 pisid->IdentifierAuthority.Value[2] = (identAuth & 0xff000000) >> 24;
714 while (parse_token( string, &string, &token ))
716 pisid->SubAuthority[i++] = token;
719 if (i != pisid->SubAuthorityCount)
721 SetLastError( ERROR_INVALID_SID );
722 return FALSE;
725 if (end)
726 assert(*end == string);
728 return TRUE;
730 else /* String constant format - Only available in winxp and above */
732 unsigned int i;
733 pisid->Revision = SDDL_REVISION;
735 for (i = 0; i < ARRAY_SIZE(well_known_sids); i++)
737 if (!wcsnicmp(well_known_sids[i].str, string, 2))
739 DWORD j;
740 pisid->SubAuthorityCount = well_known_sids[i].sid.SubAuthorityCount;
741 pisid->IdentifierAuthority = well_known_sids[i].sid.IdentifierAuthority;
742 for (j = 0; j < well_known_sids[i].sid.SubAuthorityCount; j++)
743 pisid->SubAuthority[j] = well_known_sids[i].sid.SubAuthority[j];
744 return TRUE;
748 for (i = 0; i < ARRAY_SIZE(well_known_rids); i++)
750 if (!wcsnicmp(well_known_rids[i].str, string, 2))
752 get_computer_sid(pisid);
753 pisid->SubAuthority[pisid->SubAuthorityCount] = well_known_rids[i].rid;
754 pisid->SubAuthorityCount++;
755 return TRUE;
759 FIXME("String constant not supported: %s\n", debugstr_wn(string, 2));
760 SetLastError( ERROR_INVALID_SID );
761 return FALSE;
765 /******************************************************************************
766 * ConvertStringSidToSidW (sechost.@)
768 BOOL WINAPI DECLSPEC_HOTPATCH ConvertStringSidToSidW( const WCHAR *string, PSID *sid )
770 DWORD size;
771 const WCHAR *string_end;
773 TRACE("%s, %p\n", debugstr_w(string), sid);
775 if (GetVersion() & 0x80000000)
777 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
778 return FALSE;
781 if (!string || !sid)
783 SetLastError(ERROR_INVALID_PARAMETER);
784 return FALSE;
787 if (!parse_sid( string, &string_end, NULL, &size ))
788 return FALSE;
790 if (*string_end)
792 SetLastError(ERROR_INVALID_SID);
793 return FALSE;
796 *sid = LocalAlloc( 0, size );
798 if (!parse_sid( string, NULL, *sid, &size ))
800 LocalFree( *sid );
801 return FALSE;
803 return TRUE;
806 static DWORD parse_acl_flags( const WCHAR **string_ptr )
808 DWORD flags = 0;
809 const WCHAR *string = *string_ptr;
811 while (*string && *string != '(')
813 if (*string == 'P')
815 flags |= SE_DACL_PROTECTED;
817 else if (*string == 'A')
819 string++;
820 if (*string == 'R')
821 flags |= SE_DACL_AUTO_INHERIT_REQ;
822 else if (*string == 'I')
823 flags |= SE_DACL_AUTO_INHERITED;
825 string++;
828 *string_ptr = string;
829 return flags;
832 static BYTE parse_ace_type( const WCHAR **string_ptr )
834 static const struct
836 const WCHAR *str;
837 DWORD value;
839 ace_types[] =
841 { L"AL", SYSTEM_ALARM_ACE_TYPE },
842 { L"AU", SYSTEM_AUDIT_ACE_TYPE },
843 { L"A", ACCESS_ALLOWED_ACE_TYPE },
844 { L"D", ACCESS_DENIED_ACE_TYPE },
845 { L"ML", SYSTEM_MANDATORY_LABEL_ACE_TYPE },
847 { ACCESS_ALLOWED_OBJECT_ACE_TYPE },
848 { ACCESS_DENIED_OBJECT_ACE_TYPE },
849 { SYSTEM_ALARM_OBJECT_ACE_TYPE },
850 { SYSTEM_AUDIT_OBJECT_ACE_TYPE },
854 const WCHAR *string = *string_ptr;
855 unsigned int i;
857 while (*string == ' ')
858 string++;
860 for (i = 0; i < ARRAY_SIZE(ace_types); ++i)
862 size_t len = wcslen( ace_types[i].str );
863 if (!wcsncmp( string, ace_types[i].str, len ))
865 *string_ptr = string + len;
866 return ace_types[i].value;
869 return 0;
872 static DWORD parse_ace_flag( const WCHAR *string )
874 static const struct
876 WCHAR str[3];
877 DWORD value;
879 ace_flags[] =
881 { L"CI", CONTAINER_INHERIT_ACE },
882 { L"FA", FAILED_ACCESS_ACE_FLAG },
883 { L"ID", INHERITED_ACE },
884 { L"IO", INHERIT_ONLY_ACE },
885 { L"NP", NO_PROPAGATE_INHERIT_ACE },
886 { L"OI", OBJECT_INHERIT_ACE },
887 { L"SA", SUCCESSFUL_ACCESS_ACE_FLAG },
890 unsigned int i;
892 for (i = 0; i < ARRAY_SIZE(ace_flags); ++i)
894 if (!wcsncmp( string, ace_flags[i].str, 2 ))
895 return ace_flags[i].value;
897 return 0;
900 static DWORD parse_ace_right( const WCHAR **string_ptr )
902 const WCHAR *string = *string_ptr;
903 unsigned int i;
905 if (iswdigit( string[0] ))
906 return wcstoul( string, (WCHAR **)string_ptr, 0 );
908 for (i = 0; i < ARRAY_SIZE(ace_rights); ++i)
910 if (!wcsncmp( string, ace_rights[i].str, 2 ))
912 *string_ptr += 2;
913 return ace_rights[i].value;
916 return 0;
919 static BYTE parse_ace_flags( const WCHAR **string_ptr )
921 const WCHAR *string = *string_ptr;
922 BYTE flags = 0;
924 while (*string == ' ')
925 string++;
927 while (*string != ';')
929 DWORD flag = parse_ace_flag( string );
930 if (!flag) return 0;
931 flags |= flag;
932 string += 2;
935 *string_ptr = string;
936 return flags;
939 static DWORD parse_ace_rights( const WCHAR **string_ptr )
941 DWORD rights = 0;
942 const WCHAR *string = *string_ptr;
944 while (*string == ' ')
945 string++;
947 while (*string != ';')
949 DWORD right = parse_ace_right( &string );
950 if (!right) return 0;
951 rights |= right;
954 *string_ptr = string;
955 return rights;
958 static BOOL parse_acl( const WCHAR *string, DWORD *flags, ACL *acl, DWORD *ret_size )
960 DWORD val;
961 DWORD sidlen;
962 DWORD length = sizeof(ACL);
963 DWORD acesize = 0;
964 DWORD acecount = 0;
965 ACCESS_ALLOWED_ACE *ace = NULL; /* pointer to current ACE */
967 TRACE("%s\n", debugstr_w(string));
969 if (acl) /* ace is only useful if we're setting values */
970 ace = (ACCESS_ALLOWED_ACE *)(acl + 1);
972 /* Parse ACL flags */
973 *flags = parse_acl_flags( &string );
975 /* Parse ACE */
976 while (*string == '(')
978 string++;
980 /* Parse ACE type */
981 val = parse_ace_type( &string );
982 if (ace)
983 ace->Header.AceType = val;
984 if (*string != ';')
986 SetLastError( RPC_S_INVALID_STRING_UUID );
987 return FALSE;
989 string++;
991 /* Parse ACE flags */
992 val = parse_ace_flags( &string );
993 if (ace)
994 ace->Header.AceFlags = val;
995 if (*string != ';')
996 goto err;
997 string++;
999 /* Parse ACE rights */
1000 val = parse_ace_rights( &string );
1001 if (ace)
1002 ace->Mask = val;
1003 if (*string != ';')
1004 goto err;
1005 string++;
1007 /* Parse ACE object guid */
1008 while (*string == ' ')
1009 string++;
1010 if (*string != ';')
1012 FIXME("Support for *_OBJECT_ACE_TYPE not implemented\n");
1013 goto err;
1015 string++;
1017 /* Parse ACE inherit object guid */
1018 while (*string == ' ')
1019 string++;
1020 if (*string != ';')
1022 FIXME("Support for *_OBJECT_ACE_TYPE not implemented\n");
1023 goto err;
1025 string++;
1027 /* Parse ACE account sid */
1028 if (!parse_sid( string, &string, ace ? (SID *)&ace->SidStart : NULL, &sidlen ))
1029 goto err;
1031 while (*string == ' ')
1032 string++;
1034 if (*string != ')')
1035 goto err;
1036 string++;
1038 acesize = sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + sidlen;
1039 length += acesize;
1040 if (ace)
1042 ace->Header.AceSize = acesize;
1043 ace = (ACCESS_ALLOWED_ACE *)((BYTE *)ace + acesize);
1045 acecount++;
1048 *ret_size = length;
1050 if (length > 0xffff)
1052 ERR("ACL too large\n");
1053 goto err;
1056 if (acl)
1058 acl->AclRevision = ACL_REVISION;
1059 acl->Sbz1 = 0;
1060 acl->AclSize = length;
1061 acl->AceCount = acecount;
1062 acl->Sbz2 = 0;
1064 return TRUE;
1066 err:
1067 SetLastError( ERROR_INVALID_ACL );
1068 WARN("Invalid ACE string format\n");
1069 return FALSE;
1072 static BOOL parse_sd( const WCHAR *string, SECURITY_DESCRIPTOR_RELATIVE *sd, DWORD *size)
1074 BOOL ret = FALSE;
1075 WCHAR toktype;
1076 WCHAR *tok;
1077 const WCHAR *lptoken;
1078 BYTE *next = NULL;
1079 DWORD len;
1081 *size = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
1083 tok = heap_alloc( (wcslen(string) + 1) * sizeof(WCHAR) );
1084 if (!tok)
1086 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1087 return FALSE;
1090 if (sd)
1091 next = (BYTE *)(sd + 1);
1093 while (*string == ' ')
1094 string++;
1096 while (*string)
1098 toktype = *string;
1100 /* Expect char identifier followed by ':' */
1101 string++;
1102 if (*string != ':')
1104 SetLastError( ERROR_INVALID_PARAMETER );
1105 goto out;
1107 string++;
1109 /* Extract token */
1110 lptoken = string;
1111 while (*lptoken && *lptoken != ':')
1112 lptoken++;
1114 if (*lptoken)
1115 lptoken--;
1117 len = lptoken - string;
1118 memcpy( tok, string, len * sizeof(WCHAR) );
1119 tok[len] = 0;
1121 switch (toktype)
1123 case 'O':
1125 DWORD bytes;
1127 if (!parse_sid( tok, NULL, (SID *)next, &bytes ))
1128 goto out;
1130 if (sd)
1132 sd->Owner = next - (BYTE *)sd;
1133 next += bytes; /* Advance to next token */
1136 *size += bytes;
1138 break;
1141 case 'G':
1143 DWORD bytes;
1145 if (!parse_sid( tok, NULL, (SID *)next, &bytes ))
1146 goto out;
1148 if (sd)
1150 sd->Group = next - (BYTE *)sd;
1151 next += bytes; /* Advance to next token */
1154 *size += bytes;
1156 break;
1159 case 'D':
1161 DWORD flags;
1162 DWORD bytes;
1164 if (!parse_acl( tok, &flags, (ACL *)next, &bytes ))
1165 goto out;
1167 if (sd)
1169 sd->Control |= SE_DACL_PRESENT | flags;
1170 sd->Dacl = next - (BYTE *)sd;
1171 next += bytes; /* Advance to next token */
1174 *size += bytes;
1176 break;
1179 case 'S':
1181 DWORD flags;
1182 DWORD bytes;
1184 if (!parse_acl( tok, &flags, (ACL *)next, &bytes ))
1185 goto out;
1187 if (sd)
1189 sd->Control |= SE_SACL_PRESENT | flags;
1190 sd->Sacl = next - (BYTE *)sd;
1191 next += bytes; /* Advance to next token */
1194 *size += bytes;
1196 break;
1199 default:
1200 FIXME("Unknown token\n");
1201 SetLastError( ERROR_INVALID_PARAMETER );
1202 goto out;
1205 string = lptoken;
1208 ret = TRUE;
1210 out:
1211 heap_free(tok);
1212 return ret;
1215 /******************************************************************************
1216 * ConvertStringSecurityDescriptorToSecurityDescriptorW (sechost.@)
1218 BOOL WINAPI DECLSPEC_HOTPATCH ConvertStringSecurityDescriptorToSecurityDescriptorW(
1219 const WCHAR *string, DWORD revision, PSECURITY_DESCRIPTOR *sd, ULONG *ret_size )
1221 DWORD size;
1222 SECURITY_DESCRIPTOR *psd;
1224 TRACE("%s, %lu, %p, %p\n", debugstr_w(string), revision, sd, ret_size);
1226 if (GetVersion() & 0x80000000)
1228 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1229 return FALSE;
1231 if (!string || !sd)
1233 SetLastError(ERROR_INVALID_PARAMETER);
1234 return FALSE;
1236 if (revision != SID_REVISION)
1238 SetLastError(ERROR_UNKNOWN_REVISION);
1239 return FALSE;
1242 /* Compute security descriptor length */
1243 if (!parse_sd( string, NULL, &size ))
1244 return FALSE;
1246 psd = *sd = LocalAlloc( GMEM_ZEROINIT, size );
1247 if (!psd)
1249 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1250 return FALSE;
1253 psd->Revision = SID_REVISION;
1254 psd->Control |= SE_SELF_RELATIVE;
1256 if (!parse_sd( string, (SECURITY_DESCRIPTOR_RELATIVE *)psd, &size ))
1258 LocalFree(psd);
1259 return FALSE;
1262 if (ret_size) *ret_size = size;
1263 return TRUE;