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.

6071 lines
174 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. xml.cxx
  5. Abstract:
  6. This file implements a xml policy store provider
  7. Author:
  8. Xiaoxi Tan (xtan) June-2001
  9. --*/
  10. #include "pch.hxx"
  11. #define AZD_COMPONENT AZD_XML
  12. #include <msxml2.h>
  13. #include <aclapi.h>
  14. #include "resource.h"
  15. #include <shlwapi.h>
  16. #include <lm.h>
  17. #include <lmdfs.h>
  18. #pragma warning ( push )
  19. #pragma warning ( disable : 4127 ) // avoid warning in while(TRUE)
  20. // defines
  21. #define ARRAYLEN(a) (sizeof(a)/sizeof((a)[0]))
  22. // az object tag defines in xml store
  23. // note, they are case sensitive
  24. #define AZ_XML_TAG_AZSTORE L"AzAdminManager"
  25. #define AZ_XML_TAG_APPLICATION L"AzApplication"
  26. #define AZ_XML_TAG_OPERATION L"AzOperation"
  27. #define AZ_XML_TAG_TASK L"AzTask"
  28. #define AZ_XML_TAG_GROUP L"AzApplicationGroup"
  29. #define AZ_XML_TAG_ROLE L"AzRole"
  30. #define AZ_XML_TAG_SCOPE L"AzScope"
  31. // az object data tag defines in xml store
  32. #define AZ_XML_TAG_MEMBER L"Member"
  33. #define AZ_XML_TAG_NONMEMBER L"NonMember"
  34. #define AZ_XML_TAG_OPERATIONID L"OperationID"
  35. #define AZ_XML_TAG_BIZRULE L"BizRule"
  36. #define AZ_XML_TAG_BIZRULELANGUAGE L"BizRuleLanguage"
  37. #define AZ_XML_TAG_LDAPQUERY L"LdapQuery"
  38. // az link element defines
  39. #define AZ_XML_TAG_LINK_OPERATION L"OperationLink"
  40. #define AZ_XML_TAG_LINK_TASK L"TaskLink"
  41. #define AZ_XML_TAG_LINK_APPMEMBER L"AppMemberLink"
  42. #define AZ_XML_TAG_LINK_APPNONMEMBER L"AppNonMemberLink"
  43. // az object attribute name defines in xml store
  44. #define AZ_XML_TAG_ATTR_NAME L"Name"
  45. #define AZ_XML_TAG_ATTR_DESCRIPTION L"Description"
  46. #define AZ_XML_TAG_ATTR_GUID L"Guid"
  47. #define AZ_XML_TAG_ATTR_GROUPTYPE L"GroupType"
  48. #define AZ_XML_TAG_ATTR_TIMEOUT L"DomainTimeout"
  49. #define AZ_XML_TAG_ATTR_APPCLSID L"ApplicationCLSID"
  50. #define AZ_XML_TAG_ATTR_APPVERSION L"ApplicationVersion"
  51. #define AZ_XML_TAG_ATTR_BIZRULEIP L"BizRuleImportedPath"
  52. #define AZ_XML_TAG_ATTR_ROLEDEFINITION L"RoleDefinition"
  53. #define AZ_XML_TAG_ATTR_MAXSCRIPTS L"MaxScripts"
  54. #define AZ_XML_TAG_ATTR_SCRIPTTIMEOUT L"ScriptTimeout"
  55. #define AZ_XML_TAG_ATTR_AUDITS L"Audits"
  56. #define AZ_XML_TAG_ATTR_APPLICATIONDATA L"ApplicationData"
  57. #define AZ_XML_TAG_ATTR_MAJOR_VERSION L"MajorVersion"
  58. #define AZ_XML_TAG_ATTR_MINOR_VERSION L"MinorVersion"
  59. // az group type values
  60. #define AZ_XML_VAL_GROUPTYPE_LDAPQUERY L"LdapQuery"
  61. #define AZ_XML_VAL_GROUPTYPE_BASIC L"Basic"
  62. #define AZ_XML_VAL_TRUE L"True"
  63. #define AZ_XML_VAL_FALSE L"False"
  64. // xpath defines
  65. #define AZ_XML_SELECTION_LANGUAGE L"SelectionLanguage"
  66. #define AZ_XML_XPATH L"XPath"
  67. //globals
  68. WCHAR const * const g_pwszAzTrue=AZ_XML_VAL_TRUE;
  69. WCHAR const * const g_pwszAzFalse=AZ_XML_VAL_FALSE;
  70. WCHAR const * const g_pwszBasicGroup=AZ_XML_VAL_GROUPTYPE_BASIC;
  71. WCHAR const * const g_pwszLdapGroup=AZ_XML_VAL_GROUPTYPE_LDAPQUERY;
  72. PAZPE_AZROLES_INFO XmlAzrolesInfo;
  73. //
  74. // common XML parsing errors. Currently, we map all XML parsing errors
  75. // to ERROR_BAD_FORMAT. If we decide to map different types of errors to
  76. // different system error code, then these errors are roughly grouped together
  77. // in that way. Please see myXMLErrorToHresult to real implemenation detail.
  78. //
  79. //
  80. // The following errors are more closely tied to syntax (format) errors:
  81. //
  82. #define XML_E_MISSINGEQUALS 0xC00CE501 // Missing equals sign between attribute and attribute value.
  83. #define XML_E_MISSINGQUOTE 0xC00CE502 // A string literal was expected, but no opening quote character was found.
  84. #define XML_E_COMMENTSYNTAX 0xC00CE503 // Incorrect syntax was used in a comment.
  85. #define XML_E_XMLDECLSYNTAX 0xC00CE507 // Invalid syntax for an XML declaration.
  86. #define XML_E_MISSINGWHITESPACE 0xC00CE509 // Required white space was missing.
  87. #define XML_E_EXPECTINGTAGEND 0xC00CE50A // The character '>' was expected.
  88. #define XML_E_BADCHARINDTD 0xC00CE50B // Invalid character found in document type definition (DTD).
  89. #define XML_E_MISSINGSEMICOLON 0xC00CE50D // A semicolon character was expected.
  90. #define XML_E_UNBALANCEDPAREN 0xC00CE50F // Unbalanced parentheses.
  91. #define XML_E_EXPECTINGOPENBRACKET 0xC00CE510 // An opening '[' character was expected.
  92. #define XML_E_BADENDCONDSECT 0xC00CE511 // Invalid syntax in a conditional section.
  93. #define XML_E_UNEXPECTED_WHITESPACE 0xC00CE513 // White space is not allowed at this location.
  94. #define XML_E_INCOMPLETE_ENCODING 0xC00CE514 // End of file reached in invalid state for current encoding.
  95. #define XML_E_BADCHARINMIXEDMODEL 0xC00CE515 // Mixed content model cannot contain this character.
  96. #define XML_E_MISSING_STAR 0xC00CE516 // Mixed content model must be defined as zero or more('*').
  97. #define XML_E_MISSING_PAREN 0xC00CE518 // Missing parenthesis.
  98. #define XML_E_PIDECLSYNTAX 0xC00CE51A // Invalid syntax in processing instruction declaration.
  99. #define XML_E_EXPECTINGCLOSEQUOTE 0xC00CE51B // A single or double closing quote character (\' or \") is missing.
  100. #define XML_E_MULTIPLE_COLONS 0xC00CE51C // Multiple colons are not allowed in a name.
  101. #define XML_E_WHITESPACEORQUESTIONMARK 0xC00CE520 // Expecting white space or '?'.
  102. #define XML_E_UNEXPECTEDENDTAG 0xC00CE552 // End tag was not expected at this location.
  103. #define XML_E_UNCLOSEDTAG 0xC00CE553 // The following tags were not closed: %1.
  104. #define XML_E_DUPLICATEATTRIBUTE 0xC00CE554 // Duplicate attribute.
  105. #define XML_E_MULTIPLEROOTS 0xC00CE555 // Only one top level element is allowed in an XML document.
  106. #define XML_E_INVALIDATROOTLEVEL 0xC00CE556 // Invalid at the top level of the document.
  107. #define XML_E_BADXMLDECL 0xC00CE557 // Invalid XML declaration.
  108. #define XML_E_MISSINGROOT 0xC00CE558 // XML document must have a top level element.
  109. #define XML_E_UNEXPECTEDEOF 0xC00CE559 // Unexpected end of file.
  110. #define XML_E_BADPEREFINSUBSET 0xC00CE55A // Parameter entities cannot be used inside markup declarations in an internal subset.
  111. #define XML_E_PE_NESTING 0xC00CE55B // The replacement text for a parameter entity must be properly nested with parenthesized groups.
  112. #define XML_E_INVALID_CDATACLOSINGTAG 0xC00CE55C // The literal string ']]>' is not allowed in element content.
  113. #define XML_E_UNCLOSEDPI 0xC00CE55D // Processing instruction was not closed.
  114. #define XML_E_UNCLOSEDSTARTTAG 0xC00CE55E // Element was not closed.
  115. #define XML_E_UNCLOSEDENDTAG 0xC00CE55F // End element was missing the character '>'.
  116. #define XML_E_UNCLOSEDSTRING 0xC00CE560 // A string literal was not closed.
  117. #define XML_E_UNCLOSEDCOMMENT 0xC00CE561 // A comment was not closed.
  118. #define XML_E_UNCLOSEDDECL 0xC00CE562 // A declaration was not closed.
  119. #define XML_E_UNCLOSEDMARKUPDECL 0xC00CE563 // A markup declaration was not closed.
  120. #define XML_E_UNCLOSEDCDATA 0xC00CE564 // A CDATA section was not closed.
  121. #define XML_E_BADDECLNAME 0xC00CE565 // Declaration has an invalid name.
  122. #define XML_E_BADELEMENTINDTD 0xC00CE567 // An XML element is not allowed inside a DTD.
  123. #define XML_E_RESERVEDNAMESPACE 0xC00CE568 // The namespace prefix is not allowed to start with the reserved string "xml".
  124. #define XML_E_EXPECTING_VERSION 0xC00CE569 // The 'version' attribute is required at this location.
  125. #define XML_E_EXPECTING_ENCODING 0xC00CE56A // The 'encoding' attribute is required at this location.
  126. #define XML_E_EXPECTING_NAME 0xC00CE56B // At least one name is required at this location.
  127. #define XML_E_UNEXPECTED_ATTRIBUTE 0xC00CE56C // The specified attribute was not expected at this location. The attribute may be case sensitive.
  128. #define XML_E_ENDTAGMISMATCH 0xC00CE56D // End tag '%2' does not match the start tag '%1'.
  129. #define XML_E_EXPECTING_NDATA 0xC00CE570 // NDATA keyword is missing.
  130. #define XML_E_INVALID_TYPE 0xC00CE572 // Invalid type defined in ATTLIST.
  131. #define XML_E_INVALIDXMLSPACE 0xC00CE573 // XML space attribute has invalid value. Must specify 'default' or 'preserve'.
  132. #define XML_E_MULTI_ATTR_VALUE 0xC00CE574 // Multiple names found in attribute value when only one was expected.
  133. #define XML_E_INVALID_PRESENCE 0xC00CE575 // Invalid ATTDEF declaration. Expected #REQUIRED, #IMPLIED or #FIXED.
  134. #define XML_E_BADXMLCASE 0xC00CE576 // The name 'xml' is reserved and must be lowercase.
  135. #define XML_E_CONDSECTINSUBSET 0xC00CE577 // Conditional sections are not allowed in an internal subset.
  136. #define XML_E_INVALID_STANDALONE 0xC00CE579 // The standalone attribute must have the value 'yes' or 'no'.
  137. #define XML_E_UNEXPECTED_STANDALONE 0xC00CE57A // The standalone attribute cannot be used in external entities.
  138. #define XML_E_DTDELEMENT_OUTSIDE_DTD 0xC00CE580 // Cannot have a DTD declaration outside of a DTD.
  139. #define XML_E_DUPLICATEDOCTYPE 0xC00CE581 // Cannot have multiple DOCTYPE declarations.
  140. #define XML_E_CDATAINVALID 0xC00CE578 // CDATA is not allowed in a DTD.
  141. #define XML_E_DOCTYPE_IN_DTD 0xC00CE57B // Cannot have a DOCTYPE declaration in a DTD.
  142. #define XML_E_DOCTYPE_OUTSIDE_PROLOG 0xC00CE57E // Cannot have a DOCTYPE declaration outside of a prolog.
  143. //
  144. // The following errors are more closely tied to invalid data errors
  145. // (could consider using ERROR_INVALID_DATA)
  146. //
  147. #define XML_E_BADCHARDATA 0xC00CE508 // An invalid character was found in text content.
  148. #define XML_E_BADCHARINENTREF 0xC00CE50E // An invalid character was found inside an entity reference.
  149. #define XML_E_BADCHARINDECL 0xC00CE50C // An invalid character was found inside a DTD declaration.
  150. #define XML_E_BADCHARINMODEL 0xC00CE517 // Invalid character in content model.
  151. #define XML_E_BADCHARINENUMERATION 0xC00CE519 // Invalid character found in ATTLIST enumeration.
  152. #define XML_E_INVALID_DECIMAL 0xC00CE51D // Invalid character for decimal digit.
  153. #define XML_E_INVALID_HEXIDECIMAL 0xC00CE51E // Invalid character for hexadecimal digit.
  154. #define XML_E_BADSTARTNAMECHAR 0xC00CE504 // A name was started with an invalid character.
  155. #define XML_E_BADNAMECHAR 0xC00CE505 // A name contained an invalid character.
  156. #define XML_E_BADCHARINSTRING 0xC00CE506 // A string literal contained an invalid character.
  157. #define XML_E_INVALID_UNICODE 0xC00CE51F // Invalid Unicode character value for this platform.
  158. #define XML_E_BADEXTERNALID 0xC00CE566 // External ID is invalid.
  159. #define XML_E_INVALID_MODEL 0xC00CE571 // Content model is invalid.
  160. #define XML_E_MISSING_ENTITY 0xC00CE57C // Reference to undefined entity.
  161. #define XML_E_ENTITYREF_INNAME 0xC00CE57D // Entity reference is resolved to an invalid name character.
  162. #define XML_E_INVALID_VERSION 0xC00CE57F // Invalid version number.
  163. //
  164. // The following errors are more or less tied to not-supported type of errors
  165. // (could consider using ERROR_NOT_SUPPORTED)
  166. //
  167. #define XML_E_INVALIDSWITCH 0xC00CE56F // Switch from current encoding to specified encoding not supported.
  168. #define XML_E_INVALIDENCODING 0xC00CE56E // System does not support the specified encoding.
  169. //
  170. // The following errors are not mapped to any system error codes at this time.
  171. //
  172. #define XML_E_FORMATINDEX_BADINDEX 0xC00CE306 // The value passed in to formatIndex must be greater than 0.
  173. #define XML_E_FORMATINDEX_BADFORMAT 0xC00CE307 // Invalid format string.
  174. #define XML_E_EXPECTED_TOKEN 0xC00CE380 // Expected token %1 found %2.
  175. #define XML_E_UNEXPECTED_TOKEN 0xC00CE381 // Unexpected token %1.
  176. #define XML_E_INTERNALERROR 0xC00CE512 // Internal error.
  177. #define XML_E_SUSPENDED 0xC00CE550 // The parser is suspended.
  178. #define XML_E_STOPPED 0xC00CE551 // The parser is stopped.
  179. #define XML_E_RESOURCE 0xC00CE582 // Error processing resource '%1'.
  180. // macro defines
  181. //
  182. // if object is created or dirty bit
  183. //
  184. #define ObjectIsDirty(_go, _dirtyBit) \
  185. (0x0 != (XmlAzrolesInfo->AzpeDirtyBits(_go) & (_dirtyBit)))
  186. //
  187. // _JumpIfErrorOrPressOn should be used in any routines that are called from
  188. // application (through COM API) or from az core for update cache
  189. // if it is from application, it should return error immediately.
  190. // if it is from az core, it should press on the do the next process.
  191. // The routine uses _JumpIfErrorOrPressOn should use _HandlePressOnError too
  192. // Arguments:
  193. // _hr - the current error code we check
  194. // _hr2 - current press on error code. It should be init to S_OK
  195. // _label - error jump label
  196. // _lFlag - persist flag to indicate where it comes from
  197. // _fPressOn - flag to indicate should presson on or not
  198. // pszMsg - back trace message
  199. //
  200. #define _JumpIfErrorOrPressOn(_hr, _hr2, _label, _lFlag, _fPressOn, pszMsg) \
  201. { \
  202. if (AZPE_FLAGS_PERSIST_UPDATE_CACHE & (_lFlag)) \
  203. { \
  204. if (S_OK != _hr) \
  205. { \
  206. if (_fPressOn) \
  207. { \
  208. if (S_OK == _hr2) \
  209. { \
  210. _hr2 = _hr; \
  211. } \
  212. } \
  213. else \
  214. { \
  215. _JumpError(_hr, _label, pszMsg); \
  216. } \
  217. _PrintError(_hr, pszMsg); \
  218. } \
  219. } \
  220. else \
  221. { \
  222. _JumpIfError(_hr, _label, pszMsg); \
  223. } \
  224. }
  225. //
  226. // _HandlePressOnError should be used in any routines call
  227. // _JumpIfErrorOrPressOn. It is the replacement of regular
  228. // hr = S_OK at the end of each sub-routine
  229. //
  230. #define _HandlePressOnError(_hr, _hr2) \
  231. { \
  232. if (S_OK != _hr2) \
  233. { \
  234. _hr = _hr2; \
  235. } \
  236. else \
  237. { \
  238. _hr = S_OK; \
  239. } \
  240. }
  241. // xml storage
  242. // Each provider returns a single PVOID from *PersistOpen.
  243. // That PVOID is a pointer to whatever context the provider needs to maintain a
  244. // description of the local storage.
  245. // The structure below is that context for the xml store provider.
  246. typedef struct _AZP_XML_CONTEXT
  247. {
  248. // interface pointer to xml document object
  249. IXMLDOMDocument2 *pDoc;
  250. // Policy URL
  251. LPCWSTR pwszPolicyUrl;
  252. // Handle to AzAuthorizationStore
  253. AZPE_OBJECT_HANDLE hAzAuthorizationStore;
  254. //
  255. // TRUE if the file is writable
  256. LONG IsWritable;
  257. // TRUE if the current user has SE_SECURITY_PRIVILEGE on the server containing the store.
  258. BOOLEAN HasSecurityPrivilege;
  259. FILETIME FTLastWrite;
  260. } AZP_XML_CONTEXT, *PAZP_XML_CONTEXT;
  261. //
  262. // data structure for object property/attribute
  263. //
  264. typedef struct _AZ_PROP_ENTRY {
  265. ULONG lPropId; //attribute/property property ID
  266. ENUM_AZ_DATATYPE lDataType; //data type
  267. BOOL fSingle; //single occurence, flag to determine call on AddPropertyItem
  268. ULONG lDirtyBit; //property dirty bit
  269. WCHAR const *pwszTag; //tag in xml
  270. } AZ_PROP_ENTRY;
  271. typedef struct _AZ_CHILD_ENTRY {
  272. WCHAR const *pwszChildTag; //child object tag
  273. ULONG ChildType; //child object type
  274. } AZ_CHILD_ENTRY;
  275. typedef struct _AZ_SUBMIT_LOAD_ENTRY {
  276. WCHAR const *pwszTag; // object node tag
  277. WCHAR const * const *rgpwszLkTag; // for linked item deletion
  278. AZ_PROP_ENTRY *rgpAttrs; // array of attr entry data
  279. AZ_PROP_ENTRY *rgpEles; // array of element entries
  280. AZ_CHILD_ENTRY *rgpChildren; // array of children
  281. } AZ_SUBMIT_LOAD_ENTRY;
  282. //
  283. // Procedures implemented by the xml provider
  284. //
  285. DWORD
  286. WINAPI
  287. XMLPersistOpen(
  288. IN LPCWSTR PolicyUrl,
  289. IN AZPE_OBJECT_HANDLE pAzAuthorizationStore,
  290. IN ULONG Flags,
  291. IN BOOL CreatePolicy,
  292. OUT PAZPE_PERSIST_CONTEXT PersistContext,
  293. OUT LPWSTR *pwszTargetMachine
  294. );
  295. DWORD
  296. WINAPI
  297. XMLPersistUpdateCache(
  298. IN AZPE_PERSIST_CONTEXT PersistContext,
  299. IN ULONG lPersistFlags,
  300. OUT ULONG* pulUpdateFlag
  301. );
  302. VOID
  303. WINAPI
  304. XMLPersistClose(
  305. IN AZPE_PERSIST_CONTEXT PersistContext
  306. );
  307. DWORD
  308. WINAPI
  309. XMLPersistSubmit(
  310. IN AZPE_PERSIST_CONTEXT PersistContext,
  311. IN AZPE_OBJECT_HANDLE AzpeObjectHandle,
  312. IN ULONG Flags,
  313. IN BOOLEAN DeleteMe
  314. );
  315. DWORD
  316. WINAPI
  317. XMLPersistRefresh(
  318. IN AZPE_PERSIST_CONTEXT PersistContext,
  319. IN AZPE_OBJECT_HANDLE AzpeObjectHandle,
  320. IN ULONG lPersistFlags
  321. );
  322. //
  323. // Define a provider info telling the core our interface
  324. //
  325. AZPE_PROVIDER_INFO XmlProviderInfo = {
  326. AZPE_PROVIDER_INFO_VERSION_1,
  327. AZ_XML_PROVIDER_NAME,
  328. XMLPersistOpen,
  329. XMLPersistUpdateCache,
  330. XMLPersistClose,
  331. XMLPersistSubmit,
  332. XMLPersistRefresh
  333. };
  334. //
  335. // following data entries or tables handling all object submit
  336. //
  337. //
  338. // authorization store entry
  339. //
  340. AZ_PROP_ENTRY g_AdAttrs[] = {
  341. /*
  342. {lPropId, lDataType, fSingle, lDirtyBit, pwszTag},
  343. */
  344. {AZ_PROP_AZSTORE_DOMAIN_TIMEOUT, ENUM_AZ_LONG, TRUE, AZ_DIRTY_AZSTORE_DOMAIN_TIMEOUT, AZ_XML_TAG_ATTR_TIMEOUT},
  345. {AZ_PROP_AZSTORE_SCRIPT_ENGINE_TIMEOUT, ENUM_AZ_LONG, TRUE, AZ_DIRTY_AZSTORE_SCRIPT_ENGINE_TIMEOUT, AZ_XML_TAG_ATTR_SCRIPTTIMEOUT},
  346. {AZ_PROP_AZSTORE_MAX_SCRIPT_ENGINES, ENUM_AZ_LONG, TRUE, AZ_DIRTY_AZSTORE_MAX_SCRIPT_ENGINES, AZ_XML_TAG_ATTR_MAXSCRIPTS},
  347. {AZ_PROP_GENERATE_AUDITS, ENUM_AZ_BOOL, TRUE, AZ_DIRTY_GENERATE_AUDITS, AZ_XML_TAG_ATTR_AUDITS},
  348. {AZ_PROP_APPLICATION_DATA, ENUM_AZ_BSTR, TRUE, AZ_DIRTY_APPLICATION_DATA, AZ_XML_TAG_ATTR_APPLICATIONDATA},
  349. {AZ_PROP_AZSTORE_MAJOR_VERSION, ENUM_AZ_LONG, TRUE, AZ_DIRTY_AZSTORE_MAJOR_VERSION, AZ_XML_TAG_ATTR_MAJOR_VERSION},
  350. {AZ_PROP_AZSTORE_MINOR_VERSION, ENUM_AZ_LONG, TRUE, AZ_DIRTY_AZSTORE_MINOR_VERSION, AZ_XML_TAG_ATTR_MINOR_VERSION},
  351. {0, ENUM_AZ_LONG, FALSE, 0, NULL}, //terminator entry
  352. };
  353. AZ_CHILD_ENTRY g_AdChild[] = {
  354. /*
  355. {pwszChildTag, ChildType},
  356. */
  357. {AZ_XML_TAG_APPLICATION, OBJECT_TYPE_APPLICATION},
  358. {AZ_XML_TAG_GROUP, OBJECT_TYPE_GROUP},
  359. {NULL, 0}, //terminator entry
  360. };
  361. //
  362. // application entry
  363. //
  364. AZ_PROP_ENTRY g_ApAttrs[] = {
  365. /*
  366. {lPropId, lDataType, fSingle, lDirtyBit, pwszTag},
  367. */
  368. {AZ_PROP_APPLICATION_AUTHZ_INTERFACE_CLSID, ENUM_AZ_BSTR, TRUE, AZ_DIRTY_APPLICATION_AUTHZ_INTERFACE_CLSID, AZ_XML_TAG_ATTR_APPCLSID},
  369. {AZ_PROP_APPLICATION_VERSION, ENUM_AZ_BSTR, TRUE, AZ_DIRTY_APPLICATION_VERSION, AZ_XML_TAG_ATTR_APPVERSION},
  370. {AZ_PROP_GENERATE_AUDITS, ENUM_AZ_BOOL, TRUE, AZ_DIRTY_GENERATE_AUDITS, AZ_XML_TAG_ATTR_AUDITS},
  371. {AZ_PROP_APPLICATION_DATA, ENUM_AZ_BSTR, TRUE, AZ_DIRTY_APPLICATION_DATA, AZ_XML_TAG_ATTR_APPLICATIONDATA},
  372. {0, ENUM_AZ_BOOL, FALSE, 0, NULL}, //terminator entry
  373. };
  374. AZ_CHILD_ENTRY g_ApChild[] = {
  375. /*
  376. {pwszChildTag, ChildType},
  377. */
  378. {AZ_XML_TAG_OPERATION, OBJECT_TYPE_OPERATION},
  379. {AZ_XML_TAG_TASK, OBJECT_TYPE_TASK},
  380. {AZ_XML_TAG_GROUP, OBJECT_TYPE_GROUP},
  381. {AZ_XML_TAG_SCOPE, OBJECT_TYPE_SCOPE},
  382. {AZ_XML_TAG_ROLE, OBJECT_TYPE_ROLE},
  383. {NULL, 0}, //terminator entry
  384. };
  385. //
  386. // operation entry
  387. //
  388. WCHAR const * const g_OpLkTags[] = {
  389. AZ_XML_TAG_LINK_OPERATION,
  390. NULL,
  391. };
  392. AZ_PROP_ENTRY g_OpAttrs[] = {
  393. /*
  394. {lPropId, lDataType, fSingle, lDirtyBit, pwszTag},
  395. */
  396. {AZ_PROP_APPLICATION_DATA, ENUM_AZ_BSTR, TRUE, AZ_DIRTY_APPLICATION_DATA, AZ_XML_TAG_ATTR_APPLICATIONDATA},
  397. {0, ENUM_AZ_LONG, FALSE, 0, NULL}, //terminator entry
  398. };
  399. AZ_PROP_ENTRY g_OpEles[] = {
  400. /*
  401. {lPropId, lDataType, fSingle, lDirtyBit, pwszTag},
  402. */
  403. {AZ_PROP_OPERATION_ID, ENUM_AZ_LONG, TRUE, AZ_DIRTY_OPERATION_ID, AZ_XML_TAG_OPERATIONID},
  404. {0, ENUM_AZ_LONG, FALSE, 0, NULL}, //terminator entry
  405. };
  406. //
  407. // task entry
  408. //
  409. WCHAR const * const g_TkLkTags[] = {
  410. AZ_XML_TAG_LINK_TASK,
  411. NULL,
  412. };
  413. AZ_PROP_ENTRY g_TkAttrs[] = {
  414. /*
  415. {lPropId, lDataType, fSingle, lDirtyBit, pwszTag},
  416. */
  417. {AZ_PROP_TASK_BIZRULE_IMPORTED_PATH, ENUM_AZ_BSTR, TRUE, AZ_DIRTY_TASK_BIZRULE_IMPORTED_PATH, AZ_XML_TAG_ATTR_BIZRULEIP},
  418. {AZ_PROP_TASK_IS_ROLE_DEFINITION, ENUM_AZ_BOOL, TRUE, AZ_DIRTY_TASK_IS_ROLE_DEFINITION, AZ_XML_TAG_ATTR_ROLEDEFINITION},
  419. {AZ_PROP_APPLICATION_DATA, ENUM_AZ_BSTR, TRUE, AZ_DIRTY_APPLICATION_DATA, AZ_XML_TAG_ATTR_APPLICATIONDATA},
  420. {0, ENUM_AZ_LONG, FALSE, 0, NULL}, //terminator entry
  421. };
  422. AZ_PROP_ENTRY g_TkEles[] = {
  423. /*
  424. {lPropId, lDataType, fSingle, lDirtyBit, pwszTag},
  425. */
  426. {AZ_PROP_TASK_BIZRULE_LANGUAGE, ENUM_AZ_BSTR, TRUE, AZ_DIRTY_TASK_BIZRULE_LANGUAGE, AZ_XML_TAG_BIZRULELANGUAGE},
  427. {AZ_PROP_TASK_BIZRULE, ENUM_AZ_BSTR, TRUE, AZ_DIRTY_TASK_BIZRULE, AZ_XML_TAG_BIZRULE},
  428. {AZ_PROP_TASK_OPERATIONS, ENUM_AZ_GUID_ARRAY, FALSE, AZ_DIRTY_TASK_OPERATIONS, AZ_XML_TAG_LINK_OPERATION},
  429. {AZ_PROP_TASK_TASKS, ENUM_AZ_GUID_ARRAY, FALSE, AZ_DIRTY_TASK_TASKS, AZ_XML_TAG_LINK_TASK},
  430. {0, ENUM_AZ_LONG, FALSE, 0, NULL}, //terminator entry
  431. };
  432. //
  433. // group entry
  434. //
  435. WCHAR const * const g_GpLkTags[] = {
  436. AZ_XML_TAG_LINK_APPMEMBER,
  437. AZ_XML_TAG_LINK_APPNONMEMBER,
  438. NULL,
  439. };
  440. AZ_PROP_ENTRY g_GpAttrs[] = {
  441. /*
  442. {lPropId, lDataType, fSingle, lDirtyBit, pwszTag},
  443. */
  444. {AZ_PROP_GROUP_TYPE, ENUM_AZ_GROUP_TYPE, TRUE, AZ_DIRTY_GROUP_TYPE, AZ_XML_TAG_ATTR_GROUPTYPE},
  445. {0, ENUM_AZ_LONG, FALSE, 0, NULL}, //terminator entry
  446. };
  447. AZ_PROP_ENTRY g_GpEles[] = {
  448. /*
  449. {lPropId, lDataType, fSingle, lDirtyBit, pwszTag},
  450. */
  451. {AZ_PROP_GROUP_LDAP_QUERY, ENUM_AZ_BSTR, TRUE, AZ_DIRTY_GROUP_LDAP_QUERY, AZ_XML_TAG_LDAPQUERY},
  452. {AZ_PROP_GROUP_MEMBERS, ENUM_AZ_SID_ARRAY, FALSE, AZ_DIRTY_GROUP_MEMBERS, AZ_XML_TAG_MEMBER},
  453. {AZ_PROP_GROUP_NON_MEMBERS, ENUM_AZ_SID_ARRAY, FALSE, AZ_DIRTY_GROUP_NON_MEMBERS, AZ_XML_TAG_NONMEMBER},
  454. {AZ_PROP_GROUP_APP_MEMBERS, ENUM_AZ_GUID_ARRAY, FALSE, AZ_DIRTY_GROUP_APP_MEMBERS, AZ_XML_TAG_LINK_APPMEMBER},
  455. {AZ_PROP_GROUP_APP_NON_MEMBERS, ENUM_AZ_GUID_ARRAY, FALSE, AZ_DIRTY_GROUP_APP_NON_MEMBERS, AZ_XML_TAG_LINK_APPNONMEMBER},
  456. {0, ENUM_AZ_LONG, FALSE, 0, NULL}, //terminator entry
  457. };
  458. //
  459. // scope entry
  460. //
  461. AZ_PROP_ENTRY g_SpAttrs[] = {
  462. /*
  463. {lPropId, lDataType, fSingle, lDirtyBit, pwszTag},
  464. */
  465. {AZ_PROP_APPLICATION_DATA, ENUM_AZ_BSTR, TRUE, AZ_DIRTY_APPLICATION_DATA, AZ_XML_TAG_ATTR_APPLICATIONDATA},
  466. {0, ENUM_AZ_LONG, FALSE, 0, NULL}, //terminator entry
  467. };
  468. AZ_CHILD_ENTRY g_SpChild[] = {
  469. /*
  470. {pwszChildTag, ChildType},
  471. */
  472. {AZ_XML_TAG_TASK, OBJECT_TYPE_TASK},
  473. {AZ_XML_TAG_GROUP, OBJECT_TYPE_GROUP},
  474. {AZ_XML_TAG_ROLE, OBJECT_TYPE_ROLE},
  475. {NULL, 0}, //terminator entry
  476. };
  477. //
  478. // role entry
  479. //
  480. AZ_PROP_ENTRY g_RlAttrs[] = {
  481. /*
  482. {lPropId, lDataType, fSingle, lDirtyBit, pwszTag},
  483. */
  484. {AZ_PROP_APPLICATION_DATA, ENUM_AZ_BSTR, TRUE, AZ_DIRTY_APPLICATION_DATA, AZ_XML_TAG_ATTR_APPLICATIONDATA},
  485. {0, ENUM_AZ_LONG, FALSE, 0, NULL}, //terminator entry
  486. };
  487. AZ_PROP_ENTRY g_RlEles[] = {
  488. /*
  489. {lPropId, lDataType, fSingle, lDirtyBit, pwszTag},
  490. */
  491. {AZ_PROP_ROLE_APP_MEMBERS, ENUM_AZ_GUID_ARRAY, FALSE, AZ_DIRTY_ROLE_APP_MEMBERS, AZ_XML_TAG_LINK_APPMEMBER},
  492. {AZ_PROP_ROLE_MEMBERS, ENUM_AZ_SID_ARRAY, FALSE, AZ_DIRTY_ROLE_MEMBERS, AZ_XML_TAG_MEMBER},
  493. {AZ_PROP_ROLE_OPERATIONS, ENUM_AZ_GUID_ARRAY, FALSE, AZ_DIRTY_ROLE_OPERATIONS, AZ_XML_TAG_LINK_OPERATION},
  494. {AZ_PROP_ROLE_TASKS, ENUM_AZ_GUID_ARRAY, FALSE, AZ_DIRTY_ROLE_TASKS, AZ_XML_TAG_LINK_TASK},
  495. {0, ENUM_AZ_LONG, FALSE, 0, NULL}, //terminator entry
  496. };
  497. //
  498. // ***IMPORTANT***, keep the order of element the same as defined
  499. // in OBJECT_TYPE_* (see genobj.h)
  500. //
  501. AZ_SUBMIT_LOAD_ENTRY g_SubmitLoadTable[OBJECT_TYPE_COUNT] = {
  502. /*
  503. {pwszTag, rgpwszLkTag,rgpAttrs, rgpEles, rgpChild},
  504. */
  505. {AZ_XML_TAG_AZSTORE, NULL, g_AdAttrs, NULL, g_AdChild}, //OBJECT_TYPE_AZAUTHSTORE
  506. {AZ_XML_TAG_APPLICATION, NULL, g_ApAttrs, NULL, g_ApChild}, //OBJECT_TYPE_APPLICATION
  507. {AZ_XML_TAG_OPERATION, g_OpLkTags, g_OpAttrs, g_OpEles, NULL}, //OBJECT_TYPE_OPERATION
  508. {AZ_XML_TAG_TASK, g_TkLkTags, g_TkAttrs, g_TkEles, NULL}, //OBJECT_TYPE_TASK
  509. {AZ_XML_TAG_SCOPE, NULL, g_SpAttrs, NULL, g_SpChild}, //OBJECT_TYPE_SCOPE
  510. {AZ_XML_TAG_GROUP, g_GpLkTags, g_GpAttrs, g_GpEles, NULL}, //OBJECT_TYPE_GROUP
  511. {AZ_XML_TAG_ROLE, NULL, g_RlAttrs, g_RlEles, NULL}, //OBJECT_TYPE_ROLE
  512. };
  513. //
  514. // rights for users
  515. //
  516. #define AZ_POLICY_AZSTORE_MASK_XML FILE_ALL_ACCESS
  517. #define AZ_POLICY_READER_MASK_XML FILE_GENERIC_READ
  518. #define AZ_POLICY_ACE_FLAGS_XML 0x0
  519. //
  520. // User rights for XML policy admins
  521. //
  522. AZP_POLICY_USER_RIGHTS PolicyAdminsRights = {
  523. AZ_POLICY_AZSTORE_MASK_XML,
  524. AZ_POLICY_ACE_FLAGS_XML
  525. };
  526. PAZP_POLICY_USER_RIGHTS XMLPolicyAdminsRights[] = {
  527. &PolicyAdminsRights,
  528. NULL
  529. };
  530. //
  531. // User rights for XML policy readers
  532. //
  533. AZP_POLICY_USER_RIGHTS PolicyReadersRights = {
  534. AZ_POLICY_READER_MASK_XML,
  535. AZ_POLICY_ACE_FLAGS_XML
  536. };
  537. PAZP_POLICY_USER_RIGHTS XMLPolicyReadersRights[] = {
  538. &PolicyReadersRights,
  539. NULL
  540. };
  541. //
  542. // Rights for the SACL.
  543. //
  544. AZP_POLICY_USER_RIGHTS XMLSaclRights = {
  545. DELETE|WRITE_DAC|WRITE_OWNER|FILE_GENERIC_WRITE,
  546. 0 // No Flags
  547. };
  548. //
  549. // the following functions are copied from UI (shell) team
  550. // with minor changes
  551. //
  552. BOOL
  553. IsDfsPath(
  554. IN PWSTR pszPath,
  555. OUT PWSTR pszServer,
  556. IN UINT cchServer
  557. )
  558. /*++
  559. Routine Description:
  560. This function detects if a UNC file path is a DFS path and if so,
  561. the real server name for the DFS path is returned in the pszServer buffer.
  562. Arguments:
  563. pszPath - a UNC file path to detect
  564. pszServer - buffer to receive the real server name
  565. cchServer - length (tchars) of the pszServer buffer
  566. --*/
  567. {
  568. BOOL bIsDfs = FALSE;
  569. PWSTR pszTemp=NULL;
  570. PDFS_INFO_3 pDI3 = NULL;
  571. WCHAR szServer[MAX_PATH];
  572. if (pszPath == NULL || !PathIsUNC(pszPath))
  573. return FALSE; // local machine
  574. //
  575. // allocate a temp buffer
  576. //
  577. pszTemp = (PWSTR)LocalAlloc(LPTR, (wcslen(pszPath)+1)*sizeof(TCHAR));
  578. if ( pszTemp == NULL ) {
  579. return FALSE;
  580. }
  581. wcscpy(pszTemp, pszPath);
  582. //
  583. // Check for DFS
  584. //
  585. for (;;)
  586. {
  587. DWORD dwErr;
  588. __try
  589. {
  590. // This is delay-loaded by the linker, so
  591. // must wrap with an exception handler.
  592. dwErr = NetDfsGetClientInfo(pszTemp,
  593. NULL,
  594. NULL,
  595. 3,
  596. (LPBYTE*)&pDI3);
  597. }
  598. __except(EXCEPTION_EXECUTE_HANDLER)
  599. {
  600. LocalFree(pszTemp);
  601. return FALSE;
  602. }
  603. if (NERR_Success == dwErr)
  604. {
  605. for (ULONG i = 0; i < pDI3->NumberOfStorages; i++)
  606. {
  607. if (DFS_STORAGE_STATE_ONLINE & pDI3->Storage[i].State)
  608. {
  609. bIsDfs = TRUE;
  610. szServer[0] = L'\\';
  611. szServer[1] = L'\\';
  612. wcsncpy(&szServer[2], pDI3->Storage[i].ServerName, ARRAYLEN(szServer)-2);
  613. //
  614. // If this server is active, quit looking
  615. //
  616. if (DFS_STORAGE_STATE_ACTIVE & pDI3->Storage[i].State)
  617. break;
  618. }
  619. }
  620. break;
  621. }
  622. else if (NERR_DfsNoSuchVolume == dwErr)
  623. {
  624. //
  625. // If we're at the root, then we can't go any farther.
  626. //
  627. if (PathIsRoot(pszTemp))
  628. break;
  629. //
  630. // Remove the last path element and try again, if nothing is
  631. // removed, break, don't go in infinite loop
  632. //
  633. if (!PathRemoveFileSpec(pszTemp))
  634. break;
  635. }
  636. else
  637. {
  638. //
  639. // Some other error, bail
  640. //
  641. break;
  642. }
  643. }
  644. if (bIsDfs)
  645. {
  646. //
  647. // copy the server name to the output buffer
  648. //
  649. wcsncpy(pszServer, szServer, cchServer);
  650. }
  651. //
  652. // free the alloated buffer
  653. //
  654. if (NULL != pDI3)
  655. NetApiBufferFree(pDI3);
  656. LocalFree(pszTemp);
  657. return bIsDfs;
  658. }
  659. DWORD
  660. _WNetGetConnection(
  661. IN PWSTR pszLocal,
  662. OUT PWSTR pszRemote,
  663. IN OUT LPDWORD pdwLen
  664. )
  665. /*++
  666. Routine Description:
  667. This function get an UNC path for a mapped netowrk path.
  668. It fails if the path is not a valid network path.
  669. Arguments:
  670. pszLocal - the local mapped drive letter
  671. pszRemote - the mapped remote share name
  672. pdwLen - the length of the buffer required
  673. --*/
  674. {
  675. DWORD dwErr = ERROR_PROC_NOT_FOUND;
  676. // This is the only function we call in mpr.dll, and it's delay-loaded
  677. // so wrap it with SEH.
  678. __try
  679. {
  680. dwErr = WNetGetConnection(pszLocal, pszRemote, pdwLen);
  681. }
  682. __finally
  683. {
  684. }
  685. return dwErr;
  686. }
  687. DWORD
  688. myGetRemotePath(
  689. IN PCWSTR pszInName,
  690. OUT PWSTR *ppszOutName
  691. )
  692. /*++
  693. Routine Description:
  694. Return UNC version of a path that is mapped to a remote machine
  695. Arguments:
  696. pszInName - initial path
  697. ppszOutName - UNC path returned, Must be freed by AzpFreeHeap
  698. Return value:
  699. --*/
  700. {
  701. if(!pszInName || !ppszOutName)
  702. {
  703. return ERROR_INVALID_PARAMETER;
  704. }
  705. *ppszOutName = NULL;
  706. DWORD dwErr;
  707. WCHAR szLocalName[3];
  708. WCHAR szRemoteName[MAX_PATH];
  709. DWORD dwLen = ARRAYLEN(szRemoteName);
  710. szRemoteName[0] = L'\0';
  711. //
  712. // buffer to the drive letter only
  713. //
  714. szLocalName[0] = pszInName[0];
  715. szLocalName[1] = pszInName[1];
  716. szLocalName[2] = TEXT('\0');
  717. //
  718. // try to make the connection alive by accessing the remote share
  719. // but do not care error now (if it cannot connect, the next call will fail)
  720. //
  721. GetFileAttributes(pszInName);
  722. //
  723. // get connection for the drive letter
  724. //
  725. dwErr = _WNetGetConnection(szLocalName, szRemoteName, &dwLen);
  726. if (NO_ERROR == dwErr)
  727. {
  728. //
  729. // success, get the mapped path (local or remote)
  730. //
  731. dwLen = (DWORD)wcslen(szRemoteName);
  732. } else if ( ERROR_MORE_DATA != dwErr ) {
  733. //
  734. // other errors including ERROR_NOT_CONNECTED
  735. // return the error
  736. goto CleanUp;
  737. }
  738. //
  739. // if dwErr == ERROR_MORE_DATA, dwLen already has the correct value
  740. // Skip the drive letter and add the length of the rest of the path
  741. // (including NULL)
  742. //
  743. pszInName += 2;
  744. dwLen += (DWORD)wcslen(pszInName) + 1;
  745. //
  746. // We should never get incomplete paths, so we should always
  747. // see a backslash after the "X:". If this isn't true, then
  748. // we should call GetFullPathName.
  749. //
  750. ASSERT(TEXT('\\') == *pszInName);
  751. //
  752. // Allocate the return buffer
  753. //
  754. *ppszOutName = (PWSTR)AzpAllocateHeap(dwLen * sizeof(WCHAR), "XMNAME" );
  755. if (!*ppszOutName)
  756. {
  757. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  758. goto CleanUp;
  759. }
  760. if (ERROR_MORE_DATA == dwErr)
  761. {
  762. //
  763. // Try again with the bigger buffer
  764. //
  765. dwErr = _WNetGetConnection(szLocalName, *ppszOutName, &dwLen);
  766. }
  767. else
  768. {
  769. //
  770. // WNetGetConnection succeeded from the first call. Copy the result
  771. //
  772. wcscpy(*ppszOutName, szRemoteName);
  773. }
  774. //
  775. // Copy the rest of the path
  776. //
  777. wcscat(*ppszOutName, pszInName);
  778. CleanUp:
  779. if (NO_ERROR != dwErr && *ppszOutName)
  780. {
  781. AzpFreeHeap(*ppszOutName);
  782. *ppszOutName = NULL;
  783. }
  784. return (dwErr);
  785. }
  786. void
  787. myGetVolumeInfo(
  788. IN PCWSTR pszPath,
  789. OUT PWSTR pszVolume,
  790. IN ULONG cchVolume
  791. )
  792. /*++
  793. Routine Description:
  794. This function queries the volume information for the given path
  795. Arguments:
  796. pszPath - a file path to detect
  797. pszVolume - buffer to receive the volume name
  798. cchVolume - length (tchars) of the output buffer
  799. --*/
  800. {
  801. if ( pszPath == NULL || pszVolume == NULL ) {
  802. return;
  803. }
  804. WCHAR szVolume[MAX_PATH+1];
  805. //
  806. // The path can be DFS or contain volume mount points, so start
  807. // with the full path and try GetVolumeInformation on successively
  808. // shorter paths until it succeeds or we run out of path.
  809. //
  810. // However, if it's a volume mount point, we're interested in the
  811. // the host folder's volume so back up one level to start. The
  812. // child volume is handled separately (see AddMountedVolumePage).
  813. //
  814. wcsncpy(szVolume, pszPath, ARRAYLEN(szVolume));
  815. szVolume[MAX_PATH] = '\0';
  816. //
  817. // input volume name is always a XML file name
  818. //
  819. PathRemoveFileSpec(szVolume);
  820. for (;;)
  821. {
  822. PathAddBackslash(szVolume); // GetVolumeInformation likes a trailing '\'
  823. DWORD dwFlags = 0;
  824. if (GetVolumeInformation(szVolume,
  825. NULL,
  826. NULL,
  827. NULL,
  828. NULL,
  829. &dwFlags,
  830. NULL,
  831. 0))
  832. {
  833. break;
  834. }
  835. // Access denied implies that we've reached the deepest volume
  836. // in the path; we just can't get the flags. It also implies
  837. // security, so assume persistent acls.
  838. if (ERROR_ACCESS_DENIED == GetLastError())
  839. {
  840. break;
  841. }
  842. // If we're at the root, then we can't go any farther.
  843. if (PathIsRoot(szVolume))
  844. break;
  845. // Remove the last path element and try again
  846. PathRemoveBackslash(szVolume);
  847. //if nothing is removed break instead of going in infinite loop
  848. if (!PathRemoveFileSpec(szVolume))
  849. break;
  850. }
  851. PathRemoveBackslash(szVolume);
  852. wcsncpy(pszVolume, szVolume, cchVolume);
  853. }
  854. DWORD
  855. myXMLErrorToWin32 (
  856. IN LONG lErrCode
  857. )
  858. /*++
  859. Routine Description:
  860. This routine maps XML parsing error codes to system error codes.
  861. Arguments:
  862. lErrCode - the XML parsing error to be translated.
  863. Return Value:
  864. various win32 system error codes.
  865. Note:
  866. (1) Currently, we map all errors related to parsing to ERROR_BAD_FORMAT.
  867. Other errors are not translated at all. However, this is a very coarse
  868. mapping and we might want to do a more fine-grained mapping at a
  869. later time.
  870. (2) All these XML_E_xxx are locally defined according to MSDN.
  871. Please see the definition of these constants for detail. Unfortunately I
  872. have to do that because these error codes are not available anyway I can find.
  873. --*/
  874. {
  875. switch (lErrCode)
  876. {
  877. //
  878. // the following errors match pretty well with ERROR_BAD_FORMAT
  879. //
  880. case XML_E_MISSINGEQUALS:
  881. case XML_E_MISSINGQUOTE:
  882. case XML_E_COMMENTSYNTAX:
  883. case XML_E_XMLDECLSYNTAX:
  884. case XML_E_MISSINGWHITESPACE:
  885. case XML_E_EXPECTINGTAGEND:
  886. case XML_E_BADCHARINDTD:
  887. case XML_E_MISSINGSEMICOLON:
  888. case XML_E_UNBALANCEDPAREN:
  889. case XML_E_EXPECTINGOPENBRACKET:
  890. case XML_E_BADENDCONDSECT:
  891. case XML_E_UNEXPECTED_WHITESPACE:
  892. case XML_E_INCOMPLETE_ENCODING:
  893. case XML_E_BADCHARINMIXEDMODEL:
  894. case XML_E_MISSING_STAR:
  895. case XML_E_MISSING_PAREN:
  896. case XML_E_PIDECLSYNTAX:
  897. case XML_E_EXPECTINGCLOSEQUOTE:
  898. case XML_E_MULTIPLE_COLONS:
  899. case XML_E_WHITESPACEORQUESTIONMARK:
  900. case XML_E_UNEXPECTEDENDTAG:
  901. case XML_E_UNCLOSEDTAG:
  902. case XML_E_DUPLICATEATTRIBUTE:
  903. case XML_E_MULTIPLEROOTS:
  904. case XML_E_INVALIDATROOTLEVEL:
  905. case XML_E_BADXMLDECL:
  906. case XML_E_MISSINGROOT:
  907. case XML_E_UNEXPECTEDEOF:
  908. case XML_E_BADPEREFINSUBSET:
  909. case XML_E_PE_NESTING:
  910. case XML_E_INVALID_CDATACLOSINGTAG:
  911. case XML_E_UNCLOSEDPI:
  912. case XML_E_UNCLOSEDSTARTTAG:
  913. case XML_E_UNCLOSEDENDTAG:
  914. case XML_E_UNCLOSEDSTRING:
  915. case XML_E_UNCLOSEDCOMMENT:
  916. case XML_E_UNCLOSEDDECL:
  917. case XML_E_UNCLOSEDMARKUPDECL:
  918. case XML_E_UNCLOSEDCDATA:
  919. case XML_E_BADDECLNAME:
  920. case XML_E_BADELEMENTINDTD:
  921. case XML_E_RESERVEDNAMESPACE:
  922. case XML_E_EXPECTING_VERSION:
  923. case XML_E_EXPECTING_ENCODING:
  924. case XML_E_EXPECTING_NAME:
  925. case XML_E_UNEXPECTED_ATTRIBUTE:
  926. case XML_E_ENDTAGMISMATCH:
  927. case XML_E_EXPECTING_NDATA:
  928. case XML_E_INVALID_TYPE:
  929. case XML_E_INVALIDXMLSPACE:
  930. case XML_E_MULTI_ATTR_VALUE:
  931. case XML_E_INVALID_PRESENCE:
  932. case XML_E_BADXMLCASE:
  933. case XML_E_CONDSECTINSUBSET:
  934. case XML_E_INVALID_STANDALONE:
  935. case XML_E_UNEXPECTED_STANDALONE:
  936. case XML_E_DTDELEMENT_OUTSIDE_DTD:
  937. case XML_E_DUPLICATEDOCTYPE:
  938. case XML_E_CDATAINVALID:
  939. case XML_E_DOCTYPE_IN_DTD:
  940. case XML_E_DOCTYPE_OUTSIDE_PROLOG:
  941. //
  942. // the following errors are more closely tied to ERROR_INVALID_DATA;
  943. //
  944. case XML_E_BADCHARDATA:
  945. case XML_E_BADCHARINENTREF:
  946. case XML_E_BADCHARINDECL:
  947. case XML_E_BADCHARINMODEL:
  948. case XML_E_BADCHARINENUMERATION:
  949. case XML_E_INVALID_DECIMAL:
  950. case XML_E_INVALID_HEXIDECIMAL:
  951. case XML_E_BADSTARTNAMECHAR:
  952. case XML_E_BADNAMECHAR:
  953. case XML_E_BADCHARINSTRING:
  954. case XML_E_INVALID_UNICODE:
  955. case XML_E_BADEXTERNALID:
  956. case XML_E_INVALID_MODEL:
  957. case XML_E_MISSING_ENTITY:
  958. case XML_E_ENTITYREF_INNAME:
  959. case XML_E_INVALID_VERSION:
  960. //
  961. // the following errors are more closely tied to ERROR_NOT_SUPPORTED;
  962. //
  963. case XML_E_INVALIDENCODING:
  964. case XML_E_INVALIDSWITCH:
  965. return ERROR_BAD_FORMAT;
  966. //
  967. // we don't translate the other errors:
  968. //
  969. case XML_E_FORMATINDEX_BADINDEX:
  970. case XML_E_FORMATINDEX_BADFORMAT:
  971. case XML_E_EXPECTED_TOKEN:
  972. case XML_E_UNEXPECTED_TOKEN:
  973. case XML_E_INTERNALERROR:
  974. case XML_E_SUSPENDED:
  975. case XML_E_STOPPED:
  976. case XML_E_RESOURCE:
  977. default:
  978. return lErrCode;
  979. }
  980. }
  981. HRESULT
  982. myGetXmlError(
  983. IN HRESULT hrIn,
  984. IN IXMLDOMDocument2 *pDoc,
  985. OUT OPTIONAL BSTR *pbstrReason)
  986. {
  987. HRESULT hr;
  988. HRESULT hrRet = hrIn;
  989. LONG errorCode = 0;
  990. IXMLDOMParseError *pErr = NULL;
  991. hr = pDoc->get_parseError(&pErr);
  992. _JumpIfError(hr, error, "pDoc->get_parseError");
  993. AZASSERT(NULL != pErr);
  994. hr = pErr->get_errorCode(&errorCode);
  995. _JumpIfError(hr, error, "pErr->get_errorCode");
  996. if (NULL != pbstrReason && S_OK != errorCode)
  997. {
  998. hr = pErr->get_reason(pbstrReason);
  999. _JumpIfError(hr, error, "pErr->get_reason");
  1000. }
  1001. {
  1002. #ifdef DBG
  1003. CComBSTR bstrText;
  1004. pErr->get_reason(&bstrText);
  1005. AzPrint((AZD_XML, "Loading XML file failed. Reason: %s", bstrText));
  1006. #endif
  1007. }
  1008. // take xml error code
  1009. hrRet = AZ_HRESULT(myXMLErrorToWin32(errorCode));
  1010. error:
  1011. if (NULL != pErr)
  1012. {
  1013. pErr->Release();
  1014. }
  1015. return hrRet;
  1016. }
  1017. #define _JumpIfXmlError(hr, phr, label, pDoc, pszMessage) \
  1018. { \
  1019. *(phr) = (hr); \
  1020. if (S_OK != hr) \
  1021. { \
  1022. HRESULT hrXml; \
  1023. BSTR bstrReason = NULL; \
  1024. hrXml = myGetXmlError(hr, pDoc, &bstrReason); \
  1025. if (NULL != bstrReason) \
  1026. { \
  1027. AzPrint((AZD_XML, "%s error occured: 0x%lx(%ws)\n", (pszMessage), (hrXml), (bstrReason))); \
  1028. } \
  1029. else \
  1030. { \
  1031. AzPrint((AZD_XML, "%s error occured: 0x%lx\n", (pszMessage), (hrXml))); \
  1032. } \
  1033. if (NULL != bstrReason) \
  1034. { \
  1035. SysFreeString(bstrReason); \
  1036. } \
  1037. *(phr) = hrXml; \
  1038. goto label; \
  1039. } \
  1040. }
  1041. HRESULT
  1042. myWszToBstr(
  1043. IN WCHAR const *pwsz,
  1044. OUT BSTR *pbstr)
  1045. /*
  1046. Description:
  1047. convert wsz string to a BSTR
  1048. Arguments:
  1049. IN: pwsz, a zero terminated wchar string
  1050. OUT pbstr, a pointer to a BSTR, use SysFreeString to free the resource
  1051. */
  1052. {
  1053. HRESULT hr;
  1054. if (NULL == pwsz)
  1055. {
  1056. hr = E_INVALIDARG;
  1057. _JumpError(hr, error, "invalid pwsz");
  1058. }
  1059. if (NULL == pbstr)
  1060. {
  1061. hr = E_POINTER;
  1062. _JumpIfError(hr, error, "null pbstr");
  1063. }
  1064. *pbstr = SysAllocString(pwsz);
  1065. _JumpIfOutOfMemory(&hr, error, *pbstr, "SysAllocString");
  1066. hr = S_OK;
  1067. error:
  1068. return hr;
  1069. }
  1070. HRESULT
  1071. myWszToBstrVariant(
  1072. IN WCHAR const *pwsz,
  1073. OUT VARIANT *pvar)
  1074. /*
  1075. Description:
  1076. convert wsz string to a variant with BSTR vt
  1077. Arguments:
  1078. pwsz - a zero terminated wchar string
  1079. pvar - a pointer to a variant in which a BSTR type is returned
  1080. use VariantClear to free the resource
  1081. Return:
  1082. use VariantClear to free resource in pvar
  1083. */
  1084. {
  1085. HRESULT hr;
  1086. BSTR bstr = NULL;
  1087. if (NULL == pvar)
  1088. {
  1089. hr = E_POINTER;
  1090. _JumpIfError(hr, error, "null pvar");
  1091. }
  1092. //init
  1093. VariantInit(pvar);
  1094. hr = myWszToBstr(pwsz, &bstr);
  1095. _JumpIfError(hr, error, "myWszToBstr");
  1096. pvar->vt = VT_BSTR;
  1097. pvar->bstrVal = bstr;
  1098. bstr = NULL; //release by caller
  1099. hr = S_OK;
  1100. error:
  1101. if (NULL != bstr)
  1102. {
  1103. SysFreeString(bstr);
  1104. }
  1105. return hr;
  1106. }
  1107. HRESULT
  1108. myFileExist(
  1109. IN WCHAR const *pwszFile,
  1110. OUT BOOL *pfExist)
  1111. /*
  1112. Description:
  1113. check file existence
  1114. Arguments:
  1115. pwszFile - file path
  1116. pfExist - return of file-existing flag, TRUE if file exists
  1117. Return:
  1118. */
  1119. {
  1120. HRESULT hr;
  1121. WIN32_FILE_ATTRIBUTE_DATA wfad;
  1122. //init
  1123. *pfExist = FALSE;
  1124. if (GetFileAttributesEx(
  1125. pwszFile, //xml file path
  1126. GetFileExInfoStandard,
  1127. &wfad))
  1128. {
  1129. *pfExist = TRUE;
  1130. AzPrint((AZD_XML, "xml file %ws exists.\n", pwszFile));
  1131. }
  1132. else
  1133. {
  1134. AZ_HRESULT_LASTERROR(&hr);
  1135. if (AZ_HRESULT(ERROR_FILE_NOT_FOUND) != hr)
  1136. {
  1137. _JumpError(hr, error, "GetFileAttributesEx");
  1138. }
  1139. AzPrint((AZD_XML, "xml file %ws doesn't exist.\n", pwszFile));
  1140. }
  1141. hr = S_OK;
  1142. error:
  1143. return hr;
  1144. }
  1145. DWORD
  1146. myXmlStoreHasUpdate (
  1147. IN AZP_XML_CONTEXT * pContext,
  1148. OUT BOOL * pbNeedUpdate
  1149. )
  1150. /*++
  1151. Description:
  1152. Determine whether XML file has been modified since our store loaded.
  1153. For XML store, we just rely on timestamp to test.
  1154. Arguments:
  1155. pContext - The persist context.
  1156. pbNeedUpdate - Receives the test result.
  1157. Return Value:
  1158. NO_ERROR - If test is successful
  1159. Various error code if error is encountered.
  1160. --*/
  1161. {
  1162. //
  1163. // For XML store, we just rely on timestamp to tell if
  1164. // the store has been modified
  1165. //
  1166. AZASSERT(pbNeedUpdate != NULL);
  1167. *pbNeedUpdate = FALSE;
  1168. if (pContext->FTLastWrite.dwHighDateTime == 0 &&
  1169. pContext->FTLastWrite.dwLowDateTime == 0)
  1170. {
  1171. //
  1172. // this means that it is a new store, no need to update it
  1173. //
  1174. return NO_ERROR;
  1175. }
  1176. WIN32_FILE_ATTRIBUTE_DATA fad;
  1177. DWORD dwStatus = NO_ERROR;
  1178. if (GetFileAttributesEx(pContext->pwszPolicyUrl, GetFileExInfoStandard, &fad))
  1179. {
  1180. *pbNeedUpdate = CompareFileTime(&(fad.ftLastWriteTime), &(pContext->FTLastWrite)) != 0;
  1181. }
  1182. else
  1183. {
  1184. dwStatus = GetLastError();
  1185. }
  1186. return dwStatus;
  1187. }
  1188. HRESULT
  1189. myXmlLoad (
  1190. IN VARIANT varUrl,
  1191. OUT IXMLDOMDocument2 ** ppFreshDom
  1192. )
  1193. /*++
  1194. Description:
  1195. Load a fresh XML file into XML DOM object
  1196. Arguments:
  1197. varUrl - The XML store URL.
  1198. ppFreshDom - Freshly loaded DOM
  1199. Return Value:
  1200. S_OK - If the operation completes successfully
  1201. Various error code if errors are encountered.
  1202. --*/
  1203. {
  1204. CComPtr<IXMLDOMDocument2> srpNewDom;
  1205. HRESULT Hr = CoCreateInstance(
  1206. CLSID_DOMDocument,
  1207. NULL,
  1208. CLSCTX_INPROC_SERVER,
  1209. IID_IXMLDOMDocument2,
  1210. (void**)&srpNewDom);
  1211. if (SUCCEEDED(Hr))
  1212. {
  1213. //
  1214. // This really should never fail
  1215. //
  1216. Hr = srpNewDom->put_async(FALSE);
  1217. AZASSERT(SUCCEEDED(Hr));
  1218. //
  1219. // Load the XML
  1220. //
  1221. VARIANT_BOOL varbLoad;
  1222. Hr = srpNewDom->load(varUrl, &varbLoad);
  1223. if (FAILED(Hr))
  1224. {
  1225. if (0x800c0006 == Hr)
  1226. {
  1227. AzPrint((AZD_XML, "IXMLDOMDocument2::load failed. HRESULT = %d. Intepreted as 'file not found'.", Hr));
  1228. Hr = AZ_HR_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1229. }
  1230. AzPrint((AZD_XML, "IXMLDOMDocument2::load failed. HRESULT = %d", Hr));
  1231. }
  1232. }
  1233. else
  1234. {
  1235. AzPrint((AZD_XML, "CoCreating IXMLDOMDocument2 failed. HRESULT = %d", Hr));
  1236. }
  1237. //
  1238. // If everything has worked, so we passback the fresh new DOM object.
  1239. // Otherwise, the smart pointer will release itself.
  1240. //
  1241. if (SUCCEEDED(Hr))
  1242. {
  1243. *ppFreshDom = srpNewDom.Detach();
  1244. }
  1245. return Hr;
  1246. }
  1247. DWORD
  1248. XmlCheckSecurityPrivilege(
  1249. IN LPCWSTR PolicyUrl,
  1250. IN BOOL fCreatePolicy
  1251. )
  1252. /*
  1253. Description:
  1254. Determine whether the caller has SE_SECURITY_PRIVILEGE on the machine containing
  1255. the xml store.
  1256. Arguments:
  1257. PolicyUrl - Full path name of the file to check privilege on.
  1258. If fCreatePolicy is TRUE, the file doesn't exist so the privilege is checked on
  1259. the underlying folder
  1260. fCreatePolicy - TRUE if the policy database is to be created.
  1261. FALSE if the policy database already exists
  1262. Return Value:
  1263. NO_ERROR - The caller has privilege
  1264. ERROR_PRIVILEGE_NOT_HELD - The caller has no privilege
  1265. Other errors
  1266. */
  1267. {
  1268. DWORD WinStatus;
  1269. HANDLE hToken = NULL;
  1270. LPCWSTR PathToCheck = PolicyUrl;
  1271. WCHAR PathBuffer[MAX_PATH+1];
  1272. TOKEN_PRIVILEGES NewPrivilegeState = {0};
  1273. TOKEN_PRIVILEGES OldPrivilegeState = {0};
  1274. BOOL bPrivilegeAdjusted = FALSE;
  1275. NTSTATUS Status;
  1276. UNICODE_STRING NtFileName;
  1277. OBJECT_ATTRIBUTES Obja;
  1278. HANDLE hFile = INVALID_HANDLE_VALUE;
  1279. IO_STATUS_BLOCK IoStatusBlock;
  1280. LPWSTR BufferToFree = NULL;
  1281. //
  1282. // Initialization
  1283. //
  1284. AZASSERT( PolicyUrl != NULL );
  1285. RtlInitUnicodeString(&NtFileName, NULL);
  1286. //
  1287. // If we're creating the file,
  1288. // build the name of the underlying folder.
  1289. //
  1290. if ( fCreatePolicy ) {
  1291. LPWSTR SlashPointer;
  1292. DWORD PathLength;
  1293. //
  1294. // Determine the length of the path to the underlying folder
  1295. //
  1296. SlashPointer = wcsrchr( PolicyUrl, L'\\' );
  1297. if ( SlashPointer == NULL ) {
  1298. AzPrint(( AZD_INVPARM, "XmlCheckSecurityPrivilege: invalid full path '%ws'\n", PolicyUrl ));
  1299. WinStatus = ERROR_INVALID_PARAMETER;
  1300. goto Cleanup;
  1301. }
  1302. PathLength = (ULONG)(SlashPointer - PolicyUrl) + 1;
  1303. if ( PathLength > MAX_PATH ) {
  1304. AzPrint(( AZD_INVPARM, "XmlCheckSecurityPrivilege: path is too long '%ws'\n", PolicyUrl ));
  1305. WinStatus = ERROR_INVALID_PARAMETER;
  1306. goto Cleanup;
  1307. }
  1308. //
  1309. // Grab a copy of the path
  1310. //
  1311. wcsncpy( PathBuffer, PolicyUrl, PathLength );
  1312. PathBuffer[PathLength] = '\0';
  1313. PathToCheck = PathBuffer;
  1314. }
  1315. //
  1316. // Enable the SE_SECURITY_PRIVILEGE privilege in order to read the SACL
  1317. //
  1318. //
  1319. // Get the current token to adjust the security privilege.
  1320. //
  1321. WinStatus = AzpGetCurrentToken( &hToken );
  1322. if ( WinStatus != NO_ERROR ) {
  1323. goto Cleanup;
  1324. }
  1325. //
  1326. // Adjust the privilege.
  1327. // Ignore errors since the caller might be running "net only" and that
  1328. // user might have privilege on the machine containing the XML file.
  1329. //
  1330. WinStatus = AzpChangeSinglePrivilege(
  1331. SE_SECURITY_PRIVILEGE,
  1332. hToken,
  1333. &NewPrivilegeState,
  1334. &OldPrivilegeState );
  1335. if ( WinStatus == NO_ERROR ) {
  1336. bPrivilegeAdjusted = TRUE;
  1337. }
  1338. //
  1339. // Convert the DOS pathname to an NT pathname
  1340. //
  1341. if ( !RtlDosPathNameToNtPathName_U(
  1342. PathToCheck,
  1343. &NtFileName,
  1344. NULL,
  1345. NULL
  1346. ) ) {
  1347. WinStatus = ERROR_PATH_NOT_FOUND;
  1348. goto Cleanup;
  1349. }
  1350. BufferToFree = NtFileName.Buffer;
  1351. //
  1352. // Call NtCreateFile to determine if we have the privilege
  1353. // Use NtCreateFile instead of CreateFile because:
  1354. // CreateFile always asks for SYNCHRONIZE and FILE_READ_ATTRIBUTES and we don't need them
  1355. // CreateFile cannot open directories
  1356. //
  1357. InitializeObjectAttributes(
  1358. &Obja,
  1359. &NtFileName,
  1360. OBJ_CASE_INSENSITIVE,
  1361. NULL,
  1362. NULL
  1363. );
  1364. Status = NtCreateFile(
  1365. &hFile,
  1366. ACCESS_SYSTEM_SECURITY,
  1367. &Obja,
  1368. &IoStatusBlock,
  1369. NULL,
  1370. 0, // Flags and attributes
  1371. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, // Share mode
  1372. FILE_OPEN, // Create Disposition
  1373. 0, // Create Flags
  1374. NULL, // EaBuffer
  1375. 0 ); // EaSize
  1376. if ( !NT_SUCCESS(Status) ) {
  1377. WinStatus = RtlNtStatusToDosError( Status );
  1378. goto Cleanup;
  1379. }
  1380. WinStatus = NO_ERROR;
  1381. Cleanup:
  1382. if ( hToken != NULL ) {
  1383. if ( bPrivilegeAdjusted ) {
  1384. DWORD TempStatus;
  1385. TempStatus = AzpChangeSinglePrivilege(
  1386. 0, // This is ignored since OldState is NULL.
  1387. hToken,
  1388. &OldPrivilegeState,
  1389. NULL // This should be set to NULL to specify REVERT.
  1390. );
  1391. ASSERT( TempStatus == NO_ERROR );
  1392. }
  1393. CloseHandle( hToken );
  1394. }
  1395. if ( BufferToFree != NULL ) {
  1396. RtlFreeHeap(RtlProcessHeap(), 0, BufferToFree);
  1397. }
  1398. if ( hFile != INVALID_HANDLE_VALUE ) {
  1399. NtClose(hFile);
  1400. }
  1401. return WinStatus;
  1402. }
  1403. DWORD
  1404. IsAclSupported(
  1405. IN LPCWSTR pwszFileName)
  1406. /*
  1407. Description:
  1408. check if a drive from a file path has ACL support
  1409. Arguments:
  1410. pwszFileName - file full path
  1411. Return:
  1412. error or ERROR_NOT_SUPPORTED if not ACL-able
  1413. */
  1414. {
  1415. DWORD dwErr;
  1416. WCHAR *pwszVolumePathName = NULL;
  1417. DWORD dwFlags = 0;
  1418. DWORD len;
  1419. len = (DWORD)(wcslen(pwszFileName) + 2); //by 2 in case of appending '\\'
  1420. pwszVolumePathName = (WCHAR*)AzpAllocateHeap(len * sizeof(WCHAR), "XMPATH" );
  1421. if (NULL == pwszVolumePathName)
  1422. {
  1423. dwErr = ERROR_OUTOFMEMORY;
  1424. _JumpError(dwErr, error, "AzpAllocateHeap");
  1425. }
  1426. if (!GetVolumePathName(
  1427. pwszFileName,
  1428. pwszVolumePathName,
  1429. len))
  1430. {
  1431. dwErr = GetLastError();
  1432. _JumpError(dwErr, error, "GetVolumePathName");
  1433. }
  1434. len = (DWORD)wcslen(pwszVolumePathName);
  1435. if(pwszVolumePathName[len -1] != L'\\')
  1436. {
  1437. pwszVolumePathName[len] = L'\\';
  1438. pwszVolumePathName[len++] = L'\0';
  1439. }
  1440. if (!GetVolumeInformation(
  1441. pwszVolumePathName,
  1442. NULL,
  1443. NULL,
  1444. NULL,
  1445. NULL,
  1446. &dwFlags,
  1447. NULL,
  1448. 0))
  1449. {
  1450. dwErr = GetLastError();
  1451. _JumpError(dwErr, error, "GetVolumeInformation");
  1452. }
  1453. if(0x0 == (FS_PERSISTENT_ACLS & dwFlags))
  1454. {
  1455. dwErr = ERROR_NOT_SUPPORTED;
  1456. _JumpError(dwErr, error, "ACL is not supported");
  1457. }
  1458. dwErr = NO_ERROR;
  1459. error:
  1460. if (NULL != pwszVolumePathName)
  1461. {
  1462. AzpFreeHeap(pwszVolumePathName );
  1463. }
  1464. return dwErr;
  1465. }
  1466. HRESULT
  1467. myXmlLoadAclsToAzStore(
  1468. IN PAZP_XML_CONTEXT PersistContext,
  1469. IN ULONG lPersistFlags,
  1470. IN BOOL OnlyAddPolicyAdmins
  1471. )
  1472. /*
  1473. Description:
  1474. loads xml store file DACL/SACL into the Azroles cache
  1475. Arguments:
  1476. PersistContext - Context describing the policy store
  1477. lPersistFlags - flags from the persist engine
  1478. OnlyAddPolicyAdmins - TRUE if only PolicyAdmins is to be loads
  1479. Return:
  1480. */
  1481. {
  1482. HRESULT hr;
  1483. DWORD dwErr;
  1484. BOOLEAN DoSacl;
  1485. HANDLE hToken = NULL;
  1486. TOKEN_PRIVILEGES NewPrivilegeState = {0};
  1487. TOKEN_PRIVILEGES OldPrivilegeState = {0};
  1488. BOOL bPrivilegeAdjusted = FALSE;
  1489. SECURITY_INFORMATION si = 0;
  1490. PSECURITY_DESCRIPTOR pSD = NULL;
  1491. AZASSERT(NULL != PersistContext);
  1492. //
  1493. // Only do the SACL if requested and the caller has privilege
  1494. //
  1495. DoSacl = !OnlyAddPolicyAdmins && PersistContext->HasSecurityPrivilege;
  1496. if ( DoSacl ) {
  1497. //
  1498. // Enable the SE_SECURITY_PRIVILEGE privilege in order to read the SACL
  1499. //
  1500. //
  1501. // Get the current token to adjust the security privilege.
  1502. //
  1503. dwErr = AzpGetCurrentToken( &hToken );
  1504. _JumpIfWinError(dwErr, &hr, error, "AzpGetCurrentToken");
  1505. //
  1506. // Adjust the privilege.
  1507. // Ignore errors since the caller might be running "net only" and that
  1508. // user might have privilege on the machine containing the XML file.
  1509. //
  1510. dwErr = AzpChangeSinglePrivilege(
  1511. SE_SECURITY_PRIVILEGE,
  1512. hToken,
  1513. &NewPrivilegeState,
  1514. &OldPrivilegeState );
  1515. if ( dwErr == NO_ERROR ) {
  1516. bPrivilegeAdjusted = TRUE;
  1517. }
  1518. //
  1519. // Ask for the SACL
  1520. //
  1521. si |= SACL_SECURITY_INFORMATION;
  1522. }
  1523. //
  1524. // Get file security descriptor
  1525. //
  1526. si |= DACL_SECURITY_INFORMATION;
  1527. dwErr = GetNamedSecurityInfo(
  1528. (LPWSTR)PersistContext->pwszPolicyUrl,
  1529. SE_FILE_OBJECT,
  1530. si,
  1531. NULL,
  1532. NULL,
  1533. NULL,
  1534. NULL,
  1535. &pSD);
  1536. _JumpIfWinError(dwErr, &hr, error, "GetNamedSecurityInfo");
  1537. //
  1538. // Set the security descriptor into the cache
  1539. //
  1540. dwErr = XmlAzrolesInfo->AzpeSetSecurityDescriptorIntoCache(
  1541. PersistContext->hAzAuthorizationStore,
  1542. pSD,
  1543. lPersistFlags,
  1544. &PolicyAdminsRights,
  1545. OnlyAddPolicyAdmins ? NULL : &PolicyReadersRights,
  1546. NULL,
  1547. DoSacl ? &XMLSaclRights : NULL );
  1548. _JumpIfWinError( dwErr, &hr, error, "AzpeSetSecurityDescriptorIntoCache" );
  1549. hr = S_OK;
  1550. error:
  1551. if ( hToken != NULL )
  1552. {
  1553. if ( bPrivilegeAdjusted )
  1554. {
  1555. dwErr = AzpChangeSinglePrivilege(
  1556. 0, // This is ignored since OldState is NULL.
  1557. hToken,
  1558. &OldPrivilegeState,
  1559. NULL // This should be set to NULL to specify REVERT.
  1560. );
  1561. ASSERT( dwErr == NO_ERROR );
  1562. }
  1563. CloseHandle( hToken );
  1564. }
  1565. if (NULL != pSD)
  1566. {
  1567. LocalFree(pSD);
  1568. }
  1569. return hr;
  1570. }
  1571. HRESULT
  1572. myXmlSubmitAzStoreAcls(
  1573. IN PAZP_XML_CONTEXT pPersistContext,
  1574. IN AZPE_OBJECT_HANDLE pAzAuthorizationStore,
  1575. IN ULONG lPersistFlags
  1576. )
  1577. /*
  1578. Description:
  1579. submit any acl changes to AzAuthorizationStore persist object (xml file)
  1580. Arguments:
  1581. pPersistContext - Context describing the store
  1582. pAzAuthorizationStore - AzAuthorizationStore object
  1583. lPersistFlags - flags from the persist engine
  1584. Return:
  1585. */
  1586. {
  1587. HRESULT hr;
  1588. DWORD dwErr;
  1589. PSECURITY_DESCRIPTOR pOldSd = NULL;
  1590. PSECURITY_DESCRIPTOR pNewSd = NULL;
  1591. BOOL UpdateDacl = FALSE;
  1592. PACL pDacl = NULL;
  1593. BOOL bDaclPresent;
  1594. BOOL bDaclDefaulted;
  1595. BOOL UpdateSacl = FALSE;
  1596. PACL pSacl = NULL;
  1597. BOOL bSaclPresent;
  1598. BOOL bSaclDefaulted;
  1599. HANDLE hToken = NULL;
  1600. TOKEN_PRIVILEGES NewPrivilegeState = {0};
  1601. TOKEN_PRIVILEGES OldPrivilegeState = {0};
  1602. BOOL bPrivilegeAdjusted = FALSE;
  1603. BOOL EmptyPolicyAdmins = FALSE;
  1604. SECURITY_INFORMATION si = 0;
  1605. AZASSERT(NULL != pAzAuthorizationStore);
  1606. //
  1607. // Determine whether the DACL and/or SACL need to be updated
  1608. //
  1609. if ( ObjectIsDirty( pAzAuthorizationStore, AZ_DIRTY_CREATE) ) {
  1610. UpdateDacl = TRUE;
  1611. UpdateSacl = pPersistContext->HasSecurityPrivilege;
  1612. } else {
  1613. if ( ObjectIsDirty( pAzAuthorizationStore, AZ_DIRTY_POLICY_READERS|AZ_DIRTY_POLICY_ADMINS|AZ_DIRTY_DELEGATED_POLICY_USERS) ) {
  1614. UpdateDacl = TRUE;
  1615. }
  1616. if ( ObjectIsDirty( pAzAuthorizationStore, AZ_DIRTY_APPLY_STORE_SACL) ) {
  1617. UpdateSacl = TRUE;
  1618. }
  1619. if ( !UpdateDacl && !UpdateSacl ) {
  1620. hr = S_OK;
  1621. goto error;
  1622. }
  1623. }
  1624. //
  1625. // If we need to update the SACL,
  1626. // we need privilege.
  1627. if ( UpdateSacl ) {
  1628. //
  1629. // Get the current token to adjust the security privilege.
  1630. //
  1631. dwErr = AzpGetCurrentToken( &hToken );
  1632. _JumpIfWinError(dwErr, &hr, error, "AzpGetCurrentToken");
  1633. //
  1634. // Acquire security privilege so we can get/set the SACL
  1635. //
  1636. dwErr = AzpChangeSinglePrivilege(
  1637. SE_SECURITY_PRIVILEGE,
  1638. hToken,
  1639. &NewPrivilegeState,
  1640. &OldPrivilegeState
  1641. );
  1642. _JumpIfWinError(dwErr, &hr, error, "AzpChangeSinglePrivilege");
  1643. bPrivilegeAdjusted = TRUE;
  1644. }
  1645. //
  1646. // If we didn't just create the object,
  1647. // Get the existing file security descriptor so we can merge in the changes
  1648. //
  1649. if ( !ObjectIsDirty( pAzAuthorizationStore, AZ_DIRTY_CREATE) ) {
  1650. si = (UpdateDacl ? DACL_SECURITY_INFORMATION : 0) |
  1651. (UpdateSacl ? SACL_SECURITY_INFORMATION : 0);
  1652. dwErr = GetNamedSecurityInfo(
  1653. (LPWSTR)pPersistContext->pwszPolicyUrl,
  1654. SE_FILE_OBJECT,
  1655. si,
  1656. NULL,
  1657. NULL,
  1658. NULL,
  1659. NULL,
  1660. &pOldSd);
  1661. _JumpIfWinError(dwErr, &hr, error, "GetNamedSecurityInfo");
  1662. }
  1663. //
  1664. // Get the new security descriptor for the file
  1665. //
  1666. dwErr = XmlAzrolesInfo->AzpeGetSecurityDescriptorFromCache(
  1667. pAzAuthorizationStore,
  1668. lPersistFlags,
  1669. (UpdateDacl ? XMLPolicyAdminsRights : NULL),
  1670. (UpdateDacl ? XMLPolicyReadersRights : NULL),
  1671. NULL,
  1672. NULL,
  1673. NULL,
  1674. NULL,
  1675. (UpdateSacl ? &XMLSaclRights : NULL),
  1676. pOldSd,
  1677. &pNewSd );
  1678. if ( dwErr == ERROR_EMPTY ) {
  1679. EmptyPolicyAdmins = TRUE;
  1680. dwErr = NO_ERROR;
  1681. }
  1682. _JumpIfWinError( dwErr, &hr, error, "AzpeGetSecurityDescriptorFromCache" );
  1683. //
  1684. // Update the SACL on the file
  1685. //
  1686. if ( UpdateSacl ) {
  1687. //
  1688. // Get the SACL from the returned security descriptor
  1689. //
  1690. if ( !GetSecurityDescriptorSacl(pNewSd,
  1691. &bSaclPresent,
  1692. &pSacl,
  1693. &bSaclDefaulted
  1694. ) ) {
  1695. AZ_HRESULT_LASTERROR(&hr);
  1696. _JumpError(hr, error, "GetSecurityDescriptorSacl");
  1697. }
  1698. // Indicate the SACL should be set
  1699. // The SACL is never protected.
  1700. si |= SACL_SECURITY_INFORMATION | UNPROTECTED_SACL_SECURITY_INFORMATION;
  1701. }
  1702. //
  1703. // Update the DACL on the file
  1704. //
  1705. if ( UpdateDacl ) {
  1706. //
  1707. // Get the DACL from the returned security descriptor
  1708. //
  1709. if ( !GetSecurityDescriptorDacl(pNewSd,
  1710. &bDaclPresent,
  1711. &pDacl,
  1712. &bDaclDefaulted
  1713. ) ) {
  1714. AZ_HRESULT_LASTERROR(&hr);
  1715. _JumpError(hr, error, "GetSecurityDescriptorDacl");
  1716. }
  1717. ASSERT( bDaclPresent && pDacl != NULL );
  1718. //
  1719. // Indicate the DACL should be set
  1720. // The DACL needs to have its protected bit on.
  1721. //
  1722. si |= DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION;
  1723. }
  1724. //
  1725. // Set the DACL/SACL onto the file
  1726. //
  1727. dwErr = SetNamedSecurityInfo(
  1728. (LPWSTR)pPersistContext->pwszPolicyUrl,
  1729. SE_FILE_OBJECT,
  1730. si,
  1731. NULL, //psidOwner
  1732. NULL, //psidGroup
  1733. pDacl,
  1734. pSacl); //pSacl
  1735. _JumpIfWinError(dwErr, &hr, error, "SetNamedSecurityinfo");
  1736. //
  1737. // If SetNamedSecurityinfo changed PolicyAdmins,
  1738. // load the PolicyAdmins back into the the azroles core.
  1739. //
  1740. if ( EmptyPolicyAdmins ) {
  1741. hr = myXmlLoadAclsToAzStore(
  1742. pPersistContext,
  1743. lPersistFlags,
  1744. TRUE );
  1745. _JumpIfError(hr, error, "myXmlLoadAclsToAzStore");
  1746. }
  1747. hr = S_OK;
  1748. error:
  1749. if ( hToken != NULL ) {
  1750. if ( bPrivilegeAdjusted ) {
  1751. DWORD dwIgnoreErr;
  1752. dwIgnoreErr = AzpChangeSinglePrivilege(
  1753. 0, // This is ignored since OldState is NULL.
  1754. hToken,
  1755. &OldPrivilegeState,
  1756. NULL ); // This should be set to NULL to specify REVERT.
  1757. if (dwIgnoreErr != NO_ERROR) {
  1758. AzPrint((AZD_XML, "AzpChangeSinglePrivilege failed to reset to original. Error code: %d", dwIgnoreErr));
  1759. }
  1760. }
  1761. CloseHandle( hToken );
  1762. }
  1763. XmlAzrolesInfo->AzpeFreeMemory( pNewSd );
  1764. if ( pOldSd != NULL ) {
  1765. LocalFree(pOldSd);
  1766. }
  1767. return hr;
  1768. }
  1769. HRESULT
  1770. myXmlValidateNodeType(
  1771. IXMLDOMNode *pNode,
  1772. DOMNodeType designedNodeType)
  1773. /*
  1774. Description:
  1775. make sure the node has a valid node type
  1776. Arguments:
  1777. pNode - pointer to xml node
  1778. designedNodeType - designed node type
  1779. */
  1780. {
  1781. HRESULT hr;
  1782. DOMNodeType nodeType;
  1783. AZASSERT(NULL != pNode);
  1784. hr = pNode->get_nodeType(&nodeType);
  1785. _JumpIfError(hr, error, "pNode->get_nodeType");
  1786. if (nodeType != designedNodeType)
  1787. {
  1788. // node type is not expected
  1789. hr = E_INVALIDARG;
  1790. _JumpError(hr, error, "bad node type");
  1791. }
  1792. hr = S_OK;
  1793. error:
  1794. return hr;
  1795. }
  1796. HRESULT
  1797. myXmlGetNodeAttribute(
  1798. IN IXMLDOMNode *pNode,
  1799. IN WCHAR const *pwszName,
  1800. OUT WCHAR **ppwszValue)
  1801. /*
  1802. Description:
  1803. query named attribute from xml element node
  1804. Arguments:
  1805. pNode - pointer to xml node element
  1806. pwszName - attribute name
  1807. ppwszValue - returns the value of the attribute
  1808. Return:
  1809. */
  1810. {
  1811. HRESULT hr;
  1812. IXMLDOMNamedNodeMap *pNodeMap = NULL;
  1813. IXMLDOMNode *pNodeAttr = NULL;
  1814. BSTR bstrName = NULL;
  1815. VARIANT varValue;
  1816. AZASSERT(NULL != pNode &&
  1817. NULL != pwszName &&
  1818. NULL != ppwszValue);
  1819. // init
  1820. *ppwszValue = NULL;
  1821. VariantInit(&varValue);
  1822. // validate node type
  1823. hr = myXmlValidateNodeType(pNode, NODE_ELEMENT);
  1824. _JumpIfError(hr, error, "myXmlValidateNodeType");
  1825. // get attribute list
  1826. hr = pNode->get_attributes(&pNodeMap);
  1827. _JumpIfError(hr, error, "pNode->get_attributes");
  1828. bstrName = SysAllocString(pwszName);
  1829. _JumpIfOutOfMemory(&hr, error, bstrName, "SysAllocString");
  1830. // return attribute node object
  1831. hr = pNodeMap->getNamedItem(bstrName, &pNodeAttr);
  1832. //_JumpIfError(hr, error, "pNodeMap->getNamedItem");
  1833. if (S_OK != hr || NULL == pNodeAttr)
  1834. {
  1835. // seems doesn't have the attribute
  1836. hr = AZ_HRESULT(ERROR_NOT_FOUND);
  1837. _JumpErrorQuiet(hr, error, "attribute not found");
  1838. }
  1839. // now we get attribute value
  1840. hr = pNodeAttr->get_nodeValue(&varValue);
  1841. _JumpIfError(hr, error, "pNodeAttr->get_nodeValue");
  1842. //??? may not true if we have other attribute type
  1843. AZASSERT(VT_BSTR == varValue.vt);
  1844. // we want to return the value in wchar
  1845. *ppwszValue = (WCHAR*)AzpAllocateHeap(
  1846. (wcslen(varValue.bstrVal) + 1) * sizeof(WCHAR), "XMVAL" );
  1847. _JumpIfOutOfMemory(&hr, error, *ppwszValue, "AzpAllocateHeap");
  1848. // return
  1849. wcscpy(*ppwszValue, varValue.bstrVal);
  1850. hr = S_OK;
  1851. error:
  1852. if (NULL != pNodeMap)
  1853. {
  1854. pNodeMap->Release();
  1855. }
  1856. if (NULL != pNodeAttr)
  1857. {
  1858. pNodeAttr->Release();
  1859. }
  1860. if (NULL != bstrName)
  1861. {
  1862. SysFreeString(bstrName);
  1863. }
  1864. VariantClear(&varValue);
  1865. return hr;
  1866. }
  1867. HRESULT
  1868. myXmlSetNodeAttribute(
  1869. IN IXMLDOMNode *pNode,
  1870. IN WCHAR const *pwszName,
  1871. IN WCHAR const *pwszValue,
  1872. IN OPTIONAL IXMLDOMDocument2 *pDoc)
  1873. /*
  1874. Description:
  1875. set named attribute to xml element node
  1876. Arguments:
  1877. pNode - pointer to xml node element
  1878. pwszName - attribute name
  1879. pwszValue - the value of the attribute
  1880. pDoc - NULL means the attribute must exist, otherwise it creates one if not
  1881. Return:
  1882. */
  1883. {
  1884. HRESULT hr;
  1885. IXMLDOMNamedNodeMap *pNodeMap = NULL;
  1886. IXMLDOMNode *pNodeAttr = NULL;
  1887. IXMLDOMElement *pEle = NULL;
  1888. BSTR bstrName = NULL;
  1889. VARIANT varValue;
  1890. AZASSERT(NULL != pNode &&
  1891. NULL != pwszName &&
  1892. NULL != pwszValue);
  1893. AzPrint((AZD_XML, "(myXmlSetNodeAttribute)pNode = 0x%lx\n", pNode));
  1894. // init
  1895. VariantInit(&varValue);
  1896. // validate node type
  1897. hr = myXmlValidateNodeType(pNode, NODE_ELEMENT);
  1898. _JumpIfError(hr, error, "myXmlValidateNodeType");
  1899. // get attribute list
  1900. hr = pNode->get_attributes(&pNodeMap);
  1901. _JumpIfError(hr, error, "pNode->get_attributes");
  1902. bstrName = SysAllocString(pwszName);
  1903. _JumpIfOutOfMemory(&hr, error, bstrName, "SysAllocString");
  1904. // convert value to variant
  1905. hr = myWszToBstrVariant(
  1906. pwszValue,
  1907. &varValue);
  1908. _JumpIfError(hr, error, "myWszToBstrVariant");
  1909. // return attribute node object
  1910. hr = pNodeMap->getNamedItem(bstrName, &pNodeAttr);
  1911. if (S_OK == hr)
  1912. {
  1913. AZASSERT(NULL != pNodeAttr);
  1914. // now we set attribute value
  1915. hr = pNodeAttr->put_nodeValue(varValue);
  1916. _JumpIfError(hr, error, "pNodeAttr->put_nodeValue");
  1917. }
  1918. else
  1919. {
  1920. // the attribute doesn't exist
  1921. #if DBG
  1922. {
  1923. BSTR bstrXml = NULL;
  1924. AzPrint((AZD_XML, "attribute %ws doesn't exist in the following element...\n", bstrName));
  1925. hr = pNode->get_xml(&bstrXml);
  1926. _JumpIfError(hr, error, "pNode->get_xml");
  1927. AzPrint((AZD_XML, "The node xml = %ws\n", bstrXml));
  1928. if (NULL != bstrXml) SysFreeString(bstrXml);
  1929. }
  1930. #endif //DBG
  1931. if (NULL == pDoc)
  1932. {
  1933. // must not null if create one
  1934. hr = AZ_HRESULT(ERROR_NOT_FOUND);
  1935. _JumpErrorQuiet(hr, error, "attribute not found");
  1936. }
  1937. AZASSERT(NULL == pNodeAttr);
  1938. hr = pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pEle);
  1939. _JumpIfError(hr, error, "pNode->QueryInterface");
  1940. AZASSERT(NULL != pEle);
  1941. //set attr
  1942. hr = pEle->setAttribute(
  1943. bstrName,
  1944. varValue);
  1945. _JumpIfError(hr, error, "pEle->setAttribute");
  1946. }
  1947. #if DBG
  1948. {
  1949. BSTR bstrXml = NULL;
  1950. AzPrint((AZD_XML, "set %ws attribute is done...\n", bstrName));
  1951. hr = pNode->get_xml(&bstrXml);
  1952. _JumpIfError(hr, error, "pNode->get_xml");
  1953. AzPrint((AZD_XML, "The node xml = %ws\n", bstrXml));
  1954. if (NULL != bstrXml) SysFreeString(bstrXml);
  1955. }
  1956. #endif //DBG
  1957. hr = S_OK;
  1958. error:
  1959. if (NULL != pEle)
  1960. {
  1961. pEle->Release();
  1962. }
  1963. if (NULL != pNodeMap)
  1964. {
  1965. pNodeMap->Release();
  1966. }
  1967. if (NULL != pNodeAttr)
  1968. {
  1969. pNodeAttr->Release();
  1970. }
  1971. if (NULL != bstrName)
  1972. {
  1973. SysFreeString(bstrName);
  1974. }
  1975. VariantClear(&varValue);
  1976. return hr;
  1977. }
  1978. HRESULT
  1979. myXmlValidateNodeTag(
  1980. IXMLDOMNode *pNode,
  1981. WCHAR const *pwszTag)
  1982. /*
  1983. Description:
  1984. make sure the node has a valid az tag name
  1985. Arguments:
  1986. pNode - pointer to xml node
  1987. pwszTag - designed tag name for the node
  1988. Return:
  1989. */
  1990. {
  1991. HRESULT hr;
  1992. BSTR bstrTag = NULL;
  1993. AZASSERT(NULL != pNode &&
  1994. NULL != pwszTag);
  1995. hr = pNode->get_nodeName(&bstrTag);
  1996. _JumpIfError(hr, error, "pNode->get_nodeName");
  1997. if (0 != wcscmp(pwszTag, bstrTag))
  1998. {
  1999. // node tag name is bad
  2000. hr = E_INVALIDARG;
  2001. _JumpError(hr, error, "bad tag name");
  2002. }
  2003. hr = S_OK;
  2004. error:
  2005. if (NULL != bstrTag)
  2006. {
  2007. SysFreeString(bstrTag);
  2008. }
  2009. return hr;
  2010. }
  2011. HRESULT
  2012. myXmlLoadObjectAttribute(
  2013. IN IXMLDOMNode *pNode,
  2014. IN ULONG lPersistFlags,
  2015. IN WCHAR const *pwszAttrTag,
  2016. IN AZPE_OBJECT_HANDLE pObject,
  2017. IN ULONG lPropId,
  2018. IN ENUM_AZ_DATATYPE DataType)
  2019. /*
  2020. Description: load a node attribute from persist store
  2021. to az core object
  2022. Arguments:
  2023. pNode - object node handle
  2024. lPersistFlags - persist flags passed back to az core
  2025. pwszAttrTag - attribute tag name
  2026. pObject - az core object handle
  2027. lPropId - property ID used to set on az core object
  2028. DataType - data type
  2029. Return:
  2030. */
  2031. {
  2032. HRESULT hr;
  2033. DWORD dwErr;
  2034. PVOID pV;
  2035. WCHAR *pwszAttrValue = NULL;
  2036. ULONG lNumber;
  2037. AZASSERT(NULL != pNode &&
  2038. NULL != pwszAttrTag &&
  2039. NULL != pObject);
  2040. // get attribute from xml node
  2041. hr = myXmlGetNodeAttribute(
  2042. pNode,
  2043. pwszAttrTag,
  2044. &pwszAttrValue);
  2045. if (S_OK != hr && AZ_HRESULT(ERROR_NOT_FOUND) != hr)
  2046. {
  2047. _JumpError(hr, error, "myXmlGetNodeAttribute");
  2048. }
  2049. if (NULL != pwszAttrValue)
  2050. {
  2051. switch (DataType)
  2052. {
  2053. case ENUM_AZ_BSTR:
  2054. // attribute is a string
  2055. pV = (PVOID)pwszAttrValue;
  2056. break;
  2057. case ENUM_AZ_LONG:
  2058. // atribute is a number
  2059. // convert to number
  2060. lNumber = _wtol(pwszAttrValue);
  2061. pV = (PVOID)&lNumber;
  2062. break;
  2063. case ENUM_AZ_BOOL:
  2064. // attribute is a boolean
  2065. // map to boolean id
  2066. // default to false
  2067. lNumber = FALSE; // so any strings other than TRUE
  2068. if (0 == _wcsicmp(pwszAttrValue, AZ_XML_VAL_TRUE))
  2069. {
  2070. lNumber = TRUE;
  2071. }
  2072. pV = (PVOID)&lNumber;
  2073. break;
  2074. case ENUM_AZ_GROUP_TYPE:
  2075. // set default to basic
  2076. lNumber = AZ_GROUPTYPE_BASIC;
  2077. if (0 == wcscmp(pwszAttrValue, AZ_XML_VAL_GROUPTYPE_LDAPQUERY))
  2078. {
  2079. lNumber = AZ_GROUPTYPE_LDAP_QUERY;
  2080. }
  2081. pV = (PVOID)&lNumber;
  2082. break;
  2083. default:
  2084. hr = E_INVALIDARG;
  2085. _JumpError(hr, error, "invalid attribute data type");
  2086. }
  2087. // set object attribute
  2088. dwErr = XmlAzrolesInfo->AzpeSetProperty(
  2089. pObject,
  2090. lPersistFlags,
  2091. lPropId,
  2092. pV);
  2093. _JumpIfWinError(dwErr, &hr, error, "AzpeSetProperty");
  2094. }
  2095. hr = S_OK;
  2096. error:
  2097. if (NULL != pwszAttrValue)
  2098. {
  2099. AzpFreeHeap(pwszAttrValue );
  2100. }
  2101. return hr;
  2102. }
  2103. HRESULT
  2104. myXmlSubmitObjectAttribute(
  2105. IN AZPE_OBJECT_HANDLE hObject,
  2106. IN ULONG lPersistFlags,
  2107. IN ULONG lPropId,
  2108. IN ENUM_AZ_DATATYPE DataType,
  2109. IN IXMLDOMNode *pNode,
  2110. IN WCHAR const *pwszAttrTag,
  2111. IN IXMLDOMDocument2 *pDoc)
  2112. /*
  2113. Description:
  2114. gets an object property az core object and sets the
  2115. property as an node attribute in xml doc.
  2116. This is the routine used by all object attribute submissions
  2117. Arguments:
  2118. jObject - handle of the object
  2119. lPersistFlags - flags from the persist engine
  2120. lPropId - property ID
  2121. DataType - data type of the property, one of ENUM_AZ_*
  2122. pNode - the node handle at which the property is set as attribute
  2123. pwszAttrTag - attribute tag string
  2124. pDoc - root doc node handle
  2125. Return:
  2126. */
  2127. {
  2128. HRESULT hr;
  2129. DWORD dwErr;
  2130. PVOID pvPropValue = NULL;
  2131. WCHAR const * pwszValue;
  2132. WCHAR wszNumber[20];
  2133. AZASSERT(NULL != hObject &&
  2134. NULL != pwszAttrTag &&
  2135. NULL != pNode &&
  2136. NULL != pDoc);
  2137. AzPrint((AZD_XML, "(myXmlSubmitObjectAttribute)pNode = 0x%lx\n", pNode));
  2138. // get property from az core
  2139. dwErr = XmlAzrolesInfo->AzpeGetProperty(
  2140. hObject,
  2141. lPersistFlags,
  2142. lPropId,
  2143. &pvPropValue);
  2144. _JumpIfWinError(dwErr, &hr, error, "AzpeGetProperty");
  2145. AZASSERT(NULL != pvPropValue);
  2146. switch (DataType)
  2147. {
  2148. case ENUM_AZ_BSTR:
  2149. pwszValue = (WCHAR*)pvPropValue;
  2150. break;
  2151. case ENUM_AZ_BOOL:
  2152. // init
  2153. pwszValue = g_pwszAzFalse;
  2154. if (*((BOOL*)pvPropValue))
  2155. {
  2156. pwszValue = g_pwszAzTrue;
  2157. }
  2158. break;
  2159. case ENUM_AZ_LONG:
  2160. wsprintf(wszNumber, L"%d", (*(LONG*)pvPropValue));
  2161. pwszValue = wszNumber;
  2162. break;
  2163. case ENUM_AZ_GROUP_TYPE:
  2164. // init
  2165. pwszValue = g_pwszBasicGroup;
  2166. if (AZ_GROUPTYPE_LDAP_QUERY == *((LONG*)pvPropValue))
  2167. {
  2168. pwszValue = g_pwszLdapGroup;
  2169. }
  2170. break;
  2171. default:
  2172. hr = E_INVALIDARG;
  2173. _JumpError(hr, error, "invalid attribute data type");
  2174. }
  2175. // persist the data
  2176. hr = myXmlSetNodeAttribute(
  2177. pNode,
  2178. pwszAttrTag,
  2179. pwszValue,
  2180. pDoc);
  2181. _JumpIfError(hr, error, "myXmlSetNodeAttribute");
  2182. hr = S_OK;
  2183. error:
  2184. if (NULL != pvPropValue)
  2185. {
  2186. XmlAzrolesInfo->AzpeFreeMemory(pvPropValue);
  2187. }
  2188. return hr;
  2189. }
  2190. DWORD
  2191. XMLPersistIsAcl(
  2192. IN PAZP_XML_CONTEXT pPersistContext,
  2193. IN AZPE_OBJECT_HANDLE AzpeObjectHandle,
  2194. OUT BOOL *pfAcl
  2195. )
  2196. {
  2197. UNREFERENCED_PARAMETER(pPersistContext);
  2198. AZASSERT(NULL != AzpeObjectHandle);
  2199. //init
  2200. *pfAcl = FALSE;
  2201. //
  2202. // only authorization store object has acl for xml store
  2203. // Since we don't support XML stores on FAT system, we can safely
  2204. // return TRUE as for authorization store
  2205. //
  2206. if (OBJECT_TYPE_AZAUTHSTORE == XmlAzrolesInfo->AzpeObjectType( AzpeObjectHandle ))
  2207. {
  2208. *pfAcl = TRUE;
  2209. }
  2210. return NO_ERROR;
  2211. }
  2212. HRESULT
  2213. XmlSetObjectOptions(
  2214. IN PAZP_XML_CONTEXT PersistContext,
  2215. IN ULONG lPersistFlags,
  2216. IN AZPE_OBJECT_HANDLE pObj
  2217. )
  2218. /*
  2219. Description:
  2220. Set the object options for the object
  2221. Arguments:
  2222. PersistContext - Context describing the policy store
  2223. lPersistFlags - flags from the persist engine
  2224. pObj - object to be set
  2225. Return:
  2226. */
  2227. {
  2228. HRESULT hr;
  2229. DWORD dwErr;
  2230. ULONG ObjectOptions = 0;
  2231. BOOL DaclSupported;
  2232. ULONG lObjectType = XmlAzrolesInfo->AzpeObjectType(pObj);
  2233. //
  2234. // Tell azroles about the object options
  2235. //
  2236. if ( PersistContext->IsWritable ) {
  2237. ObjectOptions |= AZPE_OPTIONS_WRITABLE;
  2238. ObjectOptions |= AZPE_OPTIONS_CREATE_CHILDREN;
  2239. }
  2240. if ( lObjectType == OBJECT_TYPE_AZAUTHSTORE ) {
  2241. dwErr = XMLPersistIsAcl( PersistContext, pObj, &DaclSupported );
  2242. _JumpIfWinError(dwErr, &hr, error, "XMLPersistIsAcl");
  2243. if ( DaclSupported ) {
  2244. ObjectOptions |= AZPE_OPTIONS_SUPPORTS_DACL;
  2245. ObjectOptions |= AZPE_OPTIONS_SUPPORTS_SACL;
  2246. }
  2247. if ( PersistContext->HasSecurityPrivilege ) {
  2248. ObjectOptions |= AZPE_OPTIONS_HAS_SECURITY_PRIVILEGE;
  2249. }
  2250. }
  2251. dwErr = XmlAzrolesInfo->AzpeSetObjectOptions(
  2252. pObj,
  2253. lPersistFlags,
  2254. ObjectOptions );
  2255. _JumpIfWinError(dwErr, &hr, error, "AzpeSetObjectOptions");
  2256. hr = S_OK;
  2257. error:
  2258. return hr;
  2259. }
  2260. HRESULT
  2261. myXmlLoadObjectCommonData(
  2262. IN PAZP_XML_CONTEXT PersistContext,
  2263. IN IXMLDOMNode *pNode,
  2264. IN ULONG lPersistFlags,
  2265. IN ULONG lObjectType,
  2266. IN AZPE_OBJECT_HANDLE pParent,
  2267. OUT OPTIONAL AZPE_OBJECT_HANDLE *ppObj)
  2268. /*
  2269. Description:
  2270. load common attributes such as decsription and guid
  2271. from xml node and create az object and set common properties
  2272. Arguments:
  2273. PersistContext - Context describing the policy store
  2274. pNode - xml node object
  2275. lPersistFlags - flags from the persist engine
  2276. lObjectType - object type (OBJECT_TYPE_*)
  2277. pObj - object to be set
  2278. Return:
  2279. */
  2280. {
  2281. HRESULT hr2 = S_OK;
  2282. HRESULT hr;
  2283. DWORD dwErr;
  2284. WCHAR *pwszName = NULL;
  2285. WCHAR *pwszGuid = NULL;
  2286. GUID GuidData;
  2287. AZPE_OBJECT_HANDLE pObj = NULL;
  2288. AZASSERT(NULL != pNode &&
  2289. NULL != pParent);
  2290. if (NULL != ppObj)
  2291. {
  2292. //init
  2293. *ppObj = NULL;
  2294. }
  2295. if (OBJECT_TYPE_AZAUTHSTORE != lObjectType)
  2296. {
  2297. // get object name from xml node to create initial az object
  2298. hr = myXmlGetNodeAttribute(
  2299. pNode,
  2300. AZ_XML_TAG_ATTR_NAME,
  2301. &pwszName);
  2302. _JumpIfError(hr, error, "myXmlGetNodeAttribute(name)");
  2303. // object guid must exist
  2304. hr = myXmlGetNodeAttribute(
  2305. pNode,
  2306. AZ_XML_TAG_ATTR_GUID,
  2307. &pwszGuid);
  2308. _JumpIfError(hr, error, "myXmlGetNodeAttribute");
  2309. hr = UuidFromString(pwszGuid, &GuidData);
  2310. _JumpIfError(hr, error, "UuidFromString");
  2311. //let's create a real az object
  2312. dwErr = XmlAzrolesInfo->AzpeCreateObject(
  2313. pParent,
  2314. lObjectType,
  2315. pwszName,
  2316. &GuidData,
  2317. lPersistFlags,
  2318. &pObj);
  2319. _JumpIfWinError(dwErr, &hr, error, "AzpeCreateObject");
  2320. AZASSERT(NULL != pObj);
  2321. }
  2322. else
  2323. {
  2324. // for AzAuthorizationStore object, it is on the top
  2325. pObj = pParent;
  2326. }
  2327. // load other common attributes
  2328. //
  2329. // load description attribute
  2330. //
  2331. hr = myXmlLoadObjectAttribute(
  2332. pNode,
  2333. lPersistFlags,
  2334. AZ_XML_TAG_ATTR_DESCRIPTION,
  2335. pObj,
  2336. AZ_PROP_DESCRIPTION,
  2337. ENUM_AZ_BSTR);
  2338. _JumpIfErrorOrPressOn(hr, hr2, error, lPersistFlags, TRUE, "myXmlLoadObjectAttribute(description)");
  2339. //
  2340. // Tell azroles about the object options
  2341. //
  2342. hr = XmlSetObjectOptions( PersistContext, lPersistFlags, pObj );
  2343. _JumpIfError(hr, error, "XmlSetObjectOptions");
  2344. //
  2345. // Return the created object to the caller
  2346. //
  2347. if (OBJECT_TYPE_AZAUTHSTORE != lObjectType &&
  2348. NULL != ppObj)
  2349. {
  2350. // return
  2351. *ppObj = pObj;
  2352. pObj = NULL;
  2353. }
  2354. _HandlePressOnError(hr, hr2);
  2355. error:
  2356. if (NULL != pwszName)
  2357. {
  2358. AzpFreeHeap(pwszName );
  2359. }
  2360. if (NULL != pwszGuid)
  2361. {
  2362. AzpFreeHeap(pwszGuid );
  2363. }
  2364. return hr;
  2365. }
  2366. HRESULT
  2367. myObAddPropertyItem(
  2368. IN AZPE_OBJECT_HANDLE pObject,
  2369. IN ULONG lPersistFlags,
  2370. IN ULONG lPropertyId,
  2371. IN ENUM_AZ_DATATYPE DataType,
  2372. IN PVOID pValue)
  2373. /*
  2374. Description:
  2375. help routine to add property items
  2376. Arguments:
  2377. pObject - az core object pointer
  2378. lPersistFlags - persist flags
  2379. lPropertyId - property ID
  2380. DataType - data type of the property
  2381. pValue - property item value
  2382. Return:
  2383. */
  2384. {
  2385. HRESULT hr;
  2386. DWORD dwErr;
  2387. if (ENUM_AZ_SID_ARRAY == DataType)
  2388. {
  2389. dwErr = XmlAzrolesInfo->AzpeAddPropertyItemSid(
  2390. pObject,
  2391. lPersistFlags,
  2392. lPropertyId,
  2393. pValue);
  2394. _JumpIfWinError(dwErr, &hr, error, "AzpeAddPropertyItemSid");
  2395. }
  2396. else
  2397. {
  2398. // guid items
  2399. dwErr = XmlAzrolesInfo->AzpeAddPropertyItemGuidString(
  2400. pObject,
  2401. lPersistFlags,
  2402. lPropertyId,
  2403. (WCHAR*)pValue);
  2404. _JumpIfWinError(dwErr, &hr, error, "AzpeAddPropertyItemGuidString");
  2405. }
  2406. hr = S_OK;
  2407. error:
  2408. return hr;
  2409. }
  2410. HRESULT
  2411. myXmlLoadProperties(
  2412. IN WCHAR const *pwszPropTag,
  2413. IN ULONG lPersistFlags,
  2414. IN ULONG lPropertyId,
  2415. IN ENUM_AZ_DATATYPE DataType,
  2416. IN BOOL fSingle,
  2417. IN IXMLDOMNode *pObjectNode,
  2418. IN AZPE_OBJECT_HANDLE pObject)
  2419. /*
  2420. Description:
  2421. load object properties into az core object
  2422. The property includes both single occurence element or multiple items
  2423. Argument:
  2424. pwszPropTag - property tag name
  2425. lPersistFlags - flags from the persist engine
  2426. lPropertyId - property ID for az group member
  2427. fSid - TRUE if element is in sid string format
  2428. fSingle - the property should be single occurence
  2429. this is used to determine call SetProperty or AddPropertyItem
  2430. pObjectNode - interface pointer to xml object node
  2431. pObject - az object handle to be set
  2432. Return:
  2433. */
  2434. {
  2435. HRESULT hr;
  2436. DWORD dwErr;
  2437. BSTR bstrPropTag = NULL;
  2438. BSTR bstrPropValue = NULL;
  2439. IXMLDOMNodeList *pPropList = NULL;
  2440. IXMLDOMNode *pPropNode = NULL;
  2441. LONG lLength;
  2442. LONG i;
  2443. LONG lValue;
  2444. VOID *pValue;
  2445. PSID pSid = NULL;
  2446. AZASSERT(NULL != pObject &&
  2447. NULL != pwszPropTag &&
  2448. NULL != pObjectNode);
  2449. // convert to bstr for tag
  2450. bstrPropTag = SysAllocString(pwszPropTag);
  2451. _JumpIfOutOfMemory(&hr, error, bstrPropTag, "SysAllocString");
  2452. // get element list
  2453. hr = pObjectNode->selectNodes(
  2454. bstrPropTag,
  2455. &pPropList);
  2456. _JumpIfError(hr, error, "pObjectNode->selectNodes");
  2457. AZASSERT(NULL != pPropList);
  2458. // get item length
  2459. hr = pPropList->get_length(&lLength);
  2460. _JumpIfError(hr, error, "pPropList->get_length");
  2461. // add each elements into az object
  2462. for (i = 0; i < lLength; ++i)
  2463. {
  2464. // get element node
  2465. hr = pPropList->get_item(i, &pPropNode);
  2466. _JumpIfError(hr, error, "pPropList->get_item");
  2467. AZASSERT(NULL != pPropNode);
  2468. // get element value
  2469. hr = pPropNode->get_text(&bstrPropValue);
  2470. _JumpIfError(hr, error, "pPropNode->get_text");
  2471. AZASSERT(NULL != bstrPropValue);
  2472. // init point to as string
  2473. pValue = (VOID*)bstrPropValue;
  2474. // if in sid format, do conversion
  2475. if (ENUM_AZ_SID_ARRAY == DataType)
  2476. {
  2477. // convert string sid to sid
  2478. if (!ConvertStringSidToSid(bstrPropValue, &pSid))
  2479. {
  2480. AZ_HRESULT_LASTERROR(&hr);
  2481. _JumpError(hr, error, "ConvertStringSidToSid");
  2482. }
  2483. AZASSERT(NULL != pSid);
  2484. pValue = (VOID*)pSid;
  2485. }
  2486. else if (ENUM_AZ_LONG == DataType)
  2487. {
  2488. lValue = _wtol(bstrPropValue);
  2489. pValue = (VOID*)&lValue;
  2490. }
  2491. if (fSingle)
  2492. {
  2493. //
  2494. // if string is empty, don't set it with the exception of BizRule
  2495. // An empty BizRule is significantly different from no biz rule in
  2496. // out current cache implementation.
  2497. //
  2498. if ( ENUM_AZ_LONG == DataType ||
  2499. (ENUM_AZ_BSTR == DataType && AZ_PROP_TASK_BIZRULE == lPropertyId) ||
  2500. (ENUM_AZ_BSTR == DataType && L'\0' != ((WCHAR*)pValue)[0])
  2501. )
  2502. {
  2503. //
  2504. // if we see a empty string for biz rule, use a one space value so that
  2505. // the cache will have a one space biz rule. Otherwise, the empty string will
  2506. // be interprected as a NULL by our string capture utility AzpCaptureString.
  2507. //
  2508. PVOID pPropValue = (AZ_PROP_TASK_BIZRULE == lPropertyId && L'\0' == ((WCHAR*)pValue)[0]) ?
  2509. L" " : pValue;
  2510. dwErr = XmlAzrolesInfo->AzpeSetProperty(
  2511. pObject,
  2512. lPersistFlags,
  2513. lPropertyId,
  2514. pPropValue);
  2515. _JumpIfWinError(dwErr, &hr, error, "AzpeSetProperty");
  2516. }
  2517. // if single, we should be done
  2518. // in case persist store has more than one, ignore the rest
  2519. goto done;
  2520. }
  2521. // now ready to add element to az object
  2522. dwErr = myObAddPropertyItem(
  2523. pObject,
  2524. lPersistFlags,
  2525. lPropertyId,
  2526. DataType,
  2527. pValue);
  2528. _JumpIfWinError(dwErr, &hr, error, "myObAddPropertyItem");
  2529. // free for the next in for loop
  2530. if (NULL != pSid)
  2531. {
  2532. LocalFree(pSid);
  2533. pSid = NULL;
  2534. }
  2535. pPropNode->Release();
  2536. pPropNode = NULL;
  2537. SysFreeString(bstrPropValue);
  2538. bstrPropValue = NULL;
  2539. }
  2540. done:
  2541. hr = S_OK;
  2542. error:
  2543. if (NULL != bstrPropTag)
  2544. {
  2545. SysFreeString(bstrPropTag);
  2546. }
  2547. if (NULL != bstrPropValue)
  2548. {
  2549. SysFreeString(bstrPropValue);
  2550. }
  2551. if (NULL != pSid)
  2552. {
  2553. LocalFree(pSid);
  2554. pSid = NULL;
  2555. }
  2556. if (NULL != pPropList)
  2557. {
  2558. pPropList->Release();
  2559. }
  2560. if (NULL != pPropNode)
  2561. {
  2562. pPropNode->Release();
  2563. }
  2564. return hr;
  2565. }
  2566. HRESULT
  2567. myXmlLoadObject(
  2568. IN PAZP_XML_CONTEXT PersistContext,
  2569. IN AZPE_OBJECT_HANDLE pParentObject,
  2570. IN ULONG lObjectType,
  2571. IN ULONG lPersistFlags,
  2572. IN BOOL fChildren,
  2573. IN BOOL fFinishAzStoreObject,
  2574. IN IXMLDOMNode *pObjectNode)
  2575. /*
  2576. Description:
  2577. load a persist object and optional all children into az core
  2578. if there is children, it will be recursive routine if load all children
  2579. Arguments:
  2580. PersistContext - Context describing the policy store
  2581. pParentObject - the parent object handle
  2582. lObjectType - the object type that is loaded
  2583. lPersistFlags - flags from the persist engine
  2584. if the flag is AZPE_FLAGS_PERSIST_OPEN, error handling returns immediately
  2585. if the flag is AZPE_FLAGS_PERSIST_UPDATE_CACHE, error handling press on.
  2586. fChildren - TRUE if load child objects
  2587. fFinishAzStoreObject - TRUE if want to call AzpeFinishObject on AzAuthorizationStore
  2588. pObjectNode - the node handle of the object
  2589. Return:
  2590. */
  2591. {
  2592. HRESULT hr2 = S_OK;
  2593. HRESULT hr;
  2594. AZPE_OBJECT_HANDLE pObject = NULL;
  2595. BSTR bstrChildTag = NULL;
  2596. IXMLDOMNodeList *pChildList = NULL;
  2597. IXMLDOMNode *pChildNode = NULL;
  2598. LONG lLength = 0;
  2599. LONG i;
  2600. AZASSERT(NULL != pParentObject &&
  2601. NULL != pObjectNode);
  2602. // load/create object and set common attributes
  2603. hr = myXmlLoadObjectCommonData(
  2604. PersistContext,
  2605. pObjectNode,
  2606. lPersistFlags,
  2607. lObjectType,
  2608. pParentObject,
  2609. &pObject);
  2610. _JumpIfErrorOrPressOn(hr, hr2, error, lPersistFlags, NULL != pObject, "myXmlLoadObjectCommonData");
  2611. if (OBJECT_TYPE_AZAUTHSTORE == lObjectType)
  2612. {
  2613. // if AzAuthorizationStore object, it is top, object points to parent
  2614. AZASSERT(NULL == pObject);
  2615. pObject = pParentObject;
  2616. }
  2617. #if DBG
  2618. else
  2619. {
  2620. AZASSERT(NULL != pObject);
  2621. }
  2622. #endif //DBG
  2623. //load object attributes
  2624. if (NULL != g_SubmitLoadTable[lObjectType].rgpAttrs)
  2625. {
  2626. // load object attributes
  2627. AZ_PROP_ENTRY *pAttrs;
  2628. for (pAttrs = g_SubmitLoadTable[lObjectType].rgpAttrs;
  2629. NULL != pAttrs[0].pwszTag; ++pAttrs)
  2630. {
  2631. hr = myXmlLoadObjectAttribute(
  2632. pObjectNode,
  2633. lPersistFlags,
  2634. pAttrs[0].pwszTag,
  2635. pObject,
  2636. pAttrs[0].lPropId,
  2637. pAttrs[0].lDataType);
  2638. _JumpIfErrorOrPressOn(hr, hr2, error, lPersistFlags, TRUE, "myXmlLoadNodeAttribute");
  2639. }
  2640. }
  2641. //load object property elements
  2642. if (NULL != g_SubmitLoadTable[lObjectType].rgpEles)
  2643. {
  2644. // load object elements
  2645. AZ_PROP_ENTRY *pEles;
  2646. for (pEles = g_SubmitLoadTable[lObjectType].rgpEles;
  2647. NULL != pEles[0].pwszTag; ++pEles)
  2648. {
  2649. hr = myXmlLoadProperties(
  2650. pEles[0].pwszTag,
  2651. lPersistFlags,
  2652. pEles[0].lPropId,
  2653. pEles[0].lDataType,
  2654. pEles[0].fSingle, //single occurence
  2655. pObjectNode,
  2656. pObject);
  2657. _JumpIfErrorOrPressOn(hr, hr2, error, lPersistFlags, TRUE, "myXmlLoadProperties");
  2658. }
  2659. }
  2660. //
  2661. // load the object children
  2662. //
  2663. if (fChildren && NULL != g_SubmitLoadTable[lObjectType].rgpChildren)
  2664. {
  2665. AZ_CHILD_ENTRY *pChild;
  2666. for (pChild = g_SubmitLoadTable[lObjectType].rgpChildren;
  2667. NULL != pChild[0].pwszChildTag; ++pChild)
  2668. {
  2669. bstrChildTag = SysAllocString(pChild->pwszChildTag);
  2670. _JumpIfOutOfMemory(&hr, error, bstrChildTag, "SysAllocString");
  2671. hr = pObjectNode->selectNodes(
  2672. bstrChildTag,
  2673. &pChildList);
  2674. _JumpIfError(hr, error, "pObjectNode->selectNodes");
  2675. hr = pChildList->get_length(&lLength);
  2676. _JumpIfError(hr, error, "pTaskList->get_length");
  2677. // add each child to the current object
  2678. for (i = 0; i < lLength; ++i)
  2679. {
  2680. // get each child node
  2681. hr = pChildList->get_item(i, &pChildNode);
  2682. _JumpIfError(hr, error, "pChildList->get_item");
  2683. AZASSERT(NULL != pChildNode);
  2684. // make sure is a valid child, at least an element
  2685. hr = myXmlValidateNodeType(
  2686. pChildNode,
  2687. NODE_ELEMENT);
  2688. if (S_OK == hr)
  2689. {
  2690. // ok, load child into the current object
  2691. hr = myXmlLoadObject(
  2692. PersistContext,
  2693. pObject, // parent, which is the current object
  2694. pChild->ChildType,
  2695. lPersistFlags,
  2696. fChildren,
  2697. fFinishAzStoreObject,
  2698. pChildNode);
  2699. _JumpIfErrorOrPressOn(hr, hr2, error, lPersistFlags, TRUE, "myXmlLoadObject");
  2700. }
  2701. // free node for the next child
  2702. pChildNode->Release();
  2703. pChildNode = NULL;
  2704. }
  2705. // free for the next
  2706. SysFreeString(bstrChildTag);
  2707. bstrChildTag = NULL;
  2708. pChildList->Release();
  2709. pChildList = NULL;
  2710. }
  2711. }
  2712. _HandlePressOnError(hr, hr2);
  2713. error:
  2714. if (NULL != bstrChildTag)
  2715. {
  2716. SysFreeString(bstrChildTag);
  2717. }
  2718. if (NULL != pChildList)
  2719. {
  2720. pChildList->Release();
  2721. }
  2722. if (NULL != pChildNode)
  2723. {
  2724. pChildNode->Release();
  2725. }
  2726. if ((NULL != pObject) &&
  2727. ((OBJECT_TYPE_AZAUTHSTORE != lObjectType) ||
  2728. (OBJECT_TYPE_AZAUTHSTORE == lObjectType && fFinishAzStoreObject)
  2729. )
  2730. )
  2731. {
  2732. XmlAzrolesInfo->AzpeObjectFinished( pObject, AzpHresultToWinStatus(hr) );
  2733. }
  2734. return hr;
  2735. }
  2736. HRESULT
  2737. myXmlGetAzStoreNode(
  2738. IN IXMLDOMDocument2 *pDoc,
  2739. OUT IXMLDOMElement **ppAzStoreNode)
  2740. /*
  2741. get the az top node, authorization store
  2742. IN: pDoc, the root node, document node
  2743. IN: ppAzStoreNode, AzAuthStore node for return
  2744. */
  2745. {
  2746. HRESULT hr;
  2747. AZASSERT(NULL != pDoc &&
  2748. NULL != ppAzStoreNode);
  2749. // get the root node, ie. the node of authorization store policy
  2750. hr = pDoc->get_documentElement(ppAzStoreNode);
  2751. _JumpIfError(hr, error, "pDoc->get_documentElement");
  2752. AZASSERT(NULL != *ppAzStoreNode);
  2753. // make sure it has the correct tag
  2754. hr = myXmlValidateNodeTag(
  2755. *ppAzStoreNode,
  2756. AZ_XML_TAG_AZSTORE);
  2757. _JumpIfError(hr, error, "myXmlValidateNodeTag");
  2758. hr = S_OK;
  2759. error:
  2760. return hr;
  2761. }
  2762. HRESULT
  2763. myXmlLoadPolicyToAzAuthorizationStore(
  2764. IN PAZP_XML_CONTEXT PersistContext,
  2765. IN BOOL fCreatePolicy,
  2766. IN ULONG lPersistFlags,
  2767. IN IXMLDOMDocument2 *pDoc)
  2768. /*
  2769. load xml policy data into az authorization store object
  2770. PersistContext - Context describing the policy store
  2771. IN: lPersistFlags, flags from the persist engine
  2772. IN: pDoc, interface pointer to xml root node, document
  2773. */
  2774. {
  2775. HRESULT hr;
  2776. IXMLDOMElement *pAzStoreNode = NULL;
  2777. AZASSERT(NULL != PersistContext &&
  2778. NULL != pDoc);
  2779. //init
  2780. // get the root node, ie. the node of ploicy
  2781. hr = myXmlGetAzStoreNode(pDoc, &pAzStoreNode);
  2782. _JumpIfError(hr, error, "myXmlGetAzStoreNode");
  2783. AZASSERT(NULL != pAzStoreNode);
  2784. // start load AzAuthorizationStore object, this call invokes
  2785. // recursively to load all AzAuthStore object children
  2786. hr = myXmlLoadObject(
  2787. PersistContext,
  2788. PersistContext->hAzAuthorizationStore,
  2789. OBJECT_TYPE_AZAUTHSTORE,
  2790. lPersistFlags,
  2791. TRUE, //load all child objects
  2792. FALSE, // we have to AzpeFinishObject later on AzAuthStore
  2793. pAzStoreNode);
  2794. _JumpIfError(hr, error, "myXmlLoadObject(AzAuthorizationStore)");
  2795. //
  2796. // On create, don't do this until AzPersistSubmit
  2797. //
  2798. if ( !fCreatePolicy ) {
  2799. // now load AzAuthStore object policy acl
  2800. hr = myXmlLoadAclsToAzStore(
  2801. PersistContext,
  2802. lPersistFlags,
  2803. FALSE );
  2804. _JumpIfError(hr, error, "myXmlLoadAclsToAzStore");
  2805. }
  2806. hr = S_OK;
  2807. error:
  2808. if (NULL != pAzStoreNode)
  2809. {
  2810. pAzStoreNode->Release();
  2811. }
  2812. XmlAzrolesInfo->AzpeObjectFinished( PersistContext->hAzAuthorizationStore, AzpHresultToWinStatus(hr) );
  2813. return hr;
  2814. }
  2815. DWORD
  2816. XMLPersistWritable(
  2817. IN PAZP_XML_CONTEXT XmlPersistContext
  2818. )
  2819. {
  2820. DWORD dwErr = NO_ERROR;
  2821. HANDLE hFile = INVALID_HANDLE_VALUE;
  2822. // init
  2823. XmlPersistContext->IsWritable = FALSE;
  2824. // xml is easy, all object writable depends on policy file permission
  2825. hFile = CreateFile(
  2826. XmlPersistContext->pwszPolicyUrl,
  2827. GENERIC_WRITE,
  2828. 0, // not shared
  2829. NULL,
  2830. OPEN_EXISTING,
  2831. 0,
  2832. NULL);
  2833. if (INVALID_HANDLE_VALUE == hFile)
  2834. {
  2835. dwErr = GetLastError();
  2836. }
  2837. else
  2838. {
  2839. XmlPersistContext->IsWritable = TRUE;
  2840. }
  2841. if (INVALID_HANDLE_VALUE != hFile)
  2842. {
  2843. CloseHandle(hFile);
  2844. }
  2845. return dwErr;
  2846. }
  2847. DWORD
  2848. XMLPersistTargetMachine(
  2849. IN PCWSTR PolicyUrl,
  2850. OUT PWSTR *ppwszTargetMachine OPTIONAL
  2851. )
  2852. /*++
  2853. Routine Description
  2854. Routine to determine the target machine name for account resolution
  2855. based on the policy URL.
  2856. For XML store, the target machine is the server (machine) name that
  2857. the XML store is physically stored. If fail to get the machine name,
  2858. the local machine (NULL) will be returned.
  2859. Arguments
  2860. PolicyUrl - the policy URL passed in
  2861. ppwszTargetMachine - the output target machine name
  2862. Return Value
  2863. NO_ERROR
  2864. --*/
  2865. {
  2866. LPWSTR pszUNC = NULL;
  2867. LPWSTR pszPath = (LPWSTR)PolicyUrl;
  2868. BOOL bIsUNC = FALSE;
  2869. DWORD WinStatus = NO_ERROR;
  2870. PWSTR szServer=NULL;
  2871. if ( PolicyUrl == NULL || ppwszTargetMachine == NULL ) {
  2872. return ERROR_INVALID_PARAMETER;
  2873. }
  2874. *ppwszTargetMachine = NULL;
  2875. if ( wcslen(PolicyUrl) <= 2 ) {
  2876. return ERROR_INVALID_PARAMETER;
  2877. }
  2878. //
  2879. // determine if the URL is a UNC path first
  2880. //
  2881. if ( PolicyUrl[0] == L'\\' && PolicyUrl[1] == L'\\' ) {
  2882. bIsUNC = TRUE;
  2883. }
  2884. if (!bIsUNC && PolicyUrl[1] != L':') {
  2885. //
  2886. // this is a relative path, which must be on the local machine
  2887. // in which case *ppwszTargetMachine is set to NULL
  2888. //
  2889. return ERROR_SUCCESS;
  2890. }
  2891. if ( !bIsUNC ) {
  2892. //
  2893. // if it's a drive letter mapping
  2894. // check to see if this is a remote path
  2895. //
  2896. WinStatus = myGetRemotePath(PolicyUrl, &pszUNC);
  2897. if ( WinStatus == NO_ERROR ) {
  2898. //
  2899. // this is a valid network path
  2900. //
  2901. pszPath = pszUNC;
  2902. } else {
  2903. //
  2904. // either this is not a network drive
  2905. // or fail to resolve the connection
  2906. // in either case, use the local machine as default
  2907. // don't care the mount point much in this case since
  2908. // the mount point and a local drive use the same server name
  2909. //
  2910. WinStatus = NO_ERROR;
  2911. goto CleanUp;
  2912. }
  2913. }
  2914. //
  2915. // the path must be a UNC path when it gets here
  2916. // get volume information related to the path (could be a mount point or DFS)
  2917. //
  2918. WCHAR szVolume[MAX_PATH];
  2919. szVolume[0] = L'\0';
  2920. myGetVolumeInfo(pszPath,
  2921. szVolume,
  2922. ARRAYLEN(szVolume));
  2923. SafeAllocaAllocate( szServer, MAX_PATH*sizeof(WCHAR) );
  2924. if ( szServer == NULL ) {
  2925. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  2926. goto CleanUp;
  2927. }
  2928. //
  2929. // get server name related to the volume
  2930. //
  2931. szServer[0] = L'\0';
  2932. BOOL bIsDfs = IsDfsPath(szVolume, szServer, MAX_PATH);
  2933. DWORD dwLen = 0;
  2934. if ( bIsDfs ) {
  2935. //
  2936. // this is a DFS volume, server name is already stored in szServer
  2937. //
  2938. dwLen = (DWORD)wcslen(szServer);
  2939. } else {
  2940. //
  2941. // not a DFS share, just use the server name in the UNC path
  2942. //
  2943. PWSTR pSlash = wcschr(&szVolume[2], L'\\');
  2944. if (pSlash)
  2945. dwLen = (ULONG)(pSlash - szVolume) - 2;
  2946. else
  2947. dwLen = (DWORD)wcslen(szVolume) - 2;
  2948. }
  2949. //
  2950. // copy the target machine name
  2951. //
  2952. *ppwszTargetMachine = (PWSTR)XmlAzrolesInfo->AzpeAllocateMemory((dwLen+1)*sizeof(WCHAR));
  2953. if ( *ppwszTargetMachine ) {
  2954. wcsncpy(*ppwszTargetMachine,
  2955. bIsDfs? szServer : szVolume + 2, // skip two backslashes
  2956. dwLen);
  2957. (*ppwszTargetMachine)[dwLen] = L'\0';
  2958. } else {
  2959. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  2960. }
  2961. CleanUp:
  2962. if ( szServer ) {
  2963. SafeAllocaFree( szServer );
  2964. }
  2965. AzpFreeHeap(pszUNC);
  2966. return WinStatus;
  2967. }
  2968. DWORD
  2969. WINAPI
  2970. XmlProviderInitialize(
  2971. IN PAZPE_AZROLES_INFO AzrolesInfo,
  2972. OUT PAZPE_PROVIDER_INFO *ProviderInfo
  2973. )
  2974. /*++
  2975. Routine Description
  2976. Routine to initialize the XML provider
  2977. Arguments
  2978. AzrolesInfo - Specifies the interface to routines in azroles.dll
  2979. ProviderInfo - Returns a pointer to the provider info for the provider
  2980. Return Value
  2981. NO_ERROR - Provider was properly initialized
  2982. ERROR_UNKNOWN_REVISION - AzrolesInfo is a version the provider doesn't support
  2983. --*/
  2984. {
  2985. //
  2986. // Ensure the azroles info is a version we understand
  2987. //
  2988. if ( AzrolesInfo->AzrolesInfoVersion < AZPE_AZROLES_INFO_VERSION_1 ) {
  2989. return ERROR_UNKNOWN_REVISION;
  2990. }
  2991. XmlAzrolesInfo = AzrolesInfo;
  2992. *ProviderInfo = &XmlProviderInfo;
  2993. return NO_ERROR;
  2994. }
  2995. HRESULT
  2996. myXMLTestVersion (
  2997. IXMLDOMDocument2 * pDoc
  2998. )
  2999. /*++
  3000. Routine Description:
  3001. This routine will determine if the major and minor version attributes
  3002. persisted in the document is allows us to continue reading
  3003. Arguments:
  3004. pDoc - COM interface to the opened XML document
  3005. Return Value:
  3006. S_OK - we can continue reading.
  3007. AZ_HRESULT(ERROR_REVISION_MISMATCH) if we can't continue reading due to version mismatch
  3008. Other HRESULT code
  3009. Note:
  3010. Current implementation is that if the store is written by a azroles.dll of a
  3011. newer major version than that of the current reading azroles.dll,
  3012. then reading is not supported.
  3013. --*/
  3014. {
  3015. CComPtr<IXMLDOMElement> srpDocElement;
  3016. HRESULT hr = pDoc->get_documentElement(&srpDocElement);
  3017. if (SUCCEEDED(hr))
  3018. {
  3019. CComVariant varMajVer;
  3020. CComBSTR bstrMajVer(AZ_XML_TAG_ATTR_MAJOR_VERSION);
  3021. if (bstrMajVer.m_str == NULL)
  3022. {
  3023. hr = E_OUTOFMEMORY;
  3024. }
  3025. else
  3026. {
  3027. hr = srpDocElement->getAttribute(bstrMajVer, &varMajVer);
  3028. }
  3029. if (SUCCEEDED(hr) && varMajVer.vt == VT_BSTR)
  3030. {
  3031. VARIANT varMajVerInt;
  3032. VariantInit(&varMajVerInt);
  3033. hr = VariantChangeType(&varMajVerInt, &varMajVer, VARIANT_NOVALUEPROP, VT_UI4);
  3034. //
  3035. // If this variant is can't even convert to an integer, we will also consider
  3036. // it a mismatch because other errors will be more misleading.
  3037. //
  3038. if ( FAILED(hr) || (varMajVerInt.ulVal > AzGlCurrAzRolesMajorVersion) )
  3039. {
  3040. hr = AZ_HRESULT(ERROR_REVISION_MISMATCH);
  3041. }
  3042. else
  3043. {
  3044. hr = S_OK;
  3045. }
  3046. }
  3047. else if ( E_OUTOFMEMORY != hr )
  3048. {
  3049. //
  3050. // Reading a BSTR out from the DOM node may fail. But we will
  3051. // consider all failures except out-of-memory as a failure
  3052. // of not having version numbers and thus a version mismatch error.
  3053. //
  3054. hr = AZ_HRESULT(ERROR_REVISION_MISMATCH);
  3055. }
  3056. }
  3057. return hr;
  3058. }
  3059. DWORD
  3060. XMLPersistOpenEx(
  3061. IN LPCWSTR PolicyUrl,
  3062. IN PAZP_XML_CONTEXT OldXmlContext OPTIONAL,
  3063. IN AZPE_OBJECT_HANDLE pAzAuthorizationStore,
  3064. IN ULONG lPersistFlags,
  3065. IN BOOL fCreatePolicy,
  3066. OUT PAZPE_PERSIST_CONTEXT PersistContext OPTIONAL,
  3067. OUT LPWSTR *pwszTargetMachine OPTIONAL
  3068. )
  3069. /*++
  3070. Routine Description:
  3071. This routine is shared betwen XMLPersistOpen and XMLPersistUpdateCache.
  3072. This routine submits reads the authz policy database from storage.
  3073. This routine also reads the policy database into cache.
  3074. On Success, the caller should call XMLPersistClose to free any resources
  3075. consumed by the open.
  3076. On entry, AzAuthorizationStore->PersistCritSect must be locked.
  3077. Arguments:
  3078. PolicyUrl - Specifies the location of the policy store
  3079. OldXmlContext - On an AzUpdateCache, specifies the existing context
  3080. pAzAuthorizationStore - Specifies the policy database that is to be read.
  3081. lPersistFlags - lPersistFlags from the persist engine describing the operation
  3082. AZPE_FLAGS_PERSIST_OPEN - Call is the original AzInitialize
  3083. AZPE_FLAGS_PERSIST_UPDATE_CACHE - Call is an AzUpdateCache
  3084. fCreatePolicy - TRUE if the policy database is to be created.
  3085. FALSE if the policy database already exists
  3086. PersistContext - On Success, returns a context that should be passed on all
  3087. subsequent calls.
  3088. The caller should call XMLPersistClose to free this context.
  3089. This parameter is only returned for AzInitialize calls
  3090. pwszTargetMachine - pointer to the target machine name where account resolution
  3091. should occur. This should be the machine where the ldap data
  3092. is stored.
  3093. Return Value:
  3094. NO_ERROR - The operation was successful
  3095. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  3096. Other status codes
  3097. --*/
  3098. {
  3099. HRESULT hr;
  3100. AZP_XML_CONTEXT *pXMLPersistContext = NULL;
  3101. ULONG PolicyUrlSize;
  3102. WCHAR FullPathBuffer[MAX_PATH+1];
  3103. ULONG FullPathLen;
  3104. //
  3105. // using CComVariant will allow us not to worry about
  3106. // clearing the variant.
  3107. //
  3108. CComVariant varParam;
  3109. VARIANT_BOOL varbLoad;
  3110. BSTR bstrEmptyPolicy = NULL;
  3111. BOOL fPolicyFileExists;
  3112. DWORD dwErr;
  3113. //
  3114. // Get the full path name so that underlying components don't have to deal with
  3115. // relative path names
  3116. //
  3117. FullPathLen = GetFullPathName( PolicyUrl,
  3118. MAX_PATH+1,
  3119. FullPathBuffer,
  3120. NULL );
  3121. if ( FullPathLen == 0 ) {
  3122. AZ_HRESULT_LASTERROR(&hr);
  3123. _JumpError(hr, error, "GetFullPathName");
  3124. } else if ( FullPathLen > MAX_PATH ) {
  3125. dwErr = ERROR_INVALID_NAME;
  3126. _JumpIfWinError(dwErr, &hr, error, "GetFullPathName");
  3127. }
  3128. //
  3129. // If this file is on a FAT file system, then we won't support it.
  3130. // And we won't to fail it early at the open stage.
  3131. //
  3132. dwErr = IsAclSupported( FullPathBuffer );
  3133. if (dwErr != NO_ERROR)
  3134. {
  3135. _JumpIfWinError(dwErr, &hr, error, "XML stores on FAT file system are not supported");
  3136. }
  3137. PolicyUrl = FullPathBuffer;
  3138. PolicyUrlSize = (FullPathLen+1) * sizeof(WCHAR);
  3139. //
  3140. // allocate a context describing this provider
  3141. //
  3142. pXMLPersistContext = (PAZP_XML_CONTEXT) AzpAllocateHeap(
  3143. sizeof( *pXMLPersistContext ) + PolicyUrlSize,
  3144. "XMCTXT" );
  3145. _JumpIfOutOfMemory(&hr, error, pXMLPersistContext, "AzpAllocateHeap");
  3146. ZeroMemory(pXMLPersistContext, sizeof(*pXMLPersistContext));
  3147. pXMLPersistContext->hAzAuthorizationStore = pAzAuthorizationStore;
  3148. //
  3149. // Cache the PolicyUrl
  3150. //
  3151. pXMLPersistContext->pwszPolicyUrl = (LPWSTR)(pXMLPersistContext+1);
  3152. RtlCopyMemory( (PVOID)pXMLPersistContext->pwszPolicyUrl,
  3153. PolicyUrl,
  3154. PolicyUrlSize );
  3155. // create xml doc interface
  3156. hr = CoCreateInstance(
  3157. CLSID_DOMDocument,
  3158. NULL,
  3159. CLSCTX_INPROC_SERVER,
  3160. IID_IXMLDOMDocument2,
  3161. (void**)&(pXMLPersistContext->pDoc));
  3162. _JumpIfError(hr, error, "CoCreateInstance");
  3163. // load xml store
  3164. hr = pXMLPersistContext->pDoc->put_async(FALSE);
  3165. _JumpIfError(hr, error, "pDoc->put_async");
  3166. if (fCreatePolicy)
  3167. {
  3168. // only real open mode allows creating new store
  3169. AZASSERT(AZPE_FLAGS_PERSIST_OPEN & lPersistFlags);
  3170. // create a new policy
  3171. // prevent creating new store if the file exists
  3172. hr = myFileExist(pXMLPersistContext->pwszPolicyUrl, &fPolicyFileExists);
  3173. _JumpIfError(hr, error, "myFileExist");
  3174. if (fPolicyFileExists)
  3175. {
  3176. hr = AZ_HRESULT(ERROR_ALREADY_EXISTS);
  3177. _JumpError(hr, error, "can't create new policy store if it exists");
  3178. }
  3179. bstrEmptyPolicy = SysAllocString(
  3180. L"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<AzAdminManager MajorVersion=\"1\" MinorVersion=\"0\">\n</AzAdminManager>");
  3181. _JumpIfOutOfMemory(&hr, error, bstrEmptyPolicy, "SysAllocString");
  3182. // load empty policy
  3183. hr = pXMLPersistContext->pDoc->loadXML(
  3184. bstrEmptyPolicy,
  3185. &varbLoad);
  3186. _JumpIfXmlError(hr, &hr, error, pXMLPersistContext->pDoc, "pDoc->loadXML")
  3187. // Assume it is writable
  3188. pXMLPersistContext->IsWritable = TRUE;
  3189. }
  3190. else
  3191. {
  3192. hr = myWszToBstrVariant(
  3193. pXMLPersistContext->pwszPolicyUrl,
  3194. &varParam);
  3195. _JumpIfError(hr, error, "myWszToBstrVariant");
  3196. // load doc object
  3197. hr = pXMLPersistContext->pDoc->load(varParam, &varbLoad);
  3198. // we want to get xml error code
  3199. hr = myGetXmlError(hr, pXMLPersistContext->pDoc, NULL);
  3200. if (0x800c0006 == hr)
  3201. {
  3202. // 0x800c0006, xml error,
  3203. // The system cannot locate the object specified.
  3204. // we want to map it file not found error
  3205. hr = AZ_HRESULT(ERROR_FILE_NOT_FOUND);
  3206. }
  3207. _JumpIfError(hr, error, "pDoc->load")
  3208. //
  3209. // now we have loaded the XML document, we need to see
  3210. // if the version of the document is what we can understand
  3211. //
  3212. hr = myXMLTestVersion(pXMLPersistContext->pDoc);
  3213. _JumpIfError(hr, error, "myXMLReadTestVersion failed.");
  3214. //
  3215. // Determine if the file is writable.
  3216. // We purposely ignore the return code in case the caller
  3217. // doesn't have write access.
  3218. //
  3219. dwErr = XMLPersistWritable( pXMLPersistContext );
  3220. if (NO_ERROR != dwErr)
  3221. {
  3222. AzPrint((AZD_XML, "XMLPersistWritable returns error code: %d", dwErr));
  3223. }
  3224. WIN32_FILE_ATTRIBUTE_DATA fad;
  3225. //
  3226. // We need the lastWrite filetime
  3227. //
  3228. if (GetFileAttributesEx(pXMLPersistContext->pwszPolicyUrl,
  3229. GetFileExInfoStandard,
  3230. &fad))
  3231. {
  3232. pXMLPersistContext->FTLastWrite = fad.ftLastWriteTime;
  3233. }
  3234. else
  3235. {
  3236. dwErr = GetLastError();
  3237. }
  3238. }
  3239. //
  3240. // Determine if the caller has security privilege
  3241. //
  3242. // For UpdateCache, the privilege is already known
  3243. //
  3244. if ( lPersistFlags & AZPE_FLAGS_PERSIST_UPDATE_CACHE ) {
  3245. pXMLPersistContext->HasSecurityPrivilege = OldXmlContext->HasSecurityPrivilege;
  3246. //
  3247. // For Initialize, determine privilege by accessing the server
  3248. //
  3249. } else {
  3250. dwErr = XmlCheckSecurityPrivilege( pXMLPersistContext->pwszPolicyUrl,
  3251. fCreatePolicy );
  3252. if ( dwErr == NO_ERROR ) {
  3253. pXMLPersistContext->HasSecurityPrivilege = TRUE;
  3254. } else if ( dwErr == ERROR_PRIVILEGE_NOT_HELD ) {
  3255. pXMLPersistContext->HasSecurityPrivilege = FALSE;
  3256. } else {
  3257. _JumpIfWinError(dwErr, &hr, error, "XmlCheckSecurityPrivilege");
  3258. }
  3259. }
  3260. //
  3261. // Load the policy database
  3262. //
  3263. hr = myXmlLoadPolicyToAzAuthorizationStore(
  3264. pXMLPersistContext,
  3265. fCreatePolicy,
  3266. lPersistFlags,
  3267. pXMLPersistContext->pDoc); //the current node in xml tree
  3268. _JumpIfError(hr, error, "myXmlLoadPolicyToAzAuthorizationStore");
  3269. //
  3270. // On an UpdateCache,
  3271. // update the old context to contain the new doc instance
  3272. //
  3273. if (AZPE_FLAGS_PERSIST_UPDATE_CACHE & lPersistFlags)
  3274. {
  3275. IXMLDOMDocument2 *pTempDoc;
  3276. pTempDoc = pXMLPersistContext->pDoc;
  3277. pXMLPersistContext->pDoc = OldXmlContext->pDoc;
  3278. OldXmlContext->pDoc = pTempDoc;
  3279. //
  3280. // On an Initialize,
  3281. // return the context to the caller.
  3282. } else {
  3283. // return the persist context to the caller
  3284. *PersistContext = (AZPE_PERSIST_CONTEXT)pXMLPersistContext;
  3285. pXMLPersistContext = NULL;
  3286. }
  3287. if ( pwszTargetMachine ) {
  3288. //
  3289. // detect the target machine name for this URL
  3290. // if couldn't determine, default to local (NULL)
  3291. // other errors such as out of memory will fail the function
  3292. //
  3293. dwErr = XMLPersistTargetMachine( PolicyUrl, pwszTargetMachine );
  3294. _JumpIfWinError(dwErr, &hr, error, "XMLPersistTargetMachine");
  3295. }
  3296. hr = S_OK;
  3297. error:
  3298. //free
  3299. if (NULL != pXMLPersistContext)
  3300. {
  3301. if (NULL != pXMLPersistContext->pDoc)
  3302. {
  3303. pXMLPersistContext->pDoc->Release();
  3304. }
  3305. AzpFreeHeap(pXMLPersistContext);
  3306. }
  3307. if (NULL != bstrEmptyPolicy)
  3308. {
  3309. SysFreeString(bstrEmptyPolicy);
  3310. }
  3311. return AzpHresultToWinStatus( hr );
  3312. }
  3313. DWORD
  3314. XMLPersistOpen(
  3315. IN LPCWSTR PolicyUrl,
  3316. IN AZPE_OBJECT_HANDLE pAzAuthorizationStore,
  3317. IN ULONG lPersistFlags,
  3318. IN BOOL fCreatePolicy,
  3319. OUT PAZPE_PERSIST_CONTEXT PersistContext,
  3320. OUT LPWSTR *pwszTargetMachine
  3321. )
  3322. /*++
  3323. Routine Description:
  3324. This routine submits reads the authz policy database from storage.
  3325. This routine also reads the policy database into cache.
  3326. On Success, the caller should call XMLPersistClose to free any resources
  3327. consumed by the open.
  3328. On entry, AzAuthorizationStore->PersistCritSect must be locked.
  3329. Arguments:
  3330. PolicyUrl - Specifies the location of the policy store
  3331. pAzAuthorizationStore - Specifies the policy database that is to be read.
  3332. lPersistFlags - lPersistFlags from the persist engine describing the operation
  3333. AZPE_FLAGS_PERSIST_OPEN - Call is the original AzInitialize
  3334. AZPE_FLAGS_PERSIST_UPDATE_CACHE - Call is an AzUpdateCache
  3335. fCreatePolicy - TRUE if the policy database is to be created.
  3336. FALSE if the policy database already exists
  3337. PersistContext - On Success, returns a context that should be passed on all
  3338. subsequent calls.
  3339. The caller should call XMLPersistClose to free this context.
  3340. pwszTargetMachine - pointer to the target machine name where account resolution
  3341. should occur. This should be the machine where the ldap data
  3342. is stored.
  3343. Return Value:
  3344. NO_ERROR - The operation was successful
  3345. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  3346. Other status codes
  3347. --*/
  3348. {
  3349. AZASSERT(AZPE_FLAGS_PERSIST_OPEN & lPersistFlags);
  3350. //
  3351. // must be freed
  3352. //
  3353. LPWSTR pwszFilePolUrl = NULL;
  3354. DWORD dwErr;
  3355. // our persist layer has determined that this is an XML policy. That means the
  3356. // URL must have the MSXML prefix and ':' following it.
  3357. if (_wcsnicmp( AZ_XML_PROVIDER_NAME, PolicyUrl, AZ_XML_PROVIDER_NAME_LENGTH) == 0) {
  3358. if (PolicyUrl[AZ_XML_PROVIDER_NAME_LENGTH] == L':')
  3359. {
  3360. PolicyUrl += AZ_XML_PROVIDER_NAME_LENGTH;
  3361. }
  3362. else
  3363. {
  3364. // this shouldn't have happened
  3365. AZASSERT(FALSE);
  3366. dwErr = ERROR_INVALID_NAME;
  3367. _JumpError(dwErr, error, "Improper MSXML URL");
  3368. }
  3369. }
  3370. else
  3371. {
  3372. // this shouldn't have happened
  3373. AZASSERT(FALSE);
  3374. dwErr = ERROR_INVALID_NAME;
  3375. _JumpError(dwErr, error, "XML provider is invoked without proper MSXML prefix");
  3376. }
  3377. // we will prefix the policy url using file: so that we can rely on file: protocol
  3378. // to handle the validity or the url.
  3379. LPCWSTR wchFileUrl = L"file";
  3380. SafeAllocaAllocate(pwszFilePolUrl, ( wcslen(wchFileUrl) + wcslen(PolicyUrl) + 1) * sizeof(WCHAR) );
  3381. if (pwszFilePolUrl == NULL)
  3382. {
  3383. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  3384. _JumpError(dwErr, error, "SafeAllocaAllocate");
  3385. }
  3386. memcpy(pwszFilePolUrl, wchFileUrl, wcslen(wchFileUrl) * sizeof(WCHAR));
  3387. memcpy(pwszFilePolUrl + wcslen(wchFileUrl), PolicyUrl, (wcslen(PolicyUrl) + 1) * sizeof(WCHAR));
  3388. WCHAR wszDosPath[MAX_PATH + 1];
  3389. DWORD dwPathLen = MAX_PATH + 1;
  3390. //
  3391. // PathCreateFromUrl will convert a file protocol URL (file:///<path>) to a dos path
  3392. // There are several gotchas:
  3393. // (1) A wellformed file URL should use 3 slashes, not 2.
  3394. // (2) However, as far as the path portion has no encodings, two slashes will work.
  3395. // (3) If you want to use encoding, then you have to use "msxml:///<path>" with 3 slashes!
  3396. //
  3397. dwErr = AzpHresultToWinStatus(PathCreateFromUrl(pwszFilePolUrl, wszDosPath, &dwPathLen, 0));
  3398. if (dwErr != NO_ERROR)
  3399. {
  3400. if (dwPathLen > MAX_PATH + 1)
  3401. {
  3402. dwErr = ERROR_INVALID_NAME;
  3403. }
  3404. _JumpError(dwErr, error, "PathCreateFromUrl");
  3405. }
  3406. else if (dwPathLen == 0)
  3407. {
  3408. dwErr = ERROR_INVALID_NAME;
  3409. _JumpError(dwErr, error, "PathCreateFromUrl");
  3410. }
  3411. //
  3412. // Call the worker routine
  3413. //
  3414. dwErr = XMLPersistOpenEx(wszDosPath,
  3415. NULL, // No old context
  3416. pAzAuthorizationStore,
  3417. lPersistFlags,
  3418. fCreatePolicy,
  3419. PersistContext,
  3420. pwszTargetMachine );
  3421. error:
  3422. if (pwszFilePolUrl != NULL)
  3423. {
  3424. SafeAllocaFree(pwszFilePolUrl);
  3425. }
  3426. return dwErr;
  3427. }
  3428. DWORD
  3429. XMLPersistUpdateCache(
  3430. IN AZPE_PERSIST_CONTEXT PersistContext,
  3431. IN ULONG lPersistFlags,
  3432. OUT ULONG * pulUpdatedFlag
  3433. )
  3434. /*++
  3435. Routine Description:
  3436. This routine updates the cache to reflect the current contents of the
  3437. policy database.
  3438. On entry, AzAuthorizationStore->PersistCritSect must be locked.
  3439. Arguments:
  3440. PersistContext - Specifies the policy database that is to be closed
  3441. lPersistFlags - lPersistFlags from the persist engine describing the operation
  3442. AZPE_FLAGS_PERSIST_UPDATE_CACHE - Call is an AzUpdateCache
  3443. pulUpdatedFlag - Passing back information whether the function call has truly
  3444. caused an update. Due to possible efficient updateCache
  3445. implementation by providers, it may decide to do nothing.
  3446. Currently, we only one bit (AZPE_FLAG_CACHE_UPDATE_STORE_LEVEL) to
  3447. indicate that the update is actually carried out.
  3448. Return Value:
  3449. NO_ERROR - The operation was successful
  3450. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  3451. Other status codes
  3452. --*/
  3453. {
  3454. AZP_XML_CONTEXT *pXMLPersistContext = (AZP_XML_CONTEXT *)PersistContext;
  3455. //
  3456. // Call the worker routine
  3457. //
  3458. AZASSERT(AZPE_FLAGS_PERSIST_UPDATE_CACHE & lPersistFlags);
  3459. AZASSERT( pXMLPersistContext != NULL );
  3460. AZASSERT( pulUpdatedFlag != NULL );
  3461. //
  3462. // assume no update at all
  3463. //
  3464. *pulUpdatedFlag = 0;
  3465. BOOL bNeedUpdate;
  3466. DWORD dwStatus = myXmlStoreHasUpdate(pXMLPersistContext, &bNeedUpdate);
  3467. if (dwStatus != NO_ERROR)
  3468. {
  3469. _JumpError(dwStatus, error, "myXmlStoreHasUpdate");
  3470. }
  3471. else if (bNeedUpdate)
  3472. {
  3473. dwStatus = XMLPersistOpenEx( pXMLPersistContext->pwszPolicyUrl,
  3474. pXMLPersistContext,
  3475. pXMLPersistContext->hAzAuthorizationStore,
  3476. lPersistFlags,
  3477. FALSE, // Don't create the store
  3478. NULL,
  3479. NULL ); // Don't return a new persist context
  3480. if (NO_ERROR == dwStatus)
  3481. {
  3482. *pulUpdatedFlag = AZPE_FLAG_CACHE_UPDATE_STORE_LEVEL;
  3483. }
  3484. }
  3485. error:
  3486. return dwStatus;
  3487. }
  3488. VOID
  3489. XMLPersistClose(
  3490. IN AZPE_PERSIST_CONTEXT PersistContext
  3491. )
  3492. /*++
  3493. Routine Description:
  3494. This routine submits close the authz policy database storage handles.
  3495. On entry, AzAuthorizationStore->PersistCritSect must be locked.
  3496. Arguments:
  3497. PersistContext - Specifies the policy database that is to be closed
  3498. Return Value:
  3499. NO_ERROR - The operation was successful
  3500. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  3501. Other status codes
  3502. --*/
  3503. {
  3504. AZP_XML_CONTEXT *pPersistContext = (AZP_XML_CONTEXT *)PersistContext;
  3505. AZASSERT(pPersistContext != NULL);
  3506. // release xml doc
  3507. pPersistContext->pDoc->Release();
  3508. // free the context itself
  3509. AzpFreeHeap(pPersistContext);
  3510. }
  3511. DWORD
  3512. XMLPersistDelete(
  3513. IN LPCWSTR PolicyUrl)
  3514. {
  3515. DWORD dwErr = NO_ERROR;
  3516. AZASSERT(NULL != PolicyUrl);
  3517. // delete xml store is simple
  3518. if (!DeleteFile( PolicyUrl))
  3519. {
  3520. dwErr = GetLastError();
  3521. }
  3522. return dwErr;
  3523. }
  3524. //
  3525. // implementation of updating xml store from az objects
  3526. //
  3527. HRESULT
  3528. myXmlGetNodeByAttribute(
  3529. IN LPCWSTR pwszAtt,
  3530. IN LPCWSTR pwszValue,
  3531. IN IXMLDOMNodeList *pNodeList,
  3532. OUT IXMLDOMNode **ppNode)
  3533. /*
  3534. find a node from a node list matching by given attribute's value.
  3535. IN: pwszAtt, the name of the attribute on which the lookup will be based on.
  3536. IN: pwszValue, the value of the attribute which we are looking for.
  3537. IN: pNodeList, interface pointer to a list of nodes
  3538. OUT: ppNode, the matched node
  3539. */
  3540. {
  3541. HRESULT hr;
  3542. LONG lLength;
  3543. LONG i;
  3544. IXMLDOMNode *pNode = NULL;
  3545. WCHAR *pwszXmlAttrValue = NULL;
  3546. AZASSERT(NULL != pwszAtt &&
  3547. NULL != pwszValue &&
  3548. NULL != pNodeList &&
  3549. NULL != ppNode);
  3550. // init
  3551. *ppNode = NULL;
  3552. // get length of the list
  3553. hr = pNodeList->get_length(&lLength);
  3554. _JumpIfError(hr, error, "pNodeList->get_length");
  3555. if (0 == lLength)
  3556. {
  3557. // not found anything
  3558. hr = AZ_HRESULT(ERROR_NOT_FOUND);
  3559. _JumpError(hr, error, "not found any node children");
  3560. }
  3561. // go through the list and retrieve guid attribute
  3562. for (i = 0; i < lLength; ++i)
  3563. {
  3564. hr = pNodeList->get_item(i, &pNode);
  3565. _JumpIfError(hr, error, "pNodeList->get_item");
  3566. AZASSERT(NULL != pNode);
  3567. // get guid attribute value
  3568. hr = myXmlGetNodeAttribute(
  3569. pNode,
  3570. pwszAtt,
  3571. &pwszXmlAttrValue);
  3572. _JumpIfError(hr, error, "myXmlGetNodeAttribute(guid)");
  3573. // see if match, use case sensitive comp
  3574. if (0 == _wcsicmp(pwszValue, pwszXmlAttrValue))
  3575. {
  3576. // ok, this is the node, return
  3577. *ppNode = pNode;
  3578. pNode = NULL;
  3579. break;
  3580. }
  3581. // free for next in loop
  3582. pNode->Release();
  3583. pNode = NULL;
  3584. AzpFreeHeap(pwszXmlAttrValue);
  3585. pwszXmlAttrValue = NULL;
  3586. }
  3587. if (NULL == *ppNode)
  3588. {
  3589. hr = AZ_HRESULT(ERROR_NOT_FOUND);
  3590. _JumpError(hr, error, "not found matched node");
  3591. }
  3592. hr = S_OK;
  3593. error:
  3594. if (NULL != pNode)
  3595. {
  3596. pNode->Release();
  3597. }
  3598. if (NULL != pwszXmlAttrValue)
  3599. {
  3600. AzpFreeHeap(pwszXmlAttrValue);
  3601. }
  3602. return hr;
  3603. }
  3604. HRESULT
  3605. myXmlGetNodeListByXPath(
  3606. IN IXMLDOMDocument2 *pDoc,
  3607. IN WCHAR const *pwszQuery,
  3608. OUT IXMLDOMNodeList **ppList)
  3609. {
  3610. HRESULT hr;
  3611. BSTR bstrQuery = NULL;
  3612. BSTR bstrSelectionLanguage = NULL;
  3613. BOOL fChangedSL = FALSE;
  3614. IXMLDOMNodeList *pList = NULL;
  3615. VARIANT varDefSelectionLanguage;
  3616. VARIANT varSelectionLanguage;
  3617. VARIANT varXPath;
  3618. AZASSERT(NULL != pDoc &&
  3619. NULL != pwszQuery &&
  3620. 0x0 != pwszQuery[0] &&
  3621. NULL != ppList);
  3622. //init
  3623. VariantInit(&varDefSelectionLanguage);
  3624. VariantInit(&varSelectionLanguage);
  3625. VariantInit(&varXPath);
  3626. // convert query to bstr
  3627. bstrQuery = SysAllocString(pwszQuery);
  3628. _JumpIfOutOfMemory(&hr, error, bstrQuery, "SysAllocString");
  3629. bstrSelectionLanguage = SysAllocString(AZ_XML_SELECTION_LANGUAGE);
  3630. _JumpIfOutOfMemory(&hr, error, bstrSelectionLanguage, "SysAllocString");
  3631. // get default selection language
  3632. hr = pDoc->getProperty(
  3633. bstrSelectionLanguage,
  3634. &varDefSelectionLanguage);
  3635. _JumpIfError(hr, error, "pDoc->getProperty(SelectionLanguage)");
  3636. AzPrint((AZD_XML, "default SelectionLanguage=%ws\n", V_BSTR(&varDefSelectionLanguage)));
  3637. hr = myWszToBstrVariant(
  3638. AZ_XML_XPATH,
  3639. &varXPath);
  3640. _JumpIfError(hr, error, "myWszToBstrVariant");
  3641. // change selection language to xpath
  3642. hr = pDoc->setProperty(
  3643. bstrSelectionLanguage,
  3644. varXPath);
  3645. _JumpIfError(hr, error, "pDoc->setProperty(SelectionLanguage)");
  3646. fChangedSL = TRUE;
  3647. // now looking for all nodes that match the xpath pattern
  3648. hr = pDoc->selectNodes(
  3649. bstrQuery,
  3650. &pList);
  3651. _JumpIfError(hr, error, "pDoc->selectNodes");
  3652. AZASSERT(NULL != pList);
  3653. //return
  3654. *ppList = pList;
  3655. pList = NULL;
  3656. hr = S_OK;
  3657. error:
  3658. // keep the following as the 1st
  3659. if (fChangedSL)
  3660. {
  3661. HRESULT hr2;
  3662. // restore the original Selection Language
  3663. hr2 = pDoc->setProperty(
  3664. bstrSelectionLanguage,
  3665. varDefSelectionLanguage);
  3666. _PrintIfError(hr2, "pDoc->getProperty(SelectionLanguage)");
  3667. }
  3668. if (NULL != bstrQuery)
  3669. {
  3670. SysFreeString(bstrQuery);
  3671. }
  3672. if (NULL != bstrSelectionLanguage)
  3673. {
  3674. SysFreeString(bstrSelectionLanguage);
  3675. }
  3676. if (NULL != pList)
  3677. {
  3678. pList->Release();
  3679. }
  3680. VariantClear(&varDefSelectionLanguage);
  3681. VariantClear(&varSelectionLanguage);
  3682. VariantClear(&varXPath);
  3683. return hr;
  3684. }
  3685. HRESULT
  3686. myXmlRemoveAllLinks(
  3687. IN IXMLDOMDocument2 *pDoc,
  3688. IN WCHAR const *pwszLinkTag,
  3689. IN GUID *pGuid)
  3690. {
  3691. HRESULT hr;
  3692. WCHAR *pwszGuid = NULL;
  3693. WCHAR *pwszQuery = NULL;
  3694. IXMLDOMNodeList *pList = NULL;
  3695. IXMLDOMNode *pNode = NULL;
  3696. IXMLDOMNode *pParentNode = NULL;
  3697. LONG lLength;
  3698. LONG i;
  3699. AZASSERT(NULL != pGuid &&
  3700. NULL != pDoc &&
  3701. NULL != pwszLinkTag);
  3702. //init
  3703. // convert guid to string guid to form xpath query
  3704. hr = UuidToString(pGuid, &pwszGuid);
  3705. _JumpIfError(hr, error, "UuidToString");
  3706. // query is in a pattern of //LinkTag[.="guid"]
  3707. // for example, query OperationLink,
  3708. // //OperationLink[.="25a63179-3663-4aa7-b0b8-48ca084d0747"]
  3709. // in which "//[.=""]" has 8 chars
  3710. pwszQuery = (WCHAR*)AzpAllocateHeap(
  3711. (wcslen(pwszLinkTag) + wcslen(pwszGuid) + 9) * sizeof(WCHAR), "XMQRY" );
  3712. _JumpIfOutOfMemory(&hr, error, pwszQuery, "AzpAllocateHeap");
  3713. wsprintf(pwszQuery, L"//%s[.=\"%s\"]", pwszLinkTag, pwszGuid);
  3714. AzPrint((AZD_XML, "XPath query(link delete)=%ws\n", pwszQuery));
  3715. hr = myXmlGetNodeListByXPath(
  3716. pDoc,
  3717. pwszQuery,
  3718. &pList);
  3719. _JumpIfError(hr, error, "myXmlGetNodeListByXPath");
  3720. // get length of the list
  3721. hr = pList->get_length(&lLength);
  3722. _JumpIfError(hr, error, "pList->get_length");
  3723. if (0 < lLength)
  3724. {
  3725. // delete all of them because linked node is gone
  3726. for (i = 0; i < lLength; ++i)
  3727. {
  3728. hr = pList->get_item(i, &pNode);
  3729. _JumpIfError(hr, error, "pList->get_item");
  3730. AZASSERT(NULL != pNode);
  3731. // get parent
  3732. hr = pNode->get_parentNode(&pParentNode);
  3733. _JumpIfError(hr, error, "pNode->get_ParentNode");
  3734. AZASSERT(NULL != pParentNode);
  3735. // now delete the node
  3736. hr = pParentNode->removeChild(
  3737. pNode,
  3738. NULL); //no return needed
  3739. _JumpIfError(hr, error, "pParentNode->removeChild");
  3740. // free for the next
  3741. pNode->Release();
  3742. pNode = NULL;
  3743. pParentNode->Release();
  3744. pParentNode = NULL;
  3745. }
  3746. }
  3747. hr = S_OK;
  3748. error:
  3749. if (NULL != pwszGuid)
  3750. {
  3751. RpcStringFree(&pwszGuid);
  3752. }
  3753. if (NULL != pwszQuery)
  3754. {
  3755. AzpFreeHeap(pwszQuery);
  3756. }
  3757. if (NULL != pNode)
  3758. {
  3759. pNode->Release();
  3760. }
  3761. if (NULL != pParentNode)
  3762. {
  3763. pParentNode->Release();
  3764. }
  3765. if (NULL != pList)
  3766. {
  3767. pList->Release();
  3768. }
  3769. return hr;
  3770. }
  3771. HRESULT
  3772. myXmlDeleteElement(
  3773. IN IXMLDOMNode *pParentNode,
  3774. IN WCHAR const *pwszElementTag,
  3775. IN WCHAR const *pwszElementData)
  3776. /*
  3777. Description:
  3778. delete a element from the node
  3779. Argument:
  3780. pDoc - doc root handle
  3781. pParentNode - node handle of the parent of the element
  3782. pwszElementTag - element tag
  3783. pwszElementData - element data
  3784. Return:
  3785. */
  3786. {
  3787. HRESULT hr;
  3788. BSTR bstrElementTag = NULL;
  3789. BSTR bstrElementData = NULL;
  3790. IXMLDOMNodeList *pNodeList = NULL;
  3791. IXMLDOMNode *pNode = NULL;
  3792. LONG lLength;
  3793. LONG i;
  3794. // let's find the element first
  3795. // convert to bstr
  3796. bstrElementTag= SysAllocString(pwszElementTag);
  3797. _JumpIfOutOfMemory(&hr, error, bstrElementTag, "SysAllocString");
  3798. // get all matched nodes, should be just one though
  3799. hr = pParentNode->selectNodes(
  3800. bstrElementTag,
  3801. &pNodeList);
  3802. _JumpIfError(hr, error, "pParentNode->selectNodes");
  3803. // get length
  3804. hr = pNodeList->get_length(&lLength);
  3805. _JumpIfError(hr, error, "pNodeList->get_length");
  3806. for (i = 0; i < lLength; ++i)
  3807. {
  3808. // get the node handle
  3809. hr = pNodeList->get_item(i, &pNode);
  3810. _JumpIfError(hr, error, "pNodeList->get_item");
  3811. // get element text
  3812. hr = pNode->get_text(&bstrElementData);
  3813. _JumpIfError(hr, error, "pNode->get_text");
  3814. // use case insensitive compare because
  3815. // all links are guid or sid, hex number is case insesitive
  3816. if (0 == _wcsicmp(pwszElementData, bstrElementData))
  3817. {
  3818. // found it
  3819. hr = pParentNode->removeChild(pNode, NULL);
  3820. _JumpIfError(hr, error, "pParentNode->removeChild");
  3821. //done, out for loop
  3822. goto done;
  3823. }
  3824. // free for next
  3825. pNode->Release();
  3826. pNode = NULL;
  3827. SysFreeString(bstrElementData);
  3828. bstrElementData = NULL;
  3829. }
  3830. // if not found, error?
  3831. AzPrint((AZD_XML, "Not found %s under tag %ws\n", pwszElementData));
  3832. done:
  3833. hr = S_OK;
  3834. error:
  3835. if (NULL != pNodeList)
  3836. {
  3837. pNodeList->Release();
  3838. }
  3839. if (NULL != pNode)
  3840. {
  3841. pNode->Release();
  3842. }
  3843. if (NULL != bstrElementTag)
  3844. {
  3845. SysFreeString(bstrElementTag);
  3846. }
  3847. if (NULL != bstrElementData)
  3848. {
  3849. SysFreeString(bstrElementData);
  3850. }
  3851. return hr;
  3852. }
  3853. HRESULT
  3854. myXmlAddElement(
  3855. IN IXMLDOMDocument2 *pDoc,
  3856. IN IXMLDOMNode *pParentNode,
  3857. IN WCHAR const *pwszElementTag,
  3858. IN WCHAR const *pwszElementData)
  3859. /*
  3860. Description:
  3861. add a new element and set data
  3862. Argument:
  3863. pDoc - doc root handle
  3864. pParentNode - node handle of the parent of the element
  3865. pwszElementTag - element tag
  3866. pwszElementData - element data
  3867. Return:
  3868. */
  3869. {
  3870. HRESULT hr;
  3871. IXMLDOMNode *pDocElementNode = NULL;
  3872. BSTR bstrElementTag = NULL;
  3873. BSTR bstrElementData = NULL;
  3874. // convert tag to bstr
  3875. bstrElementTag = SysAllocString(pwszElementTag);
  3876. _JumpIfOutOfMemory(&hr, error, bstrElementTag, "SysAllocString");
  3877. // create new empty element node
  3878. hr = pDoc->createElement(
  3879. bstrElementTag,
  3880. (IXMLDOMElement**)&pDocElementNode);
  3881. _JumpIfError(hr, error, "pDoc->createElement");
  3882. AZASSERT(NULL != pDocElementNode);
  3883. // convert element value to bstr
  3884. bstrElementData = SysAllocString(pwszElementData);
  3885. _JumpIfOutOfMemory(&hr, error, bstrElementData, "SysAllocString");
  3886. // now let's set member value
  3887. hr = pDocElementNode->put_text(bstrElementData);
  3888. _JumpIfError(hr, error, "pDocElementNode->put_text");
  3889. // attach to the right parent
  3890. hr = pParentNode->appendChild(
  3891. pDocElementNode,
  3892. NULL); //don't need return
  3893. _JumpIfError(hr, error, "pParentNode->appendChild");
  3894. hr = S_OK;
  3895. error:
  3896. if (NULL != pDocElementNode)
  3897. {
  3898. pDocElementNode->Release();
  3899. }
  3900. if (NULL != bstrElementTag)
  3901. {
  3902. SysFreeString(bstrElementTag);
  3903. }
  3904. if (NULL != bstrElementData)
  3905. {
  3906. SysFreeString(bstrElementData);
  3907. }
  3908. return hr;
  3909. }
  3910. HRESULT
  3911. myXmlUpdateSingleElement(
  3912. IN IXMLDOMDocument2 *pDoc,
  3913. IN IXMLDOMNode *pParentNode,
  3914. IN WCHAR const *pwszElementTag,
  3915. IN WCHAR const *pwszElementData)
  3916. /*
  3917. Description:
  3918. if named element tag exists, update with new data
  3919. otherwise create a new element with the data
  3920. Arguments:
  3921. pDoc - doc root handle
  3922. pParentNode - node handle of the parent of the element
  3923. pwszElementTag - element tag
  3924. pwszElementData - element data
  3925. Return:
  3926. */
  3927. {
  3928. HRESULT hr;
  3929. BSTR bstrElementTag = NULL;
  3930. BSTR bstrElementData = NULL;
  3931. IXMLDOMNodeList *pNodeList = NULL;
  3932. IXMLDOMNode *pNode = NULL;
  3933. LONG lLength;
  3934. AZASSERT(NULL != pDoc &&
  3935. NULL != pParentNode &&
  3936. NULL != pwszElementTag &&
  3937. NULL != pwszElementData);
  3938. // let's find the element first
  3939. // convert to bstr
  3940. bstrElementTag= SysAllocString(pwszElementTag);
  3941. _JumpIfOutOfMemory(&hr, error, bstrElementTag, "SysAllocString");
  3942. // get all matched nodes, should be just one though
  3943. hr = pParentNode->selectNodes(
  3944. bstrElementTag,
  3945. &pNodeList);
  3946. _JumpIfError(hr, error, "pParentNode->selectNodes");
  3947. AZASSERT(NULL != pNodeList);
  3948. // get length
  3949. hr = pNodeList->get_length(&lLength);
  3950. _JumpIfError(hr, error, "pNodeList->get_length");
  3951. if (1 < lLength)
  3952. {
  3953. // should be single occurence
  3954. hr = E_INVALIDARG;
  3955. _JumpError(hr, error, "invalid mutliple occurence");
  3956. }
  3957. if (1 == lLength)
  3958. {
  3959. // get node to do update
  3960. hr = pNodeList->get_item(0, &pNode);
  3961. _JumpIfError(hr, error, "pNodeList->get_item");
  3962. if (_wcsicmp(pwszElementTag, AZ_XML_TAG_BIZRULE) == 0 &&
  3963. (pwszElementData == NULL || wcslen(pwszElementData) == 0) )
  3964. {
  3965. //
  3966. // For BizRule, an empty string means that we will remove
  3967. // this element. Leaving this element will mean that this is a
  3968. // blank BizRule, which is quite different as no BizRule
  3969. //
  3970. hr = pParentNode->removeChild(pNode, NULL);
  3971. }
  3972. else
  3973. {
  3974. // convert to bstr
  3975. bstrElementData= SysAllocString(pwszElementData);
  3976. _JumpIfOutOfMemory(&hr, error, bstrElementData, "SysAllocString");
  3977. hr = pNode->put_text(bstrElementData);
  3978. _JumpIfError(hr, error, "pNode->put_text");
  3979. }
  3980. }
  3981. else
  3982. {
  3983. //must not existing
  3984. AZASSERT(0 == lLength);
  3985. hr = myXmlAddElement(
  3986. pDoc,
  3987. pParentNode,
  3988. pwszElementTag,
  3989. pwszElementData);
  3990. _JumpIfError(hr, error, "myXmlAddElement");
  3991. }
  3992. hr = S_OK;
  3993. error:
  3994. if (NULL != pNodeList)
  3995. {
  3996. pNodeList->Release();
  3997. }
  3998. if (NULL != pNode)
  3999. {
  4000. pNode->Release();
  4001. }
  4002. if (NULL != bstrElementTag)
  4003. {
  4004. SysFreeString(bstrElementTag);
  4005. }
  4006. if (NULL != bstrElementData)
  4007. {
  4008. SysFreeString(bstrElementData);
  4009. }
  4010. return hr;
  4011. }
  4012. #if DBG
  4013. void myDbgPrintDeltaEntry (PAZP_DELTA_ENTRY DeltaEntry)
  4014. {
  4015. AzPrint((AZD_XML, "DeltaFlags=0x%x\n", DeltaEntry->DeltaFlags));
  4016. if ((DeltaEntry->DeltaFlags & AZP_DELTA_SID) == 0)
  4017. {
  4018. AzpDumpGuid(AZD_XML, &DeltaEntry->Guid );
  4019. AzPrint(( AZD_XML, "\n" ));
  4020. }
  4021. else
  4022. {
  4023. char *pszSid = NULL;
  4024. if (ConvertSidToStringSidA(DeltaEntry->Sid, &pszSid))
  4025. {
  4026. AzPrint((AZD_XML, "Sid=%s\n", pszSid));
  4027. LocalFree(pszSid);
  4028. }
  4029. }
  4030. }
  4031. #endif //DBG
  4032. HRESULT
  4033. myXmlSubmitObjectElements(
  4034. IN IXMLDOMDocument2 *pDoc,
  4035. IN ULONG lPersistFlags,
  4036. IN IXMLDOMNode *pParentNode,
  4037. IN WCHAR const *pwszElementTag,
  4038. IN ENUM_AZ_DATATYPE DataType,
  4039. IN AZPE_OBJECT_HANDLE hObject,
  4040. IN ULONG lPropertyId)
  4041. /*
  4042. Description:
  4043. update all element data under a node
  4044. all element data are retrieved from az object GetProperty method
  4045. Arguments:
  4046. pDoc - root node for creation
  4047. lPersistFlags - flags from the persist engine
  4048. pParentNode - az object node under which the elements are updated
  4049. DataType - ENUM_AZ_ data type, it handles long, str, str/sid array
  4050. hObject - az object handle
  4051. lPropertyId - property id for GetProperty
  4052. Return:
  4053. */
  4054. {
  4055. HRESULT hr;
  4056. DWORD dwErr;
  4057. PVOID pElements = NULL;
  4058. WCHAR wszId[20];
  4059. BOOL fSid = FALSE;
  4060. BOOL fGuid = FALSE;
  4061. BOOL fList = FALSE;
  4062. ULONG i;
  4063. PAZP_DELTA_ENTRY DeltaEntry;
  4064. WCHAR *pwszElementData;
  4065. WCHAR *pwszSid = NULL;
  4066. WCHAR *pwszGuid = NULL;
  4067. ULONG DeltaArrayCount;
  4068. PAZP_DELTA_ENTRY *DeltaArray;
  4069. AZASSERT(NULL != pDoc &&
  4070. NULL != pParentNode &&
  4071. NULL != pwszElementTag &&
  4072. NULL != hObject);
  4073. //init
  4074. // handle different type of elements
  4075. switch (DataType)
  4076. {
  4077. case ENUM_AZ_BSTR:
  4078. dwErr = XmlAzrolesInfo->AzpeGetProperty(
  4079. hObject,
  4080. lPersistFlags,
  4081. lPropertyId,
  4082. &pElements);
  4083. _JumpIfWinError(dwErr, &hr, error, "AzpeGetProperty");
  4084. AZASSERT(NULL != pElements);
  4085. hr = myXmlUpdateSingleElement(
  4086. pDoc,
  4087. pParentNode,
  4088. pwszElementTag,
  4089. (WCHAR*)pElements);
  4090. _JumpIfError(hr, error, "myXmlUpdateSingleElement(ENUM_AZ_BSTR)");
  4091. break;
  4092. case ENUM_AZ_LONG:
  4093. dwErr = XmlAzrolesInfo->AzpeGetProperty(
  4094. hObject,
  4095. lPersistFlags,
  4096. lPropertyId,
  4097. &pElements);
  4098. _JumpIfWinError(dwErr, &hr, error, "AzpeGetProperty");
  4099. AZASSERT(NULL != pElements);
  4100. wsprintf(wszId, L"%d", *((LONG*)pElements));
  4101. hr = myXmlUpdateSingleElement(
  4102. pDoc,
  4103. pParentNode,
  4104. pwszElementTag,
  4105. wszId);
  4106. _JumpIfError(hr, error, "myXmlUpdateSingleElement(ENUM_AZ_LONG)");
  4107. break;
  4108. case ENUM_AZ_SID_ARRAY:
  4109. fSid = TRUE;
  4110. fList = TRUE;
  4111. break;
  4112. case ENUM_AZ_GUID_ARRAY:
  4113. fGuid = TRUE;
  4114. fList = TRUE;
  4115. break;
  4116. default:
  4117. hr = E_INVALIDARG;
  4118. _JumpError(hr, error, "internal error: invalid data type");
  4119. }
  4120. if (fList)
  4121. {
  4122. dwErr = XmlAzrolesInfo->AzpeGetDeltaArray(
  4123. hObject,
  4124. lPropertyId,
  4125. &DeltaArrayCount,
  4126. &DeltaArray );
  4127. _JumpIfWinError(dwErr, &hr, error, "AzpeGetDeltaArray");
  4128. for (i = 0; i < DeltaArrayCount; ++i)
  4129. {
  4130. // get delta entry
  4131. DeltaEntry = DeltaArray[i];
  4132. #if DBG
  4133. myDbgPrintDeltaEntry(DeltaEntry);
  4134. #endif //DBG
  4135. // convert linked object id to string
  4136. if (fSid)
  4137. {
  4138. AZASSERT(0x0 != (AZP_DELTA_SID & DeltaEntry->DeltaFlags));
  4139. // convert sid to string sid
  4140. if (!ConvertSidToStringSid(
  4141. DeltaEntry->Sid,
  4142. &pwszSid))
  4143. {
  4144. AZ_HRESULT_LASTERROR(&hr);
  4145. _JumpError(hr, error, "ConvertSidToStringSid");
  4146. }
  4147. AZASSERT(NULL != pwszSid);
  4148. pwszElementData = pwszSid;
  4149. }
  4150. else
  4151. {
  4152. //must be guid
  4153. AZASSERT(fGuid);
  4154. hr = UuidToString(
  4155. &DeltaEntry->Guid,
  4156. &pwszGuid);
  4157. _JumpIfError(hr, error, "UuidToString");
  4158. AZASSERT(NULL != pwszGuid);
  4159. pwszElementData = pwszGuid;
  4160. }
  4161. if (0x0 != (AZP_DELTA_ADD & DeltaEntry->DeltaFlags))
  4162. {
  4163. // this is add case
  4164. hr = myXmlAddElement(
  4165. pDoc,
  4166. pParentNode,
  4167. pwszElementTag,
  4168. pwszElementData);
  4169. _JumpIfError(hr, error, "myXmlAddElement");
  4170. }
  4171. else
  4172. {
  4173. // this is delete case
  4174. hr = myXmlDeleteElement(
  4175. pParentNode,
  4176. pwszElementTag,
  4177. pwszElementData);
  4178. _JumpIfError(hr, error, "myXmlDeleteElement");
  4179. }
  4180. // free for next in loop
  4181. if (fSid)
  4182. {
  4183. AZASSERT(NULL != pwszSid);
  4184. LocalFree(pwszSid);
  4185. pwszSid = NULL;
  4186. }
  4187. else if (fGuid)
  4188. {
  4189. AZASSERT(NULL != pwszGuid);
  4190. RpcStringFree(&pwszGuid);
  4191. pwszGuid = NULL;
  4192. }
  4193. }
  4194. }
  4195. hr = S_OK;
  4196. error:
  4197. if (NULL != pElements)
  4198. {
  4199. XmlAzrolesInfo->AzpeFreeMemory(pElements);
  4200. }
  4201. if (NULL != pwszSid)
  4202. {
  4203. LocalFree(pwszSid);
  4204. }
  4205. if (NULL != pwszGuid)
  4206. {
  4207. RpcStringFree(&pwszGuid);
  4208. }
  4209. return hr;
  4210. }
  4211. HRESULT
  4212. myXmlFindChildNodeByGuid(
  4213. IN IXMLDOMNode *pParentNode,
  4214. IN WCHAR const *pwszChildTag,
  4215. IN GUID *pGuid,
  4216. OUT IXMLDOMNode **ppChildNode)
  4217. /*
  4218. find a child node by matched guid attribute
  4219. IN: pParentNode, parent node from which to do searching
  4220. IN: pwszChildTag, node tag for searching
  4221. IN: pGuid, guid for attribute matching
  4222. OUT: ppChildNode, return node
  4223. */
  4224. {
  4225. HRESULT hr;
  4226. BSTR bstrChildTag = NULL;
  4227. IXMLDOMNode *pChildNode = NULL;
  4228. IXMLDOMNodeList *pChildList = NULL;
  4229. PWSTR pwszGuid = NULL;
  4230. AZASSERT(NULL != pParentNode &&
  4231. NULL != pwszChildTag &&
  4232. NULL != pGuid &&
  4233. NULL != ppChildNode);
  4234. // create child tag in bstr any way
  4235. bstrChildTag = SysAllocString(pwszChildTag);
  4236. _JumpIfOutOfMemory(&hr, error, bstrChildTag, "SysAllocString");
  4237. // get list of all children
  4238. hr = pParentNode->selectNodes(
  4239. bstrChildTag,
  4240. &pChildList);
  4241. _JumpIfError(hr, error, "pParentNode->selectNodes");
  4242. AZASSERT(NULL != pChildList);
  4243. // ok, find the child node by guid
  4244. hr = UuidToString(pGuid, &pwszGuid);
  4245. _JumpIfError(hr, error, "UuidToString");
  4246. hr = myXmlGetNodeByAttribute(
  4247. AZ_XML_TAG_ATTR_GUID,
  4248. pwszGuid,
  4249. pChildList,
  4250. &pChildNode);
  4251. _JumpIfError(hr, error, "myXmlGetNamedGuidNode");
  4252. *ppChildNode = pChildNode;
  4253. pChildNode = NULL;
  4254. hr = S_OK;
  4255. error:
  4256. if (NULL != bstrChildTag)
  4257. {
  4258. SysFreeString(bstrChildTag);
  4259. }
  4260. if (NULL != pChildList)
  4261. {
  4262. pChildList->Release();
  4263. }
  4264. if (NULL != pChildNode)
  4265. {
  4266. pChildNode->Release();
  4267. }
  4268. if (NULL != pwszGuid)
  4269. {
  4270. RpcStringFree(&pwszGuid);
  4271. }
  4272. return hr;
  4273. }
  4274. HRESULT
  4275. myXmlDetermineParentNode(
  4276. IN IXMLDOMNode *pAzStoreNode,
  4277. IN ULONG lObjectType,
  4278. IN OPTIONAL GUID *pApplicationGuid,
  4279. IN OPTIONAL GUID *pScopeGuid,
  4280. OUT IXMLDOMNode **ppParentNode)
  4281. /*
  4282. Description:
  4283. determines the parent node of the current object.
  4284. if both pApplicationGuid and pScopeGuid are NULL,
  4285. the parent node is pAzStoreNode.
  4286. if pApplicationGuid != NULL and pScopeGuid == NULL,
  4287. the parent node is application queried by the guid.
  4288. if pApplicationGuid != NULL and pScopeGuid != NULL,
  4289. the parent node is scope queried by the both guids.
  4290. Arguments:
  4291. pAzStoreNode - top parent node
  4292. lObjectType - object type flag
  4293. pApplicationGuid - the application guid under which the object lives
  4294. pScopeGuid - the scope guid under which the object lives
  4295. Return:
  4296. ppParentNode - returned parent node, freed by Release().
  4297. */
  4298. {
  4299. HRESULT hr;
  4300. IXMLDOMNode *pApplicationNode = NULL;
  4301. IXMLDOMNode *pScopeNode = NULL;
  4302. AZASSERT(NULL != pAzStoreNode &&
  4303. NULL != ppParentNode);
  4304. // init, it can be NULL if parent is AzAuthStore
  4305. *ppParentNode = NULL;
  4306. // determine parent
  4307. if (NULL != pApplicationGuid &&
  4308. OBJECT_TYPE_APPLICATION != lObjectType)
  4309. {
  4310. hr = myXmlFindChildNodeByGuid(
  4311. pAzStoreNode,
  4312. AZ_XML_TAG_APPLICATION,
  4313. pApplicationGuid,
  4314. &pApplicationNode);
  4315. _JumpIfError(hr ,error, "myXmlFindChildNodeByGuid");
  4316. AZASSERT(NULL != pApplicationNode);
  4317. if (NULL == pScopeGuid || OBJECT_TYPE_SCOPE == lObjectType)
  4318. {
  4319. // parent must be application
  4320. *ppParentNode = pApplicationNode;
  4321. // for return
  4322. pApplicationNode = NULL;
  4323. }
  4324. else
  4325. {
  4326. // should be scope
  4327. hr = myXmlFindChildNodeByGuid(
  4328. pApplicationNode,
  4329. AZ_XML_TAG_SCOPE,
  4330. pScopeGuid,
  4331. &pScopeNode);
  4332. _JumpIfError(hr ,error, "myXmlFindChildNodeByGuid");
  4333. // oh, change parent to scope
  4334. *ppParentNode = pScopeNode;
  4335. // for return
  4336. pScopeNode = NULL;
  4337. }
  4338. }
  4339. hr = S_OK;
  4340. error:
  4341. if (NULL != pApplicationNode)
  4342. {
  4343. pApplicationNode->Release();
  4344. }
  4345. if (NULL != pScopeNode)
  4346. {
  4347. pScopeNode->Release();
  4348. }
  4349. return hr;
  4350. }
  4351. HRESULT
  4352. myXmlSubmitObject(
  4353. IN IXMLDOMDocument2 *pDoc,
  4354. IN ULONG lPersistFlags,
  4355. IN IXMLDOMNode *pAzStoreNode,
  4356. IN GUID *pApplicationGuid,
  4357. IN GUID *pScopeGuid,
  4358. IN AZPE_OBJECT_HANDLE hObject,
  4359. IN ULONG lObjectType,
  4360. IN BOOL fDelete)
  4361. /*
  4362. Description:
  4363. submit a group object into persist store
  4364. Arguments:
  4365. pDoc - root of the doc for any creation
  4366. lPersistFlags - flags from the persist engine
  4367. pAzStoreNode - AzAuthStore node handle
  4368. pApplicationGuid - application guid attribute,
  4369. if NULL, the object is under AzAuthStore. if !NULL and pScopeGuid is NULL
  4370. the object is under application
  4371. pScopeGuid - scope guid attribute, if !NULL and pApplicationGuid !NULL,
  4372. the object is under scope
  4373. hObject - az object handle
  4374. lObjectType - object index in the submit table
  4375. fDelete - TRUE will delete the object
  4376. Return:
  4377. */
  4378. {
  4379. HRESULT hr;
  4380. IXMLDOMNode *pParentTemp = NULL;
  4381. IXMLDOMNode *pParentNode;
  4382. BSTR bstrObjectTag = NULL;
  4383. IXMLDOMNode *pObjectNode = NULL;
  4384. IXMLDOMNodeList *pObjectList = NULL;
  4385. IXMLDOMNode *pDocObjectNode = NULL;
  4386. WCHAR *pwszGuid = NULL;
  4387. BOOL fNewObject = FALSE;
  4388. PWSTR pwszName = NULL;
  4389. AZASSERT(NULL != pDoc &&
  4390. NULL != pAzStoreNode &&
  4391. NULL != hObject);
  4392. //init to AzAuthStore node, it may be changed from myXmlDetermineParentNode
  4393. pParentNode = pAzStoreNode;
  4394. if (OBJECT_TYPE_AZAUTHSTORE == lObjectType)
  4395. {
  4396. // AzAuthStore object
  4397. pObjectNode = pAzStoreNode;
  4398. }
  4399. else
  4400. {
  4401. // non-AzAuthStore object
  4402. // determine parent
  4403. hr = myXmlDetermineParentNode(
  4404. pAzStoreNode,
  4405. lObjectType,
  4406. pApplicationGuid,
  4407. pScopeGuid,
  4408. &pParentTemp);
  4409. _JumpIfError(hr, error, "myXmlDetermineParentNode");
  4410. // if pParentTemp == NULL, the parent is AzAuthStore
  4411. if (NULL != pParentTemp)
  4412. {
  4413. pParentNode = pParentTemp;
  4414. }
  4415. //
  4416. // handle delate or create
  4417. //
  4418. // object tag name must be in bstr
  4419. bstrObjectTag = SysAllocString(g_SubmitLoadTable[lObjectType].pwszTag);
  4420. _JumpIfOutOfMemory(&hr, error, bstrObjectTag, "SysAllocString");
  4421. // get the list of objects under parent
  4422. hr = pParentNode->selectNodes(
  4423. bstrObjectTag,
  4424. &pObjectList);
  4425. _JumpIfError(hr, error, "pParentNode->selectNodes");
  4426. // at this point we should have a list of objects under parent
  4427. AZASSERT(NULL != pObjectList);
  4428. //
  4429. // Get the GUID string
  4430. //
  4431. hr = UuidToString(XmlAzrolesInfo->AzpePersistenceGuid(hObject), &pwszGuid);
  4432. _JumpIfError(hr, error, "UuidToString");
  4433. // search the object by guid
  4434. hr = myXmlGetNodeByAttribute(
  4435. AZ_XML_TAG_ATTR_GUID,
  4436. pwszGuid,
  4437. pObjectList,
  4438. &pObjectNode);
  4439. if (S_OK != hr && AZ_HRESULT(ERROR_NOT_FOUND) != hr)
  4440. {
  4441. _JumpIfError(hr, error, "myXmlGetNamedGuidNode");
  4442. }
  4443. //
  4444. // if we can't find the node by GUID, we need to test if we can
  4445. // find the node by name. If we do, then that is a problem because
  4446. // to our clients, name is the only identity they know even though
  4447. // internally, we recognize objects by their guids.
  4448. //
  4449. if (AZ_HRESULT(ERROR_NOT_FOUND) == hr)
  4450. {
  4451. DWORD dwErr = XmlAzrolesInfo->AzpeGetProperty(hObject, lPersistFlags, AZ_PROP_NAME, (PVOID*)&pwszName);
  4452. if (dwErr != NO_ERROR)
  4453. {
  4454. _JumpIfWinError(dwErr, &hr, error, "myXmlGetNamedGuidNode");
  4455. }
  4456. //
  4457. // We must not be able to find this node by the name if
  4458. // there is no node matching by GUID
  4459. //
  4460. hr = myXmlGetNodeByAttribute(
  4461. AZ_XML_TAG_ATTR_NAME,
  4462. pwszName,
  4463. pObjectList,
  4464. &pObjectNode);
  4465. if (S_OK == hr)
  4466. {
  4467. hr = AZ_HRESULT(ERROR_ALREADY_EXISTS);
  4468. _JumpIfError(hr, error, "myXmlGetNamedGuidNode");
  4469. }
  4470. }
  4471. AzPrint((AZD_XML, "hr = 0x%lx, pObjectNode(from myXmlGetNamedGuidNode) = 0x%lx\n", hr, pObjectNode));
  4472. AZASSERT((S_OK == hr && NULL != pObjectNode) ||
  4473. (AZ_HRESULT(ERROR_NOT_FOUND) == hr && NULL == pObjectNode));
  4474. if (fDelete)
  4475. {
  4476. if (NULL != pObjectNode)
  4477. {
  4478. hr = pParentNode->removeChild(
  4479. pObjectNode,
  4480. NULL); //remove
  4481. _JumpIfError(hr, error, "pParentNode->removeChild");
  4482. }
  4483. //else
  4484. //{
  4485. // try to delete an object not existing?
  4486. // this can be from
  4487. // this object was never submitted OR
  4488. // the store has not been refreshed and
  4489. // the object is deleted by another application
  4490. //}
  4491. if (NULL != g_SubmitLoadTable[lObjectType].rgpwszLkTag)
  4492. {
  4493. // this object can be referenced by other objects
  4494. // by removing this object, we should remove all references or links
  4495. WCHAR const * const *ppwszLinkTag;
  4496. for (ppwszLinkTag = g_SubmitLoadTable[lObjectType].rgpwszLkTag;
  4497. NULL != *ppwszLinkTag; ++ppwszLinkTag)
  4498. {
  4499. // remove link
  4500. hr = myXmlRemoveAllLinks(
  4501. pDoc,
  4502. *ppwszLinkTag,
  4503. XmlAzrolesInfo->AzpePersistenceGuid(hObject));
  4504. _JumpIfError(hr, error, "myXmlRemoveAllLinks");
  4505. }
  4506. }
  4507. // deletion, it is done
  4508. goto done;
  4509. }
  4510. else
  4511. {
  4512. if (NULL == pObjectNode)
  4513. {
  4514. //
  4515. // looks the node doesn't exist, must be a new object
  4516. //
  4517. if ( !ObjectIsDirty( hObject, AZ_DIRTY_CREATE) )
  4518. {
  4519. hr = AZ_HR_FROM_WIN32(ERROR_NOT_FOUND);
  4520. _JumpError(hr, error, "Submitting changes to a non-existent object");
  4521. }
  4522. fNewObject = TRUE;
  4523. // let's create it
  4524. hr = pDoc->createElement(
  4525. bstrObjectTag,
  4526. (IXMLDOMElement**)&pDocObjectNode);
  4527. _JumpIfError(hr, error, "pDoc->createElement");
  4528. AZASSERT(NULL != pDocObjectNode);
  4529. // attach the new node to the right parent
  4530. hr = pParentNode->appendChild(
  4531. pDocObjectNode,
  4532. &pObjectNode);
  4533. _JumpIfError(hr, error, "pParentNode->appendChild");
  4534. AzPrint((AZD_XML, "A new element node, 0x%lx, is added for %s\n", pObjectNode, bstrObjectTag));
  4535. }
  4536. // at this point, we should have object node
  4537. AZASSERT(NULL != pObjectNode);
  4538. // let's update object common data
  4539. if (fNewObject)
  4540. {
  4541. // let's set object guid
  4542. // convert guid to string guid
  4543. hr = UuidToString(
  4544. XmlAzrolesInfo->AzpePersistenceGuid(hObject),
  4545. &pwszGuid);
  4546. _JumpIfError(hr, error, "UuidToString");
  4547. AZASSERT(NULL != pwszGuid);
  4548. hr = myXmlSetNodeAttribute(
  4549. pObjectNode,
  4550. AZ_XML_TAG_ATTR_GUID,
  4551. pwszGuid,
  4552. pDoc);
  4553. _JumpIfError(hr, error, "myXmlSetNodeAttribute");
  4554. }
  4555. if (ObjectIsDirty(hObject, AZ_DIRTY_NAME))
  4556. {
  4557. // submit name
  4558. hr = myXmlSubmitObjectAttribute(
  4559. hObject,
  4560. lPersistFlags,
  4561. AZ_PROP_NAME,
  4562. ENUM_AZ_BSTR,
  4563. pObjectNode,
  4564. AZ_XML_TAG_ATTR_NAME,
  4565. pDoc);
  4566. _JumpIfError(hr, error, "myXmlSubmitObjectAttribute(name)");
  4567. }
  4568. }
  4569. }
  4570. if (ObjectIsDirty( hObject, AZ_DIRTY_DESCRIPTION))
  4571. {
  4572. // every object has description
  4573. hr = myXmlSubmitObjectAttribute(
  4574. hObject,
  4575. lPersistFlags,
  4576. AZ_PROP_DESCRIPTION,
  4577. ENUM_AZ_BSTR,
  4578. pObjectNode,
  4579. AZ_XML_TAG_ATTR_DESCRIPTION,
  4580. pDoc);
  4581. _JumpIfError(hr, error, "myXmlSubmitObjectAttribute(description)");
  4582. }
  4583. //
  4584. // submit object attributes if has
  4585. //
  4586. if (NULL != g_SubmitLoadTable[lObjectType].rgpAttrs)
  4587. {
  4588. // submit object attributes
  4589. AZ_PROP_ENTRY *pAttrs;
  4590. for (pAttrs = g_SubmitLoadTable[lObjectType].rgpAttrs;
  4591. NULL != pAttrs[0].pwszTag; ++pAttrs)
  4592. {
  4593. if (ObjectIsDirty(hObject, pAttrs[0].lDirtyBit))
  4594. {
  4595. hr = myXmlSubmitObjectAttribute(
  4596. hObject,
  4597. lPersistFlags,
  4598. pAttrs[0].lPropId,
  4599. pAttrs[0].lDataType,
  4600. pObjectNode,
  4601. pAttrs[0].pwszTag,
  4602. pDoc);
  4603. _JumpIfError(hr, error, "myXmlSubmitObjectAttribute");
  4604. }
  4605. }
  4606. }
  4607. //
  4608. // submit object elements if has
  4609. //
  4610. if (NULL != g_SubmitLoadTable[lObjectType].rgpEles)
  4611. {
  4612. // submit object elements
  4613. AZ_PROP_ENTRY *pEles;
  4614. for (pEles = g_SubmitLoadTable[lObjectType].rgpEles;
  4615. NULL != pEles[0].pwszTag; ++pEles)
  4616. {
  4617. if (ObjectIsDirty(hObject, pEles[0].lDirtyBit))
  4618. {
  4619. hr = myXmlSubmitObjectElements(
  4620. pDoc,
  4621. lPersistFlags,
  4622. pObjectNode,
  4623. pEles[0].pwszTag,
  4624. pEles[0].lDataType,
  4625. hObject,
  4626. pEles[0].lPropId);
  4627. _JumpIfError(hr, error, "myXmlSubmitObjectElements");
  4628. }
  4629. }
  4630. }
  4631. done:
  4632. hr = S_OK;
  4633. error:
  4634. if (NULL != pParentTemp)
  4635. {
  4636. pParentTemp->Release();
  4637. }
  4638. if (NULL != bstrObjectTag)
  4639. {
  4640. SysFreeString(bstrObjectTag);
  4641. }
  4642. if (OBJECT_TYPE_AZAUTHSTORE != lObjectType &&
  4643. NULL != pObjectNode &&
  4644. pObjectNode != pAzStoreNode)
  4645. {
  4646. pObjectNode->Release();
  4647. AzPrint((AZD_XML, "pObjectNode, 0x%lx, is released\n", pObjectNode));
  4648. }
  4649. if (NULL != pObjectList)
  4650. {
  4651. pObjectList->Release();
  4652. }
  4653. if (NULL != pDocObjectNode)
  4654. {
  4655. pDocObjectNode->Release();
  4656. }
  4657. if (NULL != pwszGuid)
  4658. {
  4659. RpcStringFree(&pwszGuid);
  4660. }
  4661. if (NULL != pwszName)
  4662. {
  4663. AzFreeMemory(pwszName);
  4664. }
  4665. return hr;
  4666. }
  4667. DWORD
  4668. XMLPersistSubmit(
  4669. IN AZPE_PERSIST_CONTEXT PersistContext,
  4670. IN AZPE_OBJECT_HANDLE pObj,
  4671. IN ULONG lPersistFlags,
  4672. IN BOOLEAN DeleteMe
  4673. )
  4674. /*
  4675. Description:
  4676. This routine submits changes made to the authz policy database.
  4677. If the object is being created, the GenericObject->PersistenceGuid field will be
  4678. zero on input. Upon successful creation, this routine will set PersistenceGuid to
  4679. non-zero. Upon failed creation, this routine will leave PersistenceGuid as zero.
  4680. On entry, AzAuthorizationStore->PersistCritSect must be locked.
  4681. Arguments:
  4682. PersistContext - Specifies the policy database that is to be manipulated
  4683. GenericObject - Specifies the object in the database that is to be updated
  4684. in the underlying store.
  4685. lPersistFlags - lPersistFlags from the persist engine describing the operation
  4686. AZPE_FLAGS_PERSIST_OPEN - Call is the original AzInitialize
  4687. AZPE_FLAGS_PERSIST_UPDATE_CACHE - Call is an AzUpdateCache
  4688. DeleteMe - TRUE if the object and all of its children are to be deleted.
  4689. FALSE if the object is to be updated.
  4690. Return Value:
  4691. NO_ERROR - The operation was successful
  4692. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  4693. Other status codes
  4694. */
  4695. {
  4696. HRESULT hr;
  4697. AZPE_OBJECT_HANDLE pTempObj;
  4698. GUID *pAppGuid;
  4699. GUID *pScopeGuid;
  4700. IXMLDOMDocument2 *pDoc;
  4701. IXMLDOMElement *pAzStoreNode = NULL;
  4702. AZP_XML_CONTEXT *pPersistContext;
  4703. VARIANT varPolicyUrl;
  4704. ULONG lObjectType = XmlAzrolesInfo->AzpeObjectType(pObj);
  4705. ::VariantInit(&varPolicyUrl);
  4706. AZASSERT(NULL != pObj );
  4707. // init
  4708. pPersistContext = (AZP_XML_CONTEXT*)PersistContext;
  4709. AZASSERT(NULL != pPersistContext);
  4710. pDoc = pPersistContext->pDoc;
  4711. //
  4712. // Handle deletion of the authorization store object
  4713. //
  4714. if ( lObjectType == OBJECT_TYPE_AZAUTHSTORE && DeleteMe ) {
  4715. hr = XMLPersistDelete( pPersistContext->pwszPolicyUrl );
  4716. _PrintIfError(hr, "XMLPersistDelete");
  4717. goto error;
  4718. }
  4719. // determine at what level the object is located
  4720. // by knowing pAppGuid and pScopeGuid, it can tell
  4721. // for example,
  4722. // if pAppGuid=NULL && pScopeGuid=NULL && ObjectType=Group
  4723. // it is the object under AzAuthorizationStore
  4724. // if pAppGuid!=NULL && pScopeGuid!=NULL && ObjectType=Group
  4725. // it is the object under Scope
  4726. // init
  4727. pAppGuid = NULL;
  4728. pScopeGuid = NULL;
  4729. // go from the object up to AzAuthStore level
  4730. pTempObj = pObj;
  4731. while (NULL != pTempObj)
  4732. {
  4733. ULONG TempObjectType = XmlAzrolesInfo->AzpeObjectType(pTempObj);
  4734. if (OBJECT_TYPE_AZAUTHSTORE == TempObjectType)
  4735. {
  4736. break;
  4737. }
  4738. else if (OBJECT_TYPE_APPLICATION == TempObjectType)
  4739. {
  4740. // point to application name
  4741. pAppGuid = XmlAzrolesInfo->AzpePersistenceGuid( pTempObj );
  4742. }
  4743. else if (OBJECT_TYPE_SCOPE == TempObjectType)
  4744. {
  4745. // point to scope name
  4746. pScopeGuid = XmlAzrolesInfo->AzpePersistenceGuid( pTempObj );
  4747. }
  4748. // point to the parent
  4749. pTempObj = XmlAzrolesInfo->AzpeParentOfChild( pTempObj );
  4750. }
  4751. // we will get root node any way
  4752. // get the root node, ie. the node of ploicy
  4753. hr = myXmlGetAzStoreNode(
  4754. pDoc,
  4755. &pAzStoreNode);
  4756. _JumpIfError(hr, error, "myXmlGetAzStoreNode");
  4757. AZASSERT(NULL != pAzStoreNode);
  4758. // let's check if the object has a guid
  4759. if (OBJECT_TYPE_AZAUTHSTORE != lObjectType)
  4760. {
  4761. if (IsEqualGUID( *XmlAzrolesInfo->AzpePersistenceGuid(pObj), AzGlZeroGuid))
  4762. {
  4763. hr = UuidCreate( XmlAzrolesInfo->AzpePersistenceGuid(pObj) );
  4764. _JumpIfError(hr, error, "UuidCreate");
  4765. }
  4766. }
  4767. // submit object changes to persist store
  4768. hr = myXmlSubmitObject(
  4769. pDoc, // doc node
  4770. lPersistFlags,
  4771. pAzStoreNode, //AzAuthStore node
  4772. pAppGuid,
  4773. pScopeGuid,
  4774. pObj, //object handle
  4775. lObjectType,
  4776. DeleteMe);
  4777. _JumpIfError(hr, error, "myXmlSubmitObject");
  4778. // if submit called from persist engine, it must be dirty
  4779. // persist whole xml doc
  4780. AZASSERT(NULL != pPersistContext);
  4781. hr = myWszToBstrVariant(
  4782. pPersistContext->pwszPolicyUrl,
  4783. &varPolicyUrl);
  4784. _JumpIfError(hr, error, "myWszToBstrVariant");
  4785. //
  4786. // We should not blindly use the current DOM to save.
  4787. // If there has been changes to the store, then we should bring in
  4788. // those changes to this DOM and merge them and then do the save
  4789. //
  4790. BOOL bNeedUpdate;
  4791. DWORD dwStatus = myXmlStoreHasUpdate(pPersistContext, &bNeedUpdate);
  4792. if (NO_ERROR == dwStatus && bNeedUpdate)
  4793. {
  4794. //
  4795. // load a fresh copy of dom, and then update this object's changes
  4796. //
  4797. CComPtr<IXMLDOMDocument2> srpDocNew;
  4798. hr = myXmlLoad(varPolicyUrl, &srpDocNew);
  4799. if (SUCCEEDED(hr))
  4800. {
  4801. //
  4802. // put the same changes to the freshly loaded dom as well
  4803. //
  4804. CComPtr<IXMLDOMElement> srpStoreNode;
  4805. hr = srpDocNew->get_documentElement(&srpStoreNode);
  4806. if (SUCCEEDED(hr))
  4807. {
  4808. hr = myXmlSubmitObject(
  4809. srpDocNew, // doc node
  4810. lPersistFlags,
  4811. srpStoreNode, //admin node
  4812. pAppGuid,
  4813. pScopeGuid,
  4814. pObj, //object handle
  4815. lObjectType,
  4816. DeleteMe
  4817. );
  4818. }
  4819. }
  4820. if (SUCCEEDED(hr))
  4821. {
  4822. hr = srpDocNew->save(varPolicyUrl);
  4823. }
  4824. }
  4825. else if (NO_ERROR == dwStatus)
  4826. {
  4827. hr = pDoc->save(varPolicyUrl);
  4828. }
  4829. else
  4830. {
  4831. hr = AZ_HR_FROM_WIN32(dwStatus);
  4832. }
  4833. // release resource 1st
  4834. VariantClear(&varPolicyUrl);
  4835. _JumpIfError(hr, error, "pDoc->save");
  4836. // if AzAuthStore, apply acl
  4837. // we do it here because the file might not exist
  4838. if ( lObjectType == OBJECT_TYPE_AZAUTHSTORE )
  4839. {
  4840. // submit any acl changes
  4841. hr = myXmlSubmitAzStoreAcls(
  4842. pPersistContext,
  4843. pObj,
  4844. lPersistFlags );
  4845. _JumpIfError(hr, error, "myXmlSubmitAzStoreAcls");
  4846. }
  4847. //
  4848. // We will poll the filetime here only if no outside changes
  4849. // have happened
  4850. //
  4851. if (!bNeedUpdate)
  4852. {
  4853. WIN32_FILE_ATTRIBUTE_DATA fad;
  4854. if (GetFileAttributesEx(pPersistContext->pwszPolicyUrl,
  4855. GetFileExInfoStandard,
  4856. &fad))
  4857. {
  4858. pPersistContext->FTLastWrite = fad.ftLastWriteTime;
  4859. }
  4860. else
  4861. {
  4862. hr = AZ_HR_FROM_WIN32(GetLastError());
  4863. _JumpIfError(hr, error, "GetFileAttributesEx");
  4864. }
  4865. }
  4866. //
  4867. // Tell azroles about the object options
  4868. //
  4869. hr = XmlSetObjectOptions( pPersistContext, lPersistFlags, pObj );
  4870. _JumpIfError(hr, error, "XmlSetObjectOptions");
  4871. hr = S_OK;
  4872. error:
  4873. VariantClear(&varPolicyUrl);
  4874. if (NULL != pAzStoreNode)
  4875. {
  4876. pAzStoreNode->Release();
  4877. }
  4878. return hr;
  4879. }
  4880. DWORD
  4881. XMLPersistRefresh(
  4882. IN AZPE_PERSIST_CONTEXT PersistContext,
  4883. IN AZPE_OBJECT_HANDLE AzpeObjectHandle,
  4884. IN ULONG lPersistFlags
  4885. )
  4886. /*++
  4887. Routine Description:
  4888. This routine updates the attributes of the object from the policy database.
  4889. On entry, AzGlResource must be locked exclusive.
  4890. Arguments:
  4891. PersistContext - Specifies the policy database that is to be manipulated
  4892. AzpeObjectHandle - Specifies the object in the database whose cache entry is to be
  4893. updated
  4894. The GenericObject->PersistenceGuid field should be non-zero on input.
  4895. Return Value:
  4896. NO_ERROR - The operation was successful
  4897. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  4898. Other status codes
  4899. --*/
  4900. {
  4901. DWORD dwErr = NO_ERROR;
  4902. PAZP_XML_CONTEXT XmlPersistContext = (PAZP_XML_CONTEXT)PersistContext;
  4903. AZPE_OBJECT_HANDLE pParentObject;
  4904. ULONG lObjectType;
  4905. IXMLDOMNodeList *pList = NULL;
  4906. IXMLDOMNode *pObjectNode = NULL;
  4907. IXMLDOMDocument2 *pDoc;
  4908. WCHAR *pwszGuid = NULL;
  4909. WCHAR *pwszQuery = NULL;
  4910. ASSERT(NULL != AzpeObjectHandle);
  4911. //init
  4912. // get object type
  4913. lObjectType = XmlAzrolesInfo->AzpeObjectType( AzpeObjectHandle );
  4914. // get doc handle
  4915. pDoc = XmlPersistContext->pDoc;
  4916. // find the object node in the doc
  4917. if (OBJECT_TYPE_AZAUTHSTORE == lObjectType)
  4918. {
  4919. // AzAuthStore is always special, itself, no parent
  4920. // get object parent
  4921. pParentObject = AzpeObjectHandle;
  4922. // get the root node, ie. the node of ploicy
  4923. dwErr = myXmlGetAzStoreNode(pDoc, (IXMLDOMElement**)&pObjectNode);
  4924. _JumpIfError(dwErr, error, "myXmlGetAzStoreNode");
  4925. // if AzAuthStore object, refresh policy acl
  4926. dwErr = myXmlLoadAclsToAzStore(
  4927. XmlPersistContext,
  4928. lPersistFlags,
  4929. FALSE );
  4930. _JumpIfError(dwErr, error, "myXmlLoadAclsToAzStore");
  4931. }
  4932. else
  4933. {
  4934. if (IsEqualGUID( *XmlAzrolesInfo->AzpePersistenceGuid( AzpeObjectHandle ), AzGlZeroGuid))
  4935. {
  4936. // this is a new object, no need to refresh
  4937. goto done;
  4938. }
  4939. // get object parent
  4940. pParentObject = XmlAzrolesInfo->AzpeParentOfChild( AzpeObjectHandle );
  4941. ASSERT(NULL != pParentObject);
  4942. // convert object guid to string guid to form xpath query
  4943. dwErr = UuidToString( XmlAzrolesInfo->AzpePersistenceGuid( AzpeObjectHandle ), &pwszGuid);
  4944. _JumpIfError(dwErr, error, "UuidToString");
  4945. // get object node by using xpath query
  4946. // query is in a pattern of //*/$ObjectTag$[@Guid="???"]
  4947. // for example, query Operation,
  4948. // //*/AzOperation[@Guid="25a63179-3663-4aa7-b0b8-48ca084d0747"]
  4949. // in which "//*/[@=""] has 10 chars
  4950. ASSERT(NULL != g_SubmitLoadTable[lObjectType].pwszTag);
  4951. pwszQuery = (WCHAR*)AzpAllocateHeap(
  4952. (wcslen(g_SubmitLoadTable[lObjectType].pwszTag) +
  4953. wcslen(AZ_XML_TAG_ATTR_GUID) +
  4954. wcslen(pwszGuid) + 11) * sizeof(WCHAR), "XMQRY2" );
  4955. if (NULL == pwszQuery)
  4956. {
  4957. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  4958. _JumpError(dwErr, error, "AzpAllocateHeap");
  4959. }
  4960. wsprintf(pwszQuery, L"//*/%s[@%s=\"%s\"]",
  4961. g_SubmitLoadTable[lObjectType].pwszTag,
  4962. AZ_XML_TAG_ATTR_GUID,
  4963. pwszGuid);
  4964. AzPrint((AZD_XML, "XPath query(refresh)=%ws\n", pwszQuery));
  4965. dwErr = myXmlGetNodeListByXPath(
  4966. pDoc,
  4967. pwszQuery,
  4968. &pList);
  4969. _JumpIfError(dwErr, error, "myXmlGetNodeListByXPath");
  4970. #if DBG
  4971. {
  4972. LONG lLength;
  4973. // get length of the list
  4974. dwErr = pList->get_length(&lLength);
  4975. _JumpIfError(dwErr, error, "pList->get_length");
  4976. // object guid can't be shared
  4977. AZASSERT(1 == lLength);
  4978. }
  4979. #endif //DBG
  4980. dwErr = pList->get_item(0, &pObjectNode);
  4981. _JumpIfError(dwErr, error, "pList->get_item");
  4982. }
  4983. ASSERT(NULL != pObjectNode);
  4984. // now do the refresh
  4985. dwErr = myXmlLoadObject(
  4986. XmlPersistContext,
  4987. pParentObject,
  4988. lObjectType,
  4989. lPersistFlags,
  4990. FALSE, //don't load child objects
  4991. TRUE, // AzpeFinishObject right after
  4992. pObjectNode);
  4993. _JumpIfError(dwErr, error, "myXmlLoadObject(refresh)");
  4994. done:
  4995. dwErr = NO_ERROR;
  4996. error:
  4997. if (NULL != pwszGuid)
  4998. {
  4999. RpcStringFree(&pwszGuid);
  5000. }
  5001. if (NULL != pwszQuery)
  5002. {
  5003. AzpFreeHeap(pwszQuery);
  5004. }
  5005. if (NULL != pList)
  5006. {
  5007. pList->Release();
  5008. }
  5009. if (NULL != pObjectNode)
  5010. {
  5011. pObjectNode->Release();
  5012. }
  5013. return dwErr;
  5014. }
  5015. #pragma warning ( pop )