Leaked source code of windows server 2003
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.

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