Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5448 lines
152 KiB

  1. /*++
  2. Copyright (c) 1997-1998 Microsoft Corporation
  3. Module Name:
  4. sddl.c
  5. Abstract:
  6. This module implements the Security Descriptor Definition Language support functions
  7. Author:
  8. Mac McLain (MacM) Nov 07, 1997
  9. Environment:
  10. User Mode
  11. Revision History:
  12. Jin Huang (JinHuang) 3/4/98 Fix validity flags (GetAceFlagsInTable)
  13. Jin Huang (JinHuang) 3/10/98 Add SD controls (GetSDControlForString)
  14. Set SidsInitialized flag
  15. Skip any possible spaces in string
  16. Jin Huang (JinHuang) 5/1/98 Fix memory leek, error checking
  17. improve performance
  18. Alaa Abdelhalim (Alaa) 7/20/99 Initialize sbz2 field to 0 in LocalGetAclForString
  19. function.
  20. Vishnu Patankar (VishnuP) 7/5/00 Added new API ConvertStringSDToSDDomain(A/W)
  21. --*/
  22. #include "advapi.h"
  23. #include <windef.h>
  24. #include <stdio.h>
  25. #include <wchar.h>
  26. #include <sddl.h>
  27. #include <ntseapi.h>
  28. #include <seopaque.h>
  29. #include <accctrl.h>
  30. #include <rpcdce.h>
  31. #include <ntlsa.h>
  32. #include "sddlp.h"
  33. //
  34. // include and defines for ldap calls
  35. //
  36. #include <winldap.h>
  37. #include <ntldap.h>
  38. typedef LDAP * (LDAPAPI *PFN_LDAP_OPEN)( PCHAR, ULONG );
  39. typedef ULONG (LDAPAPI *PFN_LDAP_UNBIND)( LDAP * );
  40. typedef ULONG (LDAPAPI *PFN_LDAP_SEARCH)(LDAP *, PCHAR, ULONG, PCHAR, PCHAR *, ULONG,PLDAPControlA *, PLDAPControlA *, struct l_timeval *, ULONG, LDAPMessage **);
  41. typedef LDAPMessage * (LDAPAPI *PFN_LDAP_FIRST_ENTRY)( LDAP *, LDAPMessage * );
  42. typedef PCHAR * (LDAPAPI *PFN_LDAP_GET_VALUE)(LDAP *, LDAPMessage *, PCHAR );
  43. typedef ULONG (LDAPAPI *PFN_LDAP_MSGFREE)( LDAPMessage * );
  44. typedef ULONG (LDAPAPI *PFN_LDAP_VALUE_FREE)( PCHAR * );
  45. typedef ULONG (LDAPAPI *PFN_LDAP_MAP_ERROR)( ULONG );
  46. // 64K-1
  47. #define SDDL_MAX_ACL_SIZE 0xFFFF
  48. //
  49. // To allow the defines to be used as Wide strings, redefine the TEXT macro
  50. //
  51. #ifdef TEXT
  52. #undef TEXT
  53. #endif
  54. #define TEXT(quote) L##quote
  55. //
  56. // Local macros
  57. //
  58. #define STRING_GUID_LEN 36
  59. #define STRING_GUID_SIZE ( STRING_GUID_LEN * sizeof( WCHAR ) )
  60. #define SDDL_LEN_TAG( tagdef ) ( sizeof( tagdef ) / sizeof( WCHAR ) - 1 )
  61. #define SDDL_SIZE_TAG( tagdef ) ( wcslen( tagdef ) * sizeof( WCHAR ) )
  62. #define SDDL_SIZE_SEP( sep ) (sizeof( WCHAR ) )
  63. #define SDDL_VALID_DACL 0x00000001
  64. #define SDDL_VALID_SACL 0x00000002
  65. //
  66. // This structure is used to do some lookups for mapping ACES
  67. //
  68. typedef struct _STRSD_KEY_LOOKUP {
  69. PWSTR Key;
  70. ULONG KeyLen;
  71. ULONG Value;
  72. ULONG ValidityFlags;
  73. } STRSD_KEY_LOOKUP, *PSTRSD_KEY_LOOKUP;
  74. typedef enum _STRSD_SID_TYPE {
  75. ST_DOMAIN_RELATIVE = 0,
  76. ST_WORLD,
  77. ST_LOCALSY,
  78. ST_LOCAL,
  79. ST_CREATOR,
  80. ST_NTAUTH,
  81. ST_BUILTIN,
  82. ST_ROOT_DOMAIN_RELATIVE
  83. } STRSD_SID_TYPE;
  84. //
  85. // This structure is used to map account monikers to sids
  86. //
  87. typedef struct _STRSD_SID_LOOKUP {
  88. BOOLEAN Valid;
  89. WCHAR Key[SDDL_ALIAS_SIZE+2];
  90. ULONG KeyLen;
  91. PSID Sid;
  92. ULONG Rid;
  93. STRSD_SID_TYPE SidType;
  94. DWORD SidBuff[ sizeof( SID ) / sizeof( DWORD ) + 5];
  95. } STRSD_SID_LOOKUP, *PSTRSD_SID_LOOKUP;
  96. //
  97. // Globally defined sids
  98. //
  99. /* JINHUANG: not used anywhere
  100. DWORD PersonalSelfBuiltSid[sizeof(SID)/sizeof(DWORD) + 2];
  101. DWORD AuthUserBuiltSid[sizeof(SID)/sizeof(DWORD) + 2];
  102. DWORD CreatorOwnerBuiltSid[sizeof(SID)/sizeof(DWORD) + 2];
  103. DWORD CreatorGroupBuiltSid[sizeof(SID)/sizeof(DWORD) + 2];
  104. PSID PersonalSelfSid = (PSID)PersonalSelfBuiltSid;
  105. PSID AuthUserSid = (PSID)AuthUserBuiltSid;
  106. PSID CreatorOwnerSid = (PSID)CreatorOwnerBuiltSid;
  107. PSID CreatorGroupSid = (PSID)CreatorGroupBuiltSid;
  108. */
  109. CRITICAL_SECTION SddlSidLookupCritical;
  110. static DWORD SidTableReinitializeInstance=0;
  111. // JINHUANG 3/26 BVT break for dcpromo
  112. //
  113. // Some of the Valid fields were preset to TRUE with NULL Sid field. The SidLookup
  114. // table initialization is stopped if Status is not SUCCESS. So if error occurs,
  115. // for example, no domain info as in dcpromo, other SIDs will not be initialized
  116. // but the Valid fields are set to TRUE (with NULL SIDs).
  117. //
  118. // changes: 1) preset Valid field to FALSE all all lookups and set the Valid to TRUE if
  119. // the SID is really initialized
  120. // 2) do not stop the initialization process if an error occurs
  121. // if the Valid field is already TRUE (already initialized), skip the row
  122. //
  123. static STRSD_SID_LOOKUP SidLookup[] = {
  124. { FALSE, SDDL_DOMAIN_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_DOMAIN_ADMINISTRATORS ),
  125. NULL, DOMAIN_GROUP_RID_ADMINS, ST_DOMAIN_RELATIVE, 0 },
  126. { FALSE, SDDL_DOMAIN_GUESTS, SDDL_LEN_TAG( SDDL_DOMAIN_GUESTS ),
  127. NULL, DOMAIN_GROUP_RID_GUESTS, ST_DOMAIN_RELATIVE, 0 },
  128. { FALSE, SDDL_DOMAIN_USERS, SDDL_LEN_TAG( SDDL_DOMAIN_USERS ),
  129. NULL, DOMAIN_GROUP_RID_USERS, ST_DOMAIN_RELATIVE, 0 },
  130. { FALSE, SDDL_DOMAIN_DOMAIN_CONTROLLERS, SDDL_LEN_TAG( SDDL_DOMAIN_DOMAIN_CONTROLLERS ),
  131. NULL, DOMAIN_GROUP_RID_CONTROLLERS, ST_DOMAIN_RELATIVE, 0 },
  132. { FALSE, SDDL_DOMAIN_COMPUTERS, SDDL_LEN_TAG( SDDL_DOMAIN_COMPUTERS ),
  133. NULL, DOMAIN_GROUP_RID_COMPUTERS, ST_DOMAIN_RELATIVE, 0 },
  134. { FALSE, SDDL_SCHEMA_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_SCHEMA_ADMINISTRATORS ),
  135. NULL, DOMAIN_GROUP_RID_SCHEMA_ADMINS, ST_ROOT_DOMAIN_RELATIVE, 0 }, // should be root domain only ST_DOMAIN_RELATIVE,
  136. { FALSE, SDDL_ENTERPRISE_ADMINS, SDDL_LEN_TAG( SDDL_ENTERPRISE_ADMINS ),
  137. NULL, DOMAIN_GROUP_RID_ENTERPRISE_ADMINS, ST_ROOT_DOMAIN_RELATIVE, 0 }, // root domain only
  138. { FALSE, SDDL_CERT_SERV_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_CERT_SERV_ADMINISTRATORS ),
  139. NULL, DOMAIN_GROUP_RID_CERT_ADMINS, ST_DOMAIN_RELATIVE, 0 },
  140. { FALSE, SDDL_ACCOUNT_OPERATORS, SDDL_LEN_TAG( SDDL_ACCOUNT_OPERATORS ),
  141. NULL, DOMAIN_ALIAS_RID_ACCOUNT_OPS, ST_BUILTIN, 0 },
  142. { FALSE, SDDL_BACKUP_OPERATORS, SDDL_LEN_TAG( SDDL_BACKUP_OPERATORS ),
  143. NULL, DOMAIN_ALIAS_RID_BACKUP_OPS, ST_BUILTIN, 0 },
  144. { FALSE, SDDL_PRINTER_OPERATORS, SDDL_LEN_TAG( SDDL_PRINTER_OPERATORS ),
  145. NULL, DOMAIN_ALIAS_RID_PRINT_OPS, ST_BUILTIN, 0 },
  146. { FALSE, SDDL_SERVER_OPERATORS, SDDL_LEN_TAG( SDDL_SERVER_OPERATORS ),
  147. NULL, DOMAIN_ALIAS_RID_SYSTEM_OPS, ST_BUILTIN, 0 },
  148. { FALSE, SDDL_REPLICATOR, SDDL_LEN_TAG( SDDL_REPLICATOR ),
  149. NULL, DOMAIN_ALIAS_RID_REPLICATOR, ST_BUILTIN, 0 },
  150. { FALSE, SDDL_RAS_SERVERS, SDDL_LEN_TAG( SDDL_RAS_SERVERS ),
  151. NULL, DOMAIN_ALIAS_RID_RAS_SERVERS, ST_DOMAIN_RELATIVE, 0 }, // ST_LOCAL
  152. { FALSE, SDDL_AUTHENTICATED_USERS, SDDL_LEN_TAG( SDDL_AUTHENTICATED_USERS ),
  153. NULL, SECURITY_AUTHENTICATED_USER_RID, ST_NTAUTH, 0 },
  154. { FALSE, SDDL_PERSONAL_SELF, SDDL_LEN_TAG( SDDL_PERSONAL_SELF ),
  155. NULL, SECURITY_PRINCIPAL_SELF_RID, ST_NTAUTH, 0 },
  156. { FALSE, SDDL_CREATOR_OWNER, SDDL_LEN_TAG( SDDL_CREATOR_OWNER ),
  157. NULL, SECURITY_CREATOR_OWNER_RID, ST_CREATOR, 0 },
  158. { FALSE, SDDL_CREATOR_GROUP, SDDL_LEN_TAG( SDDL_CREATOR_GROUP ),
  159. NULL, SECURITY_CREATOR_GROUP_RID, ST_CREATOR, 0 },
  160. { FALSE, SDDL_LOCAL_SYSTEM, SDDL_LEN_TAG( SDDL_LOCAL_SYSTEM ),
  161. NULL, SECURITY_LOCAL_SYSTEM_RID, ST_NTAUTH, 0 },
  162. { FALSE, SDDL_INTERACTIVE, SDDL_LEN_TAG( SDDL_INTERACTIVE ),
  163. NULL, SECURITY_INTERACTIVE_RID, ST_NTAUTH, 0 },
  164. { FALSE, SDDL_NETWORK, SDDL_LEN_TAG( SDDL_NETWORK ),
  165. NULL, SECURITY_NETWORK_RID, ST_NTAUTH, 0 },
  166. { FALSE, SDDL_SERVICE, SDDL_LEN_TAG( SDDL_SERVICE ),
  167. NULL, SECURITY_SERVICE_RID, ST_NTAUTH, 0 },
  168. { FALSE, SDDL_ENTERPRISE_DOMAIN_CONTROLLERS, SDDL_LEN_TAG( SDDL_ENTERPRISE_DOMAIN_CONTROLLERS ),
  169. NULL, SECURITY_SERVER_LOGON_RID, ST_NTAUTH, 0 },
  170. { FALSE, SDDL_RESTRICTED_CODE, SDDL_LEN_TAG( SDDL_RESTRICTED_CODE ),
  171. NULL, SECURITY_RESTRICTED_CODE_RID, ST_NTAUTH, 0 },
  172. { FALSE, SDDL_ANONYMOUS, SDDL_LEN_TAG( SDDL_ANONYMOUS ),
  173. NULL, SECURITY_ANONYMOUS_LOGON_RID, ST_NTAUTH, 0 },
  174. { FALSE, SDDL_LOCAL_ADMIN, SDDL_LEN_TAG( SDDL_LOCAL_ADMIN ),
  175. NULL, DOMAIN_USER_RID_ADMIN, ST_LOCAL, 0 },
  176. { FALSE, SDDL_LOCAL_GUEST, SDDL_LEN_TAG( SDDL_LOCAL_GUEST ),
  177. NULL, DOMAIN_USER_RID_GUEST, ST_LOCAL, 0 },
  178. { FALSE, SDDL_BUILTIN_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_BUILTIN_ADMINISTRATORS ),
  179. NULL, DOMAIN_ALIAS_RID_ADMINS, ST_BUILTIN, 0 },
  180. { FALSE, SDDL_BUILTIN_GUESTS, SDDL_LEN_TAG( SDDL_BUILTIN_GUESTS ),
  181. NULL, DOMAIN_ALIAS_RID_GUESTS, ST_BUILTIN, 0 },
  182. { FALSE, SDDL_BUILTIN_USERS, SDDL_LEN_TAG( SDDL_BUILTIN_USERS ),
  183. NULL, DOMAIN_ALIAS_RID_USERS, ST_BUILTIN, 0 },
  184. { FALSE, SDDL_POWER_USERS, SDDL_LEN_TAG( SDDL_POWER_USERS ),
  185. NULL, DOMAIN_ALIAS_RID_POWER_USERS, ST_BUILTIN, 0 },
  186. { FALSE, SDDL_EVERYONE, SDDL_LEN_TAG( SDDL_EVERYONE ),
  187. NULL, SECURITY_WORLD_RID, ST_WORLD, 0 },
  188. { FALSE, SDDL_GROUP_POLICY_ADMINS, SDDL_LEN_TAG( SDDL_GROUP_POLICY_ADMINS ),
  189. NULL, DOMAIN_GROUP_RID_POLICY_ADMINS, ST_DOMAIN_RELATIVE, 0 },
  190. { FALSE, SDDL_ALIAS_PREW2KCOMPACC, SDDL_LEN_TAG( SDDL_ALIAS_PREW2KCOMPACC ),
  191. NULL, DOMAIN_ALIAS_RID_PREW2KCOMPACCESS, ST_BUILTIN, 0 },
  192. { FALSE, SDDL_LOCAL_SERVICE, SDDL_LEN_TAG( SDDL_LOCAL_SERVICE ),
  193. NULL, SECURITY_LOCAL_SERVICE_RID, ST_NTAUTH, 0 },
  194. { FALSE, SDDL_NETWORK_SERVICE, SDDL_LEN_TAG( SDDL_NETWORK_SERVICE ),
  195. NULL, SECURITY_NETWORK_SERVICE_RID, ST_NTAUTH, 0 },
  196. { FALSE, SDDL_REMOTE_DESKTOP, SDDL_LEN_TAG( SDDL_REMOTE_DESKTOP ),
  197. NULL, DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS, ST_BUILTIN, 0 },
  198. { FALSE, SDDL_NETWORK_CONFIGURATION_OPS, SDDL_LEN_TAG( SDDL_NETWORK_CONFIGURATION_OPS ),
  199. NULL, DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS, ST_BUILTIN, 0 }
  200. };
  201. STRSD_SID_LOOKUP SidLookupDomOrRootDomRelative[] = {
  202. { FALSE, SDDL_DOMAIN_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_DOMAIN_ADMINISTRATORS ),
  203. NULL, DOMAIN_GROUP_RID_ADMINS, ST_DOMAIN_RELATIVE, 0 },
  204. { FALSE, SDDL_DOMAIN_GUESTS, SDDL_LEN_TAG( SDDL_DOMAIN_GUESTS ),
  205. NULL, DOMAIN_GROUP_RID_GUESTS, ST_DOMAIN_RELATIVE, 0 },
  206. { FALSE, SDDL_DOMAIN_USERS, SDDL_LEN_TAG( SDDL_DOMAIN_USERS ),
  207. NULL, DOMAIN_GROUP_RID_USERS, ST_DOMAIN_RELATIVE, 0 },
  208. { FALSE, SDDL_DOMAIN_DOMAIN_CONTROLLERS, SDDL_LEN_TAG( SDDL_DOMAIN_DOMAIN_CONTROLLERS ),
  209. NULL, DOMAIN_GROUP_RID_CONTROLLERS, ST_DOMAIN_RELATIVE, 0 },
  210. { FALSE, SDDL_DOMAIN_COMPUTERS, SDDL_LEN_TAG( SDDL_DOMAIN_COMPUTERS ),
  211. NULL, DOMAIN_GROUP_RID_COMPUTERS, ST_DOMAIN_RELATIVE, 0 },
  212. { FALSE, SDDL_CERT_SERV_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_CERT_SERV_ADMINISTRATORS ),
  213. NULL, DOMAIN_GROUP_RID_CERT_ADMINS, ST_DOMAIN_RELATIVE, 0 },
  214. { FALSE, SDDL_RAS_SERVERS, SDDL_LEN_TAG( SDDL_RAS_SERVERS ),
  215. NULL, DOMAIN_ALIAS_RID_RAS_SERVERS, ST_DOMAIN_RELATIVE, 0 }, // ST_LOCAL
  216. { FALSE, SDDL_GROUP_POLICY_ADMINS, SDDL_LEN_TAG( SDDL_GROUP_POLICY_ADMINS ),
  217. NULL, DOMAIN_GROUP_RID_POLICY_ADMINS, ST_DOMAIN_RELATIVE, 0 },
  218. { FALSE, SDDL_SCHEMA_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_SCHEMA_ADMINISTRATORS ),
  219. NULL, DOMAIN_GROUP_RID_SCHEMA_ADMINS, ST_ROOT_DOMAIN_RELATIVE, 0 },
  220. { FALSE, SDDL_ENTERPRISE_ADMINS, SDDL_LEN_TAG( SDDL_ENTERPRISE_ADMINS ),
  221. NULL, DOMAIN_GROUP_RID_ENTERPRISE_ADMINS, ST_ROOT_DOMAIN_RELATIVE, 0 }
  222. };
  223. static DWORD RootDomSidBuf[sizeof(SID)/sizeof(DWORD)+5];
  224. static BOOL RootDomInited=FALSE;
  225. #define STRSD_REINITIALIZE_ENTER 1
  226. #define STRSD_REINITIALIZE_LEAVE 2
  227. BOOLEAN
  228. InitializeSidLookupTable(
  229. IN BYTE InitFlag
  230. );
  231. //
  232. // Control Lookup table
  233. //
  234. static STRSD_KEY_LOOKUP ControlLookup[] = {
  235. { SDDL_PROTECTED, SDDL_LEN_TAG( SDDL_PROTECTED ), SE_DACL_PROTECTED, SDDL_VALID_DACL },
  236. { SDDL_AUTO_INHERIT_REQ, SDDL_LEN_TAG( SDDL_AUTO_INHERIT_REQ ), SE_DACL_AUTO_INHERIT_REQ, SDDL_VALID_DACL },
  237. { SDDL_AUTO_INHERITED, SDDL_LEN_TAG( SDDL_AUTO_INHERITED ), SE_DACL_AUTO_INHERITED, SDDL_VALID_DACL },
  238. { SDDL_PROTECTED, SDDL_LEN_TAG( SDDL_PROTECTED ), SE_SACL_PROTECTED, SDDL_VALID_SACL },
  239. { SDDL_AUTO_INHERIT_REQ, SDDL_LEN_TAG( SDDL_AUTO_INHERIT_REQ ), SE_SACL_AUTO_INHERIT_REQ, SDDL_VALID_SACL },
  240. { SDDL_AUTO_INHERITED, SDDL_LEN_TAG( SDDL_AUTO_INHERITED ), SE_SACL_AUTO_INHERITED, SDDL_VALID_SACL }
  241. };
  242. //
  243. // Local prototypes
  244. //
  245. BOOL
  246. LocalConvertStringSidToSid(
  247. IN PWSTR String,
  248. OUT PSID *SID,
  249. OUT PWSTR *End
  250. );
  251. PSTRSD_SID_LOOKUP
  252. LookupSidInTable(
  253. IN PWSTR String, OPTIONAL
  254. IN PSID Sid OPTIONAL,
  255. IN PSID RootDomainSid OPTIONAL,
  256. IN PSID DomainSid OPTIONAL,
  257. IN PSTRSD_SID_LOOKUP tSidLookupDomOrRootDomRelativeTable OPTIONAL,
  258. IN BOOLEAN DefaultToDomain,
  259. OUT PVOID *pSASid
  260. );
  261. DWORD
  262. LocalGetSidForString(
  263. IN PWSTR String,
  264. OUT PSID *SID,
  265. OUT PWSTR *End,
  266. OUT PBOOLEAN FreeSid,
  267. IN PSID RootDomainSid OPTIONAL,
  268. IN PSID DomainSid OPTIONAL,
  269. IN PSTRSD_SID_LOOKUP tSidLookupDomOrRootDomRelativeTable OPTIONAL,
  270. IN BOOLEAN DefaultToDomain
  271. );
  272. PSTRSD_KEY_LOOKUP
  273. LookupAccessMaskInTable(
  274. IN PWSTR String, OPTIONAL
  275. IN ULONG AccessMask, OPTIONAL
  276. IN ULONG LookupFlags
  277. );
  278. PSTRSD_KEY_LOOKUP
  279. LookupAceTypeInTable(
  280. IN PWSTR String, OPTIONAL
  281. IN ULONG AceType, OPTIONAL
  282. IN ULONG LookupFlags
  283. );
  284. PSTRSD_KEY_LOOKUP
  285. LookupAceFlagsInTable(
  286. IN PWSTR String, OPTIONAL
  287. IN ULONG AceFlags OPTIONAL,
  288. IN ULONG LookupFlags
  289. );
  290. DWORD
  291. LocalGetStringForSid(
  292. IN PSID Sid,
  293. OUT PWSTR *String,
  294. IN PSID RootDomainSid OPTIONAL
  295. );
  296. DWORD
  297. LocalGetStringForControl(
  298. IN SECURITY_DESCRIPTOR_CONTROL ControlCode,
  299. IN ULONG LookupFlags,
  300. OUT PWSTR *ControlString
  301. );
  302. DWORD
  303. LocalGetSDControlForString (
  304. IN PWSTR AclString,
  305. IN ULONG LookupFlags,
  306. OUT SECURITY_DESCRIPTOR_CONTROL *pControl,
  307. OUT PWSTR *End
  308. );
  309. DWORD
  310. LocalGetAclForString (
  311. IN PWSTR AclString,
  312. IN BOOLEAN ConvertAsDacl,
  313. OUT PACL *Acl,
  314. OUT PWSTR *End,
  315. IN PSID RootDomainSid OPTIONAL,
  316. IN PSID DomainSid OPTIONAL,
  317. IN PSTRSD_SID_LOOKUP tSidLookupDomOrRootDomRelativeTable OPTIONAL,
  318. IN BOOLEAN DefaultToDomain
  319. );
  320. DWORD
  321. LocalConvertAclToString(
  322. IN PACL Acl,
  323. IN BOOLEAN AclPresent,
  324. IN BOOLEAN ConvertAsDacl,
  325. OUT PWSTR *AclString,
  326. OUT PDWORD AclStringSize,
  327. IN PSID RootDomainSid OPTIONAL
  328. );
  329. DWORD
  330. LocalConvertSDToStringSD_Rev1(
  331. IN PSID RootDomainSid OPTIONAL,
  332. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  333. IN SECURITY_INFORMATION SecurityInformation,
  334. OUT LPWSTR *StringSecurityDescriptor,
  335. OUT PULONG StringSecurityDescriptorLen OPTIONAL
  336. );
  337. DWORD
  338. LocalConvertStringSDToSD_Rev1(
  339. IN PSID RootDomainSid OPTIONAL,
  340. IN PSID DomainSid OPTIONAL,
  341. IN BOOLEAN DefaultToDomain,
  342. IN LPCWSTR StringSecurityDescriptor,
  343. OUT PSECURITY_DESCRIPTOR *SecurityDescriptor,
  344. OUT PULONG SecurityDescriptorSize OPTIONAL
  345. );
  346. BOOL
  347. SddlpGetRootDomainSid(void);
  348. //
  349. // Exported functions
  350. //
  351. BOOL
  352. APIENTRY
  353. ConvertSidToStringSidA(
  354. IN PSID Sid,
  355. OUT LPSTR *StringSid
  356. )
  357. /*++
  358. Routine Description:
  359. ANSI thunk to ConvertSidToStringSidW
  360. --*/
  361. {
  362. LPWSTR StringSidW = NULL;
  363. ULONG AnsiLen, WideLen;
  364. BOOL ReturnValue;
  365. if ( NULL == StringSid ) {
  366. //
  367. // invalid parameter
  368. //
  369. SetLastError( ERROR_INVALID_PARAMETER );
  370. return(FALSE);
  371. }
  372. ReturnValue = ConvertSidToStringSidW( Sid, &StringSidW );
  373. if ( ReturnValue ) {
  374. WideLen = wcslen( StringSidW ) + 1;
  375. AnsiLen = WideCharToMultiByte( CP_ACP,
  376. 0,
  377. StringSidW,
  378. WideLen,
  379. *StringSid,
  380. 0,
  381. NULL,
  382. NULL );
  383. if ( AnsiLen != 0 ) {
  384. *StringSid = LocalAlloc( LMEM_FIXED, AnsiLen );
  385. if ( *StringSid == NULL ) {
  386. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  387. ReturnValue = FALSE;
  388. } else {
  389. AnsiLen = WideCharToMultiByte( CP_ACP,
  390. 0,
  391. StringSidW,
  392. WideLen,
  393. *StringSid,
  394. AnsiLen,
  395. NULL,
  396. NULL );
  397. ASSERT( AnsiLen != 0 );
  398. if ( AnsiLen == 0 ) {
  399. ReturnValue = FALSE;
  400. //
  401. // jinhuang: failed, free the buffer
  402. //
  403. LocalFree(*StringSid);
  404. *StringSid = NULL;
  405. }
  406. }
  407. } else {
  408. ReturnValue = FALSE;
  409. }
  410. }
  411. //
  412. // jinhuang: free the wide buffer
  413. //
  414. if ( StringSidW ) {
  415. LocalFree(StringSidW);
  416. }
  417. if ( ReturnValue ) {
  418. SetLastError(ERROR_SUCCESS);
  419. }
  420. return( ReturnValue );
  421. }
  422. BOOL
  423. APIENTRY
  424. ConvertSidToStringSidW(
  425. IN PSID Sid,
  426. OUT LPWSTR *StringSid
  427. )
  428. /*++
  429. Routine Description:
  430. This routine converts a SID into a string representation of a SID, suitable for framing or
  431. display
  432. Arguments:
  433. Sid - SID to be converted.
  434. StringSid - Where the converted SID is returned. Allocated via LocalAlloc and needs to
  435. be freed via LocalFree.
  436. Return Value:
  437. TRUE - Success
  438. FALSE - Failure
  439. Extended error status is available using GetLastError.
  440. --*/
  441. {
  442. NTSTATUS Status;
  443. UNICODE_STRING UnicodeStringSid;
  444. if ( NULL == Sid || NULL == StringSid ) {
  445. //
  446. // invalid parameter
  447. //
  448. SetLastError( ERROR_INVALID_PARAMETER );
  449. return( FALSE );
  450. }
  451. //
  452. // Convert using the Rtl functions
  453. //
  454. Status = RtlConvertSidToUnicodeString( &UnicodeStringSid, Sid, TRUE );
  455. if ( !NT_SUCCESS( Status ) ) {
  456. BaseSetLastNTError( Status );
  457. return( FALSE );
  458. }
  459. //
  460. // Convert it to the proper allocator
  461. //
  462. *StringSid = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  463. UnicodeStringSid.Length + sizeof( WCHAR ) );
  464. if ( *StringSid == NULL ) {
  465. RtlFreeUnicodeString( &UnicodeStringSid );
  466. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  467. return( FALSE );
  468. }
  469. RtlCopyMemory( *StringSid, UnicodeStringSid.Buffer, UnicodeStringSid.Length );
  470. RtlFreeUnicodeString( &UnicodeStringSid );
  471. SetLastError(ERROR_SUCCESS);
  472. return( TRUE );
  473. }
  474. BOOL
  475. APIENTRY
  476. ConvertStringSidToSidA(
  477. IN LPCSTR StringSid,
  478. OUT PSID *Sid
  479. )
  480. /*++
  481. Routine Description:
  482. ANSI thunk to ConvertStringSidToSidW
  483. --*/
  484. {
  485. UNICODE_STRING Unicode;
  486. ANSI_STRING AnsiString;
  487. NTSTATUS Status;
  488. BOOL Result;
  489. if ( NULL == StringSid || NULL == Sid ) {
  490. SetLastError( ERROR_INVALID_PARAMETER );
  491. return(FALSE);
  492. }
  493. RtlInitAnsiString( &AnsiString, StringSid );
  494. Status = SddlpAnsiStringToUnicodeString(&Unicode,
  495. &AnsiString);
  496. if ( !NT_SUCCESS( Status ) ) {
  497. BaseSetLastNTError( Status );
  498. return FALSE;
  499. }
  500. Result = ConvertStringSidToSidW( ( LPCWSTR )Unicode.Buffer, Sid );
  501. LocalFree( Unicode.Buffer );
  502. if ( Result ) {
  503. SetLastError(ERROR_SUCCESS);
  504. }
  505. return( Result );
  506. }
  507. BOOL
  508. APIENTRY
  509. ConvertStringSidToSidW(
  510. IN LPCWSTR StringSid,
  511. OUT PSID *Sid
  512. )
  513. /*++
  514. Routine Description:
  515. This routine converts a stringized SID into a valid, functional SID
  516. Arguments:
  517. StringSid - SID to be converted.
  518. Sid - Where the converted SID is returned. Buffer is allocated via LocalAlloc and should
  519. be free via LocalFree.
  520. Return Value:
  521. TRUE - Success
  522. FALSE - Failure
  523. Extended error status is available using GetLastError.
  524. ERROR_INVALID_PARAMETER - A NULL name was given
  525. ERROR_INVALID_SID - The format of the given sid was incorrect
  526. --*/
  527. {
  528. PWSTR End = NULL;
  529. BOOL ReturnValue = FALSE;
  530. PSTRSD_SID_LOOKUP MatchedEntry=NULL;
  531. PSID pSASid=NULL;
  532. ULONG Len=0;
  533. DWORD SaveCode=0;
  534. DWORD Err=0;
  535. if ( StringSid == NULL || Sid == NULL ) {
  536. SetLastError( ERROR_INVALID_PARAMETER );
  537. } else {
  538. ReturnValue = LocalConvertStringSidToSid( ( PWSTR )StringSid, Sid, &End );
  539. if ( ReturnValue == TRUE ) {
  540. if ( ( ULONG )( End - StringSid ) != wcslen( StringSid ) ) {
  541. SetLastError( ERROR_INVALID_SID );
  542. LocalFree( *Sid );
  543. *Sid = FALSE;
  544. ReturnValue = FALSE;
  545. } else {
  546. SetLastError(ERROR_SUCCESS);
  547. }
  548. } else {
  549. SaveCode = GetLastError();
  550. //
  551. // lookup in the SidLookup table to see if it's pre-defined
  552. //
  553. MatchedEntry = LookupSidInTable( (PWSTR)StringSid,
  554. NULL,
  555. NULL,
  556. NULL,
  557. NULL,
  558. FALSE,
  559. (PVOID *)&pSASid);
  560. if ( MatchedEntry && MatchedEntry->Sid ) {
  561. //
  562. // find it in the table, check if the input string is valid
  563. //
  564. if ( wcslen( (PWSTR)StringSid ) != MatchedEntry->KeyLen ) {
  565. //
  566. // the total string length doesn't match the table define
  567. //
  568. SetLastError(ERROR_INVALID_SID);
  569. } else {
  570. //
  571. // matched! now copy it to the output buffer
  572. //
  573. Len = RtlLengthSid ( MatchedEntry->Sid );
  574. *Sid = ( PSID )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Len );
  575. if ( *Sid == NULL ) {
  576. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  577. } else {
  578. Err = RtlNtStatusToDosError(RtlCopySid ( Len, *Sid, MatchedEntry->Sid ) );
  579. if ( ERROR_SUCCESS == Err ) {
  580. ReturnValue = TRUE;
  581. } else {
  582. LocalFree(*Sid);
  583. *Sid = NULL;
  584. }
  585. SetLastError(Err);
  586. }
  587. }
  588. } else if ( pSASid && wcslen((PWSTR)StringSid) == SDDL_LEN_TAG( SDDL_SCHEMA_ADMINISTRATORS ) ) {
  589. //
  590. // this is schema admin SID
  591. //
  592. *Sid = pSASid;
  593. pSASid = NULL;
  594. ReturnValue = TRUE;
  595. SetLastError(ERROR_SUCCESS);
  596. } else {
  597. //
  598. // reset last error
  599. //
  600. SetLastError(SaveCode);
  601. }
  602. }
  603. if ( pSASid ) {
  604. LocalFree(pSASid);
  605. }
  606. }
  607. return( ReturnValue );
  608. }
  609. BOOL
  610. APIENTRY
  611. ConvertStringSecurityDescriptorToSecurityDescriptorA(
  612. IN LPCSTR StringSecurityDescriptor,
  613. IN DWORD StringSDRevision,
  614. OUT PSECURITY_DESCRIPTOR *SecurityDescriptor,
  615. OUT PULONG SecurityDescriptorSize OPTIONAL
  616. )
  617. /*++
  618. Routine Description:
  619. ANSI thunk to ConvertStringSecurityDescriptorToSecurityDescriptorW
  620. --*/
  621. {
  622. UNICODE_STRING Unicode;
  623. ANSI_STRING AnsiString;
  624. NTSTATUS Status;
  625. BOOL Result;
  626. if ( NULL == StringSecurityDescriptor ||
  627. NULL == SecurityDescriptor ) {
  628. SetLastError(ERROR_INVALID_PARAMETER);
  629. return(FALSE);
  630. }
  631. RtlInitAnsiString( &AnsiString, StringSecurityDescriptor );
  632. Status = SddlpAnsiStringToUnicodeString(&Unicode,
  633. &AnsiString);
  634. if ( !NT_SUCCESS( Status ) ) {
  635. BaseSetLastNTError( Status );
  636. return FALSE;
  637. }
  638. Result = ConvertStringSecurityDescriptorToSecurityDescriptorW( ( LPCWSTR )Unicode.Buffer,
  639. StringSDRevision,
  640. SecurityDescriptor,
  641. SecurityDescriptorSize);
  642. LocalFree( Unicode.Buffer );
  643. if ( Result ) {
  644. SetLastError(ERROR_SUCCESS);
  645. }
  646. return( Result );
  647. }
  648. BOOL
  649. APIENTRY
  650. ConvertStringSecurityDescriptorToSecurityDescriptorW(
  651. IN LPCWSTR StringSecurityDescriptor,
  652. IN DWORD StringSDRevision,
  653. OUT PSECURITY_DESCRIPTOR *SecurityDescriptor,
  654. OUT PULONG SecurityDescriptorSize OPTIONAL
  655. )
  656. /*++
  657. Routine Description:
  658. This routine converts a stringized Security descriptor into a valid, functional security
  659. descriptor
  660. Ex:
  661. SD:[O:xyz][G:xyz][D: (Ace1)(Ace2)][S: (Ace3)(Ace4)]
  662. where some Ace is (OA;CIIO; DS_READ; OT: abc; IOT: abc; SID: xyz)
  663. So a possible Security descriptor may be (as all one long string):
  664. L"O:AOG:DAD:(A;IO;RPRWXRCWDWO;;;S-1-0-0)(OA;CI;RWX;af110080-1b13-11d0-af10-0020afd3606c;"
  665. L"a153d9e0-1b13-11d0-af10-0020afd3606c;AUS)(A;SAFA;0x7800003F;;;DA)(OA;FA;X;"
  666. L"954378e0-1b13-11d0-af10-0020afd3606c;880b12a0-1b13-11d0-af10-0020afd3606c;PO)"
  667. would build a security descriptor:
  668. Revision: 0x1
  669. Sbz1: 0x0
  670. Control: 0x8014
  671. Owner: S-1-5-32-548
  672. Group:S-1-5-32-544
  673. Dacl: Revision: 4
  674. AceCount: 2
  675. InUse: 84
  676. Free: 52
  677. Flags: 0
  678. Ace 0:
  679. Type: 0
  680. Flags: 0x1
  681. Size: 0x14
  682. Mask: 0xe00e0010
  683. S-1-0-0
  684. Ace 1:
  685. Type: 5
  686. Flags: 0x2
  687. Size: 0x38
  688. Mask: 0xe0000000
  689. af110080-1b13-11d0-af100020afd3606c
  690. a153d9e0-1b13-11d0-af100020afd3606c
  691. S-1-5-11
  692. sacl: Revision: 4
  693. AceCount: 2
  694. InUse: 92
  695. Free: 44
  696. Flags: 0
  697. Ace 0:
  698. Type: 2
  699. Flags: 0xc0
  700. Size: 0x18
  701. Mask: 0xe0000000
  702. S-1-5-32-544
  703. Ace 1:
  704. Type: 7
  705. Flags: 0x80
  706. Size: 0x3c
  707. Mask: 0x20000000
  708. 954378e0-1b13-11d0-af100020afd3606c
  709. 880b12a0-1b13-11d0-af100020afd3606c
  710. S-1-5-32-550
  711. Arguments:
  712. StringSecurityDescriptor - Stringized security descriptor to be converted.
  713. StringSDRevision - String revision of the input string SD
  714. SecurityDescriptor - Where the converted SD is returned. Buffer is allocated via
  715. LocalAlloc and should be free via LocalFree. The returned security descriptor
  716. is always self relative
  717. SecurityDescriptorSize - OPTIONAL. If non-NULL, the size of the converted security
  718. descriptor is returned here.
  719. Return Value:
  720. TRUE - Success
  721. FALSE - Failure
  722. Extended error status is available using GetLastError.
  723. ERROR_INVALID_PARAMETER - A NULL input or output parameter was given
  724. ERROR_UNKNOWN_REVISION - An unsupported revision was given
  725. --*/
  726. {
  727. DWORD Err = ERROR_SUCCESS;
  728. //
  729. // Little elementary parameter checking...
  730. //
  731. if ( StringSecurityDescriptor == NULL || SecurityDescriptor == NULL ) {
  732. Err = ERROR_INVALID_PARAMETER;
  733. } else {
  734. switch ( StringSDRevision ) {
  735. case SDDL_REVISION_1:
  736. Err = LocalConvertStringSDToSD_Rev1( NULL, // no root domain sid is provided
  737. NULL, // no domain sid is provided for this API
  738. FALSE, //TRUE, do not default to domain for EA/SA
  739. StringSecurityDescriptor,
  740. SecurityDescriptor,
  741. SecurityDescriptorSize);
  742. break;
  743. default:
  744. Err = ERROR_UNKNOWN_REVISION;
  745. break;
  746. }
  747. }
  748. SetLastError( Err );
  749. return( Err == ERROR_SUCCESS );
  750. }
  751. BOOL
  752. APIENTRY
  753. ConvertSecurityDescriptorToStringSecurityDescriptorA(
  754. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  755. IN DWORD RequestedStringSDRevision,
  756. IN SECURITY_INFORMATION SecurityInformation,
  757. OUT LPSTR *StringSecurityDescriptor,
  758. OUT PULONG StringSecurityDescriptorLen OPTIONAL
  759. )
  760. /*++
  761. Routine Description:
  762. ANSI thunk to ConvertSecurityDescriptorToStringSecurityDescriptorW
  763. --*/
  764. {
  765. LPWSTR StringSecurityDescriptorW = NULL;
  766. ULONG AnsiLen, WideLen = 0;
  767. BOOL ReturnValue ;
  768. if ( StringSecurityDescriptor == NULL ) {
  769. SetLastError( ERROR_INVALID_PARAMETER );
  770. return( FALSE );
  771. }
  772. ReturnValue = ConvertSecurityDescriptorToStringSecurityDescriptorW(
  773. SecurityDescriptor,
  774. RequestedStringSDRevision,
  775. SecurityInformation,
  776. &StringSecurityDescriptorW,
  777. &WideLen );
  778. if ( ReturnValue ) {
  779. // jinhuang: WindeLen is returned from previous call
  780. // WideLen = wcslen( StringSecurityDescriptorW ) + 1;
  781. AnsiLen = WideCharToMultiByte( CP_ACP,
  782. 0,
  783. StringSecurityDescriptorW,
  784. WideLen + 1,
  785. *StringSecurityDescriptor,
  786. 0,
  787. NULL,
  788. NULL );
  789. if ( AnsiLen != 0 ) {
  790. *StringSecurityDescriptor = LocalAlloc( LMEM_FIXED, AnsiLen );
  791. if ( *StringSecurityDescriptor == NULL ) {
  792. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  793. ReturnValue = FALSE;
  794. } else {
  795. AnsiLen = WideCharToMultiByte( CP_ACP,
  796. 0,
  797. StringSecurityDescriptorW,
  798. WideLen + 1,
  799. *StringSecurityDescriptor,
  800. AnsiLen,
  801. NULL,
  802. NULL );
  803. ASSERT( AnsiLen != 0 );
  804. if ( AnsiLen == 0 ) {
  805. LocalFree(*StringSecurityDescriptor);
  806. *StringSecurityDescriptor = NULL;
  807. ReturnValue = FALSE;
  808. }
  809. //
  810. // jinhuang
  811. // output the length (optional)
  812. //
  813. if ( StringSecurityDescriptorLen ) {
  814. *StringSecurityDescriptorLen = AnsiLen;
  815. }
  816. }
  817. } else {
  818. ReturnValue = FALSE;
  819. }
  820. //
  821. // jinhuang
  822. // StringSecurityDescriptorW should be freed
  823. //
  824. LocalFree(StringSecurityDescriptorW);
  825. }
  826. if ( ReturnValue ) {
  827. SetLastError(ERROR_SUCCESS);
  828. }
  829. return( ReturnValue );
  830. }
  831. BOOL
  832. APIENTRY
  833. ConvertSecurityDescriptorToStringSecurityDescriptorW(
  834. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  835. IN DWORD RequestedStringSDRevision,
  836. IN SECURITY_INFORMATION SecurityInformation,
  837. OUT LPWSTR *StringSecurityDescriptor,
  838. OUT PULONG StringSecurityDescriptorLen OPTIONAL
  839. )
  840. /*++
  841. Routine Description:
  842. This routine converts a security descriptor into a string version persuant to SDDL definition
  843. Arguments:
  844. SecurityDescriptor - Security Descriptor to be converted.
  845. RequestedStringSDRevision - Requested revision of the output string security descriptor
  846. SecurityInformation - security information of which to be converted
  847. StringSecurityDescriptor - Where the converted SD is returned. Buffer is allocated via
  848. LocalAlloc and should be free via LocalFree.
  849. StringSecurityDescriptorLen - the optional length of the converted SD
  850. Return Value:
  851. TRUE - Success
  852. FALSE - Failure
  853. Extended error status is available using GetLastError.
  854. ERROR_INVALID_PARAMETER - A NULL input or output parameter was given
  855. ERROR_UNKNOWN_REVISION - An unsupported revision was given
  856. --*/
  857. {
  858. DWORD Err = ERROR_SUCCESS;
  859. //
  860. // A little parameter checking...
  861. //
  862. if ( (SecurityDescriptor == NULL || SecurityInformation == 0) &&
  863. StringSecurityDescriptor ) {
  864. *StringSecurityDescriptor = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, sizeof( WCHAR ) );
  865. if (*StringSecurityDescriptor) {
  866. (*StringSecurityDescriptor)[0] = L'\0';
  867. if (StringSecurityDescriptorLen) {
  868. *StringSecurityDescriptorLen = 0;
  869. }
  870. }
  871. else {
  872. Err = ERROR_NOT_ENOUGH_MEMORY;
  873. }
  874. SetLastError( Err );
  875. return( Err == ERROR_SUCCESS );
  876. }
  877. if ( SecurityDescriptor == NULL || StringSecurityDescriptor == NULL ||
  878. SecurityInformation == 0 ) {
  879. Err = ERROR_INVALID_PARAMETER;
  880. } else {
  881. switch ( RequestedStringSDRevision ) {
  882. case SDDL_REVISION_1:
  883. Err = LocalConvertSDToStringSD_Rev1( NULL, // root domain sid is not privided
  884. SecurityDescriptor,
  885. SecurityInformation,
  886. StringSecurityDescriptor,
  887. StringSecurityDescriptorLen );
  888. break;
  889. default:
  890. Err = ERROR_UNKNOWN_REVISION;
  891. break;
  892. }
  893. }
  894. SetLastError( Err );
  895. return( Err == ERROR_SUCCESS);
  896. }
  897. //
  898. // Private functions
  899. //
  900. BOOL
  901. LocalConvertStringSidToSid (
  902. IN PWSTR StringSid,
  903. OUT PSID *Sid,
  904. OUT PWSTR *End
  905. )
  906. /*++
  907. Routine Description:
  908. This routine will convert a string representation of a SID back into
  909. a sid. The expected format of the string is:
  910. "S-1-5-32-549"
  911. If a string in a different format or an incorrect or incomplete string
  912. is given, the operation is failed.
  913. The returned sid must be free via a call to LocalFree
  914. Arguments:
  915. StringSid - The string to be converted
  916. Sid - Where the created SID is to be returned
  917. End - Where in the string we stopped processing
  918. Return Value:
  919. TRUE - Success.
  920. FALSE - Failure. Additional information returned from GetLastError(). Errors set are:
  921. ERROR_SUCCESS indicates success
  922. ERROR_NOT_ENOUGH_MEMORY indicates a memory allocation for the ouput sid
  923. failed
  924. ERROR_INVALID_SID indicates that the given string did not represent a sid
  925. --*/
  926. {
  927. DWORD Err = ERROR_SUCCESS;
  928. UCHAR Revision, Subs;
  929. SID_IDENTIFIER_AUTHORITY IDAuth;
  930. PULONG SubAuth = NULL;
  931. PWSTR CurrEnd, Curr, Next;
  932. WCHAR Stub, *StubPtr = NULL;
  933. ULONG Index;
  934. INT gBase=10;
  935. INT lBase=10;
  936. ULONG Auto;
  937. if ( NULL == StringSid || NULL == Sid || NULL == End ) {
  938. SetLastError( ERROR_INVALID_PARAMETER );
  939. return( FALSE );
  940. }
  941. // if ( wcslen( StringSid ) < 2 || ( *StringSid != L'S' && *( StringSid + 1 ) != L'-' ) ) {
  942. //
  943. // no need to check length because StringSid is NULL
  944. // and if the first char is NULL, it won't access the second char
  945. //
  946. if ( (*StringSid != L'S' && *StringSid != L's') ||
  947. *( StringSid + 1 ) != L'-' ) {
  948. //
  949. // string sid should always start with S-
  950. //
  951. SetLastError( ERROR_INVALID_SID );
  952. return( FALSE );
  953. }
  954. Curr = StringSid + 2;
  955. if ( (*Curr == L'0') &&
  956. ( *(Curr+1) == L'x' ||
  957. *(Curr+1) == L'X' ) ) {
  958. gBase = 16;
  959. }
  960. Revision = ( UCHAR )wcstol( Curr, &CurrEnd, gBase );
  961. if ( CurrEnd == Curr || *CurrEnd != L'-' || *(CurrEnd+1) == L'\0' ) {
  962. //
  963. // no revision is provided, or invalid delimeter
  964. //
  965. SetLastError( ERROR_INVALID_SID );
  966. return( FALSE );
  967. }
  968. Curr = CurrEnd + 1;
  969. //
  970. // Count the number of characters in the indentifer authority...
  971. //
  972. Next = wcschr( Curr, L'-' );
  973. /*
  974. Length = 6 doesn't mean each digit is a id authority value, could be 0x...
  975. if ( Next != NULL && (Next - Curr == 6) ) {
  976. for ( Index = 0; Index < 6; Index++ ) {
  977. // IDAuth.Value[Index] = (UCHAR)Next[Index]; what is this ???
  978. IDAuth.Value[Index] = (BYTE) (Curr[Index]-L'0');
  979. }
  980. Curr +=6;
  981. } else {
  982. */
  983. if ( (*Curr == L'0') &&
  984. ( *(Curr+1) == L'x' ||
  985. *(Curr+1) == L'X' ) ) {
  986. lBase = 16;
  987. } else {
  988. lBase = gBase;
  989. }
  990. Auto = wcstoul( Curr, &CurrEnd, lBase );
  991. if ( CurrEnd == Curr || *CurrEnd != L'-' || *(CurrEnd+1) == L'\0' ) {
  992. //
  993. // no revision is provided, or invalid delimeter
  994. //
  995. SetLastError( ERROR_INVALID_SID );
  996. return( FALSE );
  997. }
  998. IDAuth.Value[0] = IDAuth.Value[1] = 0;
  999. IDAuth.Value[5] = ( UCHAR )Auto & 0xFF;
  1000. IDAuth.Value[4] = ( UCHAR )(( Auto >> 8 ) & 0xFF );
  1001. IDAuth.Value[3] = ( UCHAR )(( Auto >> 16 ) & 0xFF );
  1002. IDAuth.Value[2] = ( UCHAR )(( Auto >> 24 ) & 0xFF );
  1003. Curr = CurrEnd;
  1004. // }
  1005. //
  1006. // Now, count the number of sub auths, at least one sub auth is required
  1007. //
  1008. Subs = 0;
  1009. Next = Curr;
  1010. //
  1011. // We'll have to count our sub authoritys one character at a time,
  1012. // since there are several deliminators that we can have...
  1013. //
  1014. while ( Next ) {
  1015. if ( *Next == L'-' && *(Next-1) != L'-') {
  1016. //
  1017. // do not allow two continuous '-'s
  1018. // We've found one!
  1019. //
  1020. Subs++;
  1021. if ( (*(Next+1) == L'0') &&
  1022. ( *(Next+2) == L'x' ||
  1023. *(Next+2) == L'X' ) ) {
  1024. //
  1025. // this is hex indicator
  1026. //
  1027. Next += 2;
  1028. }
  1029. } else if ( *Next == SDDL_SEPERATORC || *Next == L'\0' ||
  1030. *Next == SDDL_ACE_ENDC || *Next == L' ' ||
  1031. ( *(Next+1) == SDDL_DELIMINATORC &&
  1032. (*Next == L'G' || *Next == L'O' || *Next == L'S')) ) {
  1033. //
  1034. // space is a terminator too
  1035. //
  1036. if ( *( Next - 1 ) == L'-' ) {
  1037. //
  1038. // shouldn't allow a SID terminated with '-'
  1039. //
  1040. Err = ERROR_INVALID_SID;
  1041. Next--;
  1042. } else {
  1043. Subs++;
  1044. }
  1045. *End = Next;
  1046. break;
  1047. } else if ( !iswxdigit( *Next ) ) {
  1048. Err = ERROR_INVALID_SID;
  1049. *End = Next;
  1050. // Subs++;
  1051. break;
  1052. } else {
  1053. //
  1054. // Note: SID is also used as a owner or group
  1055. //
  1056. // Some of the tags (namely 'D' for Dacl) fall under the category of iswxdigit, so
  1057. // if the current character is a character we care about and the next one is a
  1058. // delminiator, we'll quit
  1059. //
  1060. if ( *Next == L'D' && *( Next + 1 ) == SDDL_DELIMINATORC ) {
  1061. //
  1062. // We'll also need to temporarily truncate the string to this length so
  1063. // we don't accidentally include the character in one of the conversions
  1064. //
  1065. Stub = *Next;
  1066. StubPtr = Next;
  1067. *StubPtr = UNICODE_NULL;
  1068. *End = Next;
  1069. Subs++;
  1070. break;
  1071. }
  1072. }
  1073. Next++;
  1074. }
  1075. if ( Err == ERROR_SUCCESS ) {
  1076. if ( Subs != 0 ) Subs--;
  1077. if ( Subs != 0 ) {
  1078. Curr++;
  1079. SubAuth = ( PULONG )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Subs * sizeof( ULONG ) );
  1080. if ( SubAuth == NULL ) {
  1081. Err = ERROR_NOT_ENOUGH_MEMORY;
  1082. } else {
  1083. for ( Index = 0; Index < Subs; Index++ ) {
  1084. if ( (*Curr == L'0') &&
  1085. ( *(Curr+1) == L'x' ||
  1086. *(Curr+1) == L'X' ) ) {
  1087. lBase = 16;
  1088. } else {
  1089. lBase = gBase;
  1090. }
  1091. SubAuth[Index] = wcstoul( Curr, &CurrEnd, lBase );
  1092. Curr = CurrEnd + 1;
  1093. }
  1094. }
  1095. } else {
  1096. Err = ERROR_INVALID_SID;
  1097. }
  1098. }
  1099. //
  1100. // Now, create the SID
  1101. //
  1102. if ( Err == ERROR_SUCCESS ) {
  1103. *Sid = ( PSID )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  1104. sizeof( SID ) + Subs * sizeof( ULONG ) );
  1105. if ( *Sid == NULL ) {
  1106. Err = ERROR_NOT_ENOUGH_MEMORY;
  1107. } else {
  1108. PISID ISid = ( PISID )*Sid;
  1109. ISid->Revision = Revision;
  1110. ISid->SubAuthorityCount = Subs;
  1111. RtlCopyMemory( &( ISid->IdentifierAuthority ), &IDAuth,
  1112. sizeof( SID_IDENTIFIER_AUTHORITY ) );
  1113. RtlCopyMemory( ISid->SubAuthority, SubAuth, Subs * sizeof( ULONG ) );
  1114. }
  1115. }
  1116. LocalFree( SubAuth );
  1117. //
  1118. // Restore any character we may have stubbed out
  1119. //
  1120. if ( StubPtr ) {
  1121. *StubPtr = Stub;
  1122. }
  1123. SetLastError( Err );
  1124. return( Err == ERROR_SUCCESS );
  1125. }
  1126. PSTRSD_SID_LOOKUP
  1127. LookupSidInTable(
  1128. IN PWSTR String OPTIONAL,
  1129. IN PSID Sid OPTIONAL,
  1130. IN PSID RootDomainSid OPTIONAL,
  1131. IN PSID DomainSid OPTIONAL,
  1132. IN PSTRSD_SID_LOOKUP tSidLookupDomOrRootDomRelativeTable OPTIONAL,
  1133. IN BOOLEAN DefaultToDomain,
  1134. IN PVOID *pSASid
  1135. )
  1136. /*++
  1137. Routine Description:
  1138. This routine will determine if the given sid or string sid exists in the lookup table.
  1139. A pointer to the matching static lookup entry is returned.
  1140. Arguments:
  1141. String - The string to be looked up
  1142. Sid - The sid to be looked up.
  1143. Return Value:
  1144. Lookup table entry if found
  1145. NULL if not found
  1146. --*/
  1147. {
  1148. BOOLEAN LookupSid = FALSE;
  1149. DWORD i, SidCount = sizeof( SidLookup ) / sizeof( STRSD_SID_LOOKUP );
  1150. PSTRSD_SID_LOOKUP MatchedEntry = NULL;
  1151. DWORD DomainAdminIndex;
  1152. BOOL InitRootDomain;
  1153. ULONG Rid;
  1154. BOOL bIsSA = FALSE;
  1155. if ( String == NULL && Sid == NULL ) {
  1156. //
  1157. // JINHUANG: if both string and sid are NULL
  1158. // just return NULL
  1159. //
  1160. return((PSTRSD_SID_LOOKUP)NULL);
  1161. }
  1162. *pSASid = NULL;
  1163. InitRootDomain = FALSE;
  1164. DomainAdminIndex = SidCount;
  1165. if ( String == NULL ) {
  1166. //
  1167. // lookup on the Sid
  1168. //
  1169. LookupSid = TRUE;
  1170. //
  1171. // check if the RID is for Enterprise Admins
  1172. //
  1173. Rid = *( RtlSubAuthoritySid( Sid,
  1174. *( RtlSubAuthorityCountSid(Sid) ) - 1 ) );
  1175. if ( DOMAIN_GROUP_RID_ENTERPRISE_ADMINS == Rid ||
  1176. DOMAIN_GROUP_RID_SCHEMA_ADMINS == Rid ) {
  1177. InitRootDomain = TRUE;
  1178. if ( DOMAIN_GROUP_RID_SCHEMA_ADMINS == Rid ) {
  1179. bIsSA = TRUE;
  1180. }
  1181. }
  1182. } else {
  1183. if ( _wcsnicmp( String, SDDL_ENTERPRISE_ADMINS, SDDL_LEN_TAG( SDDL_ENTERPRISE_ADMINS ) ) == 0 ) {
  1184. //
  1185. // Enterprise admins string is requested
  1186. //
  1187. InitRootDomain = TRUE;
  1188. } else if ( _wcsnicmp( String, SDDL_SCHEMA_ADMINISTRATORS, SDDL_LEN_TAG( SDDL_SCHEMA_ADMINISTRATORS ) ) == 0 ) {
  1189. //
  1190. // schema admin is requested
  1191. //
  1192. InitRootDomain = TRUE;
  1193. bIsSA = TRUE;
  1194. }
  1195. }
  1196. //
  1197. // the new API is the caller iff DomainSid != NULL
  1198. // on demand, initialize domain relative dynamic table for new API ()
  1199. //
  1200. if ( DomainSid ) {
  1201. //
  1202. // in this search, we will deal with the per thread table and not the global table
  1203. // in actuality, this per thread table is a proper subset of the global table
  1204. //
  1205. for ( i = 0; i < sizeof(SidLookupDomOrRootDomRelative)/sizeof(STRSD_SID_LOOKUP); i++ ) {
  1206. //
  1207. // for performance, only compute SID etc. if names match.
  1208. // in case the table is sparse, this heuristic comes in handy
  1209. // this doesn't preclude future lookup calls from leveraging useful work done here
  1210. //
  1211. if ( _wcsnicmp( String,
  1212. tSidLookupDomOrRootDomRelativeTable[ i ].Key,
  1213. tSidLookupDomOrRootDomRelativeTable[ i ].KeyLen ) == 0 ) {
  1214. if (tSidLookupDomOrRootDomRelativeTable[ i ].Valid == FALSE ||
  1215. tSidLookupDomOrRootDomRelativeTable[ i ].Sid == NULL) {
  1216. PSID RootDomainSidOrDomainSid = NULL;
  1217. if ( tSidLookupDomOrRootDomRelativeTable[ i ].SidType == ST_DOMAIN_RELATIVE )
  1218. RootDomainSidOrDomainSid = DomainSid;
  1219. else if ( tSidLookupDomOrRootDomRelativeTable[ i ].SidType == ST_ROOT_DOMAIN_RELATIVE &&
  1220. RootDomainSid )
  1221. RootDomainSidOrDomainSid = RootDomainSid;
  1222. else {
  1223. //
  1224. // this will happen when the RootDomainSid is not provided when using the
  1225. // new API and so ST_ROOT_DOMAIN_RELATIVE type SIDs will get resolved wrt
  1226. // the local m/c's root domain - so we will allow the lookup to continue
  1227. // in the normal way
  1228. //
  1229. break;
  1230. }
  1231. //
  1232. // do this for legacy-code reasons
  1233. //
  1234. tSidLookupDomOrRootDomRelativeTable[ i ].Sid =
  1235. ( PSID )tSidLookupDomOrRootDomRelativeTable[ i ].SidBuff;
  1236. RtlCopyMemory( tSidLookupDomOrRootDomRelativeTable[ i ].Sid, RootDomainSidOrDomainSid,
  1237. RtlLengthSid( RootDomainSidOrDomainSid ) );
  1238. ( ( PISID )( tSidLookupDomOrRootDomRelativeTable[ i ].Sid ) )->SubAuthorityCount++;
  1239. *( RtlSubAuthoritySid( tSidLookupDomOrRootDomRelativeTable[ i ].Sid,
  1240. *( RtlSubAuthorityCountSid( RootDomainSidOrDomainSid ) ) ) ) =
  1241. tSidLookupDomOrRootDomRelativeTable[ i ].Rid;
  1242. tSidLookupDomOrRootDomRelativeTable[ i ].Valid = TRUE;
  1243. }
  1244. if (tSidLookupDomOrRootDomRelativeTable[ i ].Valid == TRUE)
  1245. MatchedEntry = &tSidLookupDomOrRootDomRelativeTable[ i ];
  1246. //
  1247. // if we get here, we have to return MatchedEntry since we know that:
  1248. //
  1249. // (a) the new API is the caller (DomainSid != NULL) and
  1250. // (b) we are dealing with ST_DOMAIN_RELATIVE or
  1251. // ST_ROOT_DOMAIN_RELATIVE type trustees (with RootDomainSid provided)
  1252. // (c) there is a match with the trustee name such as "DA" or "EA"
  1253. //
  1254. return (MatchedEntry);
  1255. }
  1256. }
  1257. }
  1258. InitializeSidLookupTable(STRSD_REINITIALIZE_ENTER);
  1259. if ( InitRootDomain &&
  1260. RootDomainSid == NULL &&
  1261. DefaultToDomain == FALSE &&
  1262. ( RootDomInited == FALSE ||
  1263. !RtlValidSid( (PSID)RootDomSidBuf ) ) ) {
  1264. //
  1265. // get the root domain sid (using ldap calls)
  1266. //
  1267. SddlpGetRootDomainSid();
  1268. }
  1269. for ( i = 0; i < SidCount; i++ ) {
  1270. //
  1271. // if new API and domain relative trustee, skip the entry
  1272. // since the global table won't be used in this scenario.
  1273. // matches for such entries are taken care of, in the per-thread table above
  1274. //
  1275. // cannot skip if InitRootDomain == TRUE since SDDL_DOMAIN_ADMINISTRATORS in
  1276. // SidLookup[] is potentially matched against, shortly
  1277. //
  1278. if ( InitRootDomain == FALSE &&
  1279. DomainSid &&
  1280. SidLookup[ i ].SidType == ST_DOMAIN_RELATIVE )
  1281. continue;
  1282. //
  1283. // if this is an entry that has been initialized, skip it
  1284. //
  1285. if ( SidLookup[ i ].Valid == FALSE ||
  1286. SidLookup[ i ].Sid == NULL ) {
  1287. if ( SidLookup[ i ].SidType == ST_ROOT_DOMAIN_RELATIVE &&
  1288. InitRootDomain ) {
  1289. if ( RootDomainSid != NULL ) {
  1290. EnterCriticalSection(&SddlSidLookupCritical);
  1291. RtlCopyMemory( SidLookup[ i ].Sid, RootDomainSid,
  1292. RtlLengthSid( RootDomainSid ) );
  1293. ( ( PISID )( SidLookup[ i ].Sid ) )->SubAuthorityCount++;
  1294. *( RtlSubAuthoritySid( SidLookup[ i ].Sid,
  1295. *( RtlSubAuthorityCountSid( RootDomainSid ) ) ) ) =
  1296. SidLookup[ i ].Rid;
  1297. SidLookup[ i ].Valid = TRUE;
  1298. LeaveCriticalSection(&SddlSidLookupCritical);
  1299. } else if ( DefaultToDomain ) {
  1300. //
  1301. // should default EA to DA and SA to domain relative
  1302. //
  1303. } else {
  1304. if ( RootDomInited && RtlValidSid( (PSID)RootDomSidBuf ) &&
  1305. ( ( SidLookup[ i ].Valid == FALSE ) ||
  1306. ( SidLookup[ i ].Sid == NULL ) ) ) {
  1307. EnterCriticalSection(&SddlSidLookupCritical);
  1308. RtlCopyMemory( SidLookup[ i ].Sid, (PSID)RootDomSidBuf,
  1309. RtlLengthSid( (PSID)RootDomSidBuf ) );
  1310. ( ( PISID )( SidLookup[ i ].Sid ) )->SubAuthorityCount++;
  1311. *( RtlSubAuthoritySid( SidLookup[ i ].Sid,
  1312. *( RtlSubAuthorityCountSid( (PSID)RootDomSidBuf ) ) ) ) =
  1313. SidLookup[ i ].Rid;
  1314. SidLookup[ i ].Valid = TRUE;
  1315. LeaveCriticalSection(&SddlSidLookupCritical);
  1316. }
  1317. }
  1318. }
  1319. if ( SidLookup[ i ].Valid == FALSE ||
  1320. SidLookup[ i ].Sid == NULL ) {
  1321. continue;
  1322. }
  1323. }
  1324. if ( LookupSid ) {
  1325. if ( RtlEqualSid( Sid, SidLookup[ i ].Sid ) ) {
  1326. break;
  1327. }
  1328. } else {
  1329. //
  1330. // check for the current key first
  1331. //
  1332. if ( _wcsnicmp( String, SidLookup[i].Key, SidLookup[i].KeyLen ) == 0 ) {
  1333. break;
  1334. } else if ( InitRootDomain && DefaultToDomain &&
  1335. (RootDomainSid == NULL) ) {
  1336. //
  1337. // looking for EA/SA, not found them,
  1338. // EA needs to default to DA, SA needs to default to domain relative
  1339. //
  1340. if ( _wcsnicmp( SDDL_DOMAIN_ADMINISTRATORS, SidLookup[i].Key, SidLookup[i].KeyLen ) == 0 ) {
  1341. DomainAdminIndex = i;
  1342. // break;
  1343. }
  1344. }
  1345. }
  1346. }
  1347. if ( i < SidCount ) {
  1348. MatchedEntry = &SidLookup[ i ];
  1349. } else if ( InitRootDomain && DefaultToDomain &&
  1350. (RootDomainSid == NULL) &&
  1351. ( DomainAdminIndex < SidCount ) ) {
  1352. if ( bIsSA ) {
  1353. //
  1354. // default to domain relative sid
  1355. //
  1356. if ( LookupSid ) {
  1357. *pSASid = (PVOID)Sid;
  1358. } else if ( SidLookup[ DomainAdminIndex ].Sid ) {
  1359. //
  1360. // allocate buffer for domain relative SA sid
  1361. // which means it's only valid on the root domain
  1362. //
  1363. i = RtlLengthSid( SidLookup[ DomainAdminIndex ].Sid );
  1364. *pSASid = (PVOID)LocalAlloc( LMEM_FIXED, i+1 );
  1365. if ( *pSASid != NULL ) {
  1366. RtlCopyMemory( (PSID)(*pSASid), SidLookup[ DomainAdminIndex ].Sid, i );
  1367. // replace the DA rid with SA rid
  1368. *( RtlSubAuthoritySid( (PSID)(*pSASid),
  1369. *( RtlSubAuthorityCountSid( SidLookup[ DomainAdminIndex ].Sid )) - 1) ) =
  1370. DOMAIN_GROUP_RID_SCHEMA_ADMINS;
  1371. }
  1372. }
  1373. } else {
  1374. //
  1375. // default to the domain admin account
  1376. //
  1377. MatchedEntry = &SidLookup[ DomainAdminIndex ];
  1378. }
  1379. }
  1380. InitializeSidLookupTable(STRSD_REINITIALIZE_LEAVE);
  1381. return( MatchedEntry );
  1382. }
  1383. DWORD
  1384. LocalGetSidForString(
  1385. IN PWSTR String,
  1386. OUT PSID *SID,
  1387. OUT PWSTR *End,
  1388. OUT PBOOLEAN FreeSid,
  1389. IN PSID RootDomainSid OPTIONAL,
  1390. IN PSID DomainSid OPTIONAL,
  1391. IN PSTRSD_SID_LOOKUP tSidLookupDomOrRootDomRelativeTable OPTIONAL,
  1392. IN BOOLEAN DefaultToDomain
  1393. )
  1394. /*++
  1395. Routine Description:
  1396. This routine will determine which sid is an appropriate match for the
  1397. given string, either as a sid moniker or as a string representation of a
  1398. sid (ie: "DA or "S-1-0-0" )
  1399. The returned sid must be free via a call to LocalFree if the *pFreeSid
  1400. output parameter is TRUE. If it's FALSE, no additional action needs to
  1401. be taken
  1402. Arguments:
  1403. String - The string to be converted
  1404. Sid - Where the created SID is to be returned
  1405. End - Where in the string we stopped processing
  1406. FreeSid - Determines whether the returned SID needs to be freed via a
  1407. call to LocalFree or not
  1408. Return Value:
  1409. ERROR_SUCCESS - success
  1410. ERROR_NON_MAPPED - An invalid format of the SID was given
  1411. --*/
  1412. {
  1413. DWORD Err = ERROR_SUCCESS;
  1414. PSTRSD_SID_LOOKUP MatchedEntry;
  1415. PSID pSidSA=NULL;
  1416. if ( String == NULL || SID == NULL || End == NULL || FreeSid == NULL ) {
  1417. return(ERROR_INVALID_PARAMETER);
  1418. }
  1419. //
  1420. // Assume we'll return a well known sid
  1421. //
  1422. *FreeSid = FALSE;
  1423. // if ( wcslen( String ) < 2 ) {
  1424. // no need to do wcslen (expensive) because we know that String is not NULL
  1425. // so just check for the first and second char
  1426. if ( *String == L'\0' || *( String +1 ) == L'\0' ) {
  1427. return( ERROR_NONE_MAPPED );
  1428. }
  1429. //
  1430. // Set our end of string pointer
  1431. //
  1432. *End = String + 2;
  1433. MatchedEntry = LookupSidInTable( String,
  1434. NULL,
  1435. RootDomainSid,
  1436. DomainSid,
  1437. tSidLookupDomOrRootDomRelativeTable,
  1438. DefaultToDomain,
  1439. (PVOID *)&pSidSA);
  1440. //
  1441. // If we didn't find a match, try it as a sid string
  1442. //
  1443. if ( MatchedEntry == NULL ) {
  1444. if ( pSidSA ) {
  1445. //
  1446. // this is schema admin lookup
  1447. //
  1448. *SID = pSidSA;
  1449. *FreeSid = TRUE;
  1450. } else {
  1451. //
  1452. // We assumed a known moniker, so we'll have to unset our end of string pointer.
  1453. // Also, if it's a not a SID, the Convert routine will return the appropriate error.
  1454. //
  1455. *End -= 2;
  1456. if ( LocalConvertStringSidToSid( String, SID, End) == FALSE ) {
  1457. Err = GetLastError();
  1458. }
  1459. if ( Err == ERROR_SUCCESS && *SID != NULL ) {
  1460. *FreeSid = TRUE;
  1461. }
  1462. }
  1463. } else {
  1464. //
  1465. // If the entry that's been selected hasn't been initialized yet, do it now
  1466. //
  1467. *SID = MatchedEntry->Sid;
  1468. }
  1469. return(Err);
  1470. }
  1471. DWORD
  1472. LocalGetStringForSid(
  1473. IN PSID Sid,
  1474. OUT PWSTR *String,
  1475. IN PSID RootDomainSid OPTIONAL
  1476. )
  1477. /*++
  1478. Routine Description:
  1479. This routine will determine which string represents a sid, either as a sid moniker or
  1480. as a string representation of a sid (ie: "DA or "S-1-0-0" )
  1481. The returned string must be free via a call to LocalFree
  1482. Arguments:
  1483. Sid - Sid to be converted
  1484. String - Where the mapped Sid is to be returned
  1485. Return Value:
  1486. ERROR_SUCCESS - success
  1487. ERROR_NON_MAPPED - An invalid format of the SID was given
  1488. ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
  1489. --*/
  1490. {
  1491. DWORD Err = ERROR_SUCCESS;
  1492. PSTRSD_SID_LOOKUP MatchedEntry;
  1493. PSID pSidSA=NULL;
  1494. DWORD Len;
  1495. if ( Sid == NULL || String == NULL ) {
  1496. return(ERROR_INVALID_PARAMETER);
  1497. }
  1498. //
  1499. // Try to find a match in the lookup table
  1500. //
  1501. MatchedEntry = LookupSidInTable( NULL,
  1502. Sid,
  1503. RootDomainSid,
  1504. NULL,
  1505. NULL,
  1506. FALSE,
  1507. (PVOID *)&pSidSA );
  1508. //
  1509. // If a match was found, return it
  1510. //
  1511. if ( MatchedEntry || pSidSA ) {
  1512. if ( MatchedEntry ) {
  1513. Len = MatchedEntry->KeyLen;
  1514. } else {
  1515. Len = wcslen(SDDL_SCHEMA_ADMINISTRATORS);
  1516. }
  1517. *String = LocalAlloc( LMEM_FIXED, ( Len * sizeof( WCHAR ) ) + sizeof( WCHAR ) );
  1518. if ( *String == NULL ) {
  1519. Err = ERROR_NOT_ENOUGH_MEMORY;
  1520. } else {
  1521. if ( MatchedEntry ) {
  1522. wcscpy( *String, MatchedEntry->Key );
  1523. } else {
  1524. wcscpy( *String, SDDL_SCHEMA_ADMINISTRATORS);
  1525. }
  1526. }
  1527. } else {
  1528. if ( ConvertSidToStringSidW( Sid, String ) == FALSE ) {
  1529. Err = GetLastError();
  1530. }
  1531. }
  1532. return(Err);
  1533. }
  1534. DWORD
  1535. LocalGetStringForControl(
  1536. IN SECURITY_DESCRIPTOR_CONTROL ControlCode,
  1537. IN ULONG LookupFlags,
  1538. OUT PWSTR *ControlString
  1539. )
  1540. {
  1541. DWORD i, ControlCount = sizeof( ControlLookup ) / sizeof( STRSD_KEY_LOOKUP );
  1542. WCHAR Buffer[256];
  1543. DWORD nOffset=0;
  1544. if ( !ControlString ) {
  1545. return(ERROR_INVALID_PARAMETER);
  1546. }
  1547. *ControlString = NULL;
  1548. for ( i = 0; i < ControlCount; i++ ) {
  1549. //
  1550. // If it doesn't match our lookup type, skip it.
  1551. //
  1552. if ( ( LookupFlags & ControlLookup[ i ].ValidityFlags ) != LookupFlags ) {
  1553. continue;
  1554. }
  1555. if ( ControlCode & ControlLookup[ i ].Value ) {
  1556. wcsncpy(Buffer+nOffset,
  1557. ControlLookup[ i ].Key,
  1558. ControlLookup[ i ].KeyLen );
  1559. nOffset += ControlLookup[ i ].KeyLen;
  1560. }
  1561. }
  1562. Buffer[nOffset] = L'\0';
  1563. if ( nOffset ) {
  1564. *ControlString = (PWSTR)LocalAlloc(0, (nOffset+1)*sizeof(WCHAR));
  1565. if ( *ControlString ) {
  1566. wcscpy(*ControlString, Buffer);
  1567. } else {
  1568. return(ERROR_NOT_ENOUGH_MEMORY);
  1569. }
  1570. }
  1571. return( ERROR_SUCCESS );
  1572. }
  1573. PSTRSD_KEY_LOOKUP
  1574. LookupAccessMaskInTable(
  1575. IN PWSTR String, OPTIONAL
  1576. IN ULONG AccessMask, OPTIONAL
  1577. IN ULONG LookupFlags
  1578. )
  1579. /*++
  1580. Routine Description:
  1581. This routine will determine if the given access mask or string right exists in the lookup
  1582. table.
  1583. A pointer to the matching static lookup entry is returned.
  1584. Arguments:
  1585. String - The string to be looked up
  1586. AccessMask - The accessMask to be looked up.
  1587. LookupFlags - Flags to use for lookup (Dacl or Sacl)
  1588. Return Value:
  1589. Lookup table entry if found
  1590. NULL if not found
  1591. --*/
  1592. {
  1593. //
  1594. // This is how the access mask is looked up. Always have the multi-char
  1595. // rights before the single char ones
  1596. //
  1597. static STRSD_KEY_LOOKUP RightsLookup[] = {
  1598. { SDDL_READ_PROPERTY, SDDL_LEN_TAG( SDDL_READ_PROPERTY ), ACTRL_DS_READ_PROP, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1599. { SDDL_WRITE_PROPERTY, SDDL_LEN_TAG( SDDL_WRITE_PROPERTY ), ACTRL_DS_WRITE_PROP, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1600. { SDDL_CREATE_CHILD, SDDL_LEN_TAG( SDDL_CREATE_CHILD ), ACTRL_DS_CREATE_CHILD, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1601. { SDDL_DELETE_CHILD, SDDL_LEN_TAG( SDDL_DELETE_CHILD ), ACTRL_DS_DELETE_CHILD, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1602. { SDDL_LIST_CHILDREN, SDDL_LEN_TAG( SDDL_LIST_CHILDREN ), ACTRL_DS_LIST, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1603. { SDDL_SELF_WRITE, SDDL_LEN_TAG( SDDL_SELF_WRITE ), ACTRL_DS_SELF, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1604. { SDDL_LIST_OBJECT, SDDL_LEN_TAG( SDDL_LIST_OBJECT ), ACTRL_DS_LIST_OBJECT, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1605. { SDDL_DELETE_TREE, SDDL_LEN_TAG( SDDL_DELETE_TREE ), ACTRL_DS_DELETE_TREE, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1606. { SDDL_CONTROL_ACCESS, SDDL_LEN_TAG( SDDL_CONTROL_ACCESS ), ACTRL_DS_CONTROL_ACCESS, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1607. { SDDL_READ_CONTROL, SDDL_LEN_TAG( SDDL_READ_CONTROL ), READ_CONTROL, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1608. { SDDL_WRITE_DAC, SDDL_LEN_TAG( SDDL_WRITE_DAC ), WRITE_DAC, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1609. { SDDL_WRITE_OWNER, SDDL_LEN_TAG( SDDL_WRITE_OWNER ), WRITE_OWNER, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1610. { SDDL_STANDARD_DELETE, SDDL_LEN_TAG( SDDL_STANDARD_DELETE ), DELETE, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1611. { SDDL_GENERIC_ALL, SDDL_LEN_TAG( SDDL_GENERIC_ALL ), GENERIC_ALL, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1612. { SDDL_GENERIC_READ, SDDL_LEN_TAG( SDDL_GENERIC_READ ), GENERIC_READ, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1613. { SDDL_GENERIC_WRITE, SDDL_LEN_TAG( SDDL_GENERIC_WRITE ), GENERIC_WRITE, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1614. { SDDL_GENERIC_EXECUTE, SDDL_LEN_TAG( SDDL_GENERIC_EXECUTE ), GENERIC_EXECUTE, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1615. { SDDL_FILE_ALL, SDDL_LEN_TAG( SDDL_FILE_ALL ), FILE_ALL_ACCESS, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1616. { SDDL_FILE_READ, SDDL_LEN_TAG( SDDL_FILE_READ ), FILE_GENERIC_READ, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1617. { SDDL_FILE_WRITE, SDDL_LEN_TAG( SDDL_FILE_WRITE ), FILE_GENERIC_WRITE, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1618. { SDDL_FILE_EXECUTE, SDDL_LEN_TAG( SDDL_FILE_EXECUTE ), FILE_GENERIC_EXECUTE, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1619. { SDDL_KEY_ALL, SDDL_LEN_TAG( SDDL_KEY_ALL ), KEY_ALL_ACCESS, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1620. { SDDL_KEY_READ, SDDL_LEN_TAG( SDDL_KEY_READ ), KEY_READ, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1621. { SDDL_KEY_WRITE, SDDL_LEN_TAG( SDDL_KEY_WRITE ), KEY_WRITE, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1622. { SDDL_KEY_EXECUTE, SDDL_LEN_TAG( SDDL_KEY_EXECUTE ), KEY_EXECUTE, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1623. };
  1624. DWORD i, RightsCount = sizeof(RightsLookup) / sizeof(STRSD_KEY_LOOKUP);
  1625. PSTRSD_KEY_LOOKUP MatchedEntry = NULL;
  1626. BOOLEAN LookupString = FALSE;
  1627. if ( String ) {
  1628. LookupString = TRUE;
  1629. }
  1630. for ( i = 0; i < RightsCount; i++ ) {
  1631. //
  1632. // If it doesn't match our lookup type, skip it.
  1633. //
  1634. if ( ( LookupFlags & RightsLookup[ i ].ValidityFlags ) != LookupFlags ) {
  1635. continue;
  1636. }
  1637. if ( LookupString ) {
  1638. if ( _wcsnicmp( String, RightsLookup[ i ].Key, RightsLookup[ i ].KeyLen ) == 0 ) {
  1639. break;
  1640. }
  1641. } else {
  1642. if ( AccessMask == RightsLookup[ i ].Value ) {
  1643. break;
  1644. }
  1645. }
  1646. }
  1647. //
  1648. // If a match was found, return it
  1649. //
  1650. if ( i < RightsCount ) {
  1651. MatchedEntry = &RightsLookup[ i ];
  1652. }
  1653. return( MatchedEntry );
  1654. }
  1655. PSTRSD_KEY_LOOKUP
  1656. LookupAceTypeInTable(
  1657. IN PWSTR String, OPTIONAL
  1658. IN ULONG AceType, OPTIONAL
  1659. IN ULONG LookupFlags
  1660. )
  1661. /*++
  1662. Routine Description:
  1663. This routine will determine if the given ace type or string type exists in the lookup
  1664. table.
  1665. A pointer to the matching static lookup entry is returned.
  1666. Arguments:
  1667. String - The string to be looked up
  1668. AceType - The ace type to be looked up.
  1669. LookupFlags - Flags to use for lookup (Dacl or Sacl)
  1670. Return Value:
  1671. Lookup table entry if found
  1672. NULL if not found
  1673. --*/
  1674. {
  1675. //
  1676. // Lookup table
  1677. //
  1678. static STRSD_KEY_LOOKUP TypeLookup[] = {
  1679. { SDDL_ACCESS_ALLOWED, SDDL_LEN_TAG( SDDL_ACCESS_ALLOWED ), ACCESS_ALLOWED_ACE_TYPE, SDDL_VALID_DACL },
  1680. { SDDL_ACCESS_DENIED, SDDL_LEN_TAG( SDDL_ACCESS_DENIED ), ACCESS_DENIED_ACE_TYPE, SDDL_VALID_DACL },
  1681. { SDDL_OBJECT_ACCESS_ALLOWED, SDDL_LEN_TAG( SDDL_OBJECT_ACCESS_ALLOWED ),
  1682. ACCESS_ALLOWED_OBJECT_ACE_TYPE, SDDL_VALID_DACL },
  1683. { SDDL_OBJECT_ACCESS_DENIED, SDDL_LEN_TAG( SDDL_OBJECT_ACCESS_DENIED ),
  1684. ACCESS_DENIED_OBJECT_ACE_TYPE, SDDL_VALID_DACL },
  1685. { SDDL_AUDIT, SDDL_LEN_TAG( SDDL_AUDIT ), SYSTEM_AUDIT_ACE_TYPE, SDDL_VALID_SACL },
  1686. { SDDL_ALARM, SDDL_LEN_TAG( SDDL_ALARM ), SYSTEM_ALARM_ACE_TYPE, SDDL_VALID_SACL },
  1687. { SDDL_OBJECT_AUDIT, SDDL_LEN_TAG( SDDL_OBJECT_AUDIT ), SYSTEM_AUDIT_OBJECT_ACE_TYPE, SDDL_VALID_SACL },
  1688. { SDDL_OBJECT_ALARM, SDDL_LEN_TAG( SDDL_OBJECT_ALARM ), SYSTEM_ALARM_OBJECT_ACE_TYPE, SDDL_VALID_SACL }
  1689. };
  1690. DWORD i, TypeCount = sizeof( TypeLookup ) / sizeof( STRSD_KEY_LOOKUP );
  1691. PSTRSD_KEY_LOOKUP MatchedEntry = NULL;
  1692. BOOLEAN LookupString = FALSE;
  1693. if ( String ) {
  1694. LookupString = TRUE;
  1695. }
  1696. for ( i = 0; i < TypeCount; i++ ) {
  1697. //
  1698. // If it doesn't match our lookup type, skip it.
  1699. //
  1700. if ( ( LookupFlags & TypeLookup[ i ].ValidityFlags ) != LookupFlags ) {
  1701. continue;
  1702. }
  1703. if ( LookupString ) {
  1704. if ( _wcsnicmp( String, TypeLookup[ i ].Key, TypeLookup[ i ].KeyLen ) == 0 ) {
  1705. break;
  1706. }
  1707. } else {
  1708. if ( AceType == TypeLookup[ i ].Value ) {
  1709. break;
  1710. }
  1711. }
  1712. }
  1713. //
  1714. // If a match was found, return it
  1715. //
  1716. if ( i < TypeCount ) {
  1717. MatchedEntry = &TypeLookup[ i ];
  1718. }
  1719. return( MatchedEntry );
  1720. }
  1721. PSTRSD_KEY_LOOKUP
  1722. LookupAceFlagsInTable(
  1723. IN PWSTR String, OPTIONAL
  1724. IN ULONG AceFlags, OPTIONAL
  1725. IN ULONG LookupFlags
  1726. )
  1727. /*++
  1728. Routine Description:
  1729. This routine will determine if the given ace flags or string flags exists in the lookup
  1730. table.
  1731. A pointer to the matching static lookup entry is returned.
  1732. Arguments:
  1733. String - The string to be looked up
  1734. AceFlags - The ace flags to be looked up.
  1735. LookupFlags - Flags to use for lookup (Dacl or Sacl)
  1736. Return Value:
  1737. Lookup table entry if found
  1738. NULL if not found
  1739. --*/
  1740. {
  1741. //
  1742. // Lookup tables
  1743. //
  1744. static STRSD_KEY_LOOKUP FlagLookup[] = {
  1745. { SDDL_CONTAINER_INHERIT, SDDL_LEN_TAG( SDDL_CONTAINER_INHERIT ), CONTAINER_INHERIT_ACE, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1746. { SDDL_OBJECT_INHERIT, SDDL_LEN_TAG( SDDL_OBJECT_INHERIT ), OBJECT_INHERIT_ACE, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1747. { SDDL_NO_PROPAGATE, SDDL_LEN_TAG( SDDL_NO_PROPAGATE ), NO_PROPAGATE_INHERIT_ACE, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1748. { SDDL_INHERIT_ONLY, SDDL_LEN_TAG( SDDL_INHERIT_ONLY ), INHERIT_ONLY_ACE, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1749. { SDDL_INHERITED, SDDL_LEN_TAG( SDDL_INHERITED ), INHERITED_ACE, SDDL_VALID_DACL | SDDL_VALID_SACL },
  1750. { SDDL_AUDIT_SUCCESS, SDDL_LEN_TAG( SDDL_AUDIT_SUCCESS ), SUCCESSFUL_ACCESS_ACE_FLAG, SDDL_VALID_SACL },
  1751. { SDDL_AUDIT_FAILURE, SDDL_LEN_TAG( SDDL_AUDIT_FAILURE ), FAILED_ACCESS_ACE_FLAG, SDDL_VALID_SACL }
  1752. };
  1753. DWORD i, FlagCount = sizeof( FlagLookup ) / sizeof( STRSD_KEY_LOOKUP );
  1754. PSTRSD_KEY_LOOKUP MatchedEntry = NULL;
  1755. BOOLEAN LookupString = FALSE;
  1756. if ( String ) {
  1757. LookupString = TRUE;
  1758. }
  1759. for ( i = 0; i < FlagCount; i++ ) {
  1760. //
  1761. // If it doesn't match our lookup type, skip it.
  1762. //
  1763. if ( ( LookupFlags & FlagLookup[ i ].ValidityFlags ) != LookupFlags ) {
  1764. continue;
  1765. }
  1766. if ( LookupString ) {
  1767. if ( _wcsnicmp( String, FlagLookup[ i ].Key, FlagLookup[ i ].KeyLen ) == 0 ) {
  1768. break;
  1769. }
  1770. } else {
  1771. if ( AceFlags == FlagLookup[ i ].Value ) {
  1772. break;
  1773. }
  1774. }
  1775. }
  1776. //
  1777. // If a match was found, return it
  1778. //
  1779. if ( i < FlagCount ) {
  1780. MatchedEntry = &FlagLookup[ i ];
  1781. }
  1782. return( MatchedEntry );
  1783. }
  1784. DWORD
  1785. LocalGetSDControlForString (
  1786. IN PWSTR ControlString,
  1787. IN ULONG LookupFlags,
  1788. OUT SECURITY_DESCRIPTOR_CONTROL *pControl,
  1789. OUT PWSTR *End
  1790. )
  1791. {
  1792. DWORD i, ControlCount = sizeof( ControlLookup ) / sizeof( STRSD_KEY_LOOKUP );
  1793. PWSTR pCursor=ControlString;
  1794. BOOL bFound;
  1795. if ( !ControlString || !pControl || !End ) {
  1796. return(ERROR_INVALID_PARAMETER);
  1797. }
  1798. *pControl = 0;
  1799. while ( pCursor && *pCursor == L' ' ) {
  1800. //
  1801. // skip any blanks
  1802. //
  1803. pCursor++;
  1804. }
  1805. do {
  1806. bFound = FALSE;
  1807. for ( i = 0; i < ControlCount; i++ ) {
  1808. //
  1809. // If it doesn't match our lookup type, skip it.
  1810. //
  1811. if ( ( LookupFlags & ControlLookup[ i ].ValidityFlags ) != LookupFlags ) {
  1812. continue;
  1813. }
  1814. if ( _wcsnicmp( pCursor,
  1815. ControlLookup[ i ].Key,
  1816. ControlLookup[ i ].KeyLen ) == 0 ) {
  1817. *pControl |= ControlLookup[ i ].Value;
  1818. pCursor += ControlLookup[ i ].KeyLen;
  1819. while ( pCursor && *pCursor == L' ' ) {
  1820. //
  1821. // skip any blanks
  1822. //
  1823. pCursor++;
  1824. }
  1825. bFound = TRUE;
  1826. break; // break the for loop
  1827. }
  1828. }
  1829. } while ( bFound );
  1830. *End = pCursor;
  1831. return( ERROR_SUCCESS );
  1832. }
  1833. DWORD
  1834. LocalGetAclForString(
  1835. IN PWSTR AclString,
  1836. IN BOOLEAN ConvertAsDacl,
  1837. OUT PACL *Acl,
  1838. OUT PWSTR *End,
  1839. IN PSID RootDomainSid OPTIONAL,
  1840. IN PSID DomainSid OPTIONAL,
  1841. IN PSTRSD_SID_LOOKUP tSidLookupDomOrRootDomRelativeTable OPTIONAL,
  1842. IN BOOLEAN DefaultToDomain
  1843. )
  1844. /*++
  1845. Routine Description:
  1846. This routine convert a string into an ACL. The format of the aces is:
  1847. Ace := ( Type; Flags; Rights; ObjGuid; IObjGuid; Sid;
  1848. Type : = A | D | OA | OD {Access, Deny, ObjectAccess, ObjectDeny}
  1849. Flags := Flags Flag
  1850. Flag : = CI | IO | NP | SA | FA {Container Inherit,Inherit Only, NoProp,
  1851. SuccessAudit, FailAdit }
  1852. Rights := Rights Right
  1853. Right := DS_READ_PROPERTY | blah blah
  1854. Guid := String representation of a GUID (via RPC UuidToString)
  1855. Sid := DA | PS | AO | PO | AU | S-* (Domain Admins, PersonalSelf, Acct Ops,
  1856. PrinterOps, AuthenticatedUsers, or
  1857. the string representation of a sid)
  1858. The seperator is a ';'.
  1859. The returned ACL must be free via a call to LocalFree
  1860. Arguments:
  1861. AclString - The string to be converted
  1862. ConvertAsDacl - Treat the input string as a dacl string
  1863. ppSid - Where the created SID is to be returned
  1864. End - Where in the string we stopped processing
  1865. Return Value:
  1866. ERROR_SUCCESS indicates success
  1867. ERROR_NOT_ENOUGH_MEMORY indicates a memory allocation for the ouput acl
  1868. failed
  1869. ERROR_INVALID_PARAMETER The string does not represent an ACL
  1870. --*/
  1871. {
  1872. DWORD Err = ERROR_SUCCESS;
  1873. DWORD AclSize = 0, AclUsed = 0;
  1874. ULONG Acls = 0, i, j;
  1875. PWSTR Curr, MaskEnd;
  1876. WCHAR ConvertGuidString[ STRING_GUID_LEN + 1];
  1877. BOOLEAN FreeSid = FALSE;
  1878. BOOL OpRes;
  1879. PSTRSD_KEY_LOOKUP MatchedEntry;
  1880. ULONG LookupFlags;
  1881. PSID SidPtr = NULL;
  1882. if ( NULL == AclString || NULL == Acl || NULL == End ) {
  1883. return(ERROR_INVALID_PARAMETER);
  1884. }
  1885. if ( ConvertAsDacl ) {
  1886. LookupFlags = SDDL_VALID_DACL;
  1887. } else {
  1888. LookupFlags = SDDL_VALID_SACL;
  1889. }
  1890. //
  1891. // First, we'll have to go through and count the number of entries that
  1892. // we have. We'll do the by computing the length of this ACL (which is
  1893. // delimited by either the end of the list or a ':' that seperates a key
  1894. // from a value
  1895. //
  1896. *End = wcschr( AclString, SDDL_DELIMINATORC );
  1897. if ( *End == AclString ) {
  1898. return(ERROR_INVALID_PARAMETER);
  1899. }
  1900. if ( *End == NULL ) {
  1901. *End = AclString + wcslen( AclString );
  1902. } else {
  1903. ( *End )--;
  1904. }
  1905. //
  1906. // Now, do the count
  1907. //
  1908. Curr = AclString;
  1909. OpRes = 0;
  1910. // while ( Curr != *End ) {
  1911. while ( Curr < *End ) {
  1912. if ( *Curr == SDDL_SEPERATORC ) {
  1913. Acls++;
  1914. } else if ( *Curr != L' ' ) {
  1915. OpRes = 1;
  1916. }
  1917. Curr++;
  1918. }
  1919. //
  1920. // Now, we've counted the total number of seperators. Make sure we
  1921. // have the right number. (There is 5 seperators per ace)
  1922. //
  1923. if ( Acls % 5 == 0 ) {
  1924. if ( Acls == 0 && OpRes ) {
  1925. //
  1926. // gabbage chars in between
  1927. //
  1928. Err = ERROR_INVALID_PARAMETER;
  1929. } else {
  1930. Acls = Acls / 5;
  1931. }
  1932. } else {
  1933. Err = ERROR_INVALID_PARAMETER;
  1934. }
  1935. if ( Err == ERROR_SUCCESS && Acls == 0 ) {
  1936. *Acl = LocalAlloc( LMEM_FIXED, sizeof( ACL ) );
  1937. if ( *Acl == NULL ) {
  1938. Err = ERROR_NOT_ENOUGH_MEMORY;
  1939. } else {
  1940. ( *Acl )->AclRevision = ACL_REVISION;
  1941. ( *Acl )->Sbz1 = ( BYTE )0;
  1942. ( *Acl )->AclSize = ( USHORT )sizeof( ACL ) ;
  1943. ( *Acl )->AceCount = 0;
  1944. ( *Acl )->Sbz2 = ( USHORT )0;
  1945. }
  1946. return( Err );
  1947. }
  1948. //
  1949. // Ok now do the allocation. We'll do a sort of worst case initial
  1950. // allocation. This saves us from having to process everything twice
  1951. // (once to size, once to build). If we determine later that we have
  1952. // an acl that is not big enough, we allocate additional space. The only
  1953. // time that this reallocation should happen is if the input string
  1954. // contains a lot of explicit SIDs. Otherwise, the chosen buffer size
  1955. // should be pretty close to the proper size
  1956. //
  1957. if ( Err == ERROR_SUCCESS ) {
  1958. AclSize = sizeof( ACL ) + ( Acls * ( sizeof( ACCESS_ALLOWED_OBJECT_ACE ) +
  1959. sizeof( SID ) + ( 6 * sizeof( ULONG ) ) ) );
  1960. if ( AclSize > SDDL_MAX_ACL_SIZE ) {
  1961. AclSize = SDDL_MAX_ACL_SIZE;
  1962. }
  1963. *Acl = ( PACL )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, AclSize );
  1964. if ( *Acl == NULL ) {
  1965. Err = ERROR_NOT_ENOUGH_MEMORY;
  1966. } else {
  1967. AclUsed = sizeof( ACL );
  1968. //
  1969. // We'll start initializing it...
  1970. //
  1971. ( *Acl )->AclRevision = ACL_REVISION;
  1972. ( *Acl )->Sbz1 = ( BYTE )0;
  1973. ( *Acl )->AclSize = ( USHORT )AclSize;
  1974. ( *Acl )->AceCount = 0;
  1975. ( *Acl )->Sbz2 = ( USHORT )0;
  1976. //
  1977. // Ok, now we'll go through and start building them all
  1978. //
  1979. Curr = AclString;
  1980. for( i = 0; i < Acls; i++ ) {
  1981. //
  1982. // First, get the type..
  1983. //
  1984. UCHAR Type;
  1985. UCHAR Flags = 0;
  1986. USHORT Size;
  1987. ACCESS_MASK Mask = 0;
  1988. GUID *ObjId = NULL, ObjGuid;
  1989. GUID *IObjId = NULL, IObjGuid;
  1990. PWSTR Next;
  1991. DWORD AceSize = 0;
  1992. //
  1993. // skip any space before (
  1994. //
  1995. while(*Curr == L' ' ) {
  1996. Curr++;
  1997. }
  1998. //
  1999. // Skip any parens that may exist in the ace list
  2000. //
  2001. if ( *Curr == SDDL_ACE_BEGINC ) {
  2002. Curr++;
  2003. }
  2004. //
  2005. // skip any space after (
  2006. //
  2007. while(*Curr == L' ' ) {
  2008. Curr++;
  2009. }
  2010. MatchedEntry = LookupAceTypeInTable( Curr, 0, LookupFlags );
  2011. if ( MatchedEntry ) {
  2012. Type = ( UCHAR )MatchedEntry->Value;
  2013. Curr += MatchedEntry->KeyLen + 1;
  2014. } else {
  2015. //
  2016. // Found an invalid type
  2017. //
  2018. Err = ERROR_INVALID_DATATYPE;
  2019. break;
  2020. }
  2021. //
  2022. // If we have any object aces, set the acl revision to REVISION_DS
  2023. //
  2024. if ( Type >= ACCESS_MIN_MS_OBJECT_ACE_TYPE && Type <= ACCESS_MAX_MS_OBJECT_ACE_TYPE ) {
  2025. ( *Acl )->AclRevision = ACL_REVISION_DS;
  2026. }
  2027. //
  2028. // skip any space before ;
  2029. //
  2030. while(*Curr == L' ' ) {
  2031. Curr++;
  2032. }
  2033. //
  2034. // Next, get the flags...
  2035. //
  2036. while ( Curr != *End ) {
  2037. if ( *Curr == SDDL_SEPERATORC ) {
  2038. Curr++;
  2039. break;
  2040. }
  2041. //
  2042. // Skip any blanks
  2043. //
  2044. while ( *Curr == L' ' ) {
  2045. Curr++;
  2046. }
  2047. MatchedEntry = LookupAceFlagsInTable( Curr, 0, LookupFlags );
  2048. if ( MatchedEntry ) {
  2049. Flags |= ( UCHAR )MatchedEntry->Value;
  2050. Curr += MatchedEntry->KeyLen;
  2051. } else {
  2052. //
  2053. // Found an invalid flag
  2054. //
  2055. Err = ERROR_INVALID_FLAGS;
  2056. break;
  2057. }
  2058. }
  2059. if ( Err != ERROR_SUCCESS ) {
  2060. break;
  2061. }
  2062. //
  2063. // skip any space after ;
  2064. //
  2065. while(*Curr == L' ' ) {
  2066. Curr++;
  2067. }
  2068. //
  2069. // Now, get the access mask
  2070. //
  2071. while( TRUE ) {
  2072. if ( *Curr == SDDL_SEPERATORC ) {
  2073. Curr++;
  2074. break;
  2075. }
  2076. //
  2077. // Skip any blanks
  2078. //
  2079. while ( *Curr == L' ' ) {
  2080. Curr++;
  2081. }
  2082. MatchedEntry = LookupAccessMaskInTable( Curr, 0, LookupFlags );
  2083. if ( MatchedEntry ) {
  2084. Mask |= MatchedEntry->Value;
  2085. Curr += MatchedEntry->KeyLen;
  2086. } else {
  2087. //
  2088. // If the rights couldn't be looked up, see if it's a converted mask
  2089. //
  2090. Mask = wcstoul( Curr, &MaskEnd, 0 );
  2091. if ( MaskEnd != Curr ) {
  2092. Curr = MaskEnd;
  2093. } else {
  2094. //
  2095. // Found an invalid right
  2096. //
  2097. Err = ERROR_INVALID_ACL;
  2098. break;
  2099. }
  2100. }
  2101. }
  2102. if ( Err != ERROR_SUCCESS ) {
  2103. break;
  2104. }
  2105. //
  2106. // If that worked, we'll get the ids
  2107. //
  2108. for ( j = 0; j < 2; j++ ) {
  2109. //
  2110. // skip any space before ;
  2111. //
  2112. while(*Curr == L' ' ) {
  2113. Curr++;
  2114. }
  2115. if ( *Curr != SDDL_SEPERATORC ) {
  2116. wcsncpy( ConvertGuidString, Curr, STRING_GUID_LEN );
  2117. ConvertGuidString[ STRING_GUID_LEN ] = UNICODE_NULL;
  2118. if ( j == 0 ) {
  2119. if ( UuidFromStringW( ConvertGuidString, &ObjGuid ) == RPC_S_OK ) {
  2120. ObjId = &ObjGuid;
  2121. } else {
  2122. Err = RPC_S_INVALID_STRING_UUID;
  2123. break;
  2124. }
  2125. } else {
  2126. if ( UuidFromStringW( ConvertGuidString, &IObjGuid ) == RPC_S_OK ) {
  2127. IObjId = &IObjGuid;
  2128. } else {
  2129. Err = RPC_S_INVALID_STRING_UUID;
  2130. break;
  2131. }
  2132. }
  2133. // success
  2134. Curr += STRING_GUID_LEN;
  2135. if ( *Curr != SDDL_SEPERATORC &&
  2136. *Curr != L' ' ) {
  2137. Err = RPC_S_INVALID_STRING_UUID;
  2138. break;
  2139. }
  2140. }
  2141. Curr++;
  2142. }
  2143. if ( Err != ERROR_SUCCESS ) {
  2144. break;
  2145. }
  2146. //
  2147. // skip any space before ;
  2148. //
  2149. while(*Curr == L' ' ) {
  2150. Curr++;
  2151. }
  2152. //
  2153. // Finally, the SID
  2154. //
  2155. if ( ERROR_SUCCESS == Err ) {
  2156. PWSTR End;
  2157. Err = LocalGetSidForString( Curr,
  2158. &SidPtr,
  2159. &End,
  2160. &FreeSid,
  2161. RootDomainSid,
  2162. DomainSid,
  2163. tSidLookupDomOrRootDomRelativeTable,
  2164. DefaultToDomain );
  2165. if ( Err == ERROR_SUCCESS ) {
  2166. if ( End == NULL ) {
  2167. Err = ERROR_INVALID_ACL;
  2168. } else {
  2169. while(*End == L' ' ) {
  2170. End++;
  2171. }
  2172. //
  2173. // a ace must be terminated by ')'
  2174. //
  2175. if ( *End != SDDL_ACE_ENDC ) {
  2176. Err = ERROR_INVALID_ACL;
  2177. } else {
  2178. Curr = End + 1;
  2179. if ( !SidPtr ) {
  2180. Err = ERROR_INVALID_ACL;
  2181. }
  2182. }
  2183. }
  2184. }
  2185. }
  2186. //
  2187. // Quit on an error
  2188. //
  2189. if ( Err != ERROR_SUCCESS ) {
  2190. break;
  2191. }
  2192. //
  2193. // Now, we'll create the ace, and add it...
  2194. //
  2195. //
  2196. // First, make sure we have the room for it
  2197. //
  2198. switch ( Type ) {
  2199. case ACCESS_ALLOWED_ACE_TYPE:
  2200. case ACCESS_DENIED_ACE_TYPE:
  2201. case SYSTEM_AUDIT_ACE_TYPE:
  2202. case SYSTEM_ALARM_ACE_TYPE:
  2203. AceSize = sizeof( ACCESS_ALLOWED_ACE );
  2204. break;
  2205. case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
  2206. case ACCESS_DENIED_OBJECT_ACE_TYPE:
  2207. case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
  2208. case SYSTEM_ALARM_OBJECT_ACE_TYPE:
  2209. AceSize = sizeof( KNOWN_OBJECT_ACE );
  2210. if ( ObjId ) {
  2211. AceSize += sizeof ( GUID );
  2212. }
  2213. if ( IObjId ) {
  2214. AceSize += sizeof ( GUID );
  2215. }
  2216. break;
  2217. default:
  2218. Err = ERROR_INVALID_ACL;
  2219. break;
  2220. }
  2221. if ( Err != ERROR_SUCCESS ) {
  2222. break;
  2223. }
  2224. AceSize += RtlLengthSid( SidPtr ) - sizeof( ULONG );
  2225. if (AceSize + AclUsed > AclSize)
  2226. {
  2227. //
  2228. // We'll have to reallocate, since our buffer isn't
  2229. // big enough...
  2230. //
  2231. PACL NewAcl;
  2232. DWORD NewSize = AclSize + ( ( Acls - i ) * AceSize );
  2233. NewAcl = ( PACL )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  2234. NewSize );
  2235. if ( NewAcl == NULL ) {
  2236. LocalFree( *Acl );
  2237. *Acl = NULL;
  2238. if ( FreeSid == TRUE ) {
  2239. LocalFree( SidPtr );
  2240. SidPtr = NULL;
  2241. FreeSid = FALSE;
  2242. }
  2243. Err = ERROR_NOT_ENOUGH_MEMORY;
  2244. break;
  2245. } else {
  2246. memcpy( NewAcl, *Acl, AclSize );
  2247. NewAcl->AclSize = ( USHORT )NewSize;
  2248. LocalFree( *Acl );
  2249. *Acl = NewAcl;
  2250. AclSize = NewSize;
  2251. }
  2252. }
  2253. AclUsed += AceSize;
  2254. SetLastError( ERROR_SUCCESS );
  2255. switch (Type)
  2256. {
  2257. case SYSTEM_AUDIT_ACE_TYPE:
  2258. OpRes = AddAuditAccessAceEx( *Acl,
  2259. ACL_REVISION,
  2260. Flags &
  2261. ~(SUCCESSFUL_ACCESS_ACE_FLAG |
  2262. FAILED_ACCESS_ACE_FLAG),
  2263. Mask,
  2264. SidPtr,
  2265. Flags & SUCCESSFUL_ACCESS_ACE_FLAG,
  2266. Flags & FAILED_ACCESS_ACE_FLAG );
  2267. break;
  2268. case ACCESS_ALLOWED_ACE_TYPE:
  2269. OpRes = AddAccessAllowedAceEx( *Acl,
  2270. ACL_REVISION,
  2271. Flags,
  2272. Mask,
  2273. SidPtr );
  2274. break;
  2275. case ACCESS_DENIED_ACE_TYPE:
  2276. OpRes = AddAccessDeniedAceEx( *Acl,
  2277. ACL_REVISION,
  2278. Flags,
  2279. Mask,
  2280. SidPtr );
  2281. break;
  2282. case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
  2283. OpRes = AddAuditAccessObjectAce( *Acl,
  2284. ACL_REVISION_DS,
  2285. Flags,
  2286. Mask,
  2287. ObjId,
  2288. IObjId,
  2289. SidPtr,
  2290. Flags & SUCCESSFUL_ACCESS_ACE_FLAG,
  2291. Flags & FAILED_ACCESS_ACE_FLAG );
  2292. break;
  2293. case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
  2294. OpRes = AddAccessAllowedObjectAce( *Acl,
  2295. ACL_REVISION_DS,
  2296. Flags,
  2297. Mask,
  2298. ObjId,
  2299. IObjId,
  2300. SidPtr );
  2301. break;
  2302. case ACCESS_DENIED_OBJECT_ACE_TYPE:
  2303. OpRes = AddAccessDeniedObjectAce( *Acl,
  2304. ACL_REVISION_DS,
  2305. Flags,
  2306. Mask,
  2307. ObjId,
  2308. IObjId,
  2309. SidPtr );
  2310. break;
  2311. default:
  2312. SetLastError( ERROR_INVALID_DATATYPE );
  2313. OpRes = FALSE;
  2314. break;
  2315. }
  2316. if ( OpRes == FALSE ) {
  2317. Err = GetLastError();
  2318. break;
  2319. }
  2320. //
  2321. // Clean up whatever memory we have to
  2322. //
  2323. if ( FreeSid == TRUE ) {
  2324. LocalFree( SidPtr );
  2325. }
  2326. SidPtr = NULL;
  2327. if ( *Curr == SDDL_ACE_BEGINC ) {
  2328. Curr++;
  2329. }
  2330. }
  2331. //
  2332. // If something didn't work, clean up
  2333. //
  2334. if ( Err != ERROR_SUCCESS ) {
  2335. LocalFree( *Acl );
  2336. *Acl = NULL;
  2337. } else {
  2338. //
  2339. // Set a more realistic acl size
  2340. //
  2341. ( *Acl )->AclSize = ( USHORT )AclUsed;
  2342. }
  2343. //
  2344. // free any SIDs buffer used
  2345. //
  2346. if ( FreeSid && SidPtr ) {
  2347. LocalFree(SidPtr);
  2348. SidPtr = NULL;
  2349. }
  2350. FreeSid = FALSE;
  2351. }
  2352. }
  2353. return(Err);
  2354. }
  2355. DWORD
  2356. LocalConvertAclToString(
  2357. IN PACL Acl,
  2358. IN BOOLEAN AclPresent,
  2359. IN BOOLEAN ConvertAsDacl,
  2360. OUT PWSTR *AclString,
  2361. OUT PDWORD AclStringSize,
  2362. IN PSID RootDomainSid OPTIONAL
  2363. )
  2364. /*++
  2365. Routine Description:
  2366. This routine convert an acl into a string. The format of the aces is:
  2367. Ace := ( Type; Flags; Rights; ObjGuid; IObjGuid; Sid;
  2368. Type : = A | D | OA | OD {Access, Deny, ObjectAccess, ObjectDeny}
  2369. Flags := Flags Flag
  2370. Flag : = CI | IO | NP | SA | FA {Container Inherit,Inherit Only, NoProp,
  2371. SuccessAudit, FailAdit }
  2372. Rights := Rights Right
  2373. Right := DS_READ_PROPERTY | blah blah
  2374. Guid := String representation of a GUID (via RPC UuidToString)
  2375. Sid := DA | PS | AO | PO | AU | S-* (Domain Admins, PersonalSelf, Acct Ops,
  2376. PrinterOps, AuthenticatedUsers, or
  2377. the string representation of a sid)
  2378. The seperator is a ';'.
  2379. The returned string must be free via a call to LocalFree
  2380. Arguments:
  2381. Acl - The acl to be converted
  2382. AclPresent - if TRUE, the acl is present, even if NULL
  2383. AclString - Where the created acl string is to be returned
  2384. ConvertAsDacl - Convert the given acl as the DACL, not the SACL
  2385. AclStringLen - The size of the allocated string is returned here
  2386. Return Value:
  2387. ERROR_SUCCESS - success
  2388. ERROR_NOT_ENOUGH_MEMORY indicates a memory allocation for the ouput acl
  2389. failed
  2390. ERROR_INVALID_PARAMETER The string does not represent an ACL
  2391. ERROR_INVALID_ACL - An unexpected access mask was encountered or a NULL acl was encountered
  2392. --*/
  2393. {
  2394. DWORD Err = ERROR_SUCCESS;
  2395. DWORD AclSize = 0, MaskSize;
  2396. PACE_HEADER AceHeader;
  2397. ULONG i, j;
  2398. PWSTR *SidStrings = NULL, Curr, Guid;
  2399. BOOLEAN *SidFrees = NULL;
  2400. UINT *pMaskAsString = NULL;
  2401. PSTRSD_KEY_LOOKUP MatchedEntry;
  2402. PSTRSD_SID_LOOKUP MatchedSidEntry;
  2403. PKNOWN_ACE KnownAce;
  2404. PKNOWN_OBJECT_ACE KnownObjectAce;
  2405. ACCESS_MASK AccessMask;
  2406. PSID Sid, pSidSA=NULL;
  2407. GUID *Obj, *Inherit;
  2408. ULONG LookupFlags;
  2409. ULONG AceFlags[ ] = {
  2410. OBJECT_INHERIT_ACE,
  2411. CONTAINER_INHERIT_ACE,
  2412. NO_PROPAGATE_INHERIT_ACE,
  2413. INHERIT_ONLY_ACE,
  2414. INHERITED_ACE,
  2415. SUCCESSFUL_ACCESS_ACE_FLAG,
  2416. FAILED_ACCESS_ACE_FLAG
  2417. };
  2418. if ( AclString == NULL || AclStringSize == NULL ) {
  2419. return(ERROR_INVALID_PARAMETER);
  2420. }
  2421. //
  2422. // treat the case when (AclPresent == TRUE and Acl == NULL)
  2423. // same as the case when AclPresent == FALSE.
  2424. // This fix is to be compatible with IsValidSecurityDescriptor()
  2425. // when ACL_PRESENT bit is set and Acl == NULL
  2426. //
  2427. if ( !AclPresent ||
  2428. (AclPresent && (Acl == NULL) ) ) {
  2429. *AclString = NULL;
  2430. *AclStringSize = 0;
  2431. return( ERROR_SUCCESS );
  2432. }
  2433. //
  2434. // If the ace count is 0, then it's an empty acl, and we don't handle those...
  2435. //
  2436. if ( Acl->AceCount == 0 ) {
  2437. *AclString = NULL;
  2438. *AclStringSize = 0;
  2439. return( ERROR_SUCCESS );
  2440. }
  2441. if ( ConvertAsDacl ) {
  2442. LookupFlags = SDDL_VALID_DACL;
  2443. } else {
  2444. LookupFlags = SDDL_VALID_SACL;
  2445. }
  2446. //
  2447. // Allocate buffers to hold sids that are looked up
  2448. //
  2449. SidStrings = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Acl->AceCount * sizeof( PWSTR ) );
  2450. if ( SidStrings == NULL ) {
  2451. return( ERROR_NOT_ENOUGH_MEMORY );
  2452. }
  2453. SidFrees = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Acl->AceCount * sizeof( BOOLEAN ) );
  2454. if ( SidFrees == NULL ) {
  2455. LocalFree( SidStrings );
  2456. return( ERROR_NOT_ENOUGH_MEMORY );
  2457. }
  2458. pMaskAsString = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Acl->AceCount * sizeof( UINT ) );
  2459. if ( pMaskAsString == NULL ) {
  2460. LocalFree( SidStrings );
  2461. LocalFree( SidFrees );
  2462. return( ERROR_NOT_ENOUGH_MEMORY );
  2463. }
  2464. AceHeader = ( PACE_HEADER )FirstAce( Acl );
  2465. //
  2466. // Size the acl, so we know how big a buffer to allocate
  2467. //
  2468. for(i = 0; i < Acl->AceCount && Err == ERROR_SUCCESS;
  2469. i++, AceHeader = ( PACE_HEADER )NextAce( AceHeader ) ) {
  2470. AclSize += sizeof( WCHAR );
  2471. //
  2472. // First, the type
  2473. //
  2474. MatchedEntry = LookupAceTypeInTable( NULL, ( ULONG )AceHeader->AceType, LookupFlags );
  2475. if ( MatchedEntry ) {
  2476. AclSize += SDDL_SIZE_TAG( MatchedEntry->Key ) + SDDL_SIZE_SEP( SDDL_SEPERATORC );
  2477. } else {
  2478. //
  2479. // Found an invalid type
  2480. //
  2481. Err = ERROR_INVALID_ACL;
  2482. break;
  2483. }
  2484. //
  2485. // Next, process the ace flags
  2486. //
  2487. for ( j = 0; j < sizeof( AceFlags ) / sizeof( ULONG ); j++ ) {
  2488. if ( ( ULONG )AceHeader->AceFlags & ( AceFlags[ j ] ) ) {
  2489. MatchedEntry = LookupAceFlagsInTable( 0, AceFlags[ j ], LookupFlags );
  2490. if ( MatchedEntry ) {
  2491. AclSize += SDDL_SIZE_TAG( MatchedEntry->Key );
  2492. }
  2493. }
  2494. }
  2495. if ( Err != ERROR_SUCCESS ) {
  2496. break;
  2497. } else {
  2498. AclSize += SDDL_SIZE_SEP( SDDL_SEPERATORC );
  2499. }
  2500. //
  2501. // Next, the rights and optionally the guids. This gets done on a per ace type basis
  2502. //
  2503. switch ( AceHeader->AceType ) {
  2504. case ACCESS_ALLOWED_ACE_TYPE:
  2505. case ACCESS_DENIED_ACE_TYPE:
  2506. case SYSTEM_AUDIT_ACE_TYPE:
  2507. case SYSTEM_ALARM_ACE_TYPE:
  2508. KnownAce = ( PKNOWN_ACE )AceHeader;
  2509. AccessMask = KnownAce->Mask;
  2510. Sid = ( PSID )&KnownAce->SidStart;
  2511. break;
  2512. case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
  2513. case ACCESS_DENIED_OBJECT_ACE_TYPE:
  2514. case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
  2515. case SYSTEM_ALARM_OBJECT_ACE_TYPE:
  2516. KnownObjectAce = ( PKNOWN_OBJECT_ACE )AceHeader;
  2517. AccessMask = KnownObjectAce->Mask;
  2518. Sid = RtlObjectAceSid( AceHeader );
  2519. //
  2520. // Deal with potential guids
  2521. //
  2522. if ( RtlObjectAceObjectType( AceHeader ) ) {
  2523. AclSize += STRING_GUID_SIZE;
  2524. }
  2525. if ( RtlObjectAceInheritedObjectType( AceHeader ) ) {
  2526. AclSize += STRING_GUID_SIZE;
  2527. }
  2528. break;
  2529. default:
  2530. Err = ERROR_INVALID_ACL;
  2531. break;
  2532. }
  2533. //
  2534. // Size the rights
  2535. //
  2536. if ( Err == ERROR_SUCCESS ) {
  2537. MaskSize = 0;
  2538. pMaskAsString[i] = 0;
  2539. //
  2540. // lookup for the exact value first
  2541. //
  2542. MatchedEntry = LookupAccessMaskInTable( 0, AccessMask, LookupFlags );
  2543. if ( MatchedEntry ) {
  2544. pMaskAsString[i] = 1;
  2545. MaskSize += SDDL_SIZE_TAG( MatchedEntry->Key );
  2546. } else {
  2547. //
  2548. // look for each bit
  2549. //
  2550. for ( j = 0; j < 32; j++ ) {
  2551. if ( AccessMask & ( 1 << j ) ) {
  2552. MatchedEntry = LookupAccessMaskInTable( 0, AccessMask & ( 1 << j ), LookupFlags );
  2553. if ( MatchedEntry ) {
  2554. MaskSize += SDDL_SIZE_TAG( MatchedEntry->Key );
  2555. } else {
  2556. //
  2557. // Found an invalid type. We'll convert the whole thing to a string
  2558. //
  2559. pMaskAsString[i] = 2;
  2560. MaskSize = 10 * sizeof( WCHAR );
  2561. break;
  2562. }
  2563. }
  2564. }
  2565. }
  2566. if ( Err != ERROR_SUCCESS ) {
  2567. break;
  2568. } else {
  2569. AclSize += MaskSize;
  2570. AclSize += SDDL_SIZE_SEP( SDDL_SEPERATORC );
  2571. }
  2572. }
  2573. if ( Err != ERROR_SUCCESS ) {
  2574. break;
  2575. }
  2576. //
  2577. // Add in space for the guid seperators
  2578. //
  2579. AclSize += 2 * SDDL_SIZE_SEP( SDDL_SEPERATORC );
  2580. //
  2581. // Finally, lookup the sids
  2582. //
  2583. MatchedSidEntry = LookupSidInTable( NULL,
  2584. Sid,
  2585. RootDomainSid,
  2586. NULL,
  2587. NULL,
  2588. FALSE,
  2589. &pSidSA );
  2590. //
  2591. // If we didn't find a match, try it as a sid string
  2592. //
  2593. if ( MatchedSidEntry == NULL ) {
  2594. if ( pSidSA ) {
  2595. //
  2596. // when sid lookup finds the sid of SA, pSidSA is assigned to Sid
  2597. // so it doesn't need to be freed.
  2598. //
  2599. SidStrings[ i ] = LocalAlloc( LMEM_FIXED, (wcslen(SDDL_SCHEMA_ADMINISTRATORS)+1)*sizeof(TCHAR) );
  2600. if ( SidStrings[ i ] == NULL ) {
  2601. Err = ERROR_NOT_ENOUGH_MEMORY;
  2602. break;
  2603. } else {
  2604. wcscpy( SidStrings[ i ], SDDL_SCHEMA_ADMINISTRATORS );
  2605. SidFrees[ i ] = TRUE;
  2606. }
  2607. } else {
  2608. if ( ConvertSidToStringSidW( Sid, &SidStrings[ i ] ) == FALSE ) {
  2609. Err = GetLastError();
  2610. break;
  2611. } else {
  2612. SidFrees[ i ] = TRUE;
  2613. }
  2614. }
  2615. } else {
  2616. //
  2617. // If the entry that's been selected hasn't been initialized yet, do it now
  2618. //
  2619. SidStrings[ i ] = MatchedSidEntry->Key;
  2620. }
  2621. AclSize += SDDL_SIZE_TAG( SidStrings[ i ] );
  2622. AclSize += sizeof( WCHAR ); // Closing paren
  2623. AclSize += sizeof( WCHAR ); // Trailing NULL
  2624. }
  2625. //
  2626. // If all of that worked, allocate the return buffer, and build the acl string
  2627. //
  2628. if ( AclSize == 0 ) {
  2629. Err = ERROR_INVALID_ACL;
  2630. }
  2631. if ( Err == ERROR_SUCCESS ) {
  2632. if ( AclSize % 2 != 0 ) {
  2633. AclSize++;
  2634. }
  2635. *AclString = LocalAlloc( LMEM_FIXED, AclSize );
  2636. if ( *AclString == NULL ) {
  2637. Err = ERROR_NOT_ENOUGH_MEMORY;
  2638. }
  2639. }
  2640. //
  2641. // Build the acl
  2642. //
  2643. if ( Err == ERROR_SUCCESS ) {
  2644. Curr = *AclString;
  2645. AceHeader = ( PACE_HEADER )FirstAce( Acl );
  2646. //
  2647. // Size the acl, so we know how big a buffer to allocate
  2648. //
  2649. for(i = 0; i < Acl->AceCount && Err == ERROR_SUCCESS;
  2650. i++, AceHeader = ( PACE_HEADER )NextAce( AceHeader ) ) {
  2651. //
  2652. // "("
  2653. //
  2654. *Curr = SDDL_ACE_BEGINC;
  2655. Curr++;
  2656. //
  2657. // By the time we get down here, we've ensured that we can lookup all the values,
  2658. // so there is no need to check for failure
  2659. //
  2660. //
  2661. // First, the type, must find it
  2662. // "T;"
  2663. //
  2664. MatchedEntry = LookupAceTypeInTable( NULL, ( ULONG )AceHeader->AceType, LookupFlags );
  2665. if ( MatchedEntry ) {
  2666. wcscpy( Curr, MatchedEntry->Key );
  2667. Curr += MatchedEntry->KeyLen;
  2668. }
  2669. *Curr = SDDL_SEPERATORC;
  2670. Curr++;
  2671. //
  2672. // Next, process the ace flags
  2673. // "CIIO;"
  2674. //
  2675. for ( j = 0; j < sizeof( AceFlags ) / sizeof( ULONG ); j++ ) {
  2676. if ( ( ULONG )AceHeader->AceFlags & ( AceFlags[ j ] ) ) {
  2677. MatchedEntry = LookupAceFlagsInTable( 0, AceFlags[ j ], LookupFlags );
  2678. if ( MatchedEntry ) {
  2679. wcscpy( Curr, MatchedEntry->Key );
  2680. Curr+= MatchedEntry->KeyLen;
  2681. }
  2682. }
  2683. }
  2684. *Curr = SDDL_SEPERATORC;
  2685. Curr++;
  2686. //
  2687. // Next, the rights and optionally the guids. This gets done on a per ace type basis
  2688. //
  2689. Obj = NULL;
  2690. Inherit = NULL;
  2691. switch ( AceHeader->AceType ) {
  2692. case ACCESS_ALLOWED_ACE_TYPE:
  2693. case ACCESS_DENIED_ACE_TYPE:
  2694. case SYSTEM_AUDIT_ACE_TYPE:
  2695. case SYSTEM_ALARM_ACE_TYPE:
  2696. KnownAce = ( PKNOWN_ACE )AceHeader;
  2697. AccessMask = KnownAce->Mask;
  2698. Sid = ( PSID )&KnownAce->SidStart;
  2699. break;
  2700. case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
  2701. case ACCESS_DENIED_OBJECT_ACE_TYPE:
  2702. case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
  2703. case SYSTEM_ALARM_OBJECT_ACE_TYPE:
  2704. KnownObjectAce = ( PKNOWN_OBJECT_ACE )AceHeader;
  2705. AccessMask = KnownObjectAce->Mask;
  2706. Sid = RtlObjectAceSid( AceHeader );
  2707. //
  2708. // Deal with potential guids
  2709. //
  2710. Inherit = RtlObjectAceInheritedObjectType( AceHeader );
  2711. Obj = RtlObjectAceObjectType( AceHeader );
  2712. break;
  2713. }
  2714. //
  2715. // Add the rights
  2716. //
  2717. if ( pMaskAsString[i] == 2 ) {
  2718. wcscpy( Curr, L"0x");
  2719. Curr += 2;
  2720. _ultow( AccessMask, Curr, 16 );
  2721. Curr += wcslen( Curr );
  2722. } else if ( pMaskAsString[i] == 1 ) {
  2723. //
  2724. // lookup for the entire value first
  2725. //
  2726. MatchedEntry = LookupAccessMaskInTable( 0, AccessMask, LookupFlags );
  2727. if ( MatchedEntry ) {
  2728. wcscpy( Curr, MatchedEntry->Key );
  2729. Curr += MatchedEntry->KeyLen;
  2730. }
  2731. } else { // 0
  2732. for ( j = 0; j < 32; j++ ) {
  2733. if ( AccessMask & (1 << j) ) {
  2734. MatchedEntry = LookupAccessMaskInTable( 0, AccessMask & ( 1 << j ), LookupFlags );
  2735. if ( MatchedEntry ) {
  2736. wcscpy( Curr, MatchedEntry->Key );
  2737. Curr += MatchedEntry->KeyLen;
  2738. } // else shouldn't happen but if it happens
  2739. // it is too late to convert it into 0x format
  2740. // because the buffer is already allocated with smaller size.
  2741. }
  2742. }
  2743. }
  2744. *Curr = SDDL_SEPERATORC;
  2745. Curr++;
  2746. //
  2747. // Optional object guid
  2748. //
  2749. if ( Obj ) {
  2750. Err = UuidToStringW( Obj, &Guid );
  2751. if ( Err != ERROR_SUCCESS ) {
  2752. break;
  2753. }
  2754. wcscpy( Curr, Guid );
  2755. Curr += wcslen( Guid );
  2756. RpcStringFreeW( &Guid );
  2757. }
  2758. *Curr = SDDL_SEPERATORC;
  2759. Curr++;
  2760. if ( Inherit ) {
  2761. Err = UuidToStringW( Inherit, &Guid );
  2762. if ( Err != ERROR_SUCCESS ) {
  2763. break;
  2764. }
  2765. wcscpy( Curr, Guid );
  2766. Curr += wcslen( Guid );
  2767. RpcStringFreeW( &Guid );
  2768. }
  2769. *Curr = SDDL_SEPERATORC;
  2770. Curr++;
  2771. //
  2772. // Finally, the sids
  2773. //
  2774. wcscpy( Curr, SidStrings[ i ] );
  2775. Curr += wcslen( SidStrings[ i ] );
  2776. *Curr = SDDL_ACE_ENDC;
  2777. Curr++;
  2778. *Curr = UNICODE_NULL;
  2779. }
  2780. }
  2781. //
  2782. // Free any allocated memory
  2783. // jinhuang: should always free the allocated buffer
  2784. //
  2785. // if ( Err != ERROR_SUCCESS && SidStrings ) {
  2786. for ( j = 0; j < Acl->AceCount; j++ ) {
  2787. if ( SidFrees[ j ] ) {
  2788. LocalFree( SidStrings[ j ] );
  2789. }
  2790. }
  2791. // }
  2792. LocalFree( SidStrings );
  2793. LocalFree( SidFrees );
  2794. LocalFree( pMaskAsString );
  2795. if ( Err != ERROR_SUCCESS ) {
  2796. LocalFree(*AclString);
  2797. *AclString = NULL;
  2798. *AclStringSize = 0;
  2799. } else {
  2800. *AclStringSize = AclSize;
  2801. }
  2802. return( Err );
  2803. }
  2804. DWORD
  2805. LocalConvertSDToStringSD_Rev1(
  2806. IN PSID RootDomainSid OPTIONAL,
  2807. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  2808. IN SECURITY_INFORMATION SecurityInformation,
  2809. OUT LPWSTR *StringSecurityDescriptor,
  2810. OUT PULONG StringSecurityDescriptorLen OPTIONAL
  2811. )
  2812. /*++
  2813. Routine Description:
  2814. This routine converts a security descriptor into a string version persuant to SDDL definition
  2815. Arguments:
  2816. SecurityDescriptor - Security Descriptor to be converted.
  2817. SecurityInformation - the security information of which component to be converted
  2818. StringSecurityDescriptor - Where the converted SD is returned. Buffer is allocated via
  2819. LocalAlloc and should be free via LocalFree.
  2820. StringSecurityDescriptorLen - optional length of the converted SD buffer.
  2821. Return Value:
  2822. TRUE - Success
  2823. FALSE - Failure
  2824. Extended error status is available using GetLastError.
  2825. --*/
  2826. {
  2827. DWORD Err = ERROR_SUCCESS;
  2828. NTSTATUS Status=STATUS_SUCCESS;
  2829. DWORD ReturnBufferSize = 0, AclSize;
  2830. PSID Owner = NULL, Group = NULL;
  2831. PACL Dacl = NULL, Sacl = NULL;
  2832. BOOLEAN Defaulted, SaclPresent=FALSE, DaclPresent=FALSE;
  2833. PWSTR OwnerString = NULL, GroupString = NULL, SaclString = NULL, DaclString = NULL;
  2834. SECURITY_DESCRIPTOR_CONTROL ControlCode;
  2835. ULONG Revision;
  2836. PWSTR DaclControl=NULL, SaclControl=NULL;
  2837. if ( SecurityDescriptor == NULL || StringSecurityDescriptor == NULL ) {
  2838. return(ERROR_INVALID_PARAMETER);
  2839. }
  2840. //
  2841. // Get the relevant security descriptor parts
  2842. // based on the SecurityInforamtion input parameter
  2843. //
  2844. if ( SecurityInformation & OWNER_SECURITY_INFORMATION ) {
  2845. Status = RtlGetOwnerSecurityDescriptor( SecurityDescriptor, &Owner, &Defaulted );
  2846. }
  2847. if ( NT_SUCCESS( Status ) &&
  2848. SecurityInformation & GROUP_SECURITY_INFORMATION ) {
  2849. Status = RtlGetGroupSecurityDescriptor( SecurityDescriptor, &Group, &Defaulted );
  2850. }
  2851. if ( NT_SUCCESS( Status ) &&
  2852. SecurityInformation & DACL_SECURITY_INFORMATION ) {
  2853. Status = RtlGetDaclSecurityDescriptor( SecurityDescriptor, &DaclPresent, &Dacl, &Defaulted );
  2854. }
  2855. if ( NT_SUCCESS( Status ) &&
  2856. SecurityInformation & SACL_SECURITY_INFORMATION ) {
  2857. Status = RtlGetSaclSecurityDescriptor( SecurityDescriptor, &SaclPresent, &Sacl, &Defaulted );
  2858. }
  2859. if ( NT_SUCCESS( Status ) ) {
  2860. Status = RtlGetControlSecurityDescriptor ( SecurityDescriptor, &ControlCode, &Revision);
  2861. }
  2862. if ( !NT_SUCCESS( Status ) ) {
  2863. Err = RtlNtStatusToDosError( Status );
  2864. return( Err );
  2865. }
  2866. //
  2867. // make sure the SidLookup table is reinitialized
  2868. //
  2869. InitializeSidLookupTable(STRSD_REINITIALIZE_ENTER);
  2870. //
  2871. // Convert the owner and group, if they exist
  2872. //
  2873. if ( Owner ) {
  2874. Err = LocalGetStringForSid( Owner,
  2875. &OwnerString,
  2876. RootDomainSid
  2877. );
  2878. }
  2879. if ( Err == ERROR_SUCCESS && Group ) {
  2880. Err = LocalGetStringForSid( Group,
  2881. &GroupString,
  2882. RootDomainSid );
  2883. }
  2884. //
  2885. // JINHUANG 3/10/98
  2886. // get DACL control string
  2887. //
  2888. if ( Err == ERROR_SUCCESS && ControlCode ) {
  2889. Err = LocalGetStringForControl(ControlCode, SDDL_VALID_DACL, &DaclControl);
  2890. }
  2891. //
  2892. // get SACL control string
  2893. //
  2894. if ( Err == ERROR_SUCCESS && ControlCode ) {
  2895. Err = LocalGetStringForControl(ControlCode, SDDL_VALID_SACL, &SaclControl);
  2896. }
  2897. //
  2898. // SACL first because the size of DACL is needed later
  2899. //
  2900. if ( Err == ERROR_SUCCESS && SaclPresent ) {
  2901. Err = LocalConvertAclToString( Sacl,
  2902. SaclPresent,
  2903. FALSE,
  2904. &SaclString,
  2905. &AclSize,
  2906. RootDomainSid );
  2907. if ( Err == ERROR_SUCCESS ) {
  2908. ReturnBufferSize += AclSize;
  2909. }
  2910. }
  2911. //
  2912. // Then, the DACL
  2913. //
  2914. if ( Err == ERROR_SUCCESS && DaclPresent ) {
  2915. Err = LocalConvertAclToString( Dacl,
  2916. DaclPresent,
  2917. TRUE,
  2918. &DaclString,
  2919. &AclSize,
  2920. RootDomainSid );
  2921. if ( Err == ERROR_SUCCESS ) {
  2922. ReturnBufferSize += AclSize;
  2923. }
  2924. }
  2925. //
  2926. // Now, if all of that worked, allocate and build the return string
  2927. //
  2928. if ( Err == ERROR_SUCCESS ) {
  2929. if ( OwnerString ) {
  2930. ReturnBufferSize += ( wcslen( OwnerString ) * sizeof( WCHAR ) ) +
  2931. SDDL_SIZE_TAG( SDDL_OWNER ) +
  2932. SDDL_SIZE_SEP( SDDL_DELIMINATORC );
  2933. }
  2934. if ( GroupString ) {
  2935. ReturnBufferSize += ( wcslen( GroupString ) * sizeof( WCHAR ) ) +
  2936. SDDL_SIZE_TAG( SDDL_GROUP ) +
  2937. SDDL_SIZE_SEP( SDDL_DELIMINATORC );
  2938. }
  2939. if ( DaclPresent ) {
  2940. ReturnBufferSize += SDDL_SIZE_TAG( SDDL_DACL ) +
  2941. SDDL_SIZE_SEP( SDDL_DELIMINATORC );
  2942. if ( DaclControl ) {
  2943. ReturnBufferSize += (wcslen( DaclControl ) * sizeof(WCHAR)) ;
  2944. }
  2945. }
  2946. if ( SaclPresent ) {
  2947. ReturnBufferSize += SDDL_SIZE_TAG( SDDL_SACL ) +
  2948. SDDL_SIZE_SEP( SDDL_DELIMINATORC );
  2949. if ( SaclControl ) {
  2950. ReturnBufferSize += (wcslen( SaclControl ) * sizeof(WCHAR)) ;
  2951. }
  2952. }
  2953. *StringSecurityDescriptor = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  2954. ReturnBufferSize + sizeof( WCHAR ) );
  2955. if ( *StringSecurityDescriptor == NULL ) {
  2956. Err = ERROR_NOT_ENOUGH_MEMORY;
  2957. } else {
  2958. //
  2959. // Build the string from the previously determined components. Note that
  2960. // if a component is not present, it is skipped.
  2961. //
  2962. DWORD dwOffset=0;
  2963. if ( OwnerString ) {
  2964. swprintf( *StringSecurityDescriptor, L"%ws%wc%ws",
  2965. SDDL_OWNER, SDDL_DELIMINATORC, OwnerString );
  2966. dwOffset = wcslen(*StringSecurityDescriptor);
  2967. }
  2968. if ( GroupString ) {
  2969. swprintf( *StringSecurityDescriptor + dwOffset,
  2970. L"%ws%wc%ws", SDDL_GROUP, SDDL_DELIMINATORC, GroupString );
  2971. Revision = wcslen( *StringSecurityDescriptor + dwOffset ); // temp use
  2972. dwOffset += Revision;
  2973. }
  2974. if ( DaclPresent ) {
  2975. if ( DaclControl ) {
  2976. swprintf( *StringSecurityDescriptor + dwOffset,
  2977. L"%ws%wc%ws", SDDL_DACL, SDDL_DELIMINATORC, DaclControl );
  2978. } else {
  2979. swprintf( *StringSecurityDescriptor + dwOffset,
  2980. L"%ws%wc", SDDL_DACL, SDDL_DELIMINATORC );
  2981. }
  2982. Revision = wcslen( *StringSecurityDescriptor + dwOffset );
  2983. dwOffset += Revision;
  2984. if ( DaclString ) {
  2985. wcscpy( *StringSecurityDescriptor + dwOffset, DaclString );
  2986. Revision = wcslen( *StringSecurityDescriptor + dwOffset ); // temp use
  2987. dwOffset += Revision; // (AclSize/sizeof(WCHAR));
  2988. }
  2989. }
  2990. if ( SaclPresent ) {
  2991. if ( SaclControl ) {
  2992. swprintf( *StringSecurityDescriptor + dwOffset,
  2993. L"%ws%wc%ws", SDDL_SACL, SDDL_DELIMINATORC, SaclControl );
  2994. } else {
  2995. swprintf( *StringSecurityDescriptor + dwOffset,
  2996. L"%ws%wc", SDDL_SACL, SDDL_DELIMINATORC );
  2997. }
  2998. Revision = wcslen( *StringSecurityDescriptor + dwOffset );
  2999. dwOffset += Revision;
  3000. if ( SaclString ) {
  3001. wcscpy( *StringSecurityDescriptor + dwOffset, SaclString);
  3002. }
  3003. }
  3004. //
  3005. // jinhuang
  3006. // output the buffer size
  3007. //
  3008. if ( StringSecurityDescriptorLen ) {
  3009. *StringSecurityDescriptorLen = ReturnBufferSize/sizeof(WCHAR);
  3010. }
  3011. }
  3012. }
  3013. //
  3014. // Free any buffers that were allocated
  3015. //
  3016. LocalFree( OwnerString );
  3017. LocalFree( GroupString );
  3018. LocalFree( SaclString );
  3019. LocalFree( DaclString );
  3020. //
  3021. // JINHUANG 3/10/98
  3022. // it's ok to free them even if they are NULL
  3023. //
  3024. LocalFree( SaclControl );
  3025. LocalFree( DaclControl );
  3026. //
  3027. // decrement the SidLookup instance
  3028. //
  3029. InitializeSidLookupTable(STRSD_REINITIALIZE_LEAVE);
  3030. return( Err );
  3031. }
  3032. DWORD
  3033. LocalConvertStringSDToSD_Rev1(
  3034. IN PSID RootDomainSid OPTIONAL,
  3035. IN PSID DomainSid OPTIONAL,
  3036. IN BOOLEAN DefaultToDomain,
  3037. IN LPCWSTR StringSecurityDescriptor,
  3038. OUT PSECURITY_DESCRIPTOR *SecurityDescriptor,
  3039. OUT PULONG SecurityDescriptorSize OPTIONAL
  3040. )
  3041. /*++
  3042. Routine Description:
  3043. This routine converts a revision 1 stringized Security descriptor into a valid, functional
  3044. security descriptor
  3045. Arguments:
  3046. StringSecurityDescriptor - Stringized security descriptor to be converted.
  3047. SecurityDescriptor - Where the converted SD is returned. Buffer is allocated via
  3048. LocalAlloc and should be free via LocalFree. The returned security descriptor
  3049. is always self relative
  3050. SecurityDescriptorSize - OPTIONAL. If non-NULL, the size of the converted security
  3051. descriptor is returned here.
  3052. SecurityInformation - OPTIONAL. If non-NULL, the security information of the converted
  3053. security descriptor is returned here.
  3054. Return Value:
  3055. TRUE - Success
  3056. FALSE - Failure
  3057. Extended error status is available using GetLastError.
  3058. ERROR_INVALID_PARAMETER - A NULL input or output parameter was given
  3059. ERROR_UNKNOWN_REVISION - An unsupported revision was given
  3060. --*/
  3061. {
  3062. DWORD Err = ERROR_SUCCESS;
  3063. PSID Owner = NULL, Group = NULL;
  3064. PACL Dacl = NULL, Sacl = NULL;
  3065. SECURITY_INFORMATION SeInfo = 0;
  3066. SECURITY_DESCRIPTOR SD;
  3067. PWSTR Curr, End;
  3068. NTSTATUS Status;
  3069. BOOLEAN FreeOwner = FALSE, FreeGroup = FALSE;
  3070. SID_IDENTIFIER_AUTHORITY UaspBuiltinAuthority = SECURITY_NT_AUTHORITY;
  3071. SID_IDENTIFIER_AUTHORITY UaspCreatorAuthority = SECURITY_CREATOR_SID_AUTHORITY;
  3072. ULONG SDSize = 0;
  3073. BOOLEAN DaclPresent = FALSE, SaclPresent = FALSE;
  3074. SECURITY_DESCRIPTOR_CONTROL DaclControl=0, SaclControl=0;
  3075. PSTRSD_SID_LOOKUP tSidLookupDomOrRootDomRelativeTable = NULL;
  3076. if ( StringSecurityDescriptor == NULL || SecurityDescriptor == NULL ) {
  3077. return(ERROR_INVALID_PARAMETER);
  3078. }
  3079. if ( SecurityDescriptorSize ) {
  3080. *SecurityDescriptorSize = 0;
  3081. }
  3082. //
  3083. // make sure the SidLookup table is reinitialized
  3084. //
  3085. InitializeSidLookupTable(STRSD_REINITIALIZE_ENTER);
  3086. //
  3087. // for the API ConvertStringSDToSDDomain, if DomainSid != NULL, we need a table on
  3088. // the heap, for this thread to stash lookups for ST_DOMAIN_RELATIVE type trustees
  3089. // this table will be freed when all lookups have been done for this thread
  3090. //
  3091. if (DomainSid) {
  3092. tSidLookupDomOrRootDomRelativeTable =
  3093. (PSTRSD_SID_LOOKUP) LocalAlloc(LMEM_ZEROINIT, sizeof(SidLookupDomOrRootDomRelative));
  3094. //
  3095. // table copy/init from the template-table
  3096. //
  3097. if (tSidLookupDomOrRootDomRelativeTable)
  3098. memcpy(tSidLookupDomOrRootDomRelativeTable,
  3099. SidLookupDomOrRootDomRelative,
  3100. sizeof(SidLookupDomOrRootDomRelative));
  3101. else
  3102. Err = ERROR_NOT_ENOUGH_MEMORY;
  3103. }
  3104. //
  3105. // Now, we'll just start parsing and building
  3106. //
  3107. Curr = ( PWSTR )StringSecurityDescriptor;
  3108. while ( Err == ERROR_SUCCESS && Curr ) {
  3109. switch( *Curr ) {
  3110. //
  3111. // Get the Owner sid
  3112. //
  3113. case L'O':
  3114. Err = ERROR_INVALID_PARAMETER;
  3115. if ( *(Curr+1) == SDDL_DELIMINATORC ) {
  3116. Curr += 2;
  3117. if ( Owner == NULL ) {
  3118. Err = LocalGetSidForString( Curr,
  3119. &Owner,
  3120. &End,
  3121. &FreeOwner,
  3122. RootDomainSid,
  3123. DomainSid,
  3124. tSidLookupDomOrRootDomRelativeTable,
  3125. DefaultToDomain );
  3126. if ( Err == ERROR_SUCCESS ) {
  3127. Curr = End;
  3128. SeInfo |= OWNER_SECURITY_INFORMATION;
  3129. }
  3130. }
  3131. }
  3132. break;
  3133. //
  3134. // Get the Group sid
  3135. //
  3136. case L'G':
  3137. Err = ERROR_INVALID_PARAMETER;
  3138. if ( *(Curr+1) == SDDL_DELIMINATORC ) {
  3139. Curr += 2;
  3140. if ( Group == NULL ) {
  3141. Err = LocalGetSidForString( Curr,
  3142. &Group,
  3143. &End,
  3144. &FreeGroup,
  3145. RootDomainSid,
  3146. DomainSid,
  3147. tSidLookupDomOrRootDomRelativeTable,
  3148. DefaultToDomain );
  3149. if ( Err == ERROR_SUCCESS ) {
  3150. Curr = End;
  3151. SeInfo |= GROUP_SECURITY_INFORMATION;
  3152. }
  3153. }
  3154. }
  3155. break;
  3156. //
  3157. // Next, the DAcl
  3158. //
  3159. case L'D':
  3160. if ( *(Curr+1) == SDDL_DELIMINATORC ) {
  3161. Curr += 2;
  3162. if ( Dacl == NULL ) {
  3163. //
  3164. // JINHUANG: 3/10/98
  3165. // look for any security descriptor controls
  3166. //
  3167. if ( *Curr != SDDL_ACE_BEGINC ) {
  3168. Err = LocalGetSDControlForString( Curr,
  3169. SDDL_VALID_DACL,
  3170. &DaclControl,
  3171. &End );
  3172. if ( Err == ERROR_SUCCESS ) {
  3173. Curr = End;
  3174. }
  3175. }
  3176. if ( Err == ERROR_SUCCESS ) {
  3177. Err = LocalGetAclForString( Curr,
  3178. TRUE,
  3179. &Dacl,
  3180. &End,
  3181. RootDomainSid,
  3182. DomainSid,
  3183. tSidLookupDomOrRootDomRelativeTable,
  3184. DefaultToDomain );
  3185. if ( Err == ERROR_SUCCESS ) {
  3186. Curr = End;
  3187. SeInfo |= DACL_SECURITY_INFORMATION;
  3188. DaclPresent = TRUE;
  3189. }
  3190. }
  3191. } else {
  3192. Err = ERROR_INVALID_PARAMETER;
  3193. }
  3194. } else {
  3195. Err = ERROR_INVALID_PARAMETER;
  3196. }
  3197. break;
  3198. //
  3199. // Finally, the SAcl
  3200. //
  3201. case L'S':
  3202. if ( *(Curr+1) == SDDL_DELIMINATORC ) {
  3203. Curr += 2;
  3204. if ( Sacl == NULL ) {
  3205. //
  3206. // JINHUANG: 3/10/98
  3207. // look for any security descriptor controls
  3208. //
  3209. if ( *Curr != SDDL_ACE_BEGINC ) {
  3210. Err = LocalGetSDControlForString( Curr,
  3211. SDDL_VALID_SACL,
  3212. &SaclControl,
  3213. &End );
  3214. if ( Err == ERROR_SUCCESS ) {
  3215. Curr = End;
  3216. }
  3217. }
  3218. if ( Err == ERROR_SUCCESS ) {
  3219. Err = LocalGetAclForString( Curr,
  3220. FALSE,
  3221. &Sacl,
  3222. &End,
  3223. RootDomainSid,
  3224. DomainSid,
  3225. tSidLookupDomOrRootDomRelativeTable,
  3226. DefaultToDomain );
  3227. if ( Err == ERROR_SUCCESS ) {
  3228. Curr = End;
  3229. SeInfo |= SACL_SECURITY_INFORMATION;
  3230. SaclPresent = TRUE;
  3231. }
  3232. }
  3233. } else {
  3234. Err = ERROR_INVALID_PARAMETER;
  3235. }
  3236. } else {
  3237. Err = ERROR_INVALID_PARAMETER;
  3238. }
  3239. break;
  3240. //
  3241. // It's a space, so ignore it
  3242. //
  3243. case L' ':
  3244. Curr++;
  3245. break;
  3246. //
  3247. // End of the string, so quit
  3248. //
  3249. case L'\0':
  3250. Curr = NULL;
  3251. break;
  3252. //
  3253. // Don't know what it is, so consider it an error
  3254. //
  3255. default:
  3256. Err = ERROR_INVALID_PARAMETER;
  3257. break;
  3258. }
  3259. }
  3260. //
  3261. // Ok, if we have the information we need, we'll create the security
  3262. // descriptor
  3263. //
  3264. if ( Err == ERROR_SUCCESS ) {
  3265. if ( InitializeSecurityDescriptor(&SD, SECURITY_DESCRIPTOR_REVISION ) == FALSE ) {
  3266. Err = GetLastError();
  3267. }
  3268. //
  3269. // JINHUANG 3/10/98
  3270. // set the security descriptor control
  3271. //
  3272. SD.Control |= (DaclControl | SaclControl);
  3273. //
  3274. // Now, add the owner and group
  3275. //
  3276. if ( Err == ERROR_SUCCESS && Owner != NULL ) {
  3277. if ( SetSecurityDescriptorOwner(&SD, Owner, FALSE ) == FALSE ) {
  3278. Err = GetLastError();
  3279. }
  3280. }
  3281. if ( Err == ERROR_SUCCESS && Group != NULL ) {
  3282. if ( SetSecurityDescriptorGroup( &SD, Group, FALSE ) == FALSE ) {
  3283. Err = GetLastError();
  3284. }
  3285. }
  3286. //
  3287. // Then the DACL and SACL
  3288. //
  3289. if ( Err == ERROR_SUCCESS && DaclPresent ) {
  3290. if ( SetSecurityDescriptorDacl( &SD, DaclPresent, Dacl, FALSE ) == FALSE ) {
  3291. Err = GetLastError();
  3292. }
  3293. }
  3294. if ( Err == ERROR_SUCCESS && SaclPresent ) {
  3295. if ( SetSecurityDescriptorSacl( &SD, SaclPresent, Sacl, FALSE ) == FALSE ) {
  3296. Err = GetLastError();
  3297. }
  3298. }
  3299. }
  3300. //
  3301. // Finally, we'll allocate our buffer and return
  3302. //
  3303. if ( Err == ERROR_SUCCESS ) {
  3304. MakeSelfRelativeSD( &SD, *SecurityDescriptor, &SDSize );
  3305. if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
  3306. *SecurityDescriptor = (PSECURITY_DESCRIPTOR) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  3307. SDSize );
  3308. if ( *SecurityDescriptor == NULL ) {
  3309. Err = ERROR_NOT_ENOUGH_MEMORY;
  3310. } else {
  3311. if ( MakeSelfRelativeSD( &SD, *SecurityDescriptor, &SDSize ) == FALSE ) {
  3312. Err = GetLastError();
  3313. LocalFree( *SecurityDescriptor );
  3314. *SecurityDescriptor = NULL;
  3315. }
  3316. }
  3317. } else {
  3318. //
  3319. // This should never happen
  3320. //
  3321. if ( GetLastError() == ERROR_SUCCESS ) {
  3322. Err = ERROR_INSUFFICIENT_BUFFER;
  3323. }
  3324. }
  3325. }
  3326. //
  3327. // Return the security descriptor size, if requested
  3328. //
  3329. if ( Err == ERROR_SUCCESS && SecurityDescriptorSize ) {
  3330. *SecurityDescriptorSize = SDSize;
  3331. }
  3332. //
  3333. // Finally, free any memory we may have allocated...
  3334. //
  3335. if ( FreeOwner == TRUE ) {
  3336. LocalFree( Owner );
  3337. }
  3338. if ( FreeGroup == TRUE ) {
  3339. LocalFree( Group );
  3340. }
  3341. LocalFree( Dacl );
  3342. LocalFree( Sacl );
  3343. if (tSidLookupDomOrRootDomRelativeTable)
  3344. LocalFree(tSidLookupDomOrRootDomRelativeTable);
  3345. //
  3346. // make sure the SidLookup table is reinitialized
  3347. //
  3348. InitializeSidLookupTable(STRSD_REINITIALIZE_LEAVE);
  3349. return( Err );
  3350. }
  3351. BOOLEAN
  3352. InitializeSidLookupTable(
  3353. IN BYTE InitFlag
  3354. )
  3355. {
  3356. SID_IDENTIFIER_AUTHORITY UaspWorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  3357. SID_IDENTIFIER_AUTHORITY UaspLocalAuthority = SECURITY_LOCAL_SID_AUTHORITY;
  3358. SID_IDENTIFIER_AUTHORITY UaspCreatorAuthority = SECURITY_CREATOR_SID_AUTHORITY;
  3359. SID_IDENTIFIER_AUTHORITY UaspNtAuthority = SECURITY_NT_AUTHORITY;
  3360. DWORD i;
  3361. OBJECT_ATTRIBUTES ObjectAttributes;
  3362. NTSTATUS Status=STATUS_SUCCESS;
  3363. LSA_HANDLE LsaPolicyHandle;
  3364. PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo = NULL;
  3365. PPOLICY_DNS_DOMAIN_INFO DnsDomainInfo = NULL;
  3366. EnterCriticalSection(&SddlSidLookupCritical);
  3367. switch ( InitFlag ) {
  3368. case STRSD_REINITIALIZE_ENTER:
  3369. SidTableReinitializeInstance++;
  3370. if ( SidTableReinitializeInstance > 1 ) {
  3371. //
  3372. // there is another thread going, no need to reinitialize the table again
  3373. //
  3374. LeaveCriticalSection(&SddlSidLookupCritical);
  3375. return TRUE;
  3376. }
  3377. break;
  3378. case STRSD_REINITIALIZE_LEAVE:
  3379. if ( SidTableReinitializeInstance > 1 ) {
  3380. SidTableReinitializeInstance--;
  3381. } else {
  3382. SidTableReinitializeInstance = 0;
  3383. }
  3384. LeaveCriticalSection(&SddlSidLookupCritical);
  3385. return TRUE;
  3386. break;
  3387. }
  3388. //
  3389. // open LSA to query domain and DNS information at once
  3390. // because some domain/local relative SIDs will be initialized
  3391. // if for some reason that the domain/DNS information can't be
  3392. // queried, the relative SIDs will be invalid for this moment.
  3393. //
  3394. InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
  3395. Status = LsaOpenPolicy( NULL, &ObjectAttributes,
  3396. POLICY_VIEW_LOCAL_INFORMATION,
  3397. &LsaPolicyHandle );
  3398. if ( NT_SUCCESS(Status) ) {
  3399. Status = LsaQueryInformationPolicy( LsaPolicyHandle,
  3400. PolicyDnsDomainInformation,
  3401. ( PVOID * )&DnsDomainInfo );
  3402. Status = LsaQueryInformationPolicy( LsaPolicyHandle,
  3403. PolicyAccountDomainInformation,
  3404. ( PVOID * )&DomainInfo );
  3405. LsaClose( LsaPolicyHandle );
  3406. }
  3407. //
  3408. // If the list of sids hasn't been built, do it now
  3409. //
  3410. // JINHUANG 3/26 BVT break,
  3411. // see comments above always try to initialization table
  3412. // but skip the ones already initialized for performance
  3413. //
  3414. for ( i = 0;
  3415. i < sizeof( SidLookup ) / sizeof( STRSD_SID_LOOKUP ); i++ ) {
  3416. if ( STRSD_REINITIALIZE_ENTER == InitFlag ) {
  3417. SidLookup[ i ].Valid = FALSE;
  3418. }
  3419. if ( SidLookup[ i ].Valid == TRUE &&
  3420. SidLookup[ i ].Sid != NULL ) {
  3421. //
  3422. // this one is already initialized
  3423. //
  3424. continue;
  3425. }
  3426. SidLookup[ i ].Sid = ( PSID )SidLookup[ i ].SidBuff;
  3427. Status = STATUS_SUCCESS;
  3428. switch ( SidLookup[ i ].SidType ) {
  3429. case ST_DOMAIN_RELATIVE:
  3430. if ( DnsDomainInfo != NULL && DnsDomainInfo->Sid != NULL ) {
  3431. RtlCopyMemory( SidLookup[ i ].Sid, DnsDomainInfo->Sid,
  3432. RtlLengthSid( DnsDomainInfo->Sid ) );
  3433. ( ( PISID )( SidLookup[ i ].Sid ) )->SubAuthorityCount++;
  3434. *( RtlSubAuthoritySid( SidLookup[ i ].Sid,
  3435. *( RtlSubAuthorityCountSid( DnsDomainInfo->Sid ) ) ) ) =
  3436. SidLookup[ i ].Rid;
  3437. SidLookup[ i ].Valid = TRUE;
  3438. }
  3439. break;
  3440. case ST_ROOT_DOMAIN_RELATIVE:
  3441. //
  3442. // will be initialized on demand
  3443. //
  3444. break;
  3445. case ST_WORLD:
  3446. RtlInitializeSid( SidLookup[ i ].Sid, &UaspWorldAuthority, 1 );
  3447. *( RtlSubAuthoritySid( SidLookup[ i ].Sid, 0 ) ) = SidLookup[ i ].Rid;
  3448. SidLookup[ i ].Valid = TRUE;
  3449. break;
  3450. case ST_LOCALSY:
  3451. RtlInitializeSid( SidLookup[ i ].Sid, &UaspLocalAuthority, 1 );
  3452. *( RtlSubAuthoritySid( SidLookup[ i ].Sid, 0 ) ) = SidLookup[ i ].Rid;
  3453. SidLookup[ i ].Valid = TRUE;
  3454. break;
  3455. case ST_LOCAL:
  3456. if ( DomainInfo != NULL && DomainInfo->DomainSid ) {
  3457. RtlCopyMemory( SidLookup[ i ].Sid, DomainInfo->DomainSid,
  3458. RtlLengthSid( DomainInfo->DomainSid ) );
  3459. ( ( PISID )( SidLookup[ i ].Sid ) )->SubAuthorityCount++;
  3460. *( RtlSubAuthoritySid( SidLookup[ i ].Sid,
  3461. *( RtlSubAuthorityCountSid( DomainInfo->DomainSid ) ) ) ) =
  3462. SidLookup[ i ].Rid;
  3463. SidLookup[ i ].Valid = TRUE;
  3464. }
  3465. break;
  3466. case ST_CREATOR:
  3467. RtlInitializeSid( SidLookup[ i ].Sid, &UaspCreatorAuthority, 1 );
  3468. *( RtlSubAuthoritySid( SidLookup[ i ].Sid, 0 ) ) = SidLookup[ i ].Rid;
  3469. SidLookup[ i ].Valid = TRUE;
  3470. break;
  3471. case ST_NTAUTH:
  3472. RtlInitializeSid( SidLookup[ i ].Sid, &UaspNtAuthority, 1 );
  3473. *( RtlSubAuthoritySid( SidLookup[ i ].Sid, 0 ) ) = SidLookup[ i ].Rid;
  3474. SidLookup[ i ].Valid = TRUE;
  3475. break;
  3476. case ST_BUILTIN:
  3477. RtlInitializeSid( SidLookup[ i ].Sid, &UaspNtAuthority, 2 );
  3478. *( RtlSubAuthoritySid( SidLookup[ i ].Sid, 0 ) ) = SECURITY_BUILTIN_DOMAIN_RID;
  3479. *( RtlSubAuthoritySid( SidLookup[ i ].Sid, 1 ) ) = SidLookup[ i ].Rid;
  3480. SidLookup[ i ].Valid = TRUE;
  3481. break;
  3482. }
  3483. }
  3484. LsaFreeMemory( DomainInfo );
  3485. LsaFreeMemory( DnsDomainInfo );
  3486. LeaveCriticalSection(&SddlSidLookupCritical);
  3487. return TRUE;
  3488. }
  3489. BOOL
  3490. APIENTRY
  3491. ConvertStringSDToSDRootDomainA(
  3492. IN PSID RootDomainSid OPTIONAL,
  3493. IN LPCSTR StringSecurityDescriptor,
  3494. IN DWORD StringSDRevision,
  3495. OUT PSECURITY_DESCRIPTOR *SecurityDescriptor,
  3496. OUT PULONG SecurityDescriptorSize OPTIONAL
  3497. )
  3498. {
  3499. UNICODE_STRING Unicode;
  3500. ANSI_STRING AnsiString;
  3501. NTSTATUS Status;
  3502. BOOL Result;
  3503. if ( NULL == StringSecurityDescriptor ||
  3504. NULL == SecurityDescriptor ) {
  3505. SetLastError(ERROR_INVALID_PARAMETER);
  3506. return(FALSE);
  3507. }
  3508. RtlInitAnsiString( &AnsiString, StringSecurityDescriptor );
  3509. Status = SddlpAnsiStringToUnicodeString(&Unicode,
  3510. &AnsiString);
  3511. if ( !NT_SUCCESS( Status ) ) {
  3512. BaseSetLastNTError( Status );
  3513. return FALSE;
  3514. }
  3515. Result = ConvertStringSDToSDRootDomainW( RootDomainSid,
  3516. ( LPCWSTR )Unicode.Buffer,
  3517. StringSDRevision,
  3518. SecurityDescriptor,
  3519. SecurityDescriptorSize);
  3520. LocalFree( Unicode.Buffer );
  3521. if ( Result ) {
  3522. SetLastError(ERROR_SUCCESS);
  3523. }
  3524. return( Result );
  3525. }
  3526. BOOL
  3527. APIENTRY
  3528. ConvertStringSDToSDRootDomainW(
  3529. IN PSID RootDomainSid OPTIONAL,
  3530. IN LPCWSTR StringSecurityDescriptor,
  3531. IN DWORD StringSDRevision,
  3532. OUT PSECURITY_DESCRIPTOR *SecurityDescriptor,
  3533. OUT PULONG SecurityDescriptorSize OPTIONAL
  3534. )
  3535. {
  3536. DWORD Err = ERROR_SUCCESS;
  3537. //
  3538. // Little elementary parameter checking...
  3539. //
  3540. if ( StringSecurityDescriptor == NULL || SecurityDescriptor == NULL ) {
  3541. Err = ERROR_INVALID_PARAMETER;
  3542. } else {
  3543. switch ( StringSDRevision ) {
  3544. case SDDL_REVISION_1:
  3545. Err = LocalConvertStringSDToSD_Rev1( RootDomainSid, // root domain sid
  3546. NULL, // no domain sid is provided for this API
  3547. TRUE, // default to domain for EA/SA if root domain sid is not provided
  3548. StringSecurityDescriptor,
  3549. SecurityDescriptor,
  3550. SecurityDescriptorSize);
  3551. break;
  3552. default:
  3553. Err = ERROR_UNKNOWN_REVISION;
  3554. break;
  3555. }
  3556. }
  3557. SetLastError( Err );
  3558. return( Err == ERROR_SUCCESS );
  3559. }
  3560. BOOL
  3561. APIENTRY
  3562. ConvertSDToStringSDRootDomainA(
  3563. IN PSID RootDomainSid OPTIONAL,
  3564. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  3565. IN DWORD RequestedStringSDRevision,
  3566. IN SECURITY_INFORMATION SecurityInformation,
  3567. OUT LPSTR *StringSecurityDescriptor OPTIONAL,
  3568. OUT PULONG StringSecurityDescriptorLen OPTIONAL
  3569. )
  3570. {
  3571. LPWSTR StringSecurityDescriptorW = NULL;
  3572. ULONG AnsiLen, WideLen = 0;
  3573. BOOL ReturnValue ;
  3574. if ( StringSecurityDescriptor == NULL ||
  3575. 0 == SecurityInformation ) {
  3576. SetLastError( ERROR_INVALID_PARAMETER );
  3577. return( FALSE );
  3578. }
  3579. ReturnValue = ConvertSDToStringSDRootDomainW(
  3580. RootDomainSid,
  3581. SecurityDescriptor,
  3582. RequestedStringSDRevision,
  3583. SecurityInformation,
  3584. &StringSecurityDescriptorW,
  3585. &WideLen );
  3586. if ( ReturnValue ) {
  3587. AnsiLen = WideCharToMultiByte( CP_ACP,
  3588. 0,
  3589. StringSecurityDescriptorW,
  3590. WideLen + 1,
  3591. *StringSecurityDescriptor,
  3592. 0,
  3593. NULL,
  3594. NULL );
  3595. if ( AnsiLen != 0 ) {
  3596. *StringSecurityDescriptor = LocalAlloc( LMEM_FIXED, AnsiLen );
  3597. if ( *StringSecurityDescriptor == NULL ) {
  3598. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  3599. ReturnValue = FALSE;
  3600. } else {
  3601. AnsiLen = WideCharToMultiByte( CP_ACP,
  3602. 0,
  3603. StringSecurityDescriptorW,
  3604. WideLen + 1,
  3605. *StringSecurityDescriptor,
  3606. AnsiLen,
  3607. NULL,
  3608. NULL );
  3609. ASSERT( AnsiLen != 0 );
  3610. if ( AnsiLen == 0 ) {
  3611. LocalFree(*StringSecurityDescriptor);
  3612. *StringSecurityDescriptor = NULL;
  3613. ReturnValue = FALSE;
  3614. }
  3615. //
  3616. // jinhuang
  3617. // output the length (optional)
  3618. //
  3619. if ( StringSecurityDescriptorLen ) {
  3620. *StringSecurityDescriptorLen = AnsiLen;
  3621. }
  3622. }
  3623. } else {
  3624. ReturnValue = FALSE;
  3625. }
  3626. LocalFree(StringSecurityDescriptorW);
  3627. }
  3628. if ( ReturnValue ) {
  3629. SetLastError(ERROR_SUCCESS);
  3630. }
  3631. return( ReturnValue );
  3632. }
  3633. BOOL
  3634. APIENTRY
  3635. ConvertSDToStringSDRootDomainW(
  3636. IN PSID RootDomainSid OPTIONAL,
  3637. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  3638. IN DWORD RequestedStringSDRevision,
  3639. IN SECURITY_INFORMATION SecurityInformation,
  3640. OUT LPWSTR *StringSecurityDescriptor OPTIONAL,
  3641. OUT PULONG StringSecurityDescriptorLen OPTIONAL
  3642. )
  3643. {
  3644. DWORD Err = ERROR_SUCCESS;
  3645. //
  3646. // A little parameter checking...
  3647. //
  3648. if ( SecurityDescriptor == NULL || StringSecurityDescriptor == NULL ||
  3649. SecurityInformation == 0 ) {
  3650. Err = ERROR_INVALID_PARAMETER;
  3651. } else {
  3652. switch ( RequestedStringSDRevision ) {
  3653. case SDDL_REVISION_1:
  3654. Err = LocalConvertSDToStringSD_Rev1( RootDomainSid, // root domain sid
  3655. SecurityDescriptor,
  3656. SecurityInformation,
  3657. StringSecurityDescriptor,
  3658. StringSecurityDescriptorLen );
  3659. break;
  3660. default:
  3661. Err = ERROR_UNKNOWN_REVISION;
  3662. break;
  3663. }
  3664. }
  3665. SetLastError( Err );
  3666. return( Err == ERROR_SUCCESS);
  3667. }
  3668. BOOL
  3669. SddlpGetRootDomainSid(void)
  3670. {
  3671. //
  3672. // get root domain sid, save it in RootDomSidBuf (global)
  3673. // this function is called within the critical section
  3674. //
  3675. // 1) ldap_open to the DC of interest.
  3676. // 2) you do not need to ldap_connect - the following step works anonymously
  3677. // 3) read the operational attribute rootDomainNamingContext and provide the
  3678. // operational control LDAP_SERVER_EXTENDED_DN_OID as defined in sdk\inc\ntldap.h.
  3679. DWORD Win32rc=NO_ERROR;
  3680. BOOL bRetValue=FALSE;
  3681. HINSTANCE hLdapDll=NULL;
  3682. PFN_LDAP_OPEN pfnLdapOpen=NULL;
  3683. PFN_LDAP_UNBIND pfnLdapUnbind=NULL;
  3684. PFN_LDAP_SEARCH pfnLdapSearch=NULL;
  3685. PFN_LDAP_FIRST_ENTRY pfnLdapFirstEntry=NULL;
  3686. PFN_LDAP_GET_VALUE pfnLdapGetValue=NULL;
  3687. PFN_LDAP_MSGFREE pfnLdapMsgFree=NULL;
  3688. PFN_LDAP_VALUE_FREE pfnLdapValueFree=NULL;
  3689. PFN_LDAP_MAP_ERROR pfnLdapMapError=NULL;
  3690. PLDAP phLdap=NULL;
  3691. LDAPControlA serverControls = { LDAP_SERVER_EXTENDED_DN_OID,
  3692. { 0, (PCHAR) NULL },
  3693. TRUE
  3694. };
  3695. LPSTR Attribs[] = { LDAP_OPATT_ROOT_DOMAIN_NAMING_CONTEXT, NULL };
  3696. PLDAPControlA rServerControls[] = { &serverControls, NULL };
  3697. PLDAPMessage pMessage = NULL;
  3698. LDAPMessage *pEntry = NULL;
  3699. PCHAR *ppszValues=NULL;
  3700. LPSTR pSidStart, pSidEnd, pParse;
  3701. BYTE *pDest;
  3702. BYTE OneByte;
  3703. hLdapDll = LoadLibraryA("wldap32.dll");
  3704. if ( hLdapDll) {
  3705. pfnLdapOpen = (PFN_LDAP_OPEN)GetProcAddress(hLdapDll,
  3706. "ldap_openA");
  3707. pfnLdapUnbind = (PFN_LDAP_UNBIND)GetProcAddress(hLdapDll,
  3708. "ldap_unbind");
  3709. pfnLdapSearch = (PFN_LDAP_SEARCH)GetProcAddress(hLdapDll,
  3710. "ldap_search_ext_sA");
  3711. pfnLdapFirstEntry = (PFN_LDAP_FIRST_ENTRY)GetProcAddress(hLdapDll,
  3712. "ldap_first_entry");
  3713. pfnLdapGetValue = (PFN_LDAP_GET_VALUE)GetProcAddress(hLdapDll,
  3714. "ldap_get_valuesA");
  3715. pfnLdapMsgFree = (PFN_LDAP_MSGFREE)GetProcAddress(hLdapDll,
  3716. "ldap_msgfree");
  3717. pfnLdapValueFree = (PFN_LDAP_VALUE_FREE)GetProcAddress(hLdapDll,
  3718. "ldap_value_freeA");
  3719. pfnLdapMapError = (PFN_LDAP_MAP_ERROR)GetProcAddress(hLdapDll,
  3720. "LdapMapErrorToWin32");
  3721. }
  3722. if ( pfnLdapOpen == NULL ||
  3723. pfnLdapUnbind == NULL ||
  3724. pfnLdapSearch == NULL ||
  3725. pfnLdapFirstEntry == NULL ||
  3726. pfnLdapGetValue == NULL ||
  3727. pfnLdapMsgFree == NULL ||
  3728. pfnLdapValueFree == NULL ||
  3729. pfnLdapMapError == NULL ) {
  3730. Win32rc = ERROR_PROC_NOT_FOUND;
  3731. } else {
  3732. //
  3733. // bind to ldap
  3734. //
  3735. phLdap = (*pfnLdapOpen)(NULL, LDAP_PORT);
  3736. if ( phLdap == NULL ) {
  3737. Win32rc = ERROR_FILE_NOT_FOUND;
  3738. }
  3739. }
  3740. if ( NO_ERROR == Win32rc ) {
  3741. //
  3742. // now get the ldap handle,
  3743. //
  3744. Win32rc = (*pfnLdapSearch)(
  3745. phLdap,
  3746. "",
  3747. LDAP_SCOPE_BASE,
  3748. "(objectClass=*)",
  3749. Attribs,
  3750. 0,
  3751. (PLDAPControlA *)&rServerControls,
  3752. NULL,
  3753. NULL,
  3754. 10000,
  3755. &pMessage);
  3756. if( Win32rc == NO_ERROR && pMessage ) {
  3757. Win32rc = ERROR_SUCCESS;
  3758. pEntry = (*pfnLdapFirstEntry)(phLdap, pMessage);
  3759. if(pEntry == NULL) {
  3760. Win32rc = (*pfnLdapMapError)( phLdap->ld_errno );
  3761. } else {
  3762. //
  3763. // Now, we'll have to get the values
  3764. //
  3765. ppszValues = (*pfnLdapGetValue)(phLdap,
  3766. pEntry,
  3767. Attribs[0]);
  3768. if( ppszValues == NULL) {
  3769. Win32rc = (*pfnLdapMapError)( phLdap->ld_errno );
  3770. } else if ( ppszValues[0] && ppszValues[0][0] != '\0' ) {
  3771. //
  3772. // ppszValues[0] is the value to parse.
  3773. // The data will be returned as something like:
  3774. // <GUID=278676f8d753d211a61ad7e2dfa25f11>;<SID=010400000000000515000000828ba6289b0bc11e67c2ef7f>;DC=colinbrdom1,DC=nttest,DC=microsoft,DC=com
  3775. // Parse through this to find the <SID=xxxxxx> part. Note that it may be missing, but the GUID= and trailer should not be.
  3776. // The xxxxx represents the hex nibbles of the SID. Translate to the binary form and case to a SID.
  3777. pSidStart = strstr(ppszValues[0], "<SID=");
  3778. if ( pSidStart ) {
  3779. //
  3780. // find the end of this SID
  3781. //
  3782. pSidEnd = strchr(pSidStart, '>');
  3783. if ( pSidEnd ) {
  3784. EnterCriticalSection(&SddlSidLookupCritical);
  3785. pParse = pSidStart + 5;
  3786. pDest = (BYTE *)RootDomSidBuf;
  3787. while ( pParse < pSidEnd-1 ) {
  3788. if ( *pParse >= '0' && *pParse <= '9' ) {
  3789. OneByte = (BYTE) ((*pParse - '0') * 16);
  3790. } else {
  3791. OneByte = (BYTE) ( (tolower(*pParse) - 'a' + 10) * 16 );
  3792. }
  3793. if ( *(pParse+1) >= '0' && *(pParse+1) <= '9' ) {
  3794. OneByte += (BYTE) ( *(pParse+1) - '0' ) ;
  3795. } else {
  3796. OneByte += (BYTE) ( tolower(*(pParse+1)) - 'a' + 10 ) ;
  3797. }
  3798. *pDest = OneByte;
  3799. pDest++;
  3800. pParse += 2;
  3801. }
  3802. RootDomInited = TRUE;
  3803. LeaveCriticalSection(&SddlSidLookupCritical);
  3804. bRetValue = TRUE;
  3805. } else {
  3806. Win32rc = ERROR_OBJECT_NOT_FOUND;
  3807. }
  3808. } else {
  3809. Win32rc = ERROR_OBJECT_NOT_FOUND;
  3810. }
  3811. (*pfnLdapValueFree)(ppszValues);
  3812. } else {
  3813. Win32rc = ERROR_OBJECT_NOT_FOUND;
  3814. }
  3815. }
  3816. (*pfnLdapMsgFree)(pMessage);
  3817. }
  3818. }
  3819. //
  3820. // even though it's not binded, use unbind to close
  3821. //
  3822. if ( phLdap != NULL && pfnLdapUnbind )
  3823. (*pfnLdapUnbind)(phLdap);
  3824. if ( hLdapDll ) {
  3825. FreeLibrary(hLdapDll);
  3826. }
  3827. SetLastError(Win32rc);
  3828. return bRetValue;
  3829. }
  3830. BOOL
  3831. APIENTRY
  3832. ConvertStringSDToSDDomainA(
  3833. IN PSID DomainSid,
  3834. IN PSID RootDomainSid OPTIONAL,
  3835. IN LPCSTR StringSecurityDescriptor,
  3836. IN DWORD StringSDRevision,
  3837. OUT PSECURITY_DESCRIPTOR *SecurityDescriptor,
  3838. OUT PULONG SecurityDescriptorSize OPTIONAL
  3839. )
  3840. /*
  3841. Routine Description:
  3842. This API is exported from advapi32.dll.
  3843. This is the ANSI version of ConvertStringSDToSDDomainW and it calls the latter API.
  3844. See description for ConvertStringSDToSDDomainW.
  3845. */
  3846. {
  3847. UNICODE_STRING Unicode;
  3848. ANSI_STRING AnsiString;
  3849. NTSTATUS Status;
  3850. BOOL Result;
  3851. if ( NULL == StringSecurityDescriptor ||
  3852. NULL == SecurityDescriptor ||
  3853. NULL == DomainSid ||
  3854. !RtlValidSid(DomainSid) ||
  3855. (RootDomainSid && !RtlValidSid(RootDomainSid)) ) {
  3856. SetLastError(ERROR_INVALID_PARAMETER);
  3857. return(FALSE);
  3858. }
  3859. RtlInitAnsiString( &AnsiString, StringSecurityDescriptor );
  3860. Status = SddlpAnsiStringToUnicodeString(&Unicode,
  3861. &AnsiString);
  3862. if ( !NT_SUCCESS( Status ) ) {
  3863. BaseSetLastNTError( Status );
  3864. return FALSE;
  3865. }
  3866. Result = ConvertStringSDToSDDomainW( DomainSid,
  3867. RootDomainSid,
  3868. ( LPCWSTR )Unicode.Buffer,
  3869. StringSDRevision,
  3870. SecurityDescriptor,
  3871. SecurityDescriptorSize);
  3872. LocalFree( Unicode.Buffer );
  3873. if ( Result ) {
  3874. SetLastError(ERROR_SUCCESS);
  3875. }
  3876. return( Result );
  3877. }
  3878. BOOL
  3879. APIENTRY
  3880. ConvertStringSDToSDDomainW(
  3881. IN PSID DomainSid,
  3882. IN PSID RootDomainSid OPTIONAL,
  3883. IN LPCWSTR StringSecurityDescriptor,
  3884. IN DWORD StringSDRevision,
  3885. OUT PSECURITY_DESCRIPTOR *SecurityDescriptor,
  3886. OUT PULONG SecurityDescriptorSize OPTIONAL
  3887. )
  3888. /*
  3889. Routine Description:
  3890. This API is exported from advapi32.dll. It is similar to ConvertSDToStringSDRootDomainW
  3891. except that it takes in a required DomainSid parameter. Domain relative trustees will be
  3892. resolved w.r.t. DomainSid.
  3893. Arguments:
  3894. IN PSID DomainSid - pointer to the domain sid w.r.t. which
  3895. ST_DOMAIN_RELATIVE type trustees are resolved against
  3896. IN PSID RootDomainSid OPTIONAL - pointer to root domain sid w.r.t. which
  3897. ST_ROOT_DOMAIN_RELATIVE type trustees are resolved against
  3898. if this is NULL, the local m/c's root domain is used
  3899. IN LPCWSTR StringSecurityDescriptor - the input SDDL string
  3900. IN DWORD StringSDRevision - SDDL revision, only SDDL_REVISION_1 is supported
  3901. OUT PSECURITY_DESCRIPTOR *SecurityDescriptor - pointer to the constructed security descriptor
  3902. OUT PULONG SecurityDescriptorSize OPTIONAL - size of the constructed security descriptor
  3903. Return Value:
  3904. TRUE if succeeded else FALSE. Caller can use GetLastError() to retrieve the error code.
  3905. */
  3906. {
  3907. DWORD Err = ERROR_SUCCESS;
  3908. //
  3909. // Little elementary parameter checking...
  3910. //
  3911. if ( StringSecurityDescriptor == NULL ||
  3912. SecurityDescriptor == NULL ||
  3913. DomainSid == NULL ||
  3914. !RtlValidSid(DomainSid) ||
  3915. (RootDomainSid && !RtlValidSid(RootDomainSid)) ) {
  3916. Err = ERROR_INVALID_PARAMETER;
  3917. } else {
  3918. switch ( StringSDRevision ) {
  3919. case SDDL_REVISION_1:
  3920. Err = LocalConvertStringSDToSD_Rev1( RootDomainSid, // no root domain sid maybe provided for this API
  3921. DomainSid, // domain sid
  3922. FALSE, // domain sid is required
  3923. StringSecurityDescriptor,
  3924. SecurityDescriptor,
  3925. SecurityDescriptorSize);
  3926. break;
  3927. default:
  3928. Err = ERROR_UNKNOWN_REVISION;
  3929. break;
  3930. }
  3931. }
  3932. SetLastError( Err );
  3933. return( Err == ERROR_SUCCESS );
  3934. }
  3935. NTSTATUS
  3936. SddlpAnsiStringToUnicodeString(
  3937. OUT PUNICODE_STRING DestinationString,
  3938. IN PANSI_STRING SourceString
  3939. )
  3940. /*++
  3941. Routine Description:
  3942. See RtlAnsiStringToUnicodeString - only difference is that Unicode Length
  3943. is immaterial here. When using this API, never depend on a well formed
  3944. UNICODE_STRING - only rely on the Buffer field.
  3945. This functions converts the specified ansi source string into a
  3946. Unicode string. The translation is done with respect to the
  3947. current system locale information.
  3948. Arguments:
  3949. DestinationString - Returns a unicode string that is equivalent to
  3950. the ansi source string. Should be freed outside using LocalFree()
  3951. SourceString - Supplies the ansi source string that is to be
  3952. converted to unicode.
  3953. Return Value:
  3954. SUCCESS - The conversion was successful
  3955. !SUCCESS - The operation failed. No storage was allocated and no
  3956. conversion was done. None.
  3957. --*/
  3958. {
  3959. ULONG UnicodeLength;
  3960. ULONG Index;
  3961. NTSTATUS st;
  3962. UnicodeLength = RtlAnsiStringToUnicodeSize(SourceString);
  3963. DestinationString->Buffer = (PWSTR) LocalAlloc(LMEM_ZEROINIT, UnicodeLength);
  3964. if ( !DestinationString->Buffer ) {
  3965. return STATUS_NO_MEMORY;
  3966. }
  3967. st = RtlMultiByteToUnicodeN(
  3968. DestinationString->Buffer,
  3969. UnicodeLength - sizeof(UNICODE_NULL),
  3970. &Index,
  3971. SourceString->Buffer,
  3972. SourceString->Length
  3973. );
  3974. if (!NT_SUCCESS(st)) {
  3975. LocalFree(DestinationString->Buffer);
  3976. DestinationString->Buffer = NULL;
  3977. return st;
  3978. }
  3979. DestinationString->Buffer[Index / sizeof(WCHAR)] = UNICODE_NULL;
  3980. return STATUS_SUCCESS;
  3981. }