widl: Strip last separator in append_namespaces if suffix is NULL.
[wine.git] / dlls / sechost / security.c
blob47ffba9ed52ff8d517519904852ae39b21fbf0a0
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 <stdarg.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "sddl.h"
25 #include "iads.h"
27 #include "wine/debug.h"
28 #include "wine/heap.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(security);
32 static const struct
34 WCHAR str[3];
35 DWORD value;
37 ace_rights[] =
39 { L"GA", GENERIC_ALL },
40 { L"GR", GENERIC_READ },
41 { L"GW", GENERIC_WRITE },
42 { L"GX", GENERIC_EXECUTE },
44 { L"RC", READ_CONTROL },
45 { L"SD", DELETE },
46 { L"WD", WRITE_DAC },
47 { L"WO", WRITE_OWNER },
49 { L"RP", ADS_RIGHT_DS_READ_PROP },
50 { L"WP", ADS_RIGHT_DS_WRITE_PROP },
51 { L"CC", ADS_RIGHT_DS_CREATE_CHILD },
52 { L"DC", ADS_RIGHT_DS_DELETE_CHILD },
53 { L"LC", ADS_RIGHT_ACTRL_DS_LIST },
54 { L"SW", ADS_RIGHT_DS_SELF },
55 { L"LO", ADS_RIGHT_DS_LIST_OBJECT },
56 { L"DT", ADS_RIGHT_DS_DELETE_TREE },
57 { L"CR", ADS_RIGHT_DS_CONTROL_ACCESS },
59 { L"FA", FILE_ALL_ACCESS },
60 { L"FR", FILE_GENERIC_READ },
61 { L"FW", FILE_GENERIC_WRITE },
62 { L"FX", FILE_GENERIC_EXECUTE },
64 { L"KA", KEY_ALL_ACCESS },
65 { L"KR", KEY_READ },
66 { L"KW", KEY_WRITE },
67 { L"KX", KEY_EXECUTE },
69 { L"NR", SYSTEM_MANDATORY_LABEL_NO_READ_UP },
70 { L"NW", SYSTEM_MANDATORY_LABEL_NO_WRITE_UP },
71 { L"NX", SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP },
74 struct max_sid
76 /* same fields as struct _SID */
77 BYTE Revision;
78 BYTE SubAuthorityCount;
79 SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
80 DWORD SubAuthority[SID_MAX_SUB_AUTHORITIES];
83 static const struct
85 WCHAR str[2];
86 WELL_KNOWN_SID_TYPE Type;
87 struct max_sid sid;
89 well_known_sids[] =
91 { {0,0}, WinNullSid, { SID_REVISION, 1, { SECURITY_NULL_SID_AUTHORITY }, { SECURITY_NULL_RID } } },
92 { {'W','D'}, WinWorldSid, { SID_REVISION, 1, { SECURITY_WORLD_SID_AUTHORITY }, { SECURITY_WORLD_RID } } },
93 { {0,0}, WinLocalSid, { SID_REVISION, 1, { SECURITY_LOCAL_SID_AUTHORITY }, { SECURITY_LOCAL_RID } } },
94 { {'C','O'}, WinCreatorOwnerSid, { SID_REVISION, 1, { SECURITY_CREATOR_SID_AUTHORITY }, { SECURITY_CREATOR_OWNER_RID } } },
95 { {'C','G'}, WinCreatorGroupSid, { SID_REVISION, 1, { SECURITY_CREATOR_SID_AUTHORITY }, { SECURITY_CREATOR_GROUP_RID } } },
96 { {'O','W'}, WinCreatorOwnerRightsSid, { SID_REVISION, 1, { SECURITY_CREATOR_SID_AUTHORITY }, { SECURITY_CREATOR_OWNER_RIGHTS_RID } } },
97 { {0,0}, WinCreatorOwnerServerSid, { SID_REVISION, 1, { SECURITY_CREATOR_SID_AUTHORITY }, { SECURITY_CREATOR_OWNER_SERVER_RID } } },
98 { {0,0}, WinCreatorGroupServerSid, { SID_REVISION, 1, { SECURITY_CREATOR_SID_AUTHORITY }, { SECURITY_CREATOR_GROUP_SERVER_RID } } },
99 { {0,0}, WinNtAuthoritySid, { SID_REVISION, 0, { SECURITY_NT_AUTHORITY }, { SECURITY_NULL_RID } } },
100 { {0,0}, WinDialupSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_DIALUP_RID } } },
101 { {'N','U'}, WinNetworkSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_NETWORK_RID } } },
102 { {0,0}, WinBatchSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_BATCH_RID } } },
103 { {'I','U'}, WinInteractiveSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_INTERACTIVE_RID } } },
104 { {'S','U'}, WinServiceSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_SERVICE_RID } } },
105 { {'A','N'}, WinAnonymousSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_ANONYMOUS_LOGON_RID } } },
106 { {0,0}, WinProxySid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_PROXY_RID } } },
107 { {'E','D'}, WinEnterpriseControllersSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_ENTERPRISE_CONTROLLERS_RID } } },
108 { {'P','S'}, WinSelfSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_PRINCIPAL_SELF_RID } } },
109 { {'A','U'}, WinAuthenticatedUserSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_AUTHENTICATED_USER_RID } } },
110 { {'R','C'}, WinRestrictedCodeSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_RESTRICTED_CODE_RID } } },
111 { {0,0}, WinTerminalServerSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_TERMINAL_SERVER_RID } } },
112 { {0,0}, WinRemoteLogonIdSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_REMOTE_LOGON_RID } } },
113 { {0,0}, WinLogonIdsSid, { SID_REVISION, SECURITY_LOGON_IDS_RID_COUNT, { SECURITY_NT_AUTHORITY }, { SECURITY_LOGON_IDS_RID } } },
114 { {'S','Y'}, WinLocalSystemSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_LOCAL_SYSTEM_RID } } },
115 { {'L','S'}, WinLocalServiceSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_LOCAL_SERVICE_RID } } },
116 { {'N','S'}, WinNetworkServiceSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_NETWORK_SERVICE_RID } } },
117 { {0,0}, WinBuiltinDomainSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID } } },
118 { {'B','A'}, WinBuiltinAdministratorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS } } },
119 { {'B','U'}, WinBuiltinUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS } } },
120 { {'B','G'}, WinBuiltinGuestsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS } } },
121 { {'P','U'}, WinBuiltinPowerUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS } } },
122 { {'A','O'}, WinBuiltinAccountOperatorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ACCOUNT_OPS } } },
123 { {'S','O'}, WinBuiltinSystemOperatorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_SYSTEM_OPS } } },
124 { {'P','O'}, WinBuiltinPrintOperatorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_PRINT_OPS } } },
125 { {'B','O'}, WinBuiltinBackupOperatorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_BACKUP_OPS } } },
126 { {'R','E'}, WinBuiltinReplicatorSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_REPLICATOR } } },
127 { {'R','U'}, WinBuiltinPreWindows2000CompatibleAccessSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_PREW2KCOMPACCESS } } },
128 { {'R','D'}, WinBuiltinRemoteDesktopUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS } } },
129 { {'N','O'}, WinBuiltinNetworkConfigurationOperatorsSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS } } },
130 { {0,0}, WinNTLMAuthenticationSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_PACKAGE_BASE_RID, SECURITY_PACKAGE_NTLM_RID } } },
131 { {0,0}, WinDigestAuthenticationSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_PACKAGE_BASE_RID, SECURITY_PACKAGE_DIGEST_RID } } },
132 { {0,0}, WinSChannelAuthenticationSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_PACKAGE_BASE_RID, SECURITY_PACKAGE_SCHANNEL_RID } } },
133 { {0,0}, WinThisOrganizationSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_THIS_ORGANIZATION_RID } } },
134 { {0,0}, WinOtherOrganizationSid, { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_OTHER_ORGANIZATION_RID } } },
135 { {0,0}, WinBuiltinIncomingForestTrustBuildersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS } } },
136 { {0,0}, WinBuiltinPerfMonitoringUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_MONITORING_USERS } } },
137 { {0,0}, WinBuiltinPerfLoggingUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_LOGGING_USERS } } },
138 { {0,0}, WinBuiltinAuthorizationAccessSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS } } },
139 { {0,0}, WinBuiltinTerminalServerLicenseServersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS } } },
140 { {0,0}, WinBuiltinDCOMUsersSid, { SID_REVISION, 2, { SECURITY_NT_AUTHORITY }, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_DCOM_USERS } } },
141 { {'L','W'}, WinLowLabelSid, { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY}, { SECURITY_MANDATORY_LOW_RID} } },
142 { {'M','E'}, WinMediumLabelSid, { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY}, { SECURITY_MANDATORY_MEDIUM_RID } } },
143 { {'H','I'}, WinHighLabelSid, { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY}, { SECURITY_MANDATORY_HIGH_RID } } },
144 { {'S','I'}, WinSystemLabelSid, { SID_REVISION, 1, { SECURITY_MANDATORY_LABEL_AUTHORITY}, { SECURITY_MANDATORY_SYSTEM_RID } } },
145 { {'A','C'}, WinBuiltinAnyPackageSid, { SID_REVISION, 2, { SECURITY_APP_PACKAGE_AUTHORITY }, { SECURITY_APP_PACKAGE_BASE_RID, SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE } } },
148 /* these SIDs must be constructed as relative to some domain - only the RID is well-known */
149 static const struct
151 WCHAR str[2];
152 WELL_KNOWN_SID_TYPE type;
153 DWORD rid;
155 well_known_rids[] =
157 { {'L','A'}, WinAccountAdministratorSid, DOMAIN_USER_RID_ADMIN },
158 { {'L','G'}, WinAccountGuestSid, DOMAIN_USER_RID_GUEST },
159 { {0,0}, WinAccountKrbtgtSid, DOMAIN_USER_RID_KRBTGT },
160 { {'D','A'}, WinAccountDomainAdminsSid, DOMAIN_GROUP_RID_ADMINS },
161 { {'D','U'}, WinAccountDomainUsersSid, DOMAIN_GROUP_RID_USERS },
162 { {'D','G'}, WinAccountDomainGuestsSid, DOMAIN_GROUP_RID_GUESTS },
163 { {'D','C'}, WinAccountComputersSid, DOMAIN_GROUP_RID_COMPUTERS },
164 { {'D','D'}, WinAccountControllersSid, DOMAIN_GROUP_RID_CONTROLLERS },
165 { {'C','A'}, WinAccountCertAdminsSid, DOMAIN_GROUP_RID_CERT_ADMINS },
166 { {'S','A'}, WinAccountSchemaAdminsSid, DOMAIN_GROUP_RID_SCHEMA_ADMINS },
167 { {'E','A'}, WinAccountEnterpriseAdminsSid, DOMAIN_GROUP_RID_ENTERPRISE_ADMINS },
168 { {'P','A'}, WinAccountPolicyAdminsSid, DOMAIN_GROUP_RID_POLICY_ADMINS },
169 { {'R','S'}, WinAccountRasAndIasServersSid, DOMAIN_ALIAS_RID_RAS_SERVERS },
173 static void print_string(const WCHAR *string, int cch, WCHAR **pwptr, ULONG *plen)
175 if (cch == -1)
176 cch = wcslen(string);
178 if (plen)
179 *plen += cch;
181 if (pwptr)
183 memcpy(*pwptr, string, sizeof(WCHAR)*cch);
184 *pwptr += cch;
188 static BOOL print_sid_numeric(PSID psid, WCHAR **pwptr, ULONG *plen)
190 DWORD i;
191 WCHAR buf[26];
192 SID *pisid = psid;
194 if( !IsValidSid( psid ) || pisid->Revision != SDDL_REVISION)
196 SetLastError(ERROR_INVALID_SID);
197 return FALSE;
200 if (pisid->IdentifierAuthority.Value[0] ||
201 pisid->IdentifierAuthority.Value[1])
203 FIXME("not matching MS' bugs\n");
204 SetLastError(ERROR_INVALID_SID);
205 return FALSE;
208 swprintf( buf, ARRAY_SIZE(buf), L"S-%u-%d", pisid->Revision, MAKELONG(
209 MAKEWORD( pisid->IdentifierAuthority.Value[5], pisid->IdentifierAuthority.Value[4] ),
210 MAKEWORD( pisid->IdentifierAuthority.Value[3], pisid->IdentifierAuthority.Value[2] )
211 ) );
212 print_string(buf, -1, pwptr, plen);
214 for( i=0; i<pisid->SubAuthorityCount; i++ )
216 swprintf( buf, ARRAY_SIZE(buf), L"-%u", pisid->SubAuthority[i] );
217 print_string(buf, -1, pwptr, plen);
219 return TRUE;
222 /******************************************************************************
223 * ConvertSidToStringSidW (sechost.@)
225 BOOL WINAPI DECLSPEC_HOTPATCH ConvertSidToStringSidW( PSID sid, WCHAR **pstr )
227 DWORD len = 0;
228 WCHAR *wstr, *wptr;
230 TRACE("%p %p\n", sid, pstr );
232 len = 0;
233 if (!print_sid_numeric( sid, NULL, &len ))
234 return FALSE;
235 wstr = wptr = LocalAlloc( 0, (len + 1) * sizeof(WCHAR) );
236 print_sid_numeric( sid, &wptr, NULL );
237 *wptr = 0;
239 *pstr = wstr;
240 return TRUE;
243 static BOOL print_sid(PSID psid, WCHAR **pwptr, ULONG *plen)
245 size_t i;
246 for (i = 0; i < ARRAY_SIZE(well_known_sids); i++)
248 if (well_known_sids[i].str[0] && EqualSid(psid, (PSID)&well_known_sids[i].sid.Revision))
250 print_string(well_known_sids[i].str, 2, pwptr, plen);
251 return TRUE;
255 return print_sid_numeric(psid, pwptr, plen);
258 static void print_rights(DWORD mask, WCHAR **pwptr, ULONG *plen)
260 static const WCHAR *bit_names[32] =
262 L"CC", /* 0 */
263 L"DC",
264 L"LC",
265 L"SW",
266 L"RP", /* 4 */
267 L"WP",
268 L"DT",
269 L"LO",
270 L"CR", /* 8 */
271 NULL,
272 NULL,
273 NULL,
274 NULL, /* 12 */
275 NULL,
276 NULL,
277 NULL,
278 L"SD", /* 16 */
279 L"RC",
280 L"WD",
281 L"WO",
282 NULL, /* 20 */
283 NULL,
284 NULL,
285 NULL,
286 NULL, /* 24 */
287 NULL,
288 NULL,
289 NULL,
290 L"GA", /* 28 */
291 L"GX",
292 L"GW",
293 L"GR",
296 WCHAR buf[15];
297 size_t i;
299 if (mask == 0)
300 return;
302 /* first check if the right have name */
303 for (i = 0; i < ARRAY_SIZE(ace_rights); i++)
305 if (mask == ace_rights[i].value)
307 print_string(ace_rights[i].str, -1, pwptr, plen);
308 return;
312 /* then check if it can be built from bit names */
313 for (i = 0; i < 32; i++)
315 if ((mask & (1 << i)) && !bit_names[i])
317 /* can't be built from bit names */
318 swprintf(buf, ARRAY_SIZE(buf), L"0x%x", mask);
319 print_string(buf, -1, pwptr, plen);
320 return;
324 /* build from bit names */
325 for (i = 0; i < 32; i++)
326 if (mask & (1 << i))
327 print_string(bit_names[i], -1, pwptr, plen);
330 static inline BOOL is_object_ace(BYTE type)
332 switch (type)
334 case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
335 case ACCESS_DENIED_OBJECT_ACE_TYPE:
336 case ACCESS_AUDIT_OBJECT_ACE_TYPE:
337 case ACCESS_ALARM_OBJECT_ACE_TYPE:
338 case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
339 case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
340 case SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
341 case SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE:
342 return TRUE;
344 default:
345 return FALSE;
349 static BOOL print_ace(void *pace, WCHAR **pwptr, ULONG *plen)
351 ACCESS_ALLOWED_ACE *piace; /* all the supported ACEs have the same memory layout */
352 DWORD *sid_start;
354 piace = pace;
356 if (piace->Header.AceType > ACCESS_MAX_MS_V5_ACE_TYPE || piace->Header.AceSize < sizeof(ACCESS_ALLOWED_ACE))
358 SetLastError(ERROR_INVALID_ACL);
359 return FALSE;
362 print_string(L"(", -1, pwptr, plen);
363 switch (piace->Header.AceType)
365 case ACCESS_ALLOWED_ACE_TYPE:
366 print_string(L"A", -1, pwptr, plen);
367 break;
368 case ACCESS_DENIED_ACE_TYPE:
369 print_string(L"D", -1, pwptr, plen);
370 break;
371 case SYSTEM_AUDIT_ACE_TYPE:
372 print_string(L"AU", -1, pwptr, plen);
373 break;
374 case SYSTEM_ALARM_ACE_TYPE:
375 print_string(L"AL", -1, pwptr, plen);
376 break;
378 print_string(L";", -1, pwptr, plen);
380 if (piace->Header.AceFlags & OBJECT_INHERIT_ACE)
381 print_string(L"OI", -1, pwptr, plen);
382 if (piace->Header.AceFlags & CONTAINER_INHERIT_ACE)
383 print_string(L"CI", -1, pwptr, plen);
384 if (piace->Header.AceFlags & NO_PROPAGATE_INHERIT_ACE)
385 print_string(L"NP", -1, pwptr, plen);
386 if (piace->Header.AceFlags & INHERIT_ONLY_ACE)
387 print_string(L"IO", -1, pwptr, plen);
388 if (piace->Header.AceFlags & INHERITED_ACE)
389 print_string(L"ID", -1, pwptr, plen);
390 if (piace->Header.AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG)
391 print_string(L"SA", -1, pwptr, plen);
392 if (piace->Header.AceFlags & FAILED_ACCESS_ACE_FLAG)
393 print_string(L"FA", -1, pwptr, plen);
394 print_string(L";", -1, pwptr, plen);
395 print_rights(piace->Mask, pwptr, plen);
396 print_string(L";", -1, pwptr, plen);
397 sid_start = &piace->SidStart;
398 if (is_object_ace(piace->Header.AceType))
400 ACCESS_ALLOWED_OBJECT_ACE *objace = pace;
402 sid_start++; /* Flags */
403 if (objace->Flags & ACE_OBJECT_TYPE_PRESENT)
404 sid_start += sizeof(GUID) / sizeof(*sid_start); /* ObjectType */
405 if (objace->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
406 sid_start += sizeof(GUID) / sizeof(*sid_start); /* InheritedObjectType */
408 /* objects not supported */
409 print_string(L";", -1, pwptr, plen);
410 /* objects not supported */
411 print_string(L";", -1, pwptr, plen);
412 if (!print_sid(sid_start, pwptr, plen))
413 return FALSE;
414 print_string(L")", -1, pwptr, plen);
415 return TRUE;
418 static BOOL print_acl(ACL *pacl, WCHAR **pwptr, ULONG *plen, SECURITY_DESCRIPTOR_CONTROL control)
420 WORD count;
421 UINT i;
423 if (control & SE_DACL_PROTECTED)
424 print_string(L"P", -1, pwptr, plen);
425 if (control & SE_DACL_AUTO_INHERIT_REQ)
426 print_string(L"AR", -1, pwptr, plen);
427 if (control & SE_DACL_AUTO_INHERITED)
428 print_string(L"AI", -1, pwptr, plen);
430 if (pacl == NULL)
431 return TRUE;
433 if (!IsValidAcl(pacl))
434 return FALSE;
436 count = pacl->AceCount;
437 for (i = 0; i < count; i++)
439 void *ace;
440 if (!GetAce(pacl, i, &ace))
441 return FALSE;
442 if (!print_ace(ace, pwptr, plen))
443 return FALSE;
446 return TRUE;
449 static BOOL print_owner(PSECURITY_DESCRIPTOR sd, WCHAR **pwptr, ULONG *plen)
451 BOOL defaulted;
452 PSID psid;
454 if (!GetSecurityDescriptorOwner(sd, &psid, &defaulted))
455 return FALSE;
457 if (psid == NULL)
458 return TRUE;
460 print_string(L"O:", -1, pwptr, plen);
461 if (!print_sid(psid, pwptr, plen))
462 return FALSE;
463 return TRUE;
466 static BOOL print_group(PSECURITY_DESCRIPTOR sd, WCHAR **pwptr, ULONG *plen)
468 BOOL defaulted;
469 PSID psid;
471 if (!GetSecurityDescriptorGroup(sd, &psid, &defaulted))
472 return FALSE;
474 if (psid == NULL)
475 return TRUE;
477 print_string(L"G:", -1, pwptr, plen);
478 if (!print_sid(psid, pwptr, plen))
479 return FALSE;
480 return TRUE;
483 static BOOL print_dacl(PSECURITY_DESCRIPTOR sd, WCHAR **pwptr, ULONG *plen)
485 SECURITY_DESCRIPTOR_CONTROL control;
486 BOOL present, defaulted;
487 DWORD revision;
488 ACL *pacl;
490 if (!GetSecurityDescriptorDacl(sd, &present, &pacl, &defaulted))
491 return FALSE;
493 if (!GetSecurityDescriptorControl(sd, &control, &revision))
494 return FALSE;
496 if (!present)
497 return TRUE;
499 print_string(L"D:", -1, pwptr, plen);
500 if (!print_acl(pacl, pwptr, plen, control))
501 return FALSE;
502 return TRUE;
505 static BOOL print_sacl(PSECURITY_DESCRIPTOR sd, WCHAR **pwptr, ULONG *plen)
507 SECURITY_DESCRIPTOR_CONTROL control;
508 BOOL present, defaulted;
509 DWORD revision;
510 ACL *pacl;
512 if (!GetSecurityDescriptorSacl(sd, &present, &pacl, &defaulted))
513 return FALSE;
515 if (!GetSecurityDescriptorControl(sd, &control, &revision))
516 return FALSE;
518 if (!present)
519 return TRUE;
521 print_string(L"S:", -1, pwptr, plen);
522 if (!print_acl(pacl, pwptr, plen, control))
523 return FALSE;
524 return TRUE;
527 /******************************************************************************
528 * ConvertSecurityDescriptorToStringSecurityDescriptorW (sechost.@)
530 BOOL WINAPI DECLSPEC_HOTPATCH ConvertSecurityDescriptorToStringSecurityDescriptorW( PSECURITY_DESCRIPTOR sd,
531 DWORD revision, SECURITY_INFORMATION flags, WCHAR **string, ULONG *ret_len )
533 ULONG len = 0;
534 WCHAR *wptr, *wstr;
536 if (revision != SDDL_REVISION_1)
538 ERR("Unhandled SDDL revision %d\n", revision);
539 SetLastError( ERROR_UNKNOWN_REVISION );
540 return FALSE;
543 if ((flags & OWNER_SECURITY_INFORMATION) && !print_owner(sd, NULL, &len))
544 return FALSE;
545 if ((flags & GROUP_SECURITY_INFORMATION) && !print_group(sd, NULL, &len))
546 return FALSE;
547 if ((flags & DACL_SECURITY_INFORMATION) && !print_dacl(sd, NULL, &len))
548 return FALSE;
549 if ((flags & SACL_SECURITY_INFORMATION) && !print_sacl(sd, NULL, &len))
550 return FALSE;
552 wstr = wptr = LocalAlloc( 0, (len + 1) * sizeof(WCHAR) );
553 if ((flags & OWNER_SECURITY_INFORMATION) && !print_owner(sd, &wptr, NULL))
555 LocalFree(wstr);
556 return FALSE;
558 if ((flags & GROUP_SECURITY_INFORMATION) && !print_group(sd, &wptr, NULL))
560 LocalFree(wstr);
561 return FALSE;
563 if ((flags & DACL_SECURITY_INFORMATION) && !print_dacl(sd, &wptr, NULL))
565 LocalFree(wstr);
566 return FALSE;
568 if ((flags & SACL_SECURITY_INFORMATION) && !print_sacl(sd, &wptr, NULL))
570 LocalFree(wstr);
571 return FALSE;
573 *wptr = 0;
575 TRACE("ret: %s, %d\n", wine_dbgstr_w(wstr), len);
576 *string = wstr;
577 if (ret_len) *ret_len = wcslen(*string) + 1;
578 return TRUE;
581 static BOOL get_computer_sid( PSID sid )
583 static const struct /* same fields as struct SID */
585 BYTE Revision;
586 BYTE SubAuthorityCount;
587 SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
588 DWORD SubAuthority[4];
589 } computer_sid =
590 { SID_REVISION, 4, { SECURITY_NT_AUTHORITY }, { SECURITY_NT_NON_UNIQUE, 0, 0, 0 } };
592 memcpy( sid, &computer_sid, sizeof(computer_sid) );
593 return TRUE;
596 static DWORD get_sid_size( const WCHAR *string )
598 if (string[0] == 'S' && string[1] == '-') /* S-R-I(-S)+ */
600 int token_count = 0;
601 while (*string)
603 if (*string == '-')
604 token_count++;
605 string++;
608 if (token_count >= 3)
609 return GetSidLengthRequired( token_count - 2 );
611 else /* String constant format - Only available in winxp and above */
613 unsigned int i;
615 for (i = 0; i < ARRAY_SIZE(well_known_sids); i++)
617 if (!wcsncmp( well_known_sids[i].str, string, 2 ))
618 return GetSidLengthRequired( well_known_sids[i].sid.SubAuthorityCount );
621 for (i = 0; i < ARRAY_SIZE(well_known_rids); i++)
623 if (!wcsncmp( well_known_rids[i].str, string, 2 ))
625 struct max_sid local;
626 get_computer_sid(&local);
627 return GetSidLengthRequired( *GetSidSubAuthorityCount(&local) + 1 );
632 return GetSidLengthRequired( 0 );
635 static BOOL parse_sid( const WCHAR *string, SID *pisid, DWORD *size )
637 while (*string == ' ')
638 string++;
640 *size = get_sid_size( string );
641 if (!pisid) /* Simply compute the size */
642 return TRUE;
644 if (string[0] == 'S' && string[1] == '-') /* S-R-I-S-S */
646 DWORD i = 0, identAuth;
647 DWORD csubauth = ((*size - GetSidLengthRequired(0)) / sizeof(DWORD));
649 string += 2; /* Advance to Revision */
650 pisid->Revision = wcstoul( string, NULL, 10 );
652 if (pisid->Revision != SDDL_REVISION)
654 TRACE("Revision %d is unknown\n", pisid->Revision);
655 SetLastError( ERROR_INVALID_SID );
656 return FALSE;
658 if (csubauth == 0)
660 TRACE("SubAuthorityCount is 0\n");
661 SetLastError( ERROR_INVALID_SID );
662 return FALSE;
665 pisid->SubAuthorityCount = csubauth;
667 /* Advance to identifier authority */
668 while (*string && *string != '-')
669 string++;
670 if (*string == '-')
671 string++;
673 /* MS' implementation can't handle values greater than 2^32 - 1, so
674 * we don't either; assume most significant bytes are always 0
676 pisid->IdentifierAuthority.Value[0] = 0;
677 pisid->IdentifierAuthority.Value[1] = 0;
678 identAuth = wcstoul( string, NULL, 10 );
679 pisid->IdentifierAuthority.Value[5] = identAuth & 0xff;
680 pisid->IdentifierAuthority.Value[4] = (identAuth & 0xff00) >> 8;
681 pisid->IdentifierAuthority.Value[3] = (identAuth & 0xff0000) >> 16;
682 pisid->IdentifierAuthority.Value[2] = (identAuth & 0xff000000) >> 24;
684 /* Advance to first sub authority */
685 while (*string && *string != '-')
686 string++;
687 if (*string == '-')
688 string++;
690 while (*string)
692 pisid->SubAuthority[i++] = wcstoul( string, NULL, 10 );
694 while (*string && *string != '-')
695 string++;
696 if (*string == '-')
697 string++;
700 if (i != pisid->SubAuthorityCount)
702 SetLastError( ERROR_INVALID_SID );
703 return FALSE;
706 return TRUE;
708 else /* String constant format - Only available in winxp and above */
710 unsigned int i;
711 pisid->Revision = SDDL_REVISION;
713 for (i = 0; i < ARRAY_SIZE(well_known_sids); i++)
715 if (!wcsncmp(well_known_sids[i].str, string, 2))
717 DWORD j;
718 pisid->SubAuthorityCount = well_known_sids[i].sid.SubAuthorityCount;
719 pisid->IdentifierAuthority = well_known_sids[i].sid.IdentifierAuthority;
720 for (j = 0; j < well_known_sids[i].sid.SubAuthorityCount; j++)
721 pisid->SubAuthority[j] = well_known_sids[i].sid.SubAuthority[j];
722 return TRUE;
726 for (i = 0; i < ARRAY_SIZE(well_known_rids); i++)
728 if (!wcsncmp(well_known_rids[i].str, string, 2))
730 get_computer_sid(pisid);
731 pisid->SubAuthority[pisid->SubAuthorityCount] = well_known_rids[i].rid;
732 pisid->SubAuthorityCount++;
733 return TRUE;
737 FIXME("String constant not supported: %s\n", debugstr_wn(string, 2));
738 SetLastError( ERROR_INVALID_SID );
739 return FALSE;
743 /******************************************************************************
744 * ConvertStringSidToSidW (sechost.@)
746 BOOL WINAPI DECLSPEC_HOTPATCH ConvertStringSidToSidW( const WCHAR *string, PSID *sid )
748 DWORD size;
750 TRACE("%s, %p\n", debugstr_w(string), sid);
752 if (GetVersion() & 0x80000000)
754 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
755 return FALSE;
758 if (!string || !sid)
760 SetLastError(ERROR_INVALID_PARAMETER);
761 return FALSE;
764 if (!parse_sid( string, NULL, &size ))
765 return FALSE;
767 *sid = LocalAlloc( 0, size );
769 if (!parse_sid( string, *sid, &size ))
771 LocalFree( *sid );
772 return FALSE;
774 return TRUE;
777 static DWORD parse_acl_flags( const WCHAR **string_ptr )
779 DWORD flags = 0;
780 const WCHAR *string = *string_ptr;
782 while (*string && *string != '(')
784 if (*string == 'P')
786 flags |= SE_DACL_PROTECTED;
788 else if (*string == 'A')
790 string++;
791 if (*string == 'R')
792 flags |= SE_DACL_AUTO_INHERIT_REQ;
793 else if (*string == 'I')
794 flags |= SE_DACL_AUTO_INHERITED;
796 string++;
799 *string_ptr = string;
800 return flags;
803 static BYTE parse_ace_type( const WCHAR **string_ptr )
805 static const struct
807 const WCHAR *str;
808 DWORD value;
810 ace_types[] =
812 { L"AL", SYSTEM_ALARM_ACE_TYPE },
813 { L"AU", SYSTEM_AUDIT_ACE_TYPE },
814 { L"A", ACCESS_ALLOWED_ACE_TYPE },
815 { L"D", ACCESS_DENIED_ACE_TYPE },
816 { L"ML", SYSTEM_MANDATORY_LABEL_ACE_TYPE },
818 { ACCESS_ALLOWED_OBJECT_ACE_TYPE },
819 { ACCESS_DENIED_OBJECT_ACE_TYPE },
820 { SYSTEM_ALARM_OBJECT_ACE_TYPE },
821 { SYSTEM_AUDIT_OBJECT_ACE_TYPE },
825 const WCHAR *string = *string_ptr;
826 unsigned int i;
828 while (*string == ' ')
829 string++;
831 for (i = 0; i < ARRAY_SIZE(ace_types); ++i)
833 size_t len = wcslen( ace_types[i].str );
834 if (!wcsncmp( string, ace_types[i].str, len ))
836 *string_ptr = string + len;
837 return ace_types[i].value;
840 return 0;
843 static DWORD parse_ace_flag( const WCHAR *string )
845 static const struct
847 WCHAR str[3];
848 DWORD value;
850 ace_flags[] =
852 { L"CI", CONTAINER_INHERIT_ACE },
853 { L"FA", FAILED_ACCESS_ACE_FLAG },
854 { L"ID", INHERITED_ACE },
855 { L"IO", INHERIT_ONLY_ACE },
856 { L"NP", NO_PROPAGATE_INHERIT_ACE },
857 { L"OI", OBJECT_INHERIT_ACE },
858 { L"SA", SUCCESSFUL_ACCESS_ACE_FLAG },
861 unsigned int i;
863 for (i = 0; i < ARRAY_SIZE(ace_flags); ++i)
865 if (!wcsncmp( string, ace_flags[i].str, 2 ))
866 return ace_flags[i].value;
868 return 0;
871 static DWORD parse_ace_right( const WCHAR *string )
873 unsigned int i;
875 for (i = 0; i < ARRAY_SIZE(ace_rights); ++i)
877 if (!wcsncmp( string, ace_rights[i].str, 2 ))
878 return ace_rights[i].value;
880 return 0;
883 static BYTE parse_ace_flags( const WCHAR **string_ptr )
885 const WCHAR *string = *string_ptr;
886 BYTE flags = 0;
888 while (*string == ' ')
889 string++;
891 while (*string != ';')
893 DWORD flag = parse_ace_flag( string );
894 if (!flag) return 0;
895 flags |= flag;
896 string += 2;
899 *string_ptr = string;
900 return flags;
903 static DWORD parse_ace_rights( const WCHAR **string_ptr )
905 DWORD rights = 0;
906 const WCHAR *string = *string_ptr;
908 while (*string == ' ')
909 string++;
911 if (string[0] == '0' && string[1] == 'x')
913 const WCHAR *p = string;
915 while (*p && *p != ';')
916 p++;
918 if (p - string <= 10 /* 8 hex digits + "0x" */ )
920 rights = wcstoul( string, NULL, 16 );
921 string = p;
923 else
924 WARN("Invalid rights string format: %s\n", debugstr_wn(string, p - string));
926 else
928 while (*string != ';')
930 DWORD right = parse_ace_right( string );
931 if (!right) return 0;
932 rights |= right;
933 string += 2;
937 *string_ptr = string;
938 return rights;
941 static BOOL parse_acl( const WCHAR *string, DWORD *flags, ACL *acl, DWORD *ret_size )
943 DWORD val;
944 DWORD sidlen;
945 DWORD length = sizeof(ACL);
946 DWORD acesize = 0;
947 DWORD acecount = 0;
948 ACCESS_ALLOWED_ACE *ace = NULL; /* pointer to current ACE */
950 TRACE("%s\n", debugstr_w(string));
952 if (acl) /* ace is only useful if we're setting values */
953 ace = (ACCESS_ALLOWED_ACE *)(acl + 1);
955 /* Parse ACL flags */
956 *flags = parse_acl_flags( &string );
958 /* Parse ACE */
959 while (*string == '(')
961 string++;
963 /* Parse ACE type */
964 val = parse_ace_type( &string );
965 if (ace)
966 ace->Header.AceType = val;
967 if (*string != ';')
969 SetLastError( RPC_S_INVALID_STRING_UUID );
970 return FALSE;
972 string++;
974 /* Parse ACE flags */
975 val = parse_ace_flags( &string );
976 if (ace)
977 ace->Header.AceFlags = val;
978 if (*string != ';')
979 goto err;
980 string++;
982 /* Parse ACE rights */
983 val = parse_ace_rights( &string );
984 if (ace)
985 ace->Mask = val;
986 if (*string != ';')
987 goto err;
988 string++;
990 /* Parse ACE object guid */
991 while (*string == ' ')
992 string++;
993 if (*string != ';')
995 FIXME("Support for *_OBJECT_ACE_TYPE not implemented\n");
996 goto err;
998 string++;
1000 /* Parse ACE inherit object guid */
1001 while (*string == ' ')
1002 string++;
1003 if (*string != ';')
1005 FIXME("Support for *_OBJECT_ACE_TYPE not implemented\n");
1006 goto err;
1008 string++;
1010 /* Parse ACE account sid */
1011 if (parse_sid( string, ace ? (SID *)&ace->SidStart : NULL, &sidlen ))
1013 while (*string && *string != ')')
1014 string++;
1017 if (*string != ')')
1018 goto err;
1019 string++;
1021 acesize = sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + sidlen;
1022 length += acesize;
1023 if (ace)
1025 ace->Header.AceSize = acesize;
1026 ace = (ACCESS_ALLOWED_ACE *)((BYTE *)ace + acesize);
1028 acecount++;
1031 *ret_size = length;
1033 if (length > 0xffff)
1035 ERR("ACL too large\n");
1036 goto err;
1039 if (acl)
1041 acl->AclRevision = ACL_REVISION;
1042 acl->Sbz1 = 0;
1043 acl->AclSize = length;
1044 acl->AceCount = acecount;
1045 acl->Sbz2 = 0;
1047 return TRUE;
1049 err:
1050 SetLastError( ERROR_INVALID_ACL );
1051 WARN("Invalid ACE string format\n");
1052 return FALSE;
1055 static BOOL parse_sd( const WCHAR *string, SECURITY_DESCRIPTOR_RELATIVE *sd, DWORD *size)
1057 BOOL ret = FALSE;
1058 WCHAR toktype;
1059 WCHAR *tok;
1060 const WCHAR *lptoken;
1061 BYTE *next = NULL;
1062 DWORD len;
1064 *size = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
1066 tok = heap_alloc( (wcslen(string) + 1) * sizeof(WCHAR) );
1067 if (!tok)
1069 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1070 return FALSE;
1073 if (sd)
1074 next = (BYTE *)(sd + 1);
1076 while (*string == ' ')
1077 string++;
1079 while (*string)
1081 toktype = *string;
1083 /* Expect char identifier followed by ':' */
1084 string++;
1085 if (*string != ':')
1087 SetLastError( ERROR_INVALID_PARAMETER );
1088 goto out;
1090 string++;
1092 /* Extract token */
1093 lptoken = string;
1094 while (*lptoken && *lptoken != ':')
1095 lptoken++;
1097 if (*lptoken)
1098 lptoken--;
1100 len = lptoken - string;
1101 memcpy( tok, string, len * sizeof(WCHAR) );
1102 tok[len] = 0;
1104 switch (toktype)
1106 case 'O':
1108 DWORD bytes;
1110 if (!parse_sid( tok, (SID *)next, &bytes ))
1111 goto out;
1113 if (sd)
1115 sd->Owner = next - (BYTE *)sd;
1116 next += bytes; /* Advance to next token */
1119 *size += bytes;
1121 break;
1124 case 'G':
1126 DWORD bytes;
1128 if (!parse_sid( tok, (SID *)next, &bytes ))
1129 goto out;
1131 if (sd)
1133 sd->Group = next - (BYTE *)sd;
1134 next += bytes; /* Advance to next token */
1137 *size += bytes;
1139 break;
1142 case 'D':
1144 DWORD flags;
1145 DWORD bytes;
1147 if (!parse_acl( tok, &flags, (ACL *)next, &bytes ))
1148 goto out;
1150 if (sd)
1152 sd->Control |= SE_DACL_PRESENT | flags;
1153 sd->Dacl = next - (BYTE *)sd;
1154 next += bytes; /* Advance to next token */
1157 *size += bytes;
1159 break;
1162 case 'S':
1164 DWORD flags;
1165 DWORD bytes;
1167 if (!parse_acl( tok, &flags, (ACL *)next, &bytes ))
1168 goto out;
1170 if (sd)
1172 sd->Control |= SE_SACL_PRESENT | flags;
1173 sd->Sacl = next - (BYTE *)sd;
1174 next += bytes; /* Advance to next token */
1177 *size += bytes;
1179 break;
1182 default:
1183 FIXME("Unknown token\n");
1184 SetLastError( ERROR_INVALID_PARAMETER );
1185 goto out;
1188 string = lptoken;
1191 ret = TRUE;
1193 out:
1194 heap_free(tok);
1195 return ret;
1198 /******************************************************************************
1199 * ConvertStringSecurityDescriptorToSecurityDescriptorW (sechost.@)
1201 BOOL WINAPI DECLSPEC_HOTPATCH ConvertStringSecurityDescriptorToSecurityDescriptorW(
1202 const WCHAR *string, DWORD revision, PSECURITY_DESCRIPTOR *sd, ULONG *ret_size )
1204 DWORD size;
1205 SECURITY_DESCRIPTOR *psd;
1207 TRACE("%s, %u, %p, %p\n", debugstr_w(string), revision, sd, ret_size);
1209 if (GetVersion() & 0x80000000)
1211 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1212 return FALSE;
1214 if (!string || !sd)
1216 SetLastError(ERROR_INVALID_PARAMETER);
1217 return FALSE;
1219 if (revision != SID_REVISION)
1221 SetLastError(ERROR_UNKNOWN_REVISION);
1222 return FALSE;
1225 /* Compute security descriptor length */
1226 if (!parse_sd( string, NULL, &size ))
1227 return FALSE;
1229 psd = *sd = LocalAlloc( GMEM_ZEROINIT, size );
1230 if (!psd)
1232 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1233 return FALSE;
1236 psd->Revision = SID_REVISION;
1237 psd->Control |= SE_SELF_RELATIVE;
1239 if (!parse_sd( string, (SECURITY_DESCRIPTOR_RELATIVE *)psd, &size ))
1241 LocalFree(psd);
1242 return FALSE;
1245 if (ret_size) *ret_size = size;
1246 return TRUE;