diff --git a/cts/cli/regression.acls.exp b/cts/cli/regression.acls.exp
index 0b6eb7397e..22c2ce9f94 100644
--- a/cts/cli/regression.acls.exp
+++ b/cts/cli/regression.acls.exp
@@ -1,2348 +1,2348 @@
 Created new pacemaker configuration
 Setting up shadow instance
 A new shadow instance was created.  To begin using it paste the following into your shell:
   CIB_shadow=cts-cli ; export CIB_shadow
 =#=#=#= Begin test: Configure some ACLs =#=#=#=
 =#=#=#= Current cib after: Configure some ACLs =#=#=#=
 <cib epoch="1" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config/>
     <nodes/>
     <resources/>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: Configure some ACLs - OK (0) =#=#=#=
 * Passed: cibadmin       - Configure some ACLs
 =#=#=#= Begin test: Enable ACLs =#=#=#=
 =#=#=#= Current cib after: Enable ACLs =#=#=#=
 <cib epoch="2" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources/>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: Enable ACLs - OK (0) =#=#=#=
 * Passed: crm_attribute  - Enable ACLs
 =#=#=#= Begin test: Set cluster option =#=#=#=
 =#=#=#= Current cib after: Set cluster option =#=#=#=
 <cib epoch="3" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources/>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: Set cluster option - OK (0) =#=#=#=
 * Passed: crm_attribute  - Set cluster option
 =#=#=#= Begin test: New ACL =#=#=#=
 =#=#=#= Current cib after: New ACL =#=#=#=
 <cib epoch="4" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources/>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: New ACL - OK (0) =#=#=#=
 * Passed: cibadmin       - New ACL
 =#=#=#= Begin test: Another ACL =#=#=#=
 =#=#=#= Current cib after: Another ACL =#=#=#=
 <cib epoch="5" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources/>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: Another ACL - OK (0) =#=#=#=
 * Passed: cibadmin       - Another ACL
 =#=#=#= Begin test: Updated ACL =#=#=#=
 =#=#=#= Current cib after: Updated ACL =#=#=#=
 <cib epoch="6" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources/>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: Updated ACL - OK (0) =#=#=#=
 * Passed: cibadmin       - Updated ACL
 =#=#=#= Begin test: unknownguy: Query configuration =#=#=#=
 Call failed: Permission denied
 =#=#=#= End test: unknownguy: Query configuration - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - unknownguy: Query configuration
 =#=#=#= Begin test: unknownguy: Set enable-acl =#=#=#=
 Error performing operation: Permission denied
 =#=#=#= End test: unknownguy: Set enable-acl - Insufficient privileges (4) =#=#=#=
 * Passed: crm_attribute  - unknownguy: Set enable-acl
 =#=#=#= Begin test: unknownguy: Set stonith-enabled =#=#=#=
 Error performing operation: Permission denied
 =#=#=#= End test: unknownguy: Set stonith-enabled - Insufficient privileges (4) =#=#=#=
 * Passed: crm_attribute  - unknownguy: Set stonith-enabled
 =#=#=#= Begin test: unknownguy: Create a resource =#=#=#=
 pcmk__check_acl 	trace: User 'unknownguy' without ACLs denied read/write access to /cib/configuration/resources/primitive[@id]
 pcmk__check_acl 	trace: User 'unknownguy' without ACLs denied read/write access to /cib/configuration/resources/primitive[@class]
 pcmk__check_acl 	trace: User 'unknownguy' without ACLs denied read/write access to /cib/configuration/resources/primitive[@provider]
 pcmk__check_acl 	trace: User 'unknownguy' without ACLs denied read/write access to /cib/configuration/resources/primitive[@type]
-pcmk__post_process_acl 	trace: Creation of <primitive> scaffolding with id="<unset>" is implicitly allowed
+pcmk__apply_creation_acl 	trace: Creation of <primitive> scaffolding with id="<unset>" is implicitly allowed
 Call failed: Permission denied
 =#=#=#= End test: unknownguy: Create a resource - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - unknownguy: Create a resource
 =#=#=#= Begin test: l33t-haxor: Query configuration =#=#=#=
 Call failed: Permission denied
 =#=#=#= End test: l33t-haxor: Query configuration - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - l33t-haxor: Query configuration
 =#=#=#= Begin test: l33t-haxor: Set enable-acl =#=#=#=
 Error performing operation: Permission denied
 =#=#=#= End test: l33t-haxor: Set enable-acl - Insufficient privileges (4) =#=#=#=
 * Passed: crm_attribute  - l33t-haxor: Set enable-acl
 =#=#=#= Begin test: l33t-haxor: Set stonith-enabled =#=#=#=
 Error performing operation: Permission denied
 =#=#=#= End test: l33t-haxor: Set stonith-enabled - Insufficient privileges (4) =#=#=#=
 * Passed: crm_attribute  - l33t-haxor: Set stonith-enabled
 =#=#=#= Begin test: l33t-haxor: Create a resource =#=#=#=
 pcmk__check_acl 	trace: Parent ACL denies user 'l33t-haxor' read/write access to /cib/configuration/resources/primitive[@id='dummy']
-pcmk__post_process_acl 	trace: ACLs disallow creation of <primitive> with id="dummy"
+pcmk__apply_creation_acl 	trace: ACLs disallow creation of <primitive> with id="dummy"
 Call failed: Permission denied
 =#=#=#= End test: l33t-haxor: Create a resource - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - l33t-haxor: Create a resource
 =#=#=#= Begin test: niceguy: Query configuration =#=#=#=
 <cib epoch="6" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources/>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: niceguy: Query configuration - OK (0) =#=#=#=
 * Passed: cibadmin       - niceguy: Query configuration
 =#=#=#= Begin test: niceguy: Set enable-acl =#=#=#=
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib/configuration/crm_config/cluster_property_set[@id='cib-bootstrap-options']/nvpair[@id='cib-bootstrap-options-enable-acl'][@value]
 Error performing operation: Permission denied
 Error setting enable-acl=false (section=crm_config, set=<null>): Permission denied
 =#=#=#= End test: niceguy: Set enable-acl - Insufficient privileges (4) =#=#=#=
 * Passed: crm_attribute  - niceguy: Set enable-acl
 =#=#=#= Begin test: niceguy: Set stonith-enabled =#=#=#=
-pcmk__post_process_acl 	trace: ACLs allow creation of <nvpair> with id="cib-bootstrap-options-stonith-enabled"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <nvpair> with id="cib-bootstrap-options-stonith-enabled"
 =#=#=#= Current cib after: niceguy: Set stonith-enabled =#=#=#=
 <cib epoch="7" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="false"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources/>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: niceguy: Set stonith-enabled - OK (0) =#=#=#=
 * Passed: crm_attribute  - niceguy: Set stonith-enabled
 =#=#=#= Begin test: niceguy: Create a resource =#=#=#=
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib/configuration/resources/primitive[@id='dummy']
-pcmk__post_process_acl 	trace: ACLs disallow creation of <primitive> with id="dummy"
+pcmk__apply_creation_acl 	trace: ACLs disallow creation of <primitive> with id="dummy"
 Call failed: Permission denied
 =#=#=#= End test: niceguy: Create a resource - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - niceguy: Create a resource
 =#=#=#= Begin test: root: Query configuration =#=#=#=
 <cib epoch="7" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="false"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources/>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: root: Query configuration - OK (0) =#=#=#=
 * Passed: cibadmin       - root: Query configuration
 =#=#=#= Begin test: root: Set stonith-enabled =#=#=#=
 =#=#=#= Current cib after: root: Set stonith-enabled =#=#=#=
 <cib epoch="8" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources/>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: root: Set stonith-enabled - OK (0) =#=#=#=
 * Passed: crm_attribute  - root: Set stonith-enabled
 =#=#=#= Begin test: root: Create a resource =#=#=#=
 =#=#=#= Current cib after: root: Create a resource =#=#=#=
 <cib epoch="9" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy"/>
     </resources>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: root: Create a resource - OK (0) =#=#=#=
 * Passed: cibadmin       - root: Create a resource
 =#=#=#= Begin test: l33t-haxor: Create a resource meta attribute =#=#=#=
 Error performing operation: Permission denied
 =#=#=#= End test: l33t-haxor: Create a resource meta attribute - Insufficient privileges (4) =#=#=#=
 * Passed: crm_resource   - l33t-haxor: Create a resource meta attribute
 =#=#=#= Begin test: l33t-haxor: Query a resource meta attribute =#=#=#=
 Error performing operation: Permission denied
 =#=#=#= End test: l33t-haxor: Query a resource meta attribute - Insufficient privileges (4) =#=#=#=
 * Passed: crm_resource   - l33t-haxor: Query a resource meta attribute
 =#=#=#= Begin test: l33t-haxor: Remove a resource meta attribute =#=#=#=
 Error performing operation: Permission denied
 =#=#=#= End test: l33t-haxor: Remove a resource meta attribute - Insufficient privileges (4) =#=#=#=
 * Passed: crm_resource   - l33t-haxor: Remove a resource meta attribute
 =#=#=#= Begin test: niceguy: Create a resource meta attribute =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
-pcmk__post_process_acl 	trace: Creation of <meta_attributes> scaffolding with id="dummy-meta_attributes" is implicitly allowed
-pcmk__post_process_acl 	trace: ACLs allow creation of <nvpair> with id="dummy-meta_attributes-target-role"
+pcmk__apply_creation_acl 	trace: Creation of <meta_attributes> scaffolding with id="dummy-meta_attributes" is implicitly allowed
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <nvpair> with id="dummy-meta_attributes-target-role"
 Set 'dummy' option: id=dummy-meta_attributes-target-role set=dummy-meta_attributes name=target-role value=Stopped
 =#=#=#= Current cib after: niceguy: Create a resource meta attribute =#=#=#=
 <cib epoch="10" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Stopped"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: niceguy: Create a resource meta attribute - OK (0) =#=#=#=
 * Passed: crm_resource   - niceguy: Create a resource meta attribute
 =#=#=#= Begin test: niceguy: Query a resource meta attribute =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 Stopped
 =#=#=#= Current cib after: niceguy: Query a resource meta attribute =#=#=#=
 <cib epoch="10" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Stopped"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: niceguy: Query a resource meta attribute - OK (0) =#=#=#=
 * Passed: crm_resource   - niceguy: Query a resource meta attribute
 =#=#=#= Begin test: niceguy: Remove a resource meta attribute =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 Deleted 'dummy' option: id=dummy-meta_attributes-target-role name=target-role
 =#=#=#= Current cib after: niceguy: Remove a resource meta attribute =#=#=#=
 <cib epoch="11" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes"/>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: niceguy: Remove a resource meta attribute - OK (0) =#=#=#=
 * Passed: crm_resource   - niceguy: Remove a resource meta attribute
 =#=#=#= Begin test: niceguy: Create a resource meta attribute =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
-pcmk__post_process_acl 	trace: ACLs allow creation of <nvpair> with id="dummy-meta_attributes-target-role"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <nvpair> with id="dummy-meta_attributes-target-role"
 Set 'dummy' option: id=dummy-meta_attributes-target-role set=dummy-meta_attributes name=target-role value=Started
 =#=#=#= Current cib after: niceguy: Create a resource meta attribute =#=#=#=
 <cib epoch="12" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: niceguy: Create a resource meta attribute - OK (0) =#=#=#=
 * Passed: crm_resource   - niceguy: Create a resource meta attribute
 =#=#=#= Begin test: badidea: Query configuration - implied deny =#=#=#=
 <cib>
   <configuration>
     <resources>
       <primitive id="dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
   </configuration>
 </cib>
 =#=#=#= End test: badidea: Query configuration - implied deny - OK (0) =#=#=#=
 * Passed: cibadmin       - badidea: Query configuration - implied deny
 =#=#=#= Begin test: betteridea: Query configuration - explicit deny =#=#=#=
 <cib>
   <configuration>
     <resources>
       <primitive id="dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
   </configuration>
 </cib>
 =#=#=#= End test: betteridea: Query configuration - explicit deny - OK (0) =#=#=#=
 * Passed: cibadmin       - betteridea: Query configuration - explicit deny
 <cib epoch="13" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: niceguy: Replace - remove acls =#=#=#=
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib[@epoch]
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib/configuration/acls
 Call failed: Permission denied
 =#=#=#= End test: niceguy: Replace - remove acls - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - niceguy: Replace - remove acls
 <cib epoch="13" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
       <primitive id="dummy2" class="ocf" provider="pacemaker" type="Dummy"/>
     </resources>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: niceguy: Replace - create resource =#=#=#=
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib[@epoch]
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib/configuration/resources/primitive[@id='dummy2']
-pcmk__post_process_acl 	trace: ACLs disallow creation of <primitive> with id="dummy2"
+pcmk__apply_creation_acl 	trace: ACLs disallow creation of <primitive> with id="dummy2"
 Call failed: Permission denied
 =#=#=#= End test: niceguy: Replace - create resource - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - niceguy: Replace - create resource
 <cib epoch="13" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="false"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: niceguy: Replace - modify attribute (deny) =#=#=#=
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib[@epoch]
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib/configuration/crm_config/cluster_property_set[@id='cib-bootstrap-options']/nvpair[@id='cib-bootstrap-options-enable-acl'][@value]
 Call failed: Permission denied
 =#=#=#= End test: niceguy: Replace - modify attribute (deny) - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - niceguy: Replace - modify attribute (deny)
 <cib epoch="13" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: niceguy: Replace - delete attribute (deny) =#=#=#=
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib[@epoch]
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib/configuration/crm_config/cluster_property_set[@id='cib-bootstrap-options']/nvpair[@id='cib-bootstrap-options-enable-acl']
 Call failed: Permission denied
 =#=#=#= End test: niceguy: Replace - delete attribute (deny) - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - niceguy: Replace - delete attribute (deny)
 <cib epoch="13" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy" description="nothing interesting">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: niceguy: Replace - create attribute (deny) =#=#=#=
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib[@epoch]
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib/configuration/resources/primitive[@id='dummy'][@description]
 Call failed: Permission denied
 =#=#=#= End test: niceguy: Replace - create attribute (deny) - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - niceguy: Replace - create attribute (deny)
 <cib epoch="13" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy" description="nothing interesting">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: bob: Replace - create attribute (allow) =#=#=#=
 =#=#=#= End test: bob: Replace - create attribute (allow) - OK (0) =#=#=#=
 * Passed: cibadmin       - bob: Replace - create attribute (allow)
 <cib epoch="14" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy" description="something interesting">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: bob: Replace - modify attribute (allow) =#=#=#=
 =#=#=#= End test: bob: Replace - modify attribute (allow) - OK (0) =#=#=#=
 * Passed: cibadmin       - bob: Replace - modify attribute (allow)
 <cib epoch="15" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy"/>
     </resources>
     <constraints/>
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
       <acl_user id="badidea">
         <read id="badidea-resources" xpath="//meta_attributes"/>
       </acl_user>
       <acl_user id="betteridea">
         <deny id="betteridea-nothing" xpath="/cib"/>
         <read id="betteridea-resources" xpath="//meta_attributes"/>
       </acl_user>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: bob: Replace - delete attribute (allow) =#=#=#=
 =#=#=#= End test: bob: Replace - delete attribute (allow) - OK (0) =#=#=#=
 * Passed: cibadmin       - bob: Replace - delete attribute (allow)
 
 
     !#!#!#!#! Upgrading to latest CIB schema and re-testing !#!#!#!#!
 =#=#=#= Begin test: root: Upgrade to latest CIB schema =#=#=#=
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_permission> with id="observer-read-1"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_permission> with id="observer-write-1"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_permission> with id="observer-write-2"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_permission> with id="admin-read-1"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_permission> with id="admin-write-1"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_target> with id="l33t-haxor"
-pcmk__post_process_acl 	trace: ACLs allow creation of <role> with id="auto-l33t-haxor"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_role> with id="auto-l33t-haxor"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_permission> with id="crook-nothing"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_target> with id="niceguy"
-pcmk__post_process_acl 	trace: ACLs allow creation of <role> with id="observer"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_target> with id="bob"
-pcmk__post_process_acl 	trace: ACLs allow creation of <role> with id="admin"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_target> with id="badidea"
-pcmk__post_process_acl 	trace: ACLs allow creation of <role> with id="auto-badidea"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_role> with id="auto-badidea"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_permission> with id="badidea-resources"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_target> with id="betteridea"
-pcmk__post_process_acl 	trace: ACLs allow creation of <role> with id="auto-betteridea"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_role> with id="auto-betteridea"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_permission> with id="betteridea-nothing"
-pcmk__post_process_acl 	trace: ACLs allow creation of <acl_permission> with id="betteridea-resources"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_permission> with id="observer-read-1"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_permission> with id="observer-write-1"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_permission> with id="observer-write-2"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_permission> with id="admin-read-1"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_permission> with id="admin-write-1"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_target> with id="l33t-haxor"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <role> with id="auto-l33t-haxor"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_role> with id="auto-l33t-haxor"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_permission> with id="crook-nothing"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_target> with id="niceguy"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <role> with id="observer"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_target> with id="bob"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <role> with id="admin"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_target> with id="badidea"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <role> with id="auto-badidea"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_role> with id="auto-badidea"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_permission> with id="badidea-resources"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_target> with id="betteridea"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <role> with id="auto-betteridea"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_role> with id="auto-betteridea"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_permission> with id="betteridea-nothing"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <acl_permission> with id="betteridea-resources"
 =#=#=#= Current cib after: root: Upgrade to latest CIB schema =#=#=#=
 <cib epoch="2" num_updates="0" admin_epoch="1">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy"/>
     </resources>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: root: Upgrade to latest CIB schema - OK (0) =#=#=#=
 * Passed: cibadmin       - root: Upgrade to latest CIB schema
 =#=#=#= Begin test: unknownguy: Query configuration =#=#=#=
 Call failed: Permission denied
 =#=#=#= End test: unknownguy: Query configuration - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - unknownguy: Query configuration
 =#=#=#= Begin test: unknownguy: Set enable-acl =#=#=#=
 Error performing operation: Permission denied
 =#=#=#= End test: unknownguy: Set enable-acl - Insufficient privileges (4) =#=#=#=
 * Passed: crm_attribute  - unknownguy: Set enable-acl
 =#=#=#= Begin test: unknownguy: Set stonith-enabled =#=#=#=
 Error performing operation: Permission denied
 =#=#=#= End test: unknownguy: Set stonith-enabled - Insufficient privileges (4) =#=#=#=
 * Passed: crm_attribute  - unknownguy: Set stonith-enabled
 =#=#=#= Begin test: unknownguy: Create a resource =#=#=#=
 pcmk__check_acl 	trace: User 'unknownguy' without ACLs denied read/write access to /cib/configuration/resources/primitive[@id]
 pcmk__check_acl 	trace: User 'unknownguy' without ACLs denied read/write access to /cib/configuration/resources/primitive[@class]
 pcmk__check_acl 	trace: User 'unknownguy' without ACLs denied read/write access to /cib/configuration/resources/primitive[@provider]
 pcmk__check_acl 	trace: User 'unknownguy' without ACLs denied read/write access to /cib/configuration/resources/primitive[@type]
-pcmk__post_process_acl 	trace: Creation of <primitive> scaffolding with id="<unset>" is implicitly allowed
+pcmk__apply_creation_acl 	trace: Creation of <primitive> scaffolding with id="<unset>" is implicitly allowed
 Call failed: Permission denied
 =#=#=#= End test: unknownguy: Create a resource - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - unknownguy: Create a resource
 =#=#=#= Begin test: l33t-haxor: Query configuration =#=#=#=
 Call failed: Permission denied
 =#=#=#= End test: l33t-haxor: Query configuration - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - l33t-haxor: Query configuration
 =#=#=#= Begin test: l33t-haxor: Set enable-acl =#=#=#=
 Error performing operation: Permission denied
 =#=#=#= End test: l33t-haxor: Set enable-acl - Insufficient privileges (4) =#=#=#=
 * Passed: crm_attribute  - l33t-haxor: Set enable-acl
 =#=#=#= Begin test: l33t-haxor: Set stonith-enabled =#=#=#=
 Error performing operation: Permission denied
 =#=#=#= End test: l33t-haxor: Set stonith-enabled - Insufficient privileges (4) =#=#=#=
 * Passed: crm_attribute  - l33t-haxor: Set stonith-enabled
 =#=#=#= Begin test: l33t-haxor: Create a resource =#=#=#=
 pcmk__check_acl 	trace: Parent ACL denies user 'l33t-haxor' read/write access to /cib/configuration/resources/primitive[@id='dummy']
-pcmk__post_process_acl 	trace: ACLs disallow creation of <primitive> with id="dummy"
+pcmk__apply_creation_acl 	trace: ACLs disallow creation of <primitive> with id="dummy"
 Call failed: Permission denied
 =#=#=#= End test: l33t-haxor: Create a resource - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - l33t-haxor: Create a resource
 =#=#=#= Begin test: niceguy: Query configuration =#=#=#=
 <cib epoch="7" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources/>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: niceguy: Query configuration - OK (0) =#=#=#=
 * Passed: cibadmin       - niceguy: Query configuration
 =#=#=#= Begin test: niceguy: Set enable-acl =#=#=#=
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib/configuration/crm_config/cluster_property_set[@id='cib-bootstrap-options']/nvpair[@id='cib-bootstrap-options-enable-acl'][@value]
 Error performing operation: Permission denied
 Error setting enable-acl=false (section=crm_config, set=<null>): Permission denied
 =#=#=#= End test: niceguy: Set enable-acl - Insufficient privileges (4) =#=#=#=
 * Passed: crm_attribute  - niceguy: Set enable-acl
 =#=#=#= Begin test: niceguy: Set stonith-enabled =#=#=#=
 =#=#=#= Current cib after: niceguy: Set stonith-enabled =#=#=#=
 <cib epoch="8" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="false"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources/>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: niceguy: Set stonith-enabled - OK (0) =#=#=#=
 * Passed: crm_attribute  - niceguy: Set stonith-enabled
 =#=#=#= Begin test: niceguy: Create a resource =#=#=#=
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib/configuration/resources/primitive[@id='dummy']
-pcmk__post_process_acl 	trace: ACLs disallow creation of <primitive> with id="dummy"
+pcmk__apply_creation_acl 	trace: ACLs disallow creation of <primitive> with id="dummy"
 Call failed: Permission denied
 =#=#=#= End test: niceguy: Create a resource - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - niceguy: Create a resource
 =#=#=#= Begin test: root: Query configuration =#=#=#=
 <cib epoch="8" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="false"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources/>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: root: Query configuration - OK (0) =#=#=#=
 * Passed: cibadmin       - root: Query configuration
 =#=#=#= Begin test: root: Set stonith-enabled =#=#=#=
 =#=#=#= Current cib after: root: Set stonith-enabled =#=#=#=
 <cib epoch="9" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources/>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: root: Set stonith-enabled - OK (0) =#=#=#=
 * Passed: crm_attribute  - root: Set stonith-enabled
 =#=#=#= Begin test: root: Create a resource =#=#=#=
 =#=#=#= Current cib after: root: Create a resource =#=#=#=
 <cib epoch="10" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy"/>
     </resources>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: root: Create a resource - OK (0) =#=#=#=
 * Passed: cibadmin       - root: Create a resource
 =#=#=#= Begin test: l33t-haxor: Create a resource meta attribute =#=#=#=
 Error performing operation: Permission denied
 =#=#=#= End test: l33t-haxor: Create a resource meta attribute - Insufficient privileges (4) =#=#=#=
 * Passed: crm_resource   - l33t-haxor: Create a resource meta attribute
 =#=#=#= Begin test: l33t-haxor: Query a resource meta attribute =#=#=#=
 Error performing operation: Permission denied
 =#=#=#= End test: l33t-haxor: Query a resource meta attribute - Insufficient privileges (4) =#=#=#=
 * Passed: crm_resource   - l33t-haxor: Query a resource meta attribute
 =#=#=#= Begin test: l33t-haxor: Remove a resource meta attribute =#=#=#=
 Error performing operation: Permission denied
 =#=#=#= End test: l33t-haxor: Remove a resource meta attribute - Insufficient privileges (4) =#=#=#=
 * Passed: crm_resource   - l33t-haxor: Remove a resource meta attribute
 =#=#=#= Begin test: niceguy: Create a resource meta attribute =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
-pcmk__post_process_acl 	trace: Creation of <meta_attributes> scaffolding with id="dummy-meta_attributes" is implicitly allowed
-pcmk__post_process_acl 	trace: ACLs allow creation of <nvpair> with id="dummy-meta_attributes-target-role"
+pcmk__apply_creation_acl 	trace: Creation of <meta_attributes> scaffolding with id="dummy-meta_attributes" is implicitly allowed
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <nvpair> with id="dummy-meta_attributes-target-role"
 Set 'dummy' option: id=dummy-meta_attributes-target-role set=dummy-meta_attributes name=target-role value=Stopped
 =#=#=#= Current cib after: niceguy: Create a resource meta attribute =#=#=#=
 <cib epoch="11" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Stopped"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: niceguy: Create a resource meta attribute - OK (0) =#=#=#=
 * Passed: crm_resource   - niceguy: Create a resource meta attribute
 =#=#=#= Begin test: niceguy: Query a resource meta attribute =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 Stopped
 =#=#=#= Current cib after: niceguy: Query a resource meta attribute =#=#=#=
 <cib epoch="11" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Stopped"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: niceguy: Query a resource meta attribute - OK (0) =#=#=#=
 * Passed: crm_resource   - niceguy: Query a resource meta attribute
 =#=#=#= Begin test: niceguy: Remove a resource meta attribute =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
 Deleted 'dummy' option: id=dummy-meta_attributes-target-role name=target-role
 =#=#=#= Current cib after: niceguy: Remove a resource meta attribute =#=#=#=
 <cib epoch="12" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes"/>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: niceguy: Remove a resource meta attribute - OK (0) =#=#=#=
 * Passed: crm_resource   - niceguy: Remove a resource meta attribute
 =#=#=#= Begin test: niceguy: Create a resource meta attribute =#=#=#=
 unpack_resources 	error: Resource start-up disabled since no STONITH resources have been defined
 unpack_resources 	error: Either configure some or disable STONITH with the stonith-enabled option
 unpack_resources 	error: NOTE: Clusters with shared data need STONITH to ensure data integrity
-pcmk__post_process_acl 	trace: ACLs allow creation of <nvpair> with id="dummy-meta_attributes-target-role"
+pcmk__apply_creation_acl 	trace: ACLs allow creation of <nvpair> with id="dummy-meta_attributes-target-role"
 Set 'dummy' option: id=dummy-meta_attributes-target-role set=dummy-meta_attributes name=target-role value=Started
 =#=#=#= Current cib after: niceguy: Create a resource meta attribute =#=#=#=
 <cib epoch="13" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= End test: niceguy: Create a resource meta attribute - OK (0) =#=#=#=
 * Passed: crm_resource   - niceguy: Create a resource meta attribute
 =#=#=#= Begin test: badidea: Query configuration - implied deny =#=#=#=
 <cib>
   <configuration>
     <resources>
       <primitive id="dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
   </configuration>
 </cib>
 =#=#=#= End test: badidea: Query configuration - implied deny - OK (0) =#=#=#=
 * Passed: cibadmin       - badidea: Query configuration - implied deny
 =#=#=#= Begin test: betteridea: Query configuration - explicit deny =#=#=#=
 <cib>
   <configuration>
     <resources>
       <primitive id="dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
   </configuration>
 </cib>
 =#=#=#= End test: betteridea: Query configuration - explicit deny - OK (0) =#=#=#=
 * Passed: cibadmin       - betteridea: Query configuration - explicit deny
 <cib epoch="14" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: niceguy: Replace - remove acls =#=#=#=
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib[@epoch]
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib/configuration/acls
 Call failed: Permission denied
 =#=#=#= End test: niceguy: Replace - remove acls - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - niceguy: Replace - remove acls
 <cib epoch="14" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
       <primitive id="dummy2" class="ocf" provider="pacemaker" type="Dummy"/>
     </resources>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: niceguy: Replace - create resource =#=#=#=
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib[@epoch]
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib/configuration/resources/primitive[@id='dummy2']
-pcmk__post_process_acl 	trace: ACLs disallow creation of <primitive> with id="dummy2"
+pcmk__apply_creation_acl 	trace: ACLs disallow creation of <primitive> with id="dummy2"
 Call failed: Permission denied
 =#=#=#= End test: niceguy: Replace - create resource - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - niceguy: Replace - create resource
 <cib epoch="14" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="false"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: niceguy: Replace - modify attribute (deny) =#=#=#=
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib[@epoch]
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib/configuration/crm_config/cluster_property_set[@id='cib-bootstrap-options']/nvpair[@id='cib-bootstrap-options-enable-acl'][@value]
 Call failed: Permission denied
 =#=#=#= End test: niceguy: Replace - modify attribute (deny) - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - niceguy: Replace - modify attribute (deny)
 <cib epoch="14" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: niceguy: Replace - delete attribute (deny) =#=#=#=
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib[@epoch]
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib/configuration/crm_config/cluster_property_set[@id='cib-bootstrap-options']/nvpair[@id='cib-bootstrap-options-enable-acl']
 Call failed: Permission denied
 =#=#=#= End test: niceguy: Replace - delete attribute (deny) - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - niceguy: Replace - delete attribute (deny)
 <cib epoch="14" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy" description="nothing interesting">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: niceguy: Replace - create attribute (deny) =#=#=#=
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib[@epoch]
 pcmk__check_acl 	trace: Default ACL denies user 'niceguy' read/write access to /cib/configuration/resources/primitive[@id='dummy'][@description]
 Call failed: Permission denied
 =#=#=#= End test: niceguy: Replace - create attribute (deny) - Insufficient privileges (4) =#=#=#=
 * Passed: cibadmin       - niceguy: Replace - create attribute (deny)
 <cib epoch="14" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy" description="nothing interesting">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: bob: Replace - create attribute (allow) =#=#=#=
 =#=#=#= End test: bob: Replace - create attribute (allow) - OK (0) =#=#=#=
 * Passed: cibadmin       - bob: Replace - create attribute (allow)
 <cib epoch="15" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy" description="something interesting">
         <meta_attributes id="dummy-meta_attributes">
           <nvpair id="dummy-meta_attributes-target-role" name="target-role" value="Started"/>
         </meta_attributes>
       </primitive>
     </resources>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: bob: Replace - modify attribute (allow) =#=#=#=
 =#=#=#= End test: bob: Replace - modify attribute (allow) - OK (0) =#=#=#=
 * Passed: cibadmin       - bob: Replace - modify attribute (allow)
 <cib epoch="16" num_updates="0" admin_epoch="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
       </cluster_property_set>
     </crm_config>
     <nodes/>
     <resources>
       <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy"/>
     </resources>
     <constraints/>
     <acls>
       <acl_target id="l33t-haxor">
         <role id="auto-l33t-haxor"/>
       </acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_target id="bob">
         <role id="admin"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <acl_permission id="admin-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="admin-write-1" kind="write" xpath="//resources"/>
       </acl_role>
       <acl_target id="badidea">
         <role id="auto-badidea"/>
       </acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
       <acl_target id="betteridea">
         <role id="auto-betteridea"/>
       </acl_target>
       <acl_role id="auto-betteridea">
         <acl_permission id="betteridea-nothing" kind="deny" xpath="/cib"/>
         <acl_permission id="betteridea-resources" kind="read" xpath="//meta_attributes"/>
       </acl_role>
     </acls>
   </configuration>
   <status/>
 </cib>
 =#=#=#= Begin test: bob: Replace - delete attribute (allow) =#=#=#=
 =#=#=#= End test: bob: Replace - delete attribute (allow) - OK (0) =#=#=#=
 * Passed: cibadmin       - bob: Replace - delete attribute (allow)
diff --git a/cts/cts-cli.in b/cts/cts-cli.in
index 58f624d0a4..24e174cb63 100755
--- a/cts/cts-cli.in
+++ b/cts/cts-cli.in
@@ -1,1070 +1,1070 @@
 #!@BASH_PATH@
 #
 # Copyright 2008-2019 the Pacemaker project contributors
 #
 # The version control history for this file may have further details.
 #
 # This source code is licensed under the GNU General Public License version 2
 # or later (GPLv2+) WITHOUT ANY WARRANTY.
 #
 
 #
 # Note on portable usage of sed: GNU/POSIX/*BSD sed have a limited subset of
 # compatible functionality. Do not use the -i option, alternation (\|),
 # \0, or character sequences such as \n or \s.
 #
 
 USAGE_TEXT="Usage: cts-cli [<options>]
 Options:
  --help          Display this text, then exit
  -V, --verbose   Display any differences from expected output
  -t 'TEST [...]' Run only specified tests (default: 'dates tools acls validity upgrade rules')
  -p DIR          Look for executables in DIR (may be specified multiple times)
  -v, --valgrind  Run all commands under valgrind
  -s              Save actual output as expected output"
 
 # If readlink supports -e (i.e. GNU), use it
 readlink -e / >/dev/null 2>/dev/null
 if [ $? -eq 0 ]; then
     test_home="$(dirname "$(readlink -e "$0")")"
 else
     test_home="$(dirname "$0")"
 fi
 
 : ${shadow=cts-cli}
 shadow_dir=$(mktemp -d ${TMPDIR:-/tmp}/cts-cli.shadow.XXXXXXXXXX)
 num_errors=0
 num_passed=0
 verbose=0
 tests="dates tools acls validity upgrade rules"
 do_save=0
 VALGRIND_CMD=
 VALGRIND_OPTS="
     -q
     --gen-suppressions=all
     --show-reachable=no
     --leak-check=full
     --trace-children=no
     --time-stamp=yes
     --num-callers=20
     --suppressions=$test_home/valgrind-pcmk.suppressions
 "
 
 # These constants must track crm_exit_t values
 CRM_EX_OK=0
 CRM_EX_ERROR=1
 CRM_EX_INSUFFICIENT_PRIV=4
 CRM_EX_USAGE=64
 CRM_EX_CONFIG=78
 CRM_EX_OLD=103
 CRM_EX_DIGEST=104
 CRM_EX_NOSUCH=105
 CRM_EX_UNSAFE=107
 CRM_EX_EXISTS=108
 CRM_EX_MULTIPLE=109
 CRM_EX_EXPIRED=110
 CRM_EX_NOT_YET_IN_EFFECT=111
 CRM_EX_INDETERMINATE=112
 
 function test_assert() {
     target=$1; shift
     cib=$1; shift
     app=`echo "$cmd" | sed 's/\ .*//'`
     printf "* Running: $app - $desc\n" 1>&2
 
     printf "=#=#=#= Begin test: $desc =#=#=#=\n"
     eval $VALGRIND_CMD $cmd 2>&1
     rc=$?
 
     if [ x$cib != x0 ]; then
         printf "=#=#=#= Current cib after: $desc =#=#=#=\n"
         CIB_user=root cibadmin -Q
     fi
 
     printf "=#=#=#= End test: $desc - $(crm_error --exit $rc) ($rc) =#=#=#=\n"
 
     if [ $rc -ne $target ]; then
         num_errors=$(( $num_errors + 1 ))
         printf "* Failed (rc=%.3d): %-14s - %s\n" $rc $app "$desc"
         printf "* Failed (rc=%.3d): %-14s - %s\n" $rc $app "$desc (`which $app`)" 1>&2
         return
         exit $CRM_EX_ERROR
     else
         printf "* Passed: %-14s - %s\n" $app "$desc"
         num_passed=$(( $num_passed + 1 ))
     fi
 }
 
 function test_tools() {
     local TMPXML
     local TMPORIG
 
     TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.xml.XXXXXXXXXX)
     TMPORIG=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.existing.xml.XXXXXXXXXX)
     export CIB_shadow_dir="${shadow_dir}"
 
     $VALGRIND_CMD crm_shadow --batch --force --create-empty $shadow  2>&1
     export CIB_shadow=$shadow
 
     desc="Validate CIB"
     cmd="cibadmin -Q"
     test_assert $CRM_EX_OK
 
     desc="Configure something before erasing"
     cmd="crm_attribute -n cluster-delay -v 60s"
     test_assert $CRM_EX_OK
 
     desc="Require --force for CIB erasure"
     cmd="cibadmin -E"
     test_assert $CRM_EX_UNSAFE
 
     desc="Allow CIB erasure with --force"
     cmd="cibadmin -E --force"
     test_assert $CRM_EX_OK
 
     desc="Query CIB"
     cmd="cibadmin -Q > $TMPORIG"
     test_assert $CRM_EX_OK
 
     desc="Set cluster option"
     cmd="crm_attribute -n cluster-delay -v 60s"
     test_assert $CRM_EX_OK
 
     desc="Query new cluster option"
     cmd="cibadmin -Q -o crm_config | grep cib-bootstrap-options-cluster-delay"
     test_assert $CRM_EX_OK
 
     desc="Query cluster options"
     cmd="cibadmin -Q -o crm_config > $TMPXML"
     test_assert $CRM_EX_OK
 
     desc="Set no-quorum policy"
     cmd="crm_attribute -n no-quorum-policy -v ignore"
     test_assert $CRM_EX_OK
 
     desc="Delete nvpair"
     cmd="cibadmin -D -o crm_config --xml-text '<nvpair id=\"cib-bootstrap-options-cluster-delay\"/>'"
     test_assert $CRM_EX_OK
 
     desc="Create operation should fail"
     cmd="cibadmin -C -o crm_config --xml-file $TMPXML"
     test_assert $CRM_EX_EXISTS
 
     desc="Modify cluster options section"
     cmd="cibadmin -M -o crm_config --xml-file $TMPXML"
     test_assert $CRM_EX_OK
 
     desc="Query updated cluster option"
     cmd="cibadmin -Q -o crm_config | grep cib-bootstrap-options-cluster-delay"
     test_assert $CRM_EX_OK
 
     desc="Set duplicate cluster option"
     cmd="crm_attribute -n cluster-delay -v 40s -s duplicate"
     test_assert $CRM_EX_OK
 
     desc="Setting multiply defined cluster option should fail"
     cmd="crm_attribute -n cluster-delay -v 30s"
     test_assert $CRM_EX_MULTIPLE
 
     desc="Set cluster option with -s"
     cmd="crm_attribute -n cluster-delay -v 30s -s duplicate"
     test_assert $CRM_EX_OK
 
     desc="Delete cluster option with -i"
     cmd="crm_attribute -n cluster-delay -D -i cib-bootstrap-options-cluster-delay"
     test_assert $CRM_EX_OK
 
     desc="Create node1 and bring it online"
     cmd="crm_simulate --live-check --in-place --node-up=node1"
     test_assert $CRM_EX_OK
 
     desc="Create node attribute"
     cmd="crm_attribute -n ram -v 1024M -N node1 -t nodes"
     test_assert $CRM_EX_OK
 
     desc="Query new node attribute"
     cmd="cibadmin -Q -o nodes | grep node1-ram"
     test_assert $CRM_EX_OK
 
     desc="Set a transient (fail-count) node attribute"
     cmd="crm_attribute -n fail-count-foo -v 3 -N node1 -t status"
     test_assert $CRM_EX_OK
 
     desc="Query a fail count"
     cmd="crm_failcount --query -r foo -N node1"
     test_assert $CRM_EX_OK
 
     desc="Delete a transient (fail-count) node attribute"
     cmd="crm_attribute -n fail-count-foo -D -N node1 -t status"
     test_assert $CRM_EX_OK
 
     desc="Digest calculation"
     cmd="cibadmin -Q | cibadmin -5 -p 2>&1 > /dev/null"
     test_assert $CRM_EX_OK
 
     # This update will fail because it has version numbers
     desc="Replace operation should fail"
     cmd="cibadmin -R --xml-file $TMPORIG"
     test_assert $CRM_EX_OLD
 
     desc="Default standby value"
     cmd="crm_standby -N node1 -G"
     test_assert $CRM_EX_OK
  
     desc="Set standby status"
     cmd="crm_standby -N node1 -v true"
     test_assert $CRM_EX_OK
  
     desc="Query standby value"
     cmd="crm_standby -N node1 -G"
     test_assert $CRM_EX_OK
  
     desc="Delete standby value"
     cmd="crm_standby -N node1 -D"
     test_assert $CRM_EX_OK
 
     desc="Create a resource"
     cmd="cibadmin -C -o resources --xml-text '<primitive id=\"dummy\" class=\"ocf\" provider=\"pacemaker\" type=\"Dummy\"/>'"
     test_assert $CRM_EX_OK
 
     desc="Create a resource meta attribute"
     cmd="crm_resource -r dummy --meta -p is-managed -v false"
     test_assert $CRM_EX_OK
 
     desc="Query a resource meta attribute"
     cmd="crm_resource -r dummy --meta -g is-managed"
     test_assert $CRM_EX_OK
 
     desc="Remove a resource meta attribute"
     cmd="crm_resource -r dummy --meta -d is-managed"
     test_assert $CRM_EX_OK
 
     desc="Create a resource attribute"
     cmd="crm_resource -r dummy -p delay -v 10s"
     test_assert $CRM_EX_OK
 
     desc="List the configured resources"
     cmd="crm_resource -L"
     test_assert $CRM_EX_OK
 
     desc="Require a destination when migrating a resource that is stopped"
     cmd="crm_resource -r dummy -M"
     test_assert $CRM_EX_USAGE
 
     desc="Don't support migration to non-existent locations"
     cmd="crm_resource -r dummy -M -N i.dont.exist"
     test_assert $CRM_EX_NOSUCH
 
     desc="Create a fencing resource"
     cmd="cibadmin -C -o resources --xml-text '<primitive id=\"Fence\" class=\"stonith\" type=\"fence_true\"/>'"
     test_assert $CRM_EX_OK
 
     desc="Bring resources online"
     cmd="crm_simulate --live-check --in-place -S"
     test_assert $CRM_EX_OK
 
     desc="Try to move a resource to its existing location"
     cmd="crm_resource -r dummy --move --host node1"
     test_assert $CRM_EX_EXISTS
 
     desc="Move a resource from its existing location"
     cmd="crm_resource -r dummy --move"
     test_assert $CRM_EX_OK
 
     desc="Clear out constraints generated by --move"
     cmd="crm_resource -r dummy --clear"
     test_assert $CRM_EX_OK
 
     desc="Default ticket granted state"
     cmd="crm_ticket -t ticketA -G granted -d false"
     test_assert $CRM_EX_OK
 
     desc="Set ticket granted state"
     cmd="crm_ticket -t ticketA -r --force"
     test_assert $CRM_EX_OK
 
     desc="Query ticket granted state"
     cmd="crm_ticket -t ticketA -G granted"
     test_assert $CRM_EX_OK
 
     desc="Delete ticket granted state"
     cmd="crm_ticket -t ticketA -D granted --force"
     test_assert $CRM_EX_OK
 
     desc="Make a ticket standby"
     cmd="crm_ticket -t ticketA -s"
     test_assert $CRM_EX_OK
 
     desc="Query ticket standby state"
     cmd="crm_ticket -t ticketA -G standby"
     test_assert $CRM_EX_OK
 
     desc="Activate a ticket"
     cmd="crm_ticket -t ticketA -a"
     test_assert $CRM_EX_OK
 
     desc="Delete ticket standby state"
     cmd="crm_ticket -t ticketA -D standby"
     test_assert $CRM_EX_OK
 
     desc="Ban a resource on unknown node"
     cmd="crm_resource -r dummy -B -N host1"
     test_assert $CRM_EX_NOSUCH
 
     desc="Create two more nodes and bring them online"
     cmd="crm_simulate --live-check --in-place --node-up=node2 --node-up=node3"
     test_assert $CRM_EX_OK
 
     desc="Ban dummy from node1"
     cmd="crm_resource -r dummy -B -N node1"
     test_assert $CRM_EX_OK
 
     desc="Ban dummy from node2"
     cmd="crm_resource -r dummy -B -N node2"
     test_assert $CRM_EX_OK
 
     desc="Relocate resources due to ban"
     cmd="crm_simulate --live-check --in-place -S"
     test_assert $CRM_EX_OK
 
     desc="Move dummy to node1"
     cmd="crm_resource -r dummy -M -N node1"
     test_assert $CRM_EX_OK
 
     desc="Clear implicit constraints for dummy on node2"
     cmd="crm_resource -r dummy -U -N node2"
     test_assert $CRM_EX_OK
 
     desc="Drop the status section"
     cmd="cibadmin -R -o status --xml-text '<status/>'"
     test_assert $CRM_EX_OK 0
     
     desc="Create a clone"
     cmd="cibadmin -C -o resources --xml-text '<clone id=\"test-clone\"><primitive id=\"test-primitive\" class=\"ocf\" provider=\"pacemaker\" type=\"Dummy\"/></clone>'"
     test_assert $CRM_EX_OK 0
 
     desc="Create a resource meta attribute"
     cmd="crm_resource -r test-primitive --meta -p is-managed -v false"
     test_assert $CRM_EX_OK
 
     desc="Create a resource meta attribute in the primitive"
     cmd="crm_resource -r test-primitive --meta -p is-managed -v false --force"
     test_assert $CRM_EX_OK
 
     desc="Update resource meta attribute with duplicates"
     cmd="crm_resource -r test-clone --meta -p is-managed -v true"
     test_assert $CRM_EX_OK
 
     desc="Update resource meta attribute with duplicates (force clone)"
     cmd="crm_resource -r test-clone --meta -p is-managed -v true --force"
     test_assert $CRM_EX_OK
 
     desc="Update child resource meta attribute with duplicates"
     cmd="crm_resource -r test-primitive --meta -p is-managed -v false"
     test_assert $CRM_EX_OK
 
     desc="Delete resource meta attribute with duplicates"
     cmd="crm_resource -r test-clone --meta -d is-managed"
     test_assert $CRM_EX_OK
 
     desc="Delete resource meta attribute in parent"
     cmd="crm_resource -r test-primitive --meta -d is-managed"
     test_assert $CRM_EX_OK
 
     desc="Create a resource meta attribute in the primitive"
     cmd="crm_resource -r test-primitive --meta -p is-managed -v false --force"
     test_assert $CRM_EX_OK
 
     desc="Update existing resource meta attribute"
     cmd="crm_resource -r test-clone --meta -p is-managed -v true"
     test_assert $CRM_EX_OK
     
     desc="Create a resource meta attribute in the parent"
     cmd="crm_resource -r test-clone --meta -p is-managed -v true --force"
     test_assert $CRM_EX_OK
 
     desc="Copy resources"
     cmd="cibadmin -Q -o resources > $TMPXML"
     test_assert $CRM_EX_OK 0
 
     desc="Delete resource paremt meta attribute (force)"
     cmd="crm_resource -r test-clone --meta -d is-managed --force"
     test_assert $CRM_EX_OK
 
     desc="Restore duplicates"
     cmd="cibadmin -R -o resources --xml-file $TMPXML"
     test_assert $CRM_EX_OK
 
     desc="Delete resource child meta attribute"
     cmd="crm_resource -r test-primitive --meta -d is-managed"
     test_assert $CRM_EX_OK
 
     desc="Specify a lifetime when moving a resource"
     cmd="crm_resource -r dummy --move --node node2 --lifetime=PT1H"
     test_assert $CRM_EX_OK
 
     desc="Try to move a resource previously moved with a lifetime"
     cmd="crm_resource -r dummy --move --node node1"
     test_assert $CRM_EX_OK
 
     desc="Ban dummy from node1 for a short time"
     cmd="crm_resource -r dummy -B -N node1 --lifetime=PT1S"
     test_assert $CRM_EX_OK
 
     desc="Remove expired constraints"
     sleep 2
     cmd="crm_resource --clear --expired"
     test_assert $CRM_EX_OK
 
     unset CIB_shadow_dir
     rm -f "$TMPXML" "$TMPORIG"
 }
 
 function test_dates() {
     desc="2014-01-01 00:30:00 - 1 Hour"
     cmd="iso8601 -d '2014-01-01 00:30:00Z' -D P-1H -E '2013-12-31 23:30:00Z'"
     test_assert $CRM_EX_OK 0
 
     for y in 06 07 08 09 10 11 12 13 14 15 16 17 18; do
         desc="20$y-W01-7"
         cmd="iso8601 -d '20$y-W01-7 00Z'"
         test_assert $CRM_EX_OK 0
 
         desc="20$y-W01-7 - round-trip"
         cmd="iso8601 -d '20$y-W01-7 00Z' -W -E '20$y-W01-7 00:00:00Z'"
         test_assert $CRM_EX_OK 0
 
         desc="20$y-W01-1"
         cmd="iso8601 -d '20$y-W01-1 00Z'"
         test_assert $CRM_EX_OK 0
 
         desc="20$y-W01-1 - round-trip"
         cmd="iso8601 -d '20$y-W01-1 00Z' -W -E '20$y-W01-1 00:00:00Z'"
         test_assert $CRM_EX_OK 0
     done
 
     desc="2009-W53-07"
     cmd="iso8601 -d '2009-W53-7 00:00:00Z' -W -E '2009-W53-7 00:00:00Z'"
     test_assert $CRM_EX_OK 0
 
     desc="2009-01-31 + 1 Month"
     cmd="iso8601 -d '2009-01-31 00:00:00Z' -D P1M -E '2009-02-28 00:00:00Z'"
     test_assert $CRM_EX_OK 0
 
     desc="2009-01-31 + 2 Months"
     cmd="iso8601 -d '2009-01-31 00:00:00Z' -D P2M -E '2009-03-31 00:00:00Z'"
     test_assert $CRM_EX_OK 0
 
     desc="2009-01-31 + 3 Months"
     cmd="iso8601 -d '2009-01-31 00:00:00Z' -D P3M -E '2009-04-30 00:00:00Z'"
     test_assert $CRM_EX_OK 0
 
     desc="2009-03-31 - 1 Month"
     cmd="iso8601 -d '2009-03-31 00:00:00Z' -D P-1M -E '2009-02-28 00:00:00Z'"
     test_assert $CRM_EX_OK 0
 }
 
 function test_acl_loop() {
     local TMPXML
 
     TMPXML="$1"
 
     # Make sure we're rejecting things for the right reasons
-    export PCMK_trace_functions=pcmk__check_acl,pcmk__post_process_acl
+    export PCMK_trace_functions=pcmk__check_acl,pcmk__apply_creation_acl
     export PCMK_stderr=1
 
     CIB_user=root cibadmin --replace --xml-text '<resources/>'
 
     export CIB_user=unknownguy
     desc="$CIB_user: Query configuration"
     cmd="cibadmin -Q"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Set enable-acl"
     cmd="crm_attribute -n enable-acl -v false"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Set stonith-enabled"
     cmd="crm_attribute -n stonith-enabled -v false"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Create a resource"
     cmd="cibadmin -C -o resources --xml-text '<primitive id=\"dummy\" class=\"ocf\" provider=\"pacemaker\" type=\"Dummy\"/>'"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     export CIB_user=l33t-haxor
     desc="$CIB_user: Query configuration"
     cmd="cibadmin -Q"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Set enable-acl"
     cmd="crm_attribute -n enable-acl -v false"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Set stonith-enabled"
     cmd="crm_attribute -n stonith-enabled -v false"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Create a resource"
     cmd="cibadmin -C -o resources --xml-text '<primitive id=\"dummy\" class=\"ocf\" provider=\"pacemaker\" type=\"Dummy\"/>'"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     export CIB_user=niceguy
     desc="$CIB_user: Query configuration"
     cmd="cibadmin -Q"
     test_assert $CRM_EX_OK 0
 
     desc="$CIB_user: Set enable-acl"
     cmd="crm_attribute -n enable-acl -v false"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Set stonith-enabled"
     cmd="crm_attribute -n stonith-enabled -v false"
     test_assert $CRM_EX_OK
 
     desc="$CIB_user: Create a resource"
     cmd="cibadmin -C -o resources --xml-text '<primitive id=\"dummy\" class=\"ocf\" provider=\"pacemaker\" type=\"Dummy\"/>'"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     export CIB_user=root
     desc="$CIB_user: Query configuration"
     cmd="cibadmin -Q"
     test_assert $CRM_EX_OK 0
 
     desc="$CIB_user: Set stonith-enabled"
     cmd="crm_attribute -n stonith-enabled -v true"
     test_assert $CRM_EX_OK
 
     desc="$CIB_user: Create a resource"
     cmd="cibadmin -C -o resources --xml-text '<primitive id=\"dummy\" class=\"ocf\" provider=\"pacemaker\" type=\"Dummy\"/>'"
     test_assert $CRM_EX_OK
 
     export CIB_user=l33t-haxor
 
     desc="$CIB_user: Create a resource meta attribute"
     cmd="crm_resource -r dummy --meta -p target-role -v Stopped"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Query a resource meta attribute"
     cmd="crm_resource -r dummy --meta -g target-role"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     desc="$CIB_user: Remove a resource meta attribute"
     cmd="crm_resource -r dummy --meta -d target-role"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     export CIB_user=niceguy
 
     desc="$CIB_user: Create a resource meta attribute"
     cmd="crm_resource -r dummy --meta -p target-role -v Stopped"
     test_assert $CRM_EX_OK
 
     desc="$CIB_user: Query a resource meta attribute"
     cmd="crm_resource -r dummy --meta -g target-role"
     test_assert $CRM_EX_OK
 
     desc="$CIB_user: Remove a resource meta attribute"
     cmd="crm_resource -r dummy --meta -d target-role"
     test_assert $CRM_EX_OK
 
     desc="$CIB_user: Create a resource meta attribute"
     cmd="crm_resource -r dummy --meta -p target-role -v Started"
     test_assert $CRM_EX_OK
 
     export CIB_user=badidea
     desc="$CIB_user: Query configuration - implied deny"
     cmd="cibadmin -Q"
     test_assert $CRM_EX_OK 0
 
     export CIB_user=betteridea
     desc="$CIB_user: Query configuration - explicit deny"
     cmd="cibadmin -Q"
     test_assert $CRM_EX_OK 0
 
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --delete --xml-text '<acls/>'
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     export CIB_user=niceguy
     desc="$CIB_user: Replace - remove acls"
     cmd="cibadmin --replace --xml-file $TMPXML"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -C -o resources --xml-text '<primitive id="dummy2" class="ocf" provider="pacemaker" type="Dummy"/>'
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     desc="$CIB_user: Replace - create resource"
     cmd="cibadmin --replace --xml-file $TMPXML"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" crm_attribute -n enable-acl -v false
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     desc="$CIB_user: Replace - modify attribute (deny)"
     cmd="cibadmin --replace --xml-file $TMPXML"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --replace --xml-text '<nvpair id="cib-bootstrap-options-enable-acl" name="enable-acl"/>'
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     desc="$CIB_user: Replace - delete attribute (deny)"
     cmd="cibadmin --replace --xml-file $TMPXML"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --modify --xml-text '<primitive id="dummy" description="nothing interesting"/>'
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     desc="$CIB_user: Replace - create attribute (deny)"
     cmd="cibadmin --replace --xml-file $TMPXML"
     test_assert $CRM_EX_INSUFFICIENT_PRIV 0
 
     CIB_user=bob
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --modify --xml-text '<primitive id="dummy" description="nothing interesting"/>'
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     desc="$CIB_user: Replace - create attribute (allow)"
     cmd="cibadmin --replace -o resources --xml-file $TMPXML"
     test_assert $CRM_EX_OK 0
 
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --modify --xml-text '<primitive id="dummy" description="something interesting"/>'
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     desc="$CIB_user: Replace - modify attribute (allow)"
     cmd="cibadmin --replace -o resources --xml-file $TMPXML"
     test_assert $CRM_EX_OK 0
 
     CIB_user=root cibadmin -Q > "$TMPXML"
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin --replace -o resources --xml-text '<primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy"/>'
     CIB_user=root CIB_file="$TMPXML" CIB_shadow="" cibadmin -Ql
 
     desc="$CIB_user: Replace - delete attribute (allow)"
     cmd="cibadmin --replace -o resources --xml-file $TMPXML"
     test_assert $CRM_EX_OK 0
 }
 
 function test_acls() {
     local SHADOWPATH
     local TMPXML
 
     TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.acls.xml.XXXXXXXXXX)
     export CIB_shadow_dir="${shadow_dir}"
 
     $VALGRIND_CMD crm_shadow --batch --force --create-empty $shadow --validate-with pacemaker-1.3 2>&1
     export CIB_shadow=$shadow
 
     cat <<EOF > "$TMPXML"
     <acls>
       <acl_user id="l33t-haxor">
         <deny id="crook-nothing" xpath="/cib"/>
       </acl_user>
       <acl_user id="niceguy">
         <role_ref id="observer"/>
       </acl_user>
       <acl_user id="bob">
         <role_ref id="admin"/>
       </acl_user>
       <acl_role id="observer">
         <read id="observer-read-1" xpath="/cib"/>
         <write id="observer-write-1" xpath="//nvpair[@name=&apos;stonith-enabled&apos;]"/>
         <write id="observer-write-2" xpath="//nvpair[@name=&apos;target-role&apos;]"/>
       </acl_role>
       <acl_role id="admin">
         <read id="admin-read-1" xpath="/cib"/>
         <write id="admin-write-1" xpath="//resources"/>
       </acl_role>
     </acls>
 EOF
 
     desc="Configure some ACLs"
     cmd="cibadmin -M -o acls --xml-file $TMPXML"
     test_assert $CRM_EX_OK
 
     desc="Enable ACLs"
     cmd="crm_attribute -n enable-acl -v true"
     test_assert $CRM_EX_OK
 
     desc="Set cluster option"
     cmd="crm_attribute -n no-quorum-policy -v ignore"
     test_assert $CRM_EX_OK
 
     desc="New ACL"
     cmd="cibadmin --create -o acls --xml-text '<acl_user id=\"badidea\"><read id=\"badidea-resources\" xpath=\"//meta_attributes\"/></acl_user>'"
     test_assert $CRM_EX_OK
 
     desc="Another ACL"
     cmd="cibadmin --create -o acls --xml-text '<acl_user id=\"betteridea\"><read id=\"betteridea-resources\" xpath=\"//meta_attributes\"/></acl_user>'"
     test_assert $CRM_EX_OK
 
     desc="Updated ACL"
     cmd="cibadmin --replace -o acls --xml-text '<acl_user id=\"betteridea\"><deny id=\"betteridea-nothing\" xpath=\"/cib\"/><read id=\"betteridea-resources\" xpath=\"//meta_attributes\"/></acl_user>'"
     test_assert $CRM_EX_OK
 
     test_acl_loop "$TMPXML"
 
     printf "\n\n    !#!#!#!#! Upgrading to latest CIB schema and re-testing !#!#!#!#!\n"
     printf "\nUpgrading to latest CIB schema and re-testing\n" 1>&2
 
     export CIB_user=root
     desc="$CIB_user: Upgrade to latest CIB schema"
     cmd="cibadmin --upgrade --force -V"
     test_assert $CRM_EX_OK
 
     SHADOWPATH="$(crm_shadow --file)"
     # sed -i isn't portable :-(
     cp -p "$SHADOWPATH" "${SHADOWPATH}.$$" # to keep permissions
     sed -e 's/epoch=.2/epoch=\"6/g' -e 's/admin_epoch=.1/admin_epoch=\"0/g' \
         "$SHADOWPATH" > "${SHADOWPATH}.$$"
     mv -- "${SHADOWPATH}.$$" "$SHADOWPATH"
 
     test_acl_loop "$TMPXML"
 
     unset CIB_shadow_dir
     rm -f "$TMPXML"
 }
 
 function test_validity() {
     local TMPGOOD
     local TMPBAD
 
     TMPGOOD=$(mktemp ${TMPDIR:-/tmp}/cts-cli.validity.good.xml.XXXXXXXXXX)
     TMPBAD=$(mktemp ${TMPDIR:-/tmp}/cts-cli.validity.bad.xml.XXXXXXXXXX)
     export CIB_shadow_dir="${shadow_dir}"
 
     $VALGRIND_CMD crm_shadow --batch --force --create-empty $shadow --validate-with pacemaker-1.2 2>&1
     export CIB_shadow=$shadow
     export PCMK_trace_functions=apply_upgrade,update_validation,cli_config_update
     export PCMK_stderr=1
 
     cibadmin -C -o resources --xml-text '<primitive id="dummy1" class="ocf" provider="pacemaker" type="Dummy"/>'
     cibadmin -C -o resources --xml-text '<primitive id="dummy2" class="ocf" provider="pacemaker" type="Dummy"/>'
     cibadmin -C -o constraints --xml-text '<rsc_order id="ord_1-2" first="dummy1" first-action="start" then="dummy2"/>'
     cibadmin -Q > "$TMPGOOD"
 
 
     desc="Try to make resulting CIB invalid (enum violation)"
     cmd="cibadmin -M -o constraints --xml-text '<rsc_order id=\"ord_1-2\" first=\"dummy1\" first-action=\"break\" then=\"dummy2\"/>'"
     test_assert $CRM_EX_CONFIG
 
     sed 's|"start"|"break"|' "$TMPGOOD" > "$TMPBAD"
     desc="Run crm_simulate with invalid CIB (enum violation)"
     cmd="crm_simulate -x $TMPBAD -S"
     test_assert $CRM_EX_CONFIG 0
 
 
     desc="Try to make resulting CIB invalid (unrecognized validate-with)"
     cmd="cibadmin -M --xml-text '<cib validate-with=\"pacemaker-9999.0\"/>'"
     test_assert $CRM_EX_CONFIG
 
     sed 's|"pacemaker-1.2"|"pacemaker-9999.0"|' "$TMPGOOD" > "$TMPBAD"
     desc="Run crm_simulate with invalid CIB (unrecognized validate-with)"
     cmd="crm_simulate -x $TMPBAD -S"
     test_assert $CRM_EX_CONFIG 0
 
 
     desc="Try to make resulting CIB invalid, but possibly recoverable (valid with X.Y+1)"
     cmd="cibadmin -C -o configuration --xml-text '<tags/>'"
     test_assert $CRM_EX_CONFIG
 
     sed 's|</configuration>|<tags/></configuration>|' "$TMPGOOD" > "$TMPBAD"
     desc="Run crm_simulate with invalid, but possibly recoverable CIB (valid with X.Y+1)"
     cmd="crm_simulate -x $TMPBAD -S"
     test_assert $CRM_EX_OK 0
 
 
     sed 's|[ 	][ 	]*validate-with="[^"]*"||' "$TMPGOOD" > "$TMPBAD"
     desc="Make resulting CIB valid, although without validate-with attribute"
     cmd="cibadmin -R --xml-file $TMPBAD"
     test_assert $CRM_EX_OK
 
     desc="Run crm_simulate with valid CIB, but without validate-with attribute"
     cmd="crm_simulate -x $TMPBAD -S"
     test_assert $CRM_EX_OK 0
 
 
     # this will just disable validation and accept the config, outputting
     # validation errors
     sed -e 's|[ 	][ 	]*validate-with="[^"]*"||' \
         -e 's|\([ 	][ 	]*epoch="[^"]*\)"|\10"|' -e 's|"start"|"break"|' \
         "$TMPGOOD" > "$TMPBAD"
     desc="Make resulting CIB invalid, and without validate-with attribute"
     cmd="cibadmin -R --xml-file $TMPBAD"
     test_assert $CRM_EX_OK
 
     desc="Run crm_simulate with invalid CIB, also without validate-with attribute"
     cmd="crm_simulate -x $TMPBAD -S"
     test_assert $CRM_EX_OK 0
 
     unset CIB_shadow_dir
     rm -f "$TMPGOOD" "$TMPBAD"
 }
 
 test_upgrade() {
     local TMPXML
 
     TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.xml.XXXXXXXXXX)
     export CIB_shadow_dir="${shadow_dir}"
 
     $VALGRIND_CMD crm_shadow --batch --force --create-empty $shadow --validate-with pacemaker-2.10 2>&1
     export CIB_shadow=$shadow
 
     desc="Set stonith-enabled=false"
     cmd="crm_attribute -n stonith-enabled -v false"
     test_assert $CRM_EX_OK
 
     cat <<EOF > "$TMPXML"
     <resources>
       <primitive id="mySmartFuse" class="ocf" provider="experiment" type="SmartFuse">
         <operations>
           <op id="mySmartFuse-start" name="start" interval="0" timeout="40s"/>
           <op id="mySmartFuse-monitor-inputpower" name="monitor" interval="30s">
             <instance_attributes id="mySmartFuse-inputpower-instanceparams">
               <nvpair id="mySmartFuse-inputpower-requires" name="requires" value="inputpower"/>
             </instance_attributes>
           </op>
           <op id="mySmartFuse-monitor-outputpower" name="monitor" interval="2s">
             <instance_attributes id="mySmartFuse-outputpower-instanceparams">
               <nvpair id="mySmartFuse-outputpower-requires" name="requires" value="outputpower"/>
             </instance_attributes>
           </op>
         </operations>
         <instance_attributes id="mySmartFuse-params">
           <nvpair id="mySmartFuse-params-ip" name="ip" value="192.0.2.10"/>
         </instance_attributes>
 	<!-- a bit hairy but valid -->
         <instance_attributes id-ref="mySmartFuse-outputpower-instanceparams"/>
       </primitive>
     </resources>
 EOF
 
     desc="Configure the initial resource"
     cmd="cibadmin -M -o resources --xml-file $TMPXML"
     test_assert $CRM_EX_OK
 
     desc="Upgrade to latest CIB schema (trigger 2.10.xsl + the wrapping)"
     cmd="cibadmin --upgrade --force -V -V"
     test_assert $CRM_EX_OK
 
     desc="Query a resource instance attribute (shall survive)"
     cmd="crm_resource -r mySmartFuse -g requires"
     test_assert $CRM_EX_OK
 
     unset CIB_shadow_dir
     rm -f "$TMPXML"
 }
 
 test_rules() {
     local TMPXML
 
     export CIB_shadow_dir="${shadow_dir}"
     $VALGRIND_CMD crm_shadow --batch --force --create-empty $shadow 2>&1
     export CIB_shadow=$shadow
 
     cibadmin -C -o resources   --xml-text '<primitive class="ocf" id="dummy" provider="heartbeat" type="Dummy" />'
     cibadmin -C -o constraints --xml-text '<rsc_location id="no-date-expression" rsc="dummy" score="-INFINITY" node="node01" />'
 
     TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.xml.XXXXXXXXXX)
     cat <<EOF > "$TMPXML"
 <rsc_location id="cli-prefer-dummy-expired" rsc="dummy">
   <rule id="cli-prefer-rule-dummy-expired" score="INFINITY">
     <date_expression id="cli-prefer-lifetime-end-dummy-expired" operation="lt" end="2019-01-01 12:00:00 -05:00"/>
   </rule>
 </rsc_location>
 EOF
 
     cibadmin -C -o constraints -x "$TMPXML"
     rm -f "$TMPXML"
 
     if [ "$(uname)" == "FreeBSD" ]; then
         tomorrow=$(date -v+1d +"%F %T %z")
     else
         tomorrow=$(date --date=tomorrow +"%F %T %z")
     fi
 
     TMPXML=$(mktemp ${TMPDIR:-/tmp}/cts-cli.tools.xml.XXXXXXXXXX)
     cat <<EOF > "$TMPXML"
 <rsc_location id="cli-prefer-dummy-not-yet" rsc="dummy">
   <rule id="cli-prefer-rule-dummy-not-yet" score="INFINITY">
     <date_expression id="cli-prefer-lifetime-end-dummy-not-yet" operation="gt" start="${tomorrow}"/>
   </rule>
 </rsc_location>
 EOF
 
     cibadmin -C -o constraints -x "$TMPXML"
     rm -f "$TMPXML"
 
     desc="Try to check a rule that doesn't exist"
     cmd="crm_rule -c -r blahblah"
     test_assert $CRM_EX_NOSUCH
 
     desc="Try to check a rule that has no date_expression"
     cmd="crm_rule -c -r no-date-expression"
     test_assert $CRM_EX_NOSUCH
 
     desc="Verify basic rule is expired"
     cmd="crm_rule -c -r cli-prefer-rule-dummy-expired"
     test_assert $CRM_EX_EXPIRED
 
     desc="Verify basic rule worked in the past"
     cmd="crm_rule -c -r cli-prefer-rule-dummy-expired -d 20180101"
     test_assert $CRM_EX_OK
 
     desc="Verify basic rule is not yet in effect"
     cmd="crm_rule -c -r cli-prefer-rule-dummy-not-yet"
     test_assert $CRM_EX_NOT_YET_IN_EFFECT
 
     unset CIB_shadow_dir
 }
 
 # Process command-line arguments
 while [ $# -gt 0 ]; do
     case "$1" in
         -t)
             tests="$2"
             shift 2
             ;;
         -V|--verbose)
             verbose=1
             shift
             ;;
         -v|--valgrind)
             export G_SLICE=always-malloc
             VALGRIND_CMD="valgrind $VALGRIND_OPTS"
             shift
             ;;
         -s)
             do_save=1
             shift
             ;;
         -p)
             export PATH="$2:$PATH"
             shift
             ;;
         --help)
             echo "$USAGE_TEXT"
             exit $CRM_EX_OK
             ;;
         *)
             echo "error: unknown option $1"
             echo
             echo "$USAGE_TEXT"
             exit $CRM_EX_USAGE
             ;;
     esac
 done
 
 for t in $tests; do
     case "$t" in
         dates) ;;
         tools) ;;
         acls) ;;
         validity) ;;
         upgrade) ;;
         rules) ;;
         *)
             echo "error: unknown test $t"
             echo
             echo "$USAGE_TEXT"
             exit $CRM_EX_USAGE
             ;;
     esac
 done
 
 # Check whether we're running from source directory
 SRCDIR=$(dirname $test_home)
 if [ -x "$SRCDIR/tools/crm_simulate" ]; then
     export PATH="$SRCDIR/tools:$PATH"
     echo "Using local binaries from: $SRCDIR/tools"
 
     if [ -x "$SRCDIR/xml" ]; then
         export PCMK_schema_directory="$SRCDIR/xml"
         echo "Using local schemas from: $PCMK_schema_directory"
     fi
 fi
 
 for t in $tests; do
     echo "Testing $t"
     TMPFILE=$(mktemp ${TMPDIR:-/tmp}/cts-cli.$t.XXXXXXXXXX)
     eval TMPFILE_$t="$TMPFILE"
     test_$t > "$TMPFILE"
 
     sed -e 's/cib-last-written.*>/>/'\
         -e 's/ last-run=\"[0-9]*\"//'\
         -e 's/crm_feature_set="[^"]*" //'\
         -e 's/validate-with="[^"]*" //'\
         -e 's/Created new pacemaker-.* configuration/Created new pacemaker configuration/'\
         -e 's/.*\(pcmk__.*\)@.*\.c:[0-9][0-9]*)/\1/g' \
         -e 's/.*\(unpack_.*\)@.*\.c:[0-9][0-9]*)/\1/g' \
         -e 's/.*\(update_validation\)@.*\.c:[0-9][0-9]*)/\1/g' \
         -e 's/.*\(apply_upgrade\)@.*\.c:[0-9][0-9]*)/\1/g' \
         -e 's/ last-rc-change=\"[0-9]*\"//'\
         -e 's|^/tmp/cts-cli\.validity\.bad.xml\.[^:]*:|validity.bad.xml:|'\
         -e 's/^Entity: line [0-9][0-9]*: //'\
         -e 's/\(validation ([0-9][0-9]* of \)[0-9][0-9]*\().*\)/\1X\2/' \
         -e 's/^Migration will take effect until: .*/Migration will take effect until:/' \
         -e 's/ end=\"[0-9][-+: 0-9]*Z*\"/ end=\"\"/' \
         -e 's/ start=\"[0-9][-+: 0-9]*Z*\"/ start=\"\"/' \
         -e 's/^Error checking rule: Device not configured/Error checking rule: No such device or address/' \
         "$TMPFILE" > "${TMPFILE}.$$"
     mv -- "${TMPFILE}.$$" "$TMPFILE"
 
     if [ $do_save -eq 1 ]; then
         cp "$TMPFILE" $test_home/cli/regression.$t.exp
     fi
 done
 
 rm -rf "${shadow_dir}"
     
 failed=0
 
 if [ $verbose -eq 1 ]; then
     echo -e "\n\nResults"
 fi
 for t in $tests; do
     eval TMPFILE="\$TMPFILE_$t"
     if [ $verbose -eq 1 ]; then
         diff -wu $test_home/cli/regression.$t.exp "$TMPFILE"
     else
         diff -w $test_home/cli/regression.$t.exp "$TMPFILE" >/dev/null 2>&1
     fi
     if [ $? -ne 0 ]; then
         failed=1
     fi
 done
 
 echo -e "\n\nSummary"
 for t in $tests; do
     eval TMPFILE="\$TMPFILE_$t"
     grep -e '^\*' "$TMPFILE"
 done
 
 if [ $num_errors -ne 0 ]; then
     echo "$num_errors tests failed; see output in:"
     for t in $tests; do
         eval TMPFILE="\$TMPFILE_$t"
         echo "    $TMPFILE"
     done
     exit $CRM_EX_ERROR
 
 elif [ $failed -eq 1 ]; then
     echo "$num_passed tests passed but output was unexpected; see output in:"
     for t in $tests; do
         eval TMPFILE="\$TMPFILE_$t"
         echo "    $TMPFILE"
     done
     exit $CRM_EX_DIGEST
 
 else
     echo $num_passed tests passed
     for t in $tests; do
         eval TMPFILE="\$TMPFILE_$t"
         rm -f "$TMPFILE"
     done
     crm_shadow --force --delete $shadow >/dev/null 2>&1
     exit $CRM_EX_OK
 fi
diff --git a/lib/common/acl.c b/lib/common/acl.c
index 910754bbb5..20c5d8c419 100644
--- a/lib/common/acl.c
+++ b/lib/common/acl.c
@@ -1,800 +1,800 @@
 /*
  * Copyright 2004-2019 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <stdio.h>
 #include <sys/types.h>
 #include <pwd.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
 
 #include <libxml/tree.h>
 
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include "crmcommon_private.h"
 
 #define MAX_XPATH_LEN	4096
 
 typedef struct xml_acl_s {
         enum xml_private_flags mode;
         char *xpath;
 } xml_acl_t;
 
 static void
 __xml_acl_free(void *data)
 {
     if (data) {
         xml_acl_t *acl = data;
 
         free(acl->xpath);
         free(acl);
     }
 }
 
 void
 pcmk__free_acls(GList *acls)
 {
     g_list_free_full(acls, __xml_acl_free);
 }
 
 static GList *
 __xml_acl_create(xmlNode *xml, GList *acls, enum xml_private_flags mode)
 {
     xml_acl_t *acl = NULL;
 
     const char *tag = crm_element_value(xml, XML_ACL_ATTR_TAG);
     const char *ref = crm_element_value(xml, XML_ACL_ATTR_REF);
     const char *xpath = crm_element_value(xml, XML_ACL_ATTR_XPATH);
     const char *attr = crm_element_value(xml, XML_ACL_ATTR_ATTRIBUTE);
 
     if (tag == NULL) {
         // @COMPAT rolling upgrades <=1.1.11
         tag = crm_element_value(xml, XML_ACL_ATTR_TAGv1);
     }
     if (ref == NULL) {
         // @COMPAT rolling upgrades <=1.1.11
         ref = crm_element_value(xml, XML_ACL_ATTR_REFv1);
     }
 
     if ((tag == NULL) && (ref == NULL) && (xpath == NULL)) {
         // Schema should prevent this, but to be safe ...
         crm_trace("Ignoring ACL <%s> element without selection criteria",
                   crm_element_name(xml));
         return NULL;
     }
 
     acl = calloc(1, sizeof (xml_acl_t));
     CRM_ASSERT(acl != NULL);
 
     acl->mode = mode;
     if (xpath) {
         acl->xpath = strdup(xpath);
         CRM_ASSERT(acl->xpath != NULL);
         crm_trace("Unpacked ACL <%s> element using xpath: %s",
                   crm_element_name(xml), acl->xpath);
 
     } else {
         int offset = 0;
         char buffer[MAX_XPATH_LEN];
 
         if (tag) {
             offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
                                "//%s", tag);
         } else {
             offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
                                "//*");
         }
 
         if (ref || attr) {
             offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
                                "[");
         }
 
         if (ref) {
             offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
                                "@id='%s'", ref);
         }
 
         // NOTE: schema currently does not allow this
         if (ref && attr) {
             offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
                                " and ");
         }
 
         if (attr) {
             offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
                                "@%s", attr);
         }
 
         if (ref || attr) {
             offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
                                "]");
         }
 
         CRM_LOG_ASSERT(offset > 0);
         acl->xpath = strdup(buffer);
         CRM_ASSERT(acl->xpath != NULL);
 
         crm_trace("Unpacked ACL <%s> element using equivalent xpath: %s",
                   crm_element_name(xml), acl->xpath);
     }
 
     return g_list_append(acls, acl);
 }
 
 /*!
  * \internal
  * \brief Unpack a user, group, or role subtree of the ACLs section
  *
  * \param[in]     acl_top    XML of entire ACLs section
  * \param[in]     acl_entry  XML of ACL element being unpacked
  * \param[in,out] acls       List of ACLs unpacked so far
  *
  * \return New head of (possibly modified) acls
  */
 static GList *
 __xml_acl_parse_entry(xmlNode *acl_top, xmlNode *acl_entry, GList *acls)
 {
     xmlNode *child = NULL;
 
     for (child = __xml_first_child(acl_entry); child;
          child = __xml_next(child)) {
         const char *tag = crm_element_name(child);
         const char *kind = crm_element_value(child, XML_ACL_ATTR_KIND);
 
         if (strcmp(XML_ACL_TAG_PERMISSION, tag) == 0){
             CRM_ASSERT(kind != NULL);
             crm_trace("Unpacking ACL <%s> element of kind '%s'", tag, kind);
             tag = kind;
         } else {
             crm_trace("Unpacking ACL <%s> element", tag);
         }
 
         if (strcmp(XML_ACL_TAG_ROLE_REF, tag) == 0
                    || strcmp(XML_ACL_TAG_ROLE_REFv1, tag) == 0) {
             const char *ref_role = crm_element_value(child, XML_ATTR_ID);
 
             if (ref_role) {
                 xmlNode *role = NULL;
 
                 for (role = __xml_first_child(acl_top); role;
                      role = __xml_next(role)) {
                     if (!strcmp(XML_ACL_TAG_ROLE, (const char *) role->name)) {
                         const char *role_id = crm_element_value(role,
                                                                 XML_ATTR_ID);
 
                         if (role_id && strcmp(ref_role, role_id) == 0) {
                             crm_trace("Unpacking referenced role '%s' in ACL <%s> element",
                                       role_id, crm_element_name(acl_entry));
                             acls = __xml_acl_parse_entry(acl_top, role, acls);
                             break;
                         }
                     }
                 }
             }
 
         } else if (strcmp(XML_ACL_TAG_READ, tag) == 0) {
             acls = __xml_acl_create(child, acls, xpf_acl_read);
 
         } else if (strcmp(XML_ACL_TAG_WRITE, tag) == 0) {
             acls = __xml_acl_create(child, acls, xpf_acl_write);
 
         } else if (strcmp(XML_ACL_TAG_DENY, tag) == 0) {
             acls = __xml_acl_create(child, acls, xpf_acl_deny);
 
         } else {
             crm_warn("Ignoring unknown ACL %s '%s'",
                      (kind? "kind" : "element"), tag);
         }
     }
 
     return acls;
 }
 
 /*
     <acls>
       <acl_target id="l33t-haxor"><role id="auto-l33t-haxor"/></acl_target>
       <acl_role id="auto-l33t-haxor">
         <acl_permission id="crook-nothing" kind="deny" xpath="/cib"/>
       </acl_role>
       <acl_target id="niceguy">
         <role id="observer"/>
       </acl_target>
       <acl_role id="observer">
         <acl_permission id="observer-read-1" kind="read" xpath="/cib"/>
         <acl_permission id="observer-write-1" kind="write" xpath="//nvpair[@name='stonith-enabled']"/>
         <acl_permission id="observer-write-2" kind="write" xpath="//nvpair[@name='target-role']"/>
       </acl_role>
       <acl_target id="badidea"><role id="auto-badidea"/></acl_target>
       <acl_role id="auto-badidea">
         <acl_permission id="badidea-resources" kind="read" xpath="//meta_attributes"/>
         <acl_permission id="badidea-resources-2" kind="deny" reference="dummy-meta_attributes"/>
       </acl_role>
     </acls>
 */
 
 static const char *
 __xml_acl_to_text(enum xml_private_flags flags)
 {
     if (is_set(flags, xpf_acl_deny)) {
         return "deny";
 
     } else if (is_set(flags, xpf_acl_write) || is_set(flags, xpf_acl_create)) {
         return "read/write";
 
     } else if (is_set(flags, xpf_acl_read)) {
         return "read";
     }
     return "none";
 }
 
 void
 pcmk__apply_acl(xmlNode *xml)
 {
     GListPtr aIter = NULL;
     xml_private_t *p = xml->doc->_private;
     xmlXPathObjectPtr xpathObj = NULL;
 
     if (xml_acl_enabled(xml) == FALSE) {
         crm_trace("Skipping ACLs for user '%s' because not enabled for this XML",
                   p->user);
         return;
     }
 
     for (aIter = p->acls; aIter != NULL; aIter = aIter->next) {
         int max = 0, lpc = 0;
         xml_acl_t *acl = aIter->data;
 
         xpathObj = xpath_search(xml, acl->xpath);
         max = numXpathResults(xpathObj);
 
         for (lpc = 0; lpc < max; lpc++) {
             xmlNode *match = getXpathResult(xpathObj, lpc);
             char *path = xml_get_path(match);
 
             p = match->_private;
             crm_trace("Applying %s ACL to %s matched by %s",
                       __xml_acl_to_text(acl->mode), path, acl->xpath);
 
 #ifdef SUSE_ACL_COMPAT
             if (is_not_set(p->flags, acl->mode)
                 && (is_set(p->flags, xpf_acl_read)
                     || is_set(p->flags, xpf_acl_write)
                     || is_set(p->flags, xpf_acl_deny))) {
                 crm_config_warn("Configuration element %s is matched by "
                                 "multiple ACL rules, only the first applies "
                                 "('%s' wins over '%s')",
                                 path, __xml_acl_to_text(p->flags),
                                 __xml_acl_to_text(acl->mode));
                 free(path);
                 continue;
             }
 #endif
             p->flags |= acl->mode;
             free(path);
         }
         crm_trace("Applied %s ACL %s (%d match%s)",
                   __xml_acl_to_text(acl->mode), acl->xpath, max,
                   ((max == 1)? "" : "es"));
         freeXpathObject(xpathObj);
     }
 
     p = xml->_private;
     if (is_not_set(p->flags, xpf_acl_read)
         && is_not_set(p->flags, xpf_acl_write)) {
 
         p->flags |= xpf_acl_deny;
         p = xml->doc->_private;
         crm_info("Applied default deny ACL for user '%s' to <%s>",
                  p->user, crm_element_name(xml));
     }
 
 }
 
 /*!
  * \internal
  * \brief Unpack ACLs for a given user
  *
  * \param[in]     source  XML with ACL definitions
  * \param[in,out] target  XML that ACLs will be applied to
  * \param[in]     user    Username whose ACLs need to be unpacked
  */
 void
 pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user)
 {
 #if ENABLE_ACL
     xml_private_t *p = NULL;
 
     if ((target == NULL) || (target->doc == NULL)
         || (target->doc->_private == NULL)) {
         return;
     }
 
     p = target->doc->_private;
     if (pcmk_acl_required(user) == FALSE) {
         crm_trace("Not unpacking ACLs because not required for user '%s'",
                   user);
 
     } else if (p->acls == NULL) {
         xmlNode *acls = get_xpath_object("//" XML_CIB_TAG_ACLS,
                                          source, LOG_TRACE);
 
         free(p->user);
         p->user = strdup(user);
 
         if (acls) {
             xmlNode *child = NULL;
 
             for (child = __xml_first_child(acls); child;
                  child = __xml_next(child)) {
                 const char *tag = crm_element_name(child);
 
                 if (!strcmp(tag, XML_ACL_TAG_USER)
                     || !strcmp(tag, XML_ACL_TAG_USERv1)) {
                     const char *id = crm_element_value(child, XML_ATTR_ID);
 
                     if (id && strcmp(id, user) == 0) {
                         crm_debug("Unpacking ACLs for user '%s'", id);
                         p->acls = __xml_acl_parse_entry(acls, child, p->acls);
                     }
                 }
             }
         }
     }
 #endif
 }
 
 static inline bool
 __xml_acl_mode_test(enum xml_private_flags allowed,
                     enum xml_private_flags requested)
 {
     if (is_set(allowed, xpf_acl_deny)) {
         return FALSE;
 
     } else if (is_set(allowed, requested)) {
         return TRUE;
 
     } else if (is_set(requested, xpf_acl_read)
                && is_set(allowed, xpf_acl_write)) {
         return TRUE;
 
     } else if (is_set(requested, xpf_acl_create)
                && is_set(allowed, xpf_acl_write)) {
         return TRUE;
 
     } else if (is_set(requested, xpf_acl_create)
                && is_set(allowed, xpf_created)) {
         return TRUE;
     }
     return FALSE;
 }
 
 /* rc = TRUE if orig_cib has been filtered
  * That means '*result' rather than 'xml' should be exploited afterwards
  */
 static bool
 __xml_purge_attributes(xmlNode *xml)
 {
     xmlNode *child = NULL;
     xmlAttr *xIter = NULL;
     bool readable_children = FALSE;
     xml_private_t *p = xml->_private;
 
     if (__xml_acl_mode_test(p->flags, xpf_acl_read)) {
         crm_trace("%s[@id=%s] is readable", crm_element_name(xml), ID(xml));
         return TRUE;
     }
 
     xIter = xml->properties;
     while (xIter != NULL) {
         xmlAttr *tmp = xIter;
         const char *prop_name = (const char *)xIter->name;
 
         xIter = xIter->next;
         if (strcmp(prop_name, XML_ATTR_ID) == 0) {
             continue;
         }
 
         xmlUnsetProp(xml, tmp->name);
     }
 
     child = __xml_first_child(xml);
     while ( child != NULL ) {
         xmlNode *tmp = child;
 
         child = __xml_next(child);
         readable_children |= __xml_purge_attributes(tmp);
     }
 
     if (readable_children == FALSE) {
         free_xml(xml); /* Nothing readable under here, purge completely */
     }
     return readable_children;
 }
 
 /*!
  * \internal
  * \brief Copy ACL-allowed portions of specified XML
  *
  * \param[in]  user        Username whose ACLs should be used
  * \param[in]  acl_source  XML containing ACLs
  * \param[in]  xml         XML to be copied
  * \param[out] result      Copy of XML portions readable via ACLs
  *
  * \return TRUE if xml exists and ACLs are required for user, otherwise FALSE
  */
 bool
 xml_acl_filtered_copy(const char *user, xmlNode *acl_source, xmlNode *xml,
                       xmlNode **result)
 {
     GListPtr aIter = NULL;
     xmlNode *target = NULL;
     xml_private_t *p = NULL;
     xml_private_t *doc = NULL;
 
     *result = NULL;
     if (xml == NULL || pcmk_acl_required(user) == FALSE) {
         crm_trace("Not filtering XML because ACLs not required for user '%s'",
                   user);
         return FALSE;
     }
 
     crm_trace("Filtering XML copy using user '%s' ACLs", user);
     target = copy_xml(xml);
     if (target == NULL) {
         return TRUE;
     }
 
     pcmk__unpack_acl(acl_source, target, user);
     pcmk__set_xml_flag(target, xpf_acl_enabled);
     pcmk__apply_acl(target);
 
     doc = target->doc->_private;
     for(aIter = doc->acls; aIter != NULL && target; aIter = aIter->next) {
         int max = 0;
         xml_acl_t *acl = aIter->data;
 
         if (acl->mode != xpf_acl_deny) {
             /* Nothing to do */
 
         } else if (acl->xpath) {
             int lpc = 0;
             xmlXPathObjectPtr xpathObj = xpath_search(target, acl->xpath);
 
             max = numXpathResults(xpathObj);
             for(lpc = 0; lpc < max; lpc++) {
                 xmlNode *match = getXpathResult(xpathObj, lpc);
 
                 if (__xml_purge_attributes(match) == FALSE && match == target) {
                     crm_trace("ACLs deny user '%s' access to entire XML document",
                               user);
                     freeXpathObject(xpathObj);
                     return TRUE;
                 }
             }
             crm_trace("Enforced deny ACL %s (%d match%s)",
                       acl->xpath, max, ((max == 1)? "" : "es"));
             freeXpathObject(xpathObj);
         }
     }
 
     p = target->_private;
     if (is_set(p->flags, xpf_acl_deny)
         && (__xml_purge_attributes(target) == FALSE)) {
         crm_trace("ACLs deny user '%s' access to entire XML document", user);
         return TRUE;
     }
 
     if (doc->acls) {
         g_list_free_full(doc->acls, __xml_acl_free);
         doc->acls = NULL;
 
     } else {
         crm_trace("User '%s' without ACLs denied access to entire XML document",
                   user);
         free_xml(target);
         target = NULL;
     }
 
     if (target) {
         *result = target;
     }
 
     return TRUE;
 }
 
 /*!
  * \internal
  * \brief Check whether creation of an XML element is implicitly allowed
  *
  * Check whether XML is a "scaffolding" element whose creation is implicitly
  * allowed regardless of ACLs (that is, it is not in the ACL section and has
  * no attributes other than "id").
  *
  * \param[in] xml  XML element to check
  *
  * \return TRUE if XML element is implicitly allowed, FALSE otherwise
  */
 static bool
 implicitly_allowed(xmlNode *xml)
 {
     char *path = NULL;
 
     for (xmlAttr *prop = xml->properties; prop != NULL; prop = prop->next) {
         if (strcmp((const char *) prop->name, XML_ATTR_ID) != 0) {
             return FALSE;
         }
     }
 
     path = xml_get_path(xml);
     if (strstr(path, "/" XML_CIB_TAG_ACLS "/") != NULL) {
         free(path);
         return FALSE;
     }
     free(path);
 
     return TRUE;
 }
 
 #define display_id(xml) (ID(xml)? ID(xml) : "<unset>")
 
 /*!
  * \internal
  * \brief Drop XML nodes created in violation of ACLs
  *
  * Given an XML element, free all of its descendent nodes created in violation
  * of ACLs, with the exception of allowing "scaffolding" elements (i.e. those
  * that aren't in the ACL section and don't have any attributes other than
  * "id").
  *
  * \param[in,out] xml        XML to check
  * \param[in]     check_top  Whether to apply checks to argument itself
  *                           (if TRUE, xml might get freed)
  */
 void
-pcmk__post_process_acl(xmlNode *xml, bool check_top)
+pcmk__apply_creation_acl(xmlNode *xml, bool check_top)
 {
     xml_private_t *p = xml->_private;
 
     if (is_set(p->flags, xpf_created)) {
         if (implicitly_allowed(xml)) {
             crm_trace("Creation of <%s> scaffolding with id=\"%s\""
                       " is implicitly allowed",
                       crm_element_name(xml), display_id(xml));
 
         } else if (pcmk__check_acl(xml, NULL, xpf_acl_write)) {
             crm_trace("ACLs allow creation of <%s> with id=\"%s\"",
                       crm_element_name(xml), display_id(xml));
 
         } else if (check_top) {
             crm_trace("ACLs disallow creation of <%s> with id=\"%s\"",
                       crm_element_name(xml), display_id(xml));
             pcmk_free_xml_subtree(xml);
             return;
 
         } else {
             crm_trace("ACLs would disallow creation of <%s> with id=\"%s\"",
                       crm_element_name(xml), display_id(xml));
         }
     }
 
     for (xmlNode *cIter = __xml_first_child(xml); cIter != NULL; ) {
         xmlNode *child = cIter;
         cIter = __xml_next(cIter); /* In case it is free'd */
-        pcmk__post_process_acl(child, TRUE);
+        pcmk__apply_creation_acl(child, TRUE);
     }
 }
 
 bool
 xml_acl_denied(xmlNode *xml)
 {
     if (xml && xml->doc && xml->doc->_private){
         xml_private_t *p = xml->doc->_private;
 
         return is_set(p->flags, xpf_acl_denied);
     }
     return FALSE;
 }
 
 void
 xml_acl_disable(xmlNode *xml)
 {
     if (xml_acl_enabled(xml)) {
         xml_private_t *p = xml->doc->_private;
 
         /* Catch anything that was created but shouldn't have been */
         pcmk__apply_acl(xml);
-        pcmk__post_process_acl(xml, FALSE);
+        pcmk__apply_creation_acl(xml, FALSE);
         clear_bit(p->flags, xpf_acl_enabled);
     }
 }
 
 bool
 xml_acl_enabled(xmlNode *xml)
 {
     if (xml && xml->doc && xml->doc->_private){
         xml_private_t *p = xml->doc->_private;
 
         return is_set(p->flags, xpf_acl_enabled);
     }
     return FALSE;
 }
 
 bool
 pcmk__check_acl(xmlNode *xml, const char *name, enum xml_private_flags mode)
 {
     CRM_ASSERT(xml);
     CRM_ASSERT(xml->doc);
     CRM_ASSERT(xml->doc->_private);
 
 #if ENABLE_ACL
     if (pcmk__tracking_xml_changes(xml, FALSE) && xml_acl_enabled(xml)) {
         int offset = 0;
         xmlNode *parent = xml;
         char buffer[MAX_XPATH_LEN];
         xml_private_t *docp = xml->doc->_private;
 
         offset = pcmk__element_xpath(NULL, xml, buffer, offset,
                                      sizeof(buffer));
         if (name) {
             offset += snprintf(buffer + offset, MAX_XPATH_LEN - offset,
                                "[@%s]", name);
         }
         CRM_LOG_ASSERT(offset > 0);
 
         if (docp->acls == NULL) {
             crm_trace("User '%s' without ACLs denied %s access to %s",
                       docp->user, __xml_acl_to_text(mode), buffer);
             pcmk__set_xml_flag(xml, xpf_acl_denied);
             return FALSE;
         }
 
         /* Walk the tree upwards looking for xml_acl_* flags
          * - Creating an attribute requires write permissions for the node
          * - Creating a child requires write permissions for the parent
          */
 
         if (name) {
             xmlAttr *attr = xmlHasProp(xml, (pcmkXmlStr) name);
 
             if (attr && mode == xpf_acl_create) {
                 mode = xpf_acl_write;
             }
         }
 
         while (parent && parent->_private) {
             xml_private_t *p = parent->_private;
             if (__xml_acl_mode_test(p->flags, mode)) {
                 return TRUE;
 
             } else if (is_set(p->flags, xpf_acl_deny)) {
                 crm_trace("Parent ACL denies user '%s' %s access to %s",
                           docp->user, __xml_acl_to_text(mode), buffer);
                 pcmk__set_xml_flag(xml, xpf_acl_denied);
                 return FALSE;
             }
             parent = parent->parent;
         }
 
         crm_trace("Default ACL denies user '%s' %s access to %s",
                   docp->user, __xml_acl_to_text(mode), buffer);
         pcmk__set_xml_flag(xml, xpf_acl_denied);
         return FALSE;
     }
 #endif
 
     return TRUE;
 }
 
 bool
 pcmk_acl_required(const char *user)
 {
 #if ENABLE_ACL
     if ((user == NULL) || (*user == '\0')) {
         crm_trace("ACLs not required because no user set");
         return FALSE;
 
     } else if (!strcmp(user, CRM_DAEMON_USER) || !strcmp(user, "root")) {
         crm_trace("ACLs not required for privileged user %s", user);
         return FALSE;
     }
     crm_trace("ACLs required for %s", user);
     return TRUE;
 #else
     crm_trace("ACLs not required because not supported by this build");
     return FALSE;
 #endif
 }
 
 #if ENABLE_ACL
 char *
 uid2username(uid_t uid)
 {
     struct passwd *pwent = getpwuid(uid);
 
     if (pwent == NULL) {
         crm_perror(LOG_INFO, "Cannot get user details for user ID %d", uid);
         return NULL;
     }
     return strdup(pwent->pw_name);
 }
 
 const char *
 crm_acl_get_set_user(xmlNode *request, const char *field, const char *peer_user)
 {
     static const char *effective_user = NULL;
     const char *requested_user = NULL;
     const char *user = NULL;
 
     if (effective_user == NULL) {
         effective_user = uid2username(geteuid());
         if (effective_user == NULL) {
             effective_user = strdup("#unprivileged");
             CRM_CHECK(effective_user != NULL, return NULL);
             crm_err("Unable to determine effective user, assuming unprivileged for ACLs");
         }
     }
 
     requested_user = crm_element_value(request, XML_ACL_TAG_USER);
     if (requested_user == NULL) {
         /* @COMPAT rolling upgrades <=1.1.11
          *
          * field is checked for backward compatibility with older versions that
          * did not use XML_ACL_TAG_USER.
          */
         requested_user = crm_element_value(request, field);
     }
 
     if (is_privileged(effective_user) == FALSE) {
         /* We're not running as a privileged user, set or overwrite any existing
          * value for $XML_ACL_TAG_USER
          */
         user = effective_user;
 
     } else if (peer_user == NULL && requested_user == NULL) {
         /* No user known or requested, use 'effective_user' and make sure one is
          * set for the request
          */
         user = effective_user;
 
     } else if (peer_user == NULL) {
         /* No user known, trusting 'requested_user' */
         user = requested_user;
 
     } else if (is_privileged(peer_user) == FALSE) {
         /* The peer is not a privileged user, set or overwrite any existing
          * value for $XML_ACL_TAG_USER
          */
         user = peer_user;
 
     } else if (requested_user == NULL) {
         /* Even if we're privileged, make sure there is always a value set */
         user = peer_user;
 
     } else {
         /* Legal delegation to 'requested_user' */
         user = requested_user;
     }
 
     // This requires pointer comparison, not string comparison
     if (user != crm_element_value(request, XML_ACL_TAG_USER)) {
         crm_xml_add(request, XML_ACL_TAG_USER, user);
     }
 
     if (field != NULL && user != crm_element_value(request, field)) {
         crm_xml_add(request, field, user);
     }
 
     return requested_user;
 }
 #endif
diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h
index b153873156..dfb1e54010 100644
--- a/lib/common/crmcommon_private.h
+++ b/lib/common/crmcommon_private.h
@@ -1,89 +1,89 @@
 /*
  * Copyright 2018-2019 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #ifndef CRMCOMMON_PRIVATE__H
 #  define CRMCOMMON_PRIVATE__H
 
 /* This header is for the sole use of libcrmcommon, so that functions can be
  * declared with G_GNUC_INTERNAL for efficiency.
  */
 
 enum xml_private_flags {
      xpf_none        = 0x0000,
      xpf_dirty       = 0x0001,
      xpf_deleted     = 0x0002,
      xpf_created     = 0x0004,
      xpf_modified    = 0x0008,
 
      xpf_tracking    = 0x0010,
      xpf_processed   = 0x0020,
      xpf_skip        = 0x0040,
      xpf_moved       = 0x0080,
 
      xpf_acl_enabled = 0x0100,
      xpf_acl_read    = 0x0200,
      xpf_acl_write   = 0x0400,
      xpf_acl_deny    = 0x0800,
 
      xpf_acl_create  = 0x1000,
      xpf_acl_denied  = 0x2000,
      xpf_lazy        = 0x4000,
 };
 
 typedef struct xml_private_s {
         long check;
         uint32_t flags;
         char *user;
         GListPtr acls;
         GListPtr deleted_objs;
 } xml_private_t;
 
 G_GNUC_INTERNAL
 void pcmk__set_xml_flag(xmlNode *xml, enum xml_private_flags flag);
 
 G_GNUC_INTERNAL
 bool pcmk__tracking_xml_changes(xmlNode *xml, bool lazy);
 
 G_GNUC_INTERNAL
 int pcmk__element_xpath(const char *prefix, xmlNode *xml, char *buffer,
                         int offset, size_t buffer_size);
 
 G_GNUC_INTERNAL
 void pcmk__free_acls(GList *acls);
 
 G_GNUC_INTERNAL
 void pcmk__unpack_acl(xmlNode *source, xmlNode *target, const char *user);
 
 G_GNUC_INTERNAL
 bool pcmk__check_acl(xmlNode *xml, const char *name,
                      enum xml_private_flags mode);
 
 G_GNUC_INTERNAL
 void pcmk__apply_acl(xmlNode *xml);
 
 G_GNUC_INTERNAL
-void pcmk__post_process_acl(xmlNode *xml, bool check_top);
+void pcmk__apply_creation_acl(xmlNode *xml, bool check_top);
 
 G_GNUC_INTERNAL
 void pcmk__mark_xml_attr_dirty(xmlAttr *a);
 
 static inline xmlAttr *
 pcmk__first_xml_attr(const xmlNode *xml)
 {
     return xml? xml->properties : NULL;
 }
 
 static inline const char *
 pcmk__xml_attr_value(const xmlAttr *attr)
 {
     return ((attr == NULL) || (attr->children == NULL))? NULL
            : (const char *) attr->children->content;
 }
 
 #endif  // CRMCOMMON_PRIVATE__H
diff --git a/lib/common/xml.c b/lib/common/xml.c
index 0fc743b42b..bdc5dd5c62 100644
--- a/lib/common/xml.c
+++ b/lib/common/xml.c
@@ -1,4337 +1,4337 @@
 /*
  * Copyright 2004-2019 the Pacemaker project contributors
  *
  * The version control history for this file may have further details.
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <time.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
 
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/common/iso8601_internal.h>
 #include <crm/common/xml.h>
 #include <crm/common/xml_internal.h>  /* CRM_XML_LOG_BASE */
 #include "crmcommon_private.h"
 
 #if HAVE_BZLIB_H
 #  include <bzlib.h>
 #endif
 
 #define XML_BUFFER_SIZE	4096
 #define XML_PARSER_DEBUG 0
 
 typedef struct {
     int found;
     const char *string;
 } filter_t;
 
 typedef struct xml_deleted_obj_s {
         char *path;
         int position;
 } xml_deleted_obj_t;
 
 /* *INDENT-OFF* */
 
 static filter_t filter[] = {
     { 0, XML_ATTR_ORIGIN },
     { 0, XML_CIB_ATTR_WRITTEN },
     { 0, XML_ATTR_UPDATE_ORIG },
     { 0, XML_ATTR_UPDATE_CLIENT },
     { 0, XML_ATTR_UPDATE_USER },
 };
 /* *INDENT-ON* */
 
 static xmlNode *subtract_xml_comment(xmlNode * parent, xmlNode * left, xmlNode * right, gboolean * changed);
 static xmlNode *find_xml_comment(xmlNode * root, xmlNode * search_comment, gboolean exact);
 static int add_xml_comment(xmlNode * parent, xmlNode * target, xmlNode * update);
 
 #define CHUNK_SIZE 1024
 
 bool
 pcmk__tracking_xml_changes(xmlNode *xml, bool lazy)
 {
     if(xml == NULL || xml->doc == NULL || xml->doc->_private == NULL) {
         return FALSE;
     } else if(is_not_set(((xml_private_t *)xml->doc->_private)->flags, xpf_tracking)) {
         return FALSE;
     } else if (lazy && is_not_set(((xml_private_t *)xml->doc->_private)->flags,
                                   xpf_lazy)) {
         return FALSE;
     }
     return TRUE;
 }
 
 #define buffer_print(buffer, max, offset, fmt, args...) do {            \
         int rc = (max);                                                 \
         if(buffer) {                                                    \
             rc = snprintf((buffer) + (offset), (max) - (offset), fmt, ##args); \
         }                                                               \
         if(buffer && rc < 0) {                                          \
             crm_perror(LOG_ERR, "snprintf failed at offset %d", offset); \
             (buffer)[(offset)] = 0;                                     \
             break;                                                      \
         } else if(rc >= ((max) - (offset))) {                           \
             char *tmp = NULL;                                           \
             (max) = QB_MAX(CHUNK_SIZE, (max) * 2);                      \
             tmp = realloc_safe((buffer), (max));                        \
             CRM_ASSERT(tmp);                                            \
             (buffer) = tmp;                                             \
         } else {                                                        \
             offset += rc;                                               \
             break;                                                      \
         }                                                               \
     } while(1);
 
 static void
 insert_prefix(int options, char **buffer, int *offset, int *max, int depth)
 {
     if (options & xml_log_option_formatted) {
         size_t spaces = 2 * depth;
 
         if ((*buffer) == NULL || spaces >= ((*max) - (*offset))) {
             (*max) = QB_MAX(CHUNK_SIZE, (*max) * 2);
             (*buffer) = realloc_safe((*buffer), (*max));
         }
         memset((*buffer) + (*offset), ' ', spaces);
         (*offset) += spaces;
     }
 }
 
 static void
 set_parent_flag(xmlNode *xml, long flag) 
 {
 
     for(; xml; xml = xml->parent) {
         xml_private_t *p = xml->_private;
 
         if(p == NULL) {
             /* During calls to xmlDocCopyNode(), _private will be unset for parent nodes */
         } else {
             p->flags |= flag;
             /* crm_trace("Setting flag %x due to %s[@id=%s]", flag, xml->name, ID(xml)); */
         }
     }
 }
 
 void
 pcmk__set_xml_flag(xmlNode *xml, enum xml_private_flags flag)
 {
 
     if(xml && xml->doc && xml->doc->_private){
         /* During calls to xmlDocCopyNode(), xml->doc may be unset */
         xml_private_t *p = xml->doc->_private;
 
         p->flags |= flag;
         /* crm_trace("Setting flag %x due to %s[@id=%s]", flag, xml->name, ID(xml)); */
     }
 }
 
 static void
 __xml_node_dirty(xmlNode *xml) 
 {
     pcmk__set_xml_flag(xml, xpf_dirty);
     set_parent_flag(xml, xpf_dirty);
 }
 
 static void
 __xml_node_clean(xmlNode *xml) 
 {
     xmlNode *cIter = NULL;
     xml_private_t *p = xml->_private;
 
     if(p) {
         p->flags = 0;
     }
 
     for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
         __xml_node_clean(cIter);
     }
 }
 
 static void
 crm_node_created(xmlNode *xml) 
 {
     xmlNode *cIter = NULL;
     xml_private_t *p = xml->_private;
 
     if(p && pcmk__tracking_xml_changes(xml, FALSE)) {
         if(is_not_set(p->flags, xpf_created)) {
             p->flags |= xpf_created;
             __xml_node_dirty(xml);
         }
 
         for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
            crm_node_created(cIter);
         }
     }
 }
 
 void
 pcmk__mark_xml_attr_dirty(xmlAttr *a) 
 {
     xmlNode *parent = a->parent;
     xml_private_t *p = NULL;
 
     p = a->_private;
     p->flags |= (xpf_dirty|xpf_modified);
     p->flags = (p->flags & ~xpf_deleted);
     /* crm_trace("Setting flag %x due to %s[@id=%s, @%s=%s]", */
     /*           xpf_dirty, parent?parent->name:NULL, ID(parent), a->name, a->children->content); */
 
     __xml_node_dirty(parent);
 }
 
 int get_tag_name(const char *input, size_t offset, size_t max);
 int get_attr_name(const char *input, size_t offset, size_t max);
 int get_attr_value(const char *input, size_t offset, size_t max);
 gboolean can_prune_leaf(xmlNode * xml_node);
 
 static int add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * update, gboolean as_diff);
 
 #define XML_PRIVATE_MAGIC (long) 0x81726354
 
 static void
 __xml_deleted_obj_free(void *data)
 {
     if(data) {
         xml_deleted_obj_t *deleted_obj = data;
 
         free(deleted_obj->path);
         free(deleted_obj);
     }
 }
 
 static void
 __xml_private_clean(xml_private_t *p)
 {
     if(p) {
         CRM_ASSERT(p->check == XML_PRIVATE_MAGIC);
 
         free(p->user);
         p->user = NULL;
 
         if(p->acls) {
             pcmk__free_acls(p->acls);
             p->acls = NULL;
         }
 
         if(p->deleted_objs) {
             g_list_free_full(p->deleted_objs, __xml_deleted_obj_free);
             p->deleted_objs = NULL;
         }
     }
 }
 
 
 static void
 __xml_private_free(xml_private_t *p)
 {
     __xml_private_clean(p);
     free(p);
 }
 
 static void
 pcmkDeregisterNode(xmlNodePtr node)
 {
     /* need to explicitly avoid our custom _private field cleanup when
        called from internal XSLT cleanup (xsltApplyStylesheetInternal
        -> xsltFreeTransformContext -> xsltFreeRVTs -> xmlFreeDoc)
        onto result tree fragments, represented as standalone documents
        with otherwise infeasible space-prefixed name (xsltInternals.h:
        XSLT_MARK_RES_TREE_FRAG) and carrying it's own load at _private
        field -- later assert on the XML_PRIVATE_MAGIC would explode */
     if (node->type != XML_DOCUMENT_NODE || node->name == NULL
             || node->name[0] != ' ') {
         __xml_private_free(node->_private);
     }
 }
 
 static void
 pcmkRegisterNode(xmlNodePtr node)
 {
     xml_private_t *p = NULL;
 
     switch(node->type) {
         case XML_ELEMENT_NODE:
         case XML_DOCUMENT_NODE:
         case XML_ATTRIBUTE_NODE:
         case XML_COMMENT_NODE:
             p = calloc(1, sizeof(xml_private_t));
             p->check = XML_PRIVATE_MAGIC;
             /* Flags will be reset if necessary when tracking is enabled */
             p->flags |= (xpf_dirty|xpf_created);
             node->_private = p;
             break;
         case XML_TEXT_NODE:
         case XML_DTD_NODE:
         case XML_CDATA_SECTION_NODE:
             break;
         default:
             /* Ignore */
             crm_trace("Ignoring %p %d", node, node->type);
             CRM_LOG_ASSERT(node->type == XML_ELEMENT_NODE);
             break;
     }
 
     if(p && pcmk__tracking_xml_changes(node, FALSE)) {
         /* XML_ELEMENT_NODE doesn't get picked up here, node->doc is
          * not hooked up at the point we are called
          */
         pcmk__set_xml_flag(node, xpf_dirty);
         __xml_node_dirty(node);
     }
 }
 
 void
 xml_track_changes(xmlNode * xml, const char *user, xmlNode *acl_source, bool enforce_acls) 
 {
     xml_accept_changes(xml);
     crm_trace("Tracking changes%s to %p", enforce_acls?" with ACLs":"", xml);
     pcmk__set_xml_flag(xml, xpf_tracking);
     if(enforce_acls) {
         if(acl_source == NULL) {
             acl_source = xml;
         }
         pcmk__set_xml_flag(xml, xpf_acl_enabled);
         pcmk__unpack_acl(acl_source, xml, user);
         pcmk__apply_acl(xml);
     }
 }
 
 bool xml_tracking_changes(xmlNode * xml)
 {
     if(xml == NULL) {
         return FALSE;
 
     } else if(is_set(((xml_private_t *)xml->doc->_private)->flags, xpf_tracking)) {
         return TRUE;
     }
     return FALSE;
 }
 
 bool xml_document_dirty(xmlNode *xml) 
 {
     if(xml != NULL && xml->doc && xml->doc->_private) {
         xml_private_t *doc = xml->doc->_private;
 
         return is_set(doc->flags, xpf_dirty);
     }
     return FALSE;
 }
 
 /*
 <diff format="2.0">
   <version>
     <source admin_epoch="1" epoch="2" num_updates="3"/>
     <target admin_epoch="1" epoch="3" num_updates="0"/>
   </version>
   <change operation="add" xpath="/cib/configuration/nodes">
     <node id="node2" uname="node2" description="foo"/>
   </change>
   <change operation="add" xpath="/cib/configuration/nodes/node[node2]">
     <instance_attributes id="nodes-node"><!-- NOTE: can be a full tree -->
       <nvpair id="nodes-node2-ram" name="ram" value="1024M"/>
     </instance_attributes>
   </change>
   <change operation="update" xpath="/cib/configuration/nodes[@id='node2']">
     <change-list>
       <change-attr operation="set" name="type" value="member"/>
       <change-attr operation="unset" name="description"/>
     </change-list>
     <change-result>
       <node id="node2" uname="node2" type="member"/><!-- NOTE: not recursive -->
     </change-result>
   </change>
   <change operation="delete" xpath="/cib/configuration/nodes/node[@id='node3'] /">
   <change operation="update" xpath="/cib/configuration/resources/group[@id='g1']">
     <change-list>
       <change-attr operation="set" name="description" value="some grabage here"/>
     </change-list>
     <change-result>
       <group id="g1" description="some grabage here"/><!-- NOTE: not recursive -->
     </change-result>
   </change>
   <change operation="update" xpath="/cib/status/node_state[@id='node2]/lrm[@id='node2']/lrm_resources/lrm_resource[@id='Fence']">
     <change-list>
       <change-attr operation="set" name="oper" value="member"/>
       <change-attr operation="set" name="operation_key" value="Fence_start_0"/>
       <change-attr operation="set" name="operation" value="start"/>
       <change-attr operation="set" name="transition-key" value="2:-1:0:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"/>
       <change-attr operation="set" name="transition-magic" value="0:0;2:-1:0:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"/>
       <change-attr operation="set" name="call-id" value="2"/>
       <change-attr operation="set" name="rc-code" value="0"/>
     </change-list>
     <change-result>
       <lrm_rsc_op id="Fence_last_0" operation_key="Fence_start_0" operation="start" crm-debug-origin="crm_simulate"  transition-key="2:-1:0:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" transition-magic="0:0;2:-1:0:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" call-id="2" rc-code="0" op-status="0" interval="0" exec-time="0" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
     </change-result>
   </change>
 </diff>
  */
 static int __xml_offset(xmlNode *xml) 
 {
     int position = 0;
     xmlNode *cIter = NULL;
 
     for(cIter = xml; cIter->prev; cIter = cIter->prev) {
         xml_private_t *p = ((xmlNode*)cIter->prev)->_private;
 
         if(is_not_set(p->flags, xpf_skip)) {
             position++;
         }
     }
 
     return position;
 }
 
 static int __xml_offset_no_deletions(xmlNode *xml) 
 {
     int position = 0;
     xmlNode *cIter = NULL;
 
     for(cIter = xml; cIter->prev; cIter = cIter->prev) {
         xml_private_t *p = ((xmlNode*)cIter->prev)->_private;
 
         if(is_not_set(p->flags, xpf_deleted)) {
             position++;
         }
     }
 
     return position;
 }
 
 static void
 __xml_build_changes(xmlNode * xml, xmlNode *patchset)
 {
     xmlNode *cIter = NULL;
     xmlAttr *pIter = NULL;
     xmlNode *change = NULL;
     xml_private_t *p = xml->_private;
 
     if(patchset && is_set(p->flags, xpf_created)) {
         int offset = 0;
         char buffer[XML_BUFFER_SIZE];
 
         if (pcmk__element_xpath(NULL, xml->parent, buffer, offset,
                                 sizeof(buffer)) > 0) {
             int position = __xml_offset_no_deletions(xml);
 
             change = create_xml_node(patchset, XML_DIFF_CHANGE);
 
             crm_xml_add(change, XML_DIFF_OP, "create");
             crm_xml_add(change, XML_DIFF_PATH, buffer);
             crm_xml_add_int(change, XML_DIFF_POSITION, position);
             add_node_copy(change, xml);
         }
 
         return;
     }
 
     for (pIter = pcmk__first_xml_attr(xml); pIter != NULL; pIter = pIter->next) {
         xmlNode *attr = NULL;
 
         p = pIter->_private;
         if(is_not_set(p->flags, xpf_deleted) && is_not_set(p->flags, xpf_dirty)) {
             continue;
         }
 
         if(change == NULL) {
             int offset = 0;
             char buffer[XML_BUFFER_SIZE];
 
             if (pcmk__element_xpath(NULL, xml, buffer, offset,
                                     sizeof(buffer)) > 0) {
                 change = create_xml_node(patchset, XML_DIFF_CHANGE);
 
                 crm_xml_add(change, XML_DIFF_OP, "modify");
                 crm_xml_add(change, XML_DIFF_PATH, buffer);
 
                 change = create_xml_node(change, XML_DIFF_LIST);
             }
         }
 
         attr = create_xml_node(change, XML_DIFF_ATTR);
 
         crm_xml_add(attr, XML_NVPAIR_ATTR_NAME, (const char *)pIter->name);
         if(p->flags & xpf_deleted) {
             crm_xml_add(attr, XML_DIFF_OP, "unset");
 
         } else {
             const char *value = crm_element_value(xml, (const char *)pIter->name);
 
             crm_xml_add(attr, XML_DIFF_OP, "set");
             crm_xml_add(attr, XML_NVPAIR_ATTR_VALUE, value);
         }
     }
 
     if(change) {
         xmlNode *result = NULL;
 
         change = create_xml_node(change->parent, XML_DIFF_RESULT);
         result = create_xml_node(change, (const char *)xml->name);
 
         for (pIter = pcmk__first_xml_attr(xml); pIter != NULL; pIter = pIter->next) {
             const char *value = crm_element_value(xml, (const char *)pIter->name);
 
             p = pIter->_private;
             if (is_not_set(p->flags, xpf_deleted)) {
                 crm_xml_add(result, (const char *)pIter->name, value);
             }
         }
     }
 
     for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
         __xml_build_changes(cIter, patchset);
     }
 
     p = xml->_private;
     if(patchset && is_set(p->flags, xpf_moved)) {
         int offset = 0;
         char buffer[XML_BUFFER_SIZE];
 
         crm_trace("%s.%s moved to position %d", xml->name, ID(xml), __xml_offset(xml));
         if (pcmk__element_xpath(NULL, xml, buffer, offset,
                                 sizeof(buffer)) > 0) {
             change = create_xml_node(patchset, XML_DIFF_CHANGE);
 
             crm_xml_add(change, XML_DIFF_OP, "move");
             crm_xml_add(change, XML_DIFF_PATH, buffer);
             crm_xml_add_int(change, XML_DIFF_POSITION, __xml_offset_no_deletions(xml));
         }
     }
 }
 
 static void
 __xml_accept_changes(xmlNode * xml)
 {
     xmlNode *cIter = NULL;
     xmlAttr *pIter = NULL;
     xml_private_t *p = xml->_private;
 
     p->flags = xpf_none;
     pIter = pcmk__first_xml_attr(xml);
 
     while (pIter != NULL) {
         const xmlChar *name = pIter->name;
 
         p = pIter->_private;
         pIter = pIter->next;
 
         if(p->flags & xpf_deleted) {
             xml_remove_prop(xml, (const char *)name);
 
         } else {
             p->flags = xpf_none;
         }
     }
 
     for (cIter = __xml_first_child(xml); cIter != NULL; cIter = __xml_next(cIter)) {
         __xml_accept_changes(cIter);
     }
 }
 
 static bool
 is_config_change(xmlNode *xml)
 {
     GListPtr gIter = NULL;
     xml_private_t *p = NULL;
     xmlNode *config = first_named_child(xml, XML_CIB_TAG_CONFIGURATION);
 
     if(config) {
         p = config->_private;
     }
     if(p && is_set(p->flags, xpf_dirty)) {
         return TRUE;
     }
 
     if(xml->doc && xml->doc->_private) {
         p = xml->doc->_private;
         for(gIter = p->deleted_objs; gIter; gIter = gIter->next) {
             xml_deleted_obj_t *deleted_obj = gIter->data;
 
             if(strstr(deleted_obj->path, "/"XML_TAG_CIB"/"XML_CIB_TAG_CONFIGURATION) != NULL) {
                 return TRUE;
             }
         }
     }
 
     return FALSE;
 }
 
 static void
 xml_repair_v1_diff(xmlNode * last, xmlNode * next, xmlNode * local_diff, gboolean changed)
 {
     int lpc = 0;
     xmlNode *cib = NULL;
     xmlNode *diff_child = NULL;
 
     const char *tag = NULL;
 
     const char *vfields[] = {
         XML_ATTR_GENERATION_ADMIN,
         XML_ATTR_GENERATION,
         XML_ATTR_NUMUPDATES,
     };
 
     if (local_diff == NULL) {
         crm_trace("Nothing to do");
         return;
     }
 
     tag = "diff-removed";
     diff_child = find_xml_node(local_diff, tag, FALSE);
     if (diff_child == NULL) {
         diff_child = create_xml_node(local_diff, tag);
     }
 
     tag = XML_TAG_CIB;
     cib = find_xml_node(diff_child, tag, FALSE);
     if (cib == NULL) {
         cib = create_xml_node(diff_child, tag);
     }
 
     for(lpc = 0; last && lpc < DIMOF(vfields); lpc++){
         const char *value = crm_element_value(last, vfields[lpc]);
 
         crm_xml_add(diff_child, vfields[lpc], value);
         if(changed || lpc == 2) {
             crm_xml_add(cib, vfields[lpc], value);
         }
     }
 
     tag = "diff-added";
     diff_child = find_xml_node(local_diff, tag, FALSE);
     if (diff_child == NULL) {
         diff_child = create_xml_node(local_diff, tag);
     }
 
     tag = XML_TAG_CIB;
     cib = find_xml_node(diff_child, tag, FALSE);
     if (cib == NULL) {
         cib = create_xml_node(diff_child, tag);
     }
 
     for(lpc = 0; next && lpc < DIMOF(vfields); lpc++){
         const char *value = crm_element_value(next, vfields[lpc]);
 
         crm_xml_add(diff_child, vfields[lpc], value);
     }
 
     if (next) {
         xmlAttrPtr xIter = NULL;
 
         for (xIter = next->properties; xIter; xIter = xIter->next) {
             const char *p_name = (const char *)xIter->name;
             const char *p_value = crm_element_value(next, p_name);
 
             xmlSetProp(cib, (pcmkXmlStr) p_name, (pcmkXmlStr) p_value);
         }
     }
 
     crm_log_xml_explicit(local_diff, "Repaired-diff");
 }
 
 static xmlNode *
 xml_create_patchset_v1(xmlNode *source, xmlNode *target, bool config, bool suppress)
 {
     xmlNode *patchset = diff_xml_object(source, target, suppress);
 
     if(patchset) {
         CRM_LOG_ASSERT(xml_document_dirty(target));
         xml_repair_v1_diff(source, target, patchset, config);
         crm_xml_add(patchset, "format", "1");
     }
     return patchset;
 }
 
 static xmlNode *
 xml_create_patchset_v2(xmlNode *source, xmlNode *target)
 {
     int lpc = 0;
     GListPtr gIter = NULL;
     xml_private_t *doc = NULL;
 
     xmlNode *v = NULL;
     xmlNode *version = NULL;
     xmlNode *patchset = NULL;
     const char *vfields[] = {
         XML_ATTR_GENERATION_ADMIN,
         XML_ATTR_GENERATION,
         XML_ATTR_NUMUPDATES,
     };
 
     CRM_ASSERT(target);
     if(xml_document_dirty(target) == FALSE) {
         return NULL;
     }
 
     CRM_ASSERT(target->doc);
     doc = target->doc->_private;
 
     patchset = create_xml_node(NULL, XML_TAG_DIFF);
     crm_xml_add_int(patchset, "format", 2);
 
     version = create_xml_node(patchset, XML_DIFF_VERSION);
 
     v = create_xml_node(version, XML_DIFF_VSOURCE);
     for(lpc = 0; lpc < DIMOF(vfields); lpc++){
         const char *value = crm_element_value(source, vfields[lpc]);
 
         if(value == NULL) {
             value = "1";
         }
         crm_xml_add(v, vfields[lpc], value);
     }
 
     v = create_xml_node(version, XML_DIFF_VTARGET);
     for(lpc = 0; lpc < DIMOF(vfields); lpc++){
         const char *value = crm_element_value(target, vfields[lpc]);
 
         if(value == NULL) {
             value = "1";
         }
         crm_xml_add(v, vfields[lpc], value);
     }
 
     for(gIter = doc->deleted_objs; gIter; gIter = gIter->next) {
         xml_deleted_obj_t *deleted_obj = gIter->data;
         xmlNode *change = create_xml_node(patchset, XML_DIFF_CHANGE);
 
         crm_xml_add(change, XML_DIFF_OP, "delete");
         crm_xml_add(change, XML_DIFF_PATH, deleted_obj->path);
         if (deleted_obj->position >= 0) {
             crm_xml_add_int(change, XML_DIFF_POSITION, deleted_obj->position);
         }
     }
 
     __xml_build_changes(target, patchset);
     return patchset;
 }
 
 xmlNode *
 xml_create_patchset(int format, xmlNode *source, xmlNode *target, bool *config_changed, bool manage_version)
 {
     int counter = 0;
     bool config = FALSE;
     xmlNode *patch = NULL;
     const char *version = crm_element_value(source, XML_ATTR_CRM_VERSION);
 
     xml_acl_disable(target);
     if(xml_document_dirty(target) == FALSE) {
         crm_trace("No change %d", format);
         return NULL; /* No change */
     }
 
     config = is_config_change(target);
     if(config_changed) {
         *config_changed = config;
     }
 
     if(manage_version && config) {
         crm_trace("Config changed %d", format);
         crm_xml_add(target, XML_ATTR_NUMUPDATES, "0");
 
         crm_element_value_int(target, XML_ATTR_GENERATION, &counter);
         crm_xml_add_int(target, XML_ATTR_GENERATION, counter+1);
 
     } else if(manage_version) {
         crm_element_value_int(target, XML_ATTR_NUMUPDATES, &counter);
         crm_trace("Status changed %d - %d %s", format, counter, crm_element_value(source, XML_ATTR_NUMUPDATES));
         crm_xml_add_int(target, XML_ATTR_NUMUPDATES, counter+1);
     }
 
     if(format == 0) {
         if (compare_version("3.0.8", version) < 0) {
             format = 2;
 
         } else {
             format = 1;
         }
         crm_trace("Using patch format %d for version: %s", format, version);
     }
 
     switch(format) {
         case 1:
             patch = xml_create_patchset_v1(source, target, config, FALSE);
             break;
         case 2:
             patch = xml_create_patchset_v2(source, target);
             break;
         default:
             crm_err("Unknown patch format: %d", format);
             return NULL;
     }
 
     return patch;
 }
 
 void
 patchset_process_digest(xmlNode *patch, xmlNode *source, xmlNode *target, bool with_digest)
 {
     int format = 1;
     const char *version = NULL;
     char *digest = NULL;
 
     if (patch == NULL || source == NULL || target == NULL) {
         return;
     }
 
     /* NOTE: We should always call xml_accept_changes() before calculating digest. */
     /* Otherwise, with an on-tracking dirty target, we could get a wrong digest. */
     CRM_LOG_ASSERT(xml_document_dirty(target) == FALSE);
 
     crm_element_value_int(patch, "format", &format);
     if (format > 1 && with_digest == FALSE) {
         return;
     }
 
     version = crm_element_value(source, XML_ATTR_CRM_VERSION);
     digest = calculate_xml_versioned_digest(target, FALSE, TRUE, version);
 
     crm_xml_add(patch, XML_ATTR_DIGEST, digest);
     free(digest);
 
     return;
 }
 
 static void
 __xml_log_element(int log_level, const char *file, const char *function, int line,
                   const char *prefix, xmlNode * data, int depth, int options);
 
 void
 xml_log_patchset(uint8_t log_level, const char *function, xmlNode * patchset)
 {
     int format = 1;
     xmlNode *child = NULL;
     xmlNode *added = NULL;
     xmlNode *removed = NULL;
     gboolean is_first = TRUE;
 
     int add[] = { 0, 0, 0 };
     int del[] = { 0, 0, 0 };
 
     const char *fmt = NULL;
     const char *digest = NULL;
     int options = xml_log_option_formatted;
 
     static struct qb_log_callsite *patchset_cs = NULL;
 
     if (patchset_cs == NULL) {
         patchset_cs = qb_log_callsite_get(function, __FILE__, "xml-patchset", log_level, __LINE__, 0);
     }
 
     if (patchset == NULL) {
         crm_trace("Empty patch");
         return;
 
     } else if (log_level == 0) {
         /* Log to stdout */
     } else if (crm_is_callsite_active(patchset_cs, log_level, 0) == FALSE) {
         return;
     }
 
     xml_patch_versions(patchset, add, del);
     fmt = crm_element_value(patchset, "format");
     digest = crm_element_value(patchset, XML_ATTR_DIGEST);
 
     if (add[2] != del[2] || add[1] != del[1] || add[0] != del[0]) {
         do_crm_log_alias(log_level, __FILE__, function, __LINE__,
                          "Diff: --- %d.%d.%d %s", del[0], del[1], del[2], fmt);
         do_crm_log_alias(log_level, __FILE__, function, __LINE__,
                          "Diff: +++ %d.%d.%d %s", add[0], add[1], add[2], digest);
 
     } else if (patchset != NULL && (add[0] || add[1] || add[2])) {
         do_crm_log_alias(log_level, __FILE__, function, __LINE__, 
                          "%s: Local-only Change: %d.%d.%d", function ? function : "",
                          add[0], add[1], add[2]);
     }
 
     crm_element_value_int(patchset, "format", &format);
     if(format == 2) {
         xmlNode *change = NULL;
 
         for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) {
             const char *op = crm_element_value(change, XML_DIFF_OP);
             const char *xpath = crm_element_value(change, XML_DIFF_PATH);
 
             if(op == NULL) {
             } else if(strcmp(op, "create") == 0) {
                 int lpc = 0, max = 0;
                 char *prefix = crm_strdup_printf("++ %s: ", xpath);
 
                 max = strlen(prefix);
                 __xml_log_element(log_level, __FILE__, function, __LINE__, prefix, change->children,
                                   0, xml_log_option_formatted|xml_log_option_open);
 
                 for(lpc = 2; lpc < max; lpc++) {
                     prefix[lpc] = ' ';
                 }
 
                 __xml_log_element(log_level, __FILE__, function, __LINE__, prefix, change->children,
                                   0, xml_log_option_formatted|xml_log_option_close|xml_log_option_children);
                 free(prefix);
 
             } else if(strcmp(op, "move") == 0) {
                 do_crm_log_alias(log_level, __FILE__, function, __LINE__, "+~ %s moved to offset %s", xpath, crm_element_value(change, XML_DIFF_POSITION));
 
             } else if(strcmp(op, "modify") == 0) {
                 xmlNode *clist = first_named_child(change, XML_DIFF_LIST);
                 char buffer_set[XML_BUFFER_SIZE];
                 char buffer_unset[XML_BUFFER_SIZE];
                 int o_set = 0;
                 int o_unset = 0;
 
                 buffer_set[0] = 0;
                 buffer_unset[0] = 0;
                 for (child = __xml_first_child(clist); child != NULL; child = __xml_next(child)) {
                     const char *name = crm_element_value(child, "name");
 
                     op = crm_element_value(child, XML_DIFF_OP);
                     if(op == NULL) {
                     } else if(strcmp(op, "set") == 0) {
                         const char *value = crm_element_value(child, "value");
 
                         if(o_set > 0) {
                             o_set += snprintf(buffer_set + o_set, XML_BUFFER_SIZE - o_set, ", ");
                         }
                         o_set += snprintf(buffer_set + o_set, XML_BUFFER_SIZE - o_set, "@%s=%s", name, value);
 
                     } else if(strcmp(op, "unset") == 0) {
                         if(o_unset > 0) {
                             o_unset += snprintf(buffer_unset + o_unset, XML_BUFFER_SIZE - o_unset, ", ");
                         }
                         o_unset += snprintf(buffer_unset + o_unset, XML_BUFFER_SIZE - o_unset, "@%s", name);
                     }
                 }
                 if(o_set) {
                     do_crm_log_alias(log_level, __FILE__, function, __LINE__, "+  %s:  %s", xpath, buffer_set);
                 }
                 if(o_unset) {
                     do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s:  %s", xpath, buffer_unset);
                 }
 
             } else if(strcmp(op, "delete") == 0) {
                 int position = -1;
 
                 crm_element_value_int(change, XML_DIFF_POSITION, &position);
                 if (position >= 0) {
                     do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s (%d)", xpath, position);
 
                 } else {
                     do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s", xpath);
                 }
             }
         }
         return;
     }
 
     if (log_level < LOG_DEBUG || function == NULL) {
         options |= xml_log_option_diff_short;
     }
 
     removed = find_xml_node(patchset, "diff-removed", FALSE);
     for (child = __xml_first_child(removed); child != NULL; child = __xml_next(child)) {
         log_data_element(log_level, __FILE__, function, __LINE__, "- ", child, 0,
                          options | xml_log_option_diff_minus);
         if (is_first) {
             is_first = FALSE;
         } else {
             do_crm_log_alias(log_level, __FILE__, function, __LINE__, " --- ");
         }
     }
 
     is_first = TRUE;
     added = find_xml_node(patchset, "diff-added", FALSE);
     for (child = __xml_first_child(added); child != NULL; child = __xml_next(child)) {
         log_data_element(log_level, __FILE__, function, __LINE__, "+ ", child, 0,
                          options | xml_log_option_diff_plus);
         if (is_first) {
             is_first = FALSE;
         } else {
             do_crm_log_alias(log_level, __FILE__, function, __LINE__, " +++ ");
         }
     }
 }
 
 void
 xml_log_changes(uint8_t log_level, const char *function, xmlNode * xml)
 {
     GListPtr gIter = NULL;
     xml_private_t *doc = NULL;
 
     CRM_ASSERT(xml);
     CRM_ASSERT(xml->doc);
 
     doc = xml->doc->_private;
     if(is_not_set(doc->flags, xpf_dirty)) {
         return;
     }
 
     for(gIter = doc->deleted_objs; gIter; gIter = gIter->next) {
         xml_deleted_obj_t *deleted_obj = gIter->data;
 
         if (deleted_obj->position >= 0) {
             do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s (%d)",
                              deleted_obj->path, deleted_obj->position);
 
         } else {
             do_crm_log_alias(log_level, __FILE__, function, __LINE__, "-- %s",
                              deleted_obj->path);
         }
     }
 
     log_data_element(log_level, __FILE__, function, __LINE__, "+ ", xml, 0,
                      xml_log_option_formatted|xml_log_option_dirty_add);
 }
 
 void
 xml_accept_changes(xmlNode * xml)
 {
     xmlNode *top = NULL;
     xml_private_t *doc = NULL;
 
     if(xml == NULL) {
         return;
     }
 
     crm_trace("Accepting changes to %p", xml);
     doc = xml->doc->_private;
     top = xmlDocGetRootElement(xml->doc);
 
     __xml_private_clean(xml->doc->_private);
 
     if(is_not_set(doc->flags, xpf_dirty)) {
         doc->flags = xpf_none;
         return;
     }
 
     doc->flags = xpf_none;
     __xml_accept_changes(top);
 }
 
 static xmlNode *
 find_element(xmlNode *haystack, xmlNode *needle, gboolean exact)
 {
     CRM_CHECK(needle != NULL, return NULL);
     return (needle->type == XML_COMMENT_NODE)?
            find_xml_comment(haystack, needle, exact)
            : find_entity(haystack, crm_element_name(needle), ID(needle));
 }
 
 /* Simplified version for applying v1-style XML patches */
 static void
 __subtract_xml_object(xmlNode * target, xmlNode * patch)
 {
     xmlNode *patch_child = NULL;
     xmlNode *cIter = NULL;
     xmlAttrPtr xIter = NULL;
 
     char *id = NULL;
     const char *name = NULL;
     const char *value = NULL;
 
     if (target == NULL || patch == NULL) {
         return;
     }
 
     if (target->type == XML_COMMENT_NODE) {
         gboolean dummy;
 
         subtract_xml_comment(target->parent, target, patch, &dummy);
     }
 
     name = crm_element_name(target);
     CRM_CHECK(name != NULL, return);
     CRM_CHECK(safe_str_eq(crm_element_name(target), crm_element_name(patch)), return);
     CRM_CHECK(safe_str_eq(ID(target), ID(patch)), return);
 
     /* check for XML_DIFF_MARKER in a child */
     id = crm_element_value_copy(target, XML_ATTR_ID);
     value = crm_element_value(patch, XML_DIFF_MARKER);
     if (value != NULL && strcmp(value, "removed:top") == 0) {
         crm_trace("We are the root of the deletion: %s.id=%s", name, id);
         free_xml(target);
         free(id);
         return;
     }
 
     for (xIter = pcmk__first_xml_attr(patch); xIter != NULL; xIter = xIter->next) {
         const char *p_name = (const char *)xIter->name;
 
         /* Removing and then restoring the id field would change the ordering of properties */
         if (safe_str_neq(p_name, XML_ATTR_ID)) {
             xml_remove_prop(target, p_name);
         }
     }
 
     /* changes to child objects */
     cIter = __xml_first_child(target);
     while (cIter) {
         xmlNode *target_child = cIter;
 
         cIter = __xml_next(cIter);
         patch_child = find_element(patch, target_child, FALSE);
         __subtract_xml_object(target_child, patch_child);
     }
     free(id);
 }
 
 static void
 __add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * patch)
 {
     xmlNode *patch_child = NULL;
     xmlNode *target_child = NULL;
     xmlAttrPtr xIter = NULL;
 
     const char *id = NULL;
     const char *name = NULL;
     const char *value = NULL;
 
     if (patch == NULL) {
         return;
     } else if (parent == NULL && target == NULL) {
         return;
     }
 
     /* check for XML_DIFF_MARKER in a child */
     value = crm_element_value(patch, XML_DIFF_MARKER);
     if (target == NULL
         && value != NULL
         && strcmp(value, "added:top") == 0) {
         id = ID(patch);
         name = crm_element_name(patch);
         crm_trace("We are the root of the addition: %s.id=%s", name, id);
         add_node_copy(parent, patch);
         return;
 
     } else if(target == NULL) {
         id = ID(patch);
         name = crm_element_name(patch);
         crm_err("Could not locate: %s.id=%s", name, id);
         return;
     }
 
     if (target->type == XML_COMMENT_NODE) {
         add_xml_comment(parent, target, patch);
     }
 
     name = crm_element_name(target);
     CRM_CHECK(name != NULL, return);
     CRM_CHECK(safe_str_eq(crm_element_name(target), crm_element_name(patch)), return);
     CRM_CHECK(safe_str_eq(ID(target), ID(patch)), return);
 
     for (xIter = pcmk__first_xml_attr(patch); xIter != NULL; xIter = xIter->next) {
         const char *p_name = (const char *)xIter->name;
         const char *p_value = crm_element_value(patch, p_name);
 
         xml_remove_prop(target, p_name); /* Preserve the patch order */
         crm_xml_add(target, p_name, p_value);
     }
 
     /* changes to child objects */
     for (patch_child = __xml_first_child(patch); patch_child != NULL;
          patch_child = __xml_next(patch_child)) {
 
         target_child = find_element(target, patch_child, FALSE);
         __add_xml_object(target, target_child, patch_child);
     }
 }
 
 /*!
  * \internal
  * \brief Find additions or removals in a patch set
  *
  * \param[in]     patchset   XML of patch
  * \param[in]     format     Patch version
  * \param[in]     added      TRUE if looking for additions, FALSE if removals
  * \param[in,out] patch_node Will be set to node if found
  *
  * \return TRUE if format is valid, FALSE if invalid
  */
 static bool
 find_patch_xml_node(xmlNode *patchset, int format, bool added,
                     xmlNode **patch_node)
 {
     xmlNode *cib_node;
     const char *label;
 
     switch(format) {
         case 1:
             label = added? "diff-added" : "diff-removed";
             *patch_node = find_xml_node(patchset, label, FALSE);
             cib_node = find_xml_node(*patch_node, "cib", FALSE);
             if (cib_node != NULL) {
                 *patch_node = cib_node;
             }
             break;
         case 2:
             label = added? "target" : "source";
             *patch_node = find_xml_node(patchset, "version", FALSE);
             *patch_node = find_xml_node(*patch_node, label, FALSE);
             break;
         default:
             crm_warn("Unknown patch format: %d", format);
             *patch_node = NULL;
             return FALSE;
     }
     return TRUE;
 }
 
 bool xml_patch_versions(xmlNode *patchset, int add[3], int del[3])
 {
     int lpc = 0;
     int format = 1;
     xmlNode *tmp = NULL;
 
     const char *vfields[] = {
         XML_ATTR_GENERATION_ADMIN,
         XML_ATTR_GENERATION,
         XML_ATTR_NUMUPDATES,
     };
 
 
     crm_element_value_int(patchset, "format", &format);
 
     /* Process removals */
     if (!find_patch_xml_node(patchset, format, FALSE, &tmp)) {
         return -EINVAL;
     }
     if (tmp) {
         for(lpc = 0; lpc < DIMOF(vfields); lpc++) {
             crm_element_value_int(tmp, vfields[lpc], &(del[lpc]));
             crm_trace("Got %d for del[%s]", del[lpc], vfields[lpc]);
         }
     }
 
     /* Process additions */
     if (!find_patch_xml_node(patchset, format, TRUE, &tmp)) {
         return -EINVAL;
     }
     if (tmp) {
         for(lpc = 0; lpc < DIMOF(vfields); lpc++) {
             crm_element_value_int(tmp, vfields[lpc], &(add[lpc]));
             crm_trace("Got %d for add[%s]", add[lpc], vfields[lpc]);
         }
     }
 
     return pcmk_ok;
 }
 
 static int
 xml_patch_version_check(xmlNode *xml, xmlNode *patchset, int format) 
 {
     int lpc = 0;
     bool changed = FALSE;
 
     int this[] = { 0, 0, 0 };
     int add[] = { 0, 0, 0 };
     int del[] = { 0, 0, 0 };
 
     const char *vfields[] = {
         XML_ATTR_GENERATION_ADMIN,
         XML_ATTR_GENERATION,
         XML_ATTR_NUMUPDATES,
     };
 
     for(lpc = 0; lpc < DIMOF(vfields); lpc++) {
         crm_element_value_int(xml, vfields[lpc], &(this[lpc]));
         crm_trace("Got %d for this[%s]", this[lpc], vfields[lpc]);
         if (this[lpc] < 0) {
             this[lpc] = 0;
         }
     }
 
     /* Set some defaults in case nothing is present */
     add[0] = this[0];
     add[1] = this[1];
     add[2] = this[2] + 1;
     for(lpc = 0; lpc < DIMOF(vfields); lpc++) {
         del[lpc] = this[lpc];
     }
 
     xml_patch_versions(patchset, add, del);
 
     for(lpc = 0; lpc < DIMOF(vfields); lpc++) {
         if(this[lpc] < del[lpc]) {
             crm_debug("Current %s is too low (%d.%d.%d < %d.%d.%d --> %d.%d.%d)", vfields[lpc],
                       this[0], this[1], this[2], del[0], del[1], del[2], add[0], add[1], add[2]);
             return -pcmk_err_diff_resync;
 
         } else if(this[lpc] > del[lpc]) {
             crm_info("Current %s is too high (%d.%d.%d > %d.%d.%d --> %d.%d.%d) %p", vfields[lpc],
                      this[0], this[1], this[2], del[0], del[1], del[2], add[0], add[1], add[2], patchset);
             crm_log_xml_info(patchset, "OldPatch");
             return -pcmk_err_old_data;
         }
     }
 
     for(lpc = 0; lpc < DIMOF(vfields); lpc++) {
         if(add[lpc] > del[lpc]) {
             changed = TRUE;
         }
     }
 
     if(changed == FALSE) {
         crm_notice("Versions did not change in patch %d.%d.%d", add[0], add[1], add[2]);
         return -pcmk_err_old_data;
     }
 
     crm_debug("Can apply patch %d.%d.%d to %d.%d.%d",
              add[0], add[1], add[2], this[0], this[1], this[2]);
     return pcmk_ok;
 }
 
 static int
 xml_apply_patchset_v1(xmlNode *xml, xmlNode *patchset)
 {
     int rc = pcmk_ok;
     int root_nodes_seen = 0;
 
     xmlNode *child_diff = NULL;
     xmlNode *added = find_xml_node(patchset, "diff-added", FALSE);
     xmlNode *removed = find_xml_node(patchset, "diff-removed", FALSE);
     xmlNode *old = copy_xml(xml);
 
     crm_trace("Subtraction Phase");
     for (child_diff = __xml_first_child(removed); child_diff != NULL;
          child_diff = __xml_next(child_diff)) {
         CRM_CHECK(root_nodes_seen == 0, rc = FALSE);
         if (root_nodes_seen == 0) {
             __subtract_xml_object(xml, child_diff);
         }
         root_nodes_seen++;
     }
 
     if (root_nodes_seen > 1) {
         crm_err("(-) Diffs cannot contain more than one change set... saw %d", root_nodes_seen);
         rc = -ENOTUNIQ;
     }
 
     root_nodes_seen = 0;
     crm_trace("Addition Phase");
     if (rc == pcmk_ok) {
         xmlNode *child_diff = NULL;
 
         for (child_diff = __xml_first_child(added); child_diff != NULL;
              child_diff = __xml_next(child_diff)) {
             CRM_CHECK(root_nodes_seen == 0, rc = FALSE);
             if (root_nodes_seen == 0) {
                 __add_xml_object(NULL, xml, child_diff);
             }
             root_nodes_seen++;
         }
     }
 
     if (root_nodes_seen > 1) {
         crm_err("(+) Diffs cannot contain more than one change set... saw %d", root_nodes_seen);
         rc = -ENOTUNIQ;
     }
 
     purge_diff_markers(xml);       /* Purge prior to checking the digest */
 
     free_xml(old);
     return rc;
 }
 
 static xmlNode *
 __first_xml_child_match(xmlNode *parent, const char *name, const char *id, int position)
 {
     xmlNode *cIter = NULL;
 
     for (cIter = __xml_first_child(parent); cIter != NULL; cIter = __xml_next(cIter)) {
         if(strcmp((const char *)cIter->name, name) != 0) {
             continue;
         } else if(id) {
             const char *cid = ID(cIter);
             if(cid == NULL || strcmp(cid, id) != 0) {
                 continue;
             }
         }
 
         /* The "position" makes sense only for XML comments for now */
         if (cIter->type == XML_COMMENT_NODE
             && position >= 0
             && __xml_offset(cIter) != position) {
             continue;
         }
 
         return cIter;
     }
     return NULL;
 }
 
 /*!
  * \internal
  * \brief Simplified, more efficient alternative to get_xpath_object()
  *
  * \param[in] top              Root of XML to search
  * \param[in] key              Search xpath
  * \param[in] target_position  If deleting, where to delete
  *
  * \return XML child matching xpath if found, NULL otherwise
  *
  * \note This only works on simplified xpaths found in v2 patchset diffs,
  *       i.e. the only allowed search predicate is [@id='XXX'].
  */
 static xmlNode *
 __xml_find_path(xmlNode *top, const char *key, int target_position)
 {
     xmlNode *target = (xmlNode*) top->doc;
     const char *current = key;
     char *section;
     char *remainder;
     char *id;
     char *tag;
     char *path = NULL;
     int rc;
     size_t key_len;
 
     CRM_CHECK(key != NULL, return NULL);
     key_len = strlen(key);
 
     /* These are scanned from key after a slash, so they can't be bigger
      * than key_len - 1 characters plus a null terminator.
      */
 
     remainder = calloc(key_len, sizeof(char));
     CRM_ASSERT(remainder != NULL);
 
     section = calloc(key_len, sizeof(char));
     CRM_ASSERT(section != NULL);
 
     id = calloc(key_len, sizeof(char));
     CRM_ASSERT(id != NULL);
 
     tag = calloc(key_len, sizeof(char));
     CRM_ASSERT(tag != NULL);
 
     do {
         // Look for /NEXT_COMPONENT/REMAINING_COMPONENTS
         rc = sscanf(current, "/%[^/]%s", section, remainder);
         if (rc > 0) {
             // Separate FIRST_COMPONENT into TAG[@id='ID']
             int f = sscanf(section, "%[^[][@id='%[^']", tag, id);
             int current_position = -1;
 
             /* The target position is for the final component tag, so only use
              * it if there is nothing left to search after this component.
              */
             if ((rc == 1) && (target_position >= 0)) {
                 current_position = target_position;
             }
 
             switch (f) {
                 case 1:
                     target = __first_xml_child_match(target, tag, NULL, current_position);
                     break;
                 case 2:
                     target = __first_xml_child_match(target, tag, id, current_position);
                     break;
                 default:
                     // This should not be possible
                     target = NULL;
                     break;
             }
             current = remainder;
         }
 
     // Continue if something remains to search, and we've matched so far
     } while ((rc == 2) && target);
 
     if (target) {
         crm_trace("Found %s for %s",
                   (path = (char *) xmlGetNodePath(target)), key);
         free(path);
     } else {
         crm_debug("No match for %s", key);
     }
 
     free(remainder);
     free(section);
     free(tag);
     free(id);
     return target;
 }
 
 typedef struct xml_change_obj_s {
     xmlNode *change;
     xmlNode *match;
 } xml_change_obj_t;
 
 static gint
 sort_change_obj_by_position(gconstpointer a, gconstpointer b)
 {
     const xml_change_obj_t *change_obj_a = a;
     const xml_change_obj_t *change_obj_b = b;
     int position_a = -1;
     int position_b = -1;
 
     crm_element_value_int(change_obj_a->change, XML_DIFF_POSITION, &position_a);
     crm_element_value_int(change_obj_b->change, XML_DIFF_POSITION, &position_b);
 
     if (position_a < position_b) {
         return -1;
 
     } else if (position_a > position_b) {
         return 1;
     }
 
     return 0;
 }
 
 static int
 xml_apply_patchset_v2(xmlNode *xml, xmlNode *patchset)
 {
     int rc = pcmk_ok;
     xmlNode *change = NULL;
     GListPtr change_objs = NULL;
     GListPtr gIter = NULL;
 
     for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) {
         xmlNode *match = NULL;
         const char *op = crm_element_value(change, XML_DIFF_OP);
         const char *xpath = crm_element_value(change, XML_DIFF_PATH);
         int position = -1;
 
         if(op == NULL) {
             continue;
         }
 
         crm_trace("Processing %s %s", change->name, op);
 
         // "delete" changes for XML comments are generated with "position"
         if(strcmp(op, "delete") == 0) {
             crm_element_value_int(change, XML_DIFF_POSITION, &position);
         }
         match = __xml_find_path(xml, xpath, position);
         crm_trace("Performing %s on %s with %p", op, xpath, match);
 
         if(match == NULL && strcmp(op, "delete") == 0) {
             crm_debug("No %s match for %s in %p", op, xpath, xml->doc);
             continue;
 
         } else if(match == NULL) {
             crm_err("No %s match for %s in %p", op, xpath, xml->doc);
             rc = -pcmk_err_diff_failed;
             continue;
 
         } else if (strcmp(op, "create") == 0 || strcmp(op, "move") == 0) {
             // Delay the adding of a "create" object
             xml_change_obj_t *change_obj = calloc(1, sizeof(xml_change_obj_t));
 
             CRM_ASSERT(change_obj != NULL);
 
             change_obj->change = change;
             change_obj->match = match;
 
             change_objs = g_list_append(change_objs, change_obj);
 
             if (strcmp(op, "move") == 0) {
                 // Temporarily put the "move" object after the last sibling
                 if (match->parent != NULL && match->parent->last != NULL) {
                     xmlAddNextSibling(match->parent->last, match);
                 }
             }
 
         } else if(strcmp(op, "delete") == 0) {
             free_xml(match);
 
         } else if(strcmp(op, "modify") == 0) {
             xmlAttr *pIter = pcmk__first_xml_attr(match);
             xmlNode *attrs = __xml_first_child(first_named_child(change, XML_DIFF_RESULT));
 
             if(attrs == NULL) {
                 rc = -ENOMSG;
                 continue;
             }
             while(pIter != NULL) {
                 const char *name = (const char *)pIter->name;
 
                 pIter = pIter->next;
                 xml_remove_prop(match, name);
             }
 
             for (pIter = pcmk__first_xml_attr(attrs); pIter != NULL; pIter = pIter->next) {
                 const char *name = (const char *)pIter->name;
                 const char *value = crm_element_value(attrs, name);
 
                 crm_xml_add(match, name, value);
             }
 
         } else {
             crm_err("Unknown operation: %s", op);
             rc = -pcmk_err_diff_failed;
         }
     }
 
     // Changes should be generated in the right order. Double checking.
     change_objs = g_list_sort(change_objs, sort_change_obj_by_position);
 
     for (gIter = change_objs; gIter; gIter = gIter->next) {
         xml_change_obj_t *change_obj = gIter->data;
         xmlNode *match = change_obj->match;
         const char *op = NULL;
         const char *xpath = NULL;
 
         change = change_obj->change;
 
         op = crm_element_value(change, XML_DIFF_OP);
         xpath = crm_element_value(change, XML_DIFF_PATH);
 
         crm_trace("Continue performing %s on %s with %p", op, xpath, match);
 
         if(strcmp(op, "create") == 0) {
             int position = 0;
             xmlNode *child = NULL;
             xmlNode *match_child = NULL;
 
             match_child = match->children;
             crm_element_value_int(change, XML_DIFF_POSITION, &position);
 
             while(match_child && position != __xml_offset(match_child)) {
                 match_child = match_child->next;
             }
 
             child = xmlDocCopyNode(change->children, match->doc, 1);
             if(match_child) {
                 crm_trace("Adding %s at position %d", child->name, position);
                 xmlAddPrevSibling(match_child, child);
 
             } else if(match->last) { /* Add to the end */
                 crm_trace("Adding %s at position %d (end)", child->name, position);
                 xmlAddNextSibling(match->last, child);
 
             } else {
                 crm_trace("Adding %s at position %d (first)", child->name, position);
                 CRM_LOG_ASSERT(position == 0);
                 xmlAddChild(match, child);
             }
             crm_node_created(child);
 
         } else if(strcmp(op, "move") == 0) {
             int position = 0;
 
             crm_element_value_int(change, XML_DIFF_POSITION, &position);
             if(position != __xml_offset(match)) {
                 xmlNode *match_child = NULL;
                 int p = position;
 
                 if(p > __xml_offset(match)) {
                     p++; /* Skip ourselves */
                 }
 
                 CRM_ASSERT(match->parent != NULL);
                 match_child = match->parent->children;
 
                 while(match_child && p != __xml_offset(match_child)) {
                     match_child = match_child->next;
                 }
 
                 crm_trace("Moving %s to position %d (was %d, prev %p, %s %p)",
                          match->name, position, __xml_offset(match), match->prev,
                          match_child?"next":"last", match_child?match_child:match->parent->last);
 
                 if(match_child) {
                     xmlAddPrevSibling(match_child, match);
 
                 } else {
                     CRM_ASSERT(match->parent->last != NULL);
                     xmlAddNextSibling(match->parent->last, match);
                 }
 
             } else {
                 crm_trace("%s is already in position %d", match->name, position);
             }
 
             if(position != __xml_offset(match)) {
                 crm_err("Moved %s.%s to position %d instead of %d (%p)",
                         match->name, ID(match), __xml_offset(match), position, match->prev);
                 rc = -pcmk_err_diff_failed;
             }
         }
     }
 
     g_list_free_full(change_objs, free);
     return rc;
 }
 
 int
 xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version) 
 {
     int format = 1;
     int rc = pcmk_ok;
     xmlNode *old = NULL;
     const char *digest = crm_element_value(patchset, XML_ATTR_DIGEST);
 
     if(patchset == NULL) {
         return rc;
     }
 
     xml_log_patchset(LOG_TRACE, __FUNCTION__, patchset);
 
     crm_element_value_int(patchset, "format", &format);
     if(check_version) {
         rc = xml_patch_version_check(xml, patchset, format);
         if(rc != pcmk_ok) {
             return rc;
         }
     }
 
     if(digest) {
         /* Make it available for logging if the result doesn't have the expected digest */
         old = copy_xml(xml);
     }
 
     if(rc == pcmk_ok) {
         switch(format) {
             case 1:
                 rc = xml_apply_patchset_v1(xml, patchset);
                 break;
             case 2:
                 rc = xml_apply_patchset_v2(xml, patchset);
                 break;
             default:
                 crm_err("Unknown patch format: %d", format);
                 rc = -EINVAL;
         }
     }
 
     if(rc == pcmk_ok && digest) {
         static struct qb_log_callsite *digest_cs = NULL;
 
         char *new_digest = NULL;
         char *version = crm_element_value_copy(xml, XML_ATTR_CRM_VERSION);
 
         if (digest_cs == NULL) {
             digest_cs =
                 qb_log_callsite_get(__func__, __FILE__, "diff-digest", LOG_TRACE, __LINE__,
                                     crm_trace_nonlog);
         }
 
         new_digest = calculate_xml_versioned_digest(xml, FALSE, TRUE, version);
         if (safe_str_neq(new_digest, digest)) {
             crm_info("v%d digest mis-match: expected %s, calculated %s", format, digest, new_digest);
             rc = -pcmk_err_diff_failed;
 
             if (digest_cs && digest_cs->targets) {
                 save_xml_to_file(old,     "PatchDigest:input", NULL);
                 save_xml_to_file(xml,     "PatchDigest:result", NULL);
                 save_xml_to_file(patchset,"PatchDigest:diff", NULL);
 
             } else {
                 crm_trace("%p %.6x", digest_cs, digest_cs ? digest_cs->targets : 0);
             }
 
         } else {
             crm_trace("v%d digest matched: expected %s, calculated %s", format, digest, new_digest);
         }
         free(new_digest);
         free(version);
     }
     free_xml(old);
     return rc;
 }
 
 xmlNode *
 find_xml_node(xmlNode * root, const char *search_path, gboolean must_find)
 {
     xmlNode *a_child = NULL;
     const char *name = "NULL";
 
     if (root != NULL) {
         name = crm_element_name(root);
     }
 
     if (search_path == NULL) {
         crm_warn("Will never find <NULL>");
         return NULL;
     }
 
     for (a_child = __xml_first_child(root); a_child != NULL; a_child = __xml_next(a_child)) {
         if (strcmp((const char *)a_child->name, search_path) == 0) {
 /* 		crm_trace("returning node (%s).", crm_element_name(a_child)); */
             return a_child;
         }
     }
 
     if (must_find) {
         crm_warn("Could not find %s in %s.", search_path, name);
     } else if (root != NULL) {
         crm_trace("Could not find %s in %s.", search_path, name);
     } else {
         crm_trace("Could not find %s in <NULL>.", search_path);
     }
 
     return NULL;
 }
 
 /* As the name suggests, the perfect match is required for both node
    name and fully specified attribute, otherwise, when attribute not
    specified, the outcome is the first node matching on the name. */
 static xmlNode *
 find_entity_by_attr_or_just_name(xmlNode *parent, const char *node_name,
                                  const char *attr_n, const char *attr_v)
 {
     xmlNode *child;
 
     /* ensure attr_v specified when attr_n is */
     CRM_CHECK(attr_n == NULL || attr_v != NULL, return NULL);
 
     for (child = __xml_first_child(parent); child != NULL; child = __xml_next(child)) {
         /* XXX uncertain if the first check is strictly necessary here */
         if (node_name == NULL || !strcmp((const char *) child->name, node_name)) {
             if (attr_n == NULL
                     || crm_str_eq(crm_element_value(child, attr_n), attr_v, TRUE)) {
                 return child;
             }
         }
     }
 
     crm_trace("node <%s%s%s%s%s> not found in %s", crm_str(node_name),
               attr_n ? " " : "",
               attr_n ? attr_n : "",
               attr_n ? "=" : "",
               attr_n ? attr_v : "",
               crm_element_name(parent));
 
     return NULL;
 }
 
 xmlNode *
 find_entity(xmlNode *parent, const char *node_name, const char *id)
 {
     return find_entity_by_attr_or_just_name(parent, node_name,
                                             (id == NULL) ? id : XML_ATTR_ID, id);
 }
 
 void
 copy_in_properties(xmlNode * target, xmlNode * src)
 {
     if (src == NULL) {
         crm_warn("No node to copy properties from");
 
     } else if (target == NULL) {
         crm_err("No node to copy properties into");
 
     } else {
         xmlAttrPtr pIter = NULL;
 
         for (pIter = pcmk__first_xml_attr(src); pIter != NULL; pIter = pIter->next) {
             const char *p_name = (const char *)pIter->name;
             const char *p_value = pcmk__xml_attr_value(pIter);
 
             expand_plus_plus(target, p_name, p_value);
         }
     }
 
     return;
 }
 
 void
 fix_plus_plus_recursive(xmlNode * target)
 {
     /* TODO: Remove recursion and use xpath searches for value++ */
     xmlNode *child = NULL;
     xmlAttrPtr pIter = NULL;
 
     for (pIter = pcmk__first_xml_attr(target); pIter != NULL; pIter = pIter->next) {
         const char *p_name = (const char *)pIter->name;
         const char *p_value = pcmk__xml_attr_value(pIter);
 
         expand_plus_plus(target, p_name, p_value);
     }
     for (child = __xml_first_child(target); child != NULL; child = __xml_next(child)) {
         fix_plus_plus_recursive(child);
     }
 }
 
 void
 expand_plus_plus(xmlNode * target, const char *name, const char *value)
 {
     int offset = 1;
     int name_len = 0;
     int int_value = 0;
     int value_len = 0;
 
     const char *old_value = NULL;
 
     if (value == NULL || name == NULL) {
         return;
     }
 
     old_value = crm_element_value(target, name);
 
     if (old_value == NULL) {
         /* if no previous value, set unexpanded */
         goto set_unexpanded;
 
     } else if (strstr(value, name) != value) {
         goto set_unexpanded;
     }
 
     name_len = strlen(name);
     value_len = strlen(value);
     if (value_len < (name_len + 2)
         || value[name_len] != '+' || (value[name_len + 1] != '+' && value[name_len + 1] != '=')) {
         goto set_unexpanded;
     }
 
     /* if we are expanding ourselves,
      * then no previous value was set and leave int_value as 0
      */
     if (old_value != value) {
         int_value = char2score(old_value);
     }
 
     if (value[name_len + 1] != '+') {
         const char *offset_s = value + (name_len + 2);
 
         offset = char2score(offset_s);
     }
     int_value += offset;
 
     if (int_value > INFINITY) {
         int_value = (int)INFINITY;
     }
 
     crm_xml_add_int(target, name, int_value);
     return;
 
   set_unexpanded:
     if (old_value == value) {
         /* the old value is already set, nothing to do */
         return;
     }
     crm_xml_add(target, name, value);
     return;
 }
 
 xmlDoc *
 getDocPtr(xmlNode * node)
 {
     xmlDoc *doc = NULL;
 
     CRM_CHECK(node != NULL, return NULL);
 
     doc = node->doc;
     if (doc == NULL) {
         doc = xmlNewDoc((pcmkXmlStr) "1.0");
         xmlDocSetRootElement(doc, node);
         xmlSetTreeDoc(node, doc);
     }
     return doc;
 }
 
 xmlNode *
 add_node_copy(xmlNode * parent, xmlNode * src_node)
 {
     xmlNode *child = NULL;
     xmlDoc *doc = getDocPtr(parent);
 
     CRM_CHECK(src_node != NULL, return NULL);
 
     child = xmlDocCopyNode(src_node, doc, 1);
     xmlAddChild(parent, child);
     crm_node_created(child);
     return child;
 }
 
 int
 add_node_nocopy(xmlNode * parent, const char *name, xmlNode * child)
 {
     add_node_copy(parent, child);
     free_xml(child);
     return 1;
 }
 
 xmlNode *
 create_xml_node(xmlNode * parent, const char *name)
 {
     xmlDoc *doc = NULL;
     xmlNode *node = NULL;
 
     if (name == NULL || name[0] == 0) {
         CRM_CHECK(name != NULL && name[0] == 0, return NULL);
         return NULL;
     }
 
     if (parent == NULL) {
         doc = xmlNewDoc((pcmkXmlStr) "1.0");
         node = xmlNewDocRawNode(doc, NULL, (pcmkXmlStr) name, NULL);
         xmlDocSetRootElement(doc, node);
 
     } else {
         doc = getDocPtr(parent);
         node = xmlNewDocRawNode(doc, NULL, (pcmkXmlStr) name, NULL);
         xmlAddChild(parent, node);
     }
     crm_node_created(node);
     return node;
 }
 
 int
 pcmk__element_xpath(const char *prefix, xmlNode *xml, char *buffer,
                     int offset, size_t buffer_size)
 {
     const char *id = ID(xml);
 
     if(offset == 0 && prefix == NULL && xml->parent) {
         offset = pcmk__element_xpath(NULL, xml->parent, buffer, offset,
                                      buffer_size);
     }
 
     if(id) {
         offset += snprintf(buffer + offset, buffer_size - offset,
                            "/%s[@id='%s']", (const char *) xml->name, id);
     } else if(xml->name) {
         offset += snprintf(buffer + offset, buffer_size - offset,
                            "/%s", (const char *) xml->name);
     }
 
     return offset;
 }
 
 char *
 xml_get_path(xmlNode *xml)
 {
     int offset = 0;
     char buffer[XML_BUFFER_SIZE];
 
     if (pcmk__element_xpath(NULL, xml, buffer, offset, sizeof(buffer)) > 0) {
         return strdup(buffer);
     }
     return NULL;
 }
 
 /*!
  * Free an XML element and all of its children, removing it from its parent
  *
  * \param[in] xml  XML element to free
  */
 void
 pcmk_free_xml_subtree(xmlNode *xml)
 {
     xmlUnlinkNode(xml); // Detaches from parent and siblings
     xmlFreeNode(xml);   // Frees
 }
 
 static void
 free_xml_with_position(xmlNode * child, int position)
 {
     if (child != NULL) {
         xmlNode *top = NULL;
         xmlDoc *doc = child->doc;
         xml_private_t *p = child->_private;
 
         if (doc != NULL) {
             top = xmlDocGetRootElement(doc);
         }
 
         if (doc != NULL && top == child) {
             /* Free everything */
             xmlFreeDoc(doc);
 
         } else if (pcmk__check_acl(child, NULL, xpf_acl_write) == FALSE) {
             int offset = 0;
             char buffer[XML_BUFFER_SIZE];
 
             pcmk__element_xpath(NULL, child, buffer, offset, sizeof(buffer));
             crm_trace("Cannot remove %s %x", buffer, p->flags);
             return;
 
         } else {
             if (doc && pcmk__tracking_xml_changes(child, FALSE)
                 && is_not_set(p->flags, xpf_created)) {
                 int offset = 0;
                 char buffer[XML_BUFFER_SIZE];
 
                 if (pcmk__element_xpath(NULL, child, buffer, offset,
                                         sizeof(buffer)) > 0) {
                     xml_deleted_obj_t *deleted_obj = calloc(1, sizeof(xml_deleted_obj_t));
 
                     crm_trace("Deleting %s %p from %p", buffer, child, doc);
 
                     deleted_obj->path = strdup(buffer);
 
                     deleted_obj->position = -1;
                     /* Record the "position" only for XML comments for now */
                     if (child->type == XML_COMMENT_NODE) {
                         if (position >= 0) {
                             deleted_obj->position = position;
 
                         } else {
                             deleted_obj->position = __xml_offset(child);
                         }
                     }
 
                     p = doc->_private;
                     p->deleted_objs = g_list_append(p->deleted_objs, deleted_obj);
                     pcmk__set_xml_flag(child, xpf_dirty);
                 }
             }
             pcmk_free_xml_subtree(child);
         }
     }
 }
 
 
 void
 free_xml(xmlNode * child)
 {
     free_xml_with_position(child, -1);
 }
 
 xmlNode *
 copy_xml(xmlNode * src)
 {
     xmlDoc *doc = xmlNewDoc((pcmkXmlStr) "1.0");
     xmlNode *copy = xmlDocCopyNode(src, doc, 1);
 
     xmlDocSetRootElement(doc, copy);
     xmlSetTreeDoc(copy, doc);
     return copy;
 }
 
 static void
 crm_xml_err(void *ctx, const char *fmt, ...)
 G_GNUC_PRINTF(2, 3);
 
 static void
 crm_xml_err(void *ctx, const char *fmt, ...)
 {
     va_list ap;
     static struct qb_log_callsite *xml_error_cs = NULL;
 
     if (xml_error_cs == NULL) {
         xml_error_cs = qb_log_callsite_get(
             __func__, __FILE__, "xml library error", LOG_TRACE, __LINE__, crm_trace_nonlog);
     }
 
     va_start(ap, fmt);
     if (xml_error_cs && xml_error_cs->targets) {
         CRM_XML_LOG_BASE(LOG_ERR, TRUE,
                          crm_abort(__FILE__, __PRETTY_FUNCTION__, __LINE__, "xml library error",
                                    TRUE, TRUE),
                          "XML Error: ", fmt, ap);
     } else {
         CRM_XML_LOG_BASE(LOG_ERR, TRUE, 0, "XML Error: ", fmt, ap);
     }
     va_end(ap);
 }
 
 xmlNode *
 string2xml(const char *input)
 {
     xmlNode *xml = NULL;
     xmlDocPtr output = NULL;
     xmlParserCtxtPtr ctxt = NULL;
     xmlErrorPtr last_error = NULL;
 
     if (input == NULL) {
         crm_err("Can't parse NULL input");
         return NULL;
     }
 
     /* create a parser context */
     ctxt = xmlNewParserCtxt();
     CRM_CHECK(ctxt != NULL, return NULL);
 
     /* xmlCtxtUseOptions(ctxt, XML_PARSE_NOBLANKS|XML_PARSE_RECOVER); */
 
     xmlCtxtResetLastError(ctxt);
     xmlSetGenericErrorFunc(ctxt, crm_xml_err);
     /* initGenericErrorDefaultFunc(crm_xml_err); */
     output =
         xmlCtxtReadDoc(ctxt, (pcmkXmlStr) input, NULL, NULL,
                        XML_PARSE_NOBLANKS | XML_PARSE_RECOVER);
     if (output) {
         xml = xmlDocGetRootElement(output);
     }
     last_error = xmlCtxtGetLastError(ctxt);
     if (last_error && last_error->code != XML_ERR_OK) {
         /* crm_abort(__FILE__,__FUNCTION__,__LINE__, "last_error->code != XML_ERR_OK", TRUE, TRUE); */
         /*
          * http://xmlsoft.org/html/libxml-xmlerror.html#xmlErrorLevel
          * http://xmlsoft.org/html/libxml-xmlerror.html#xmlParserErrors
          */
         crm_warn("Parsing failed (domain=%d, level=%d, code=%d): %s",
                  last_error->domain, last_error->level, last_error->code, last_error->message);
 
         if (last_error->code == XML_ERR_DOCUMENT_EMPTY) {
             CRM_LOG_ASSERT("Cannot parse an empty string");
 
         } else if (last_error->code != XML_ERR_DOCUMENT_END) {
             crm_err("Couldn't%s parse %d chars: %s", xml ? " fully" : "", (int)strlen(input),
                     input);
             if (xml != NULL) {
                 crm_log_xml_err(xml, "Partial");
             }
 
         } else {
             int len = strlen(input);
             int lpc = 0;
 
             while(lpc < len) {
                 crm_warn("Parse error[+%.3d]: %.80s", lpc, input+lpc);
                 lpc += 80;
             }
 
             CRM_LOG_ASSERT("String parsing error");
         }
     }
 
     xmlFreeParserCtxt(ctxt);
     return xml;
 }
 
 xmlNode *
 stdin2xml(void)
 {
     size_t data_length = 0;
     size_t read_chars = 0;
 
     char *xml_buffer = NULL;
     xmlNode *xml_obj = NULL;
 
     do {
         xml_buffer = realloc_safe(xml_buffer, data_length + XML_BUFFER_SIZE);
         read_chars = fread(xml_buffer + data_length, 1, XML_BUFFER_SIZE, stdin);
         data_length += read_chars;
     } while (read_chars == XML_BUFFER_SIZE);
 
     if (data_length == 0) {
         crm_warn("No XML supplied on stdin");
         free(xml_buffer);
         return NULL;
     }
 
     xml_buffer[data_length] = '\0';
     xml_obj = string2xml(xml_buffer);
     free(xml_buffer);
 
     crm_log_xml_trace(xml_obj, "Created fragment");
     return xml_obj;
 }
 
 static char *
 decompress_file(const char *filename)
 {
     char *buffer = NULL;
 
 #if HAVE_BZLIB_H
     int rc = 0;
     size_t length = 0, read_len = 0;
 
     BZFILE *bz_file = NULL;
     FILE *input = fopen(filename, "r");
 
     if (input == NULL) {
         crm_perror(LOG_ERR, "Could not open %s for reading", filename);
         return NULL;
     }
 
     bz_file = BZ2_bzReadOpen(&rc, input, 0, 0, NULL, 0);
     if (rc != BZ_OK) {
         crm_err("Could not prepare to read compressed %s: %s "
                 CRM_XS " bzerror=%d", filename, bz2_strerror(rc), rc);
         BZ2_bzReadClose(&rc, bz_file);
         return NULL;
     }
 
     rc = BZ_OK;
     while (rc == BZ_OK) {
         buffer = realloc_safe(buffer, XML_BUFFER_SIZE + length + 1);
         read_len = BZ2_bzRead(&rc, bz_file, buffer + length, XML_BUFFER_SIZE);
 
         crm_trace("Read %ld bytes from file: %d", (long)read_len, rc);
 
         if (rc == BZ_OK || rc == BZ_STREAM_END) {
             length += read_len;
         }
     }
 
     buffer[length] = '\0';
 
     if (rc != BZ_STREAM_END) {
         crm_err("Could not read compressed %s: %s "
                 CRM_XS " bzerror=%d", filename, bz2_strerror(rc), rc);
         free(buffer);
         buffer = NULL;
     }
 
     BZ2_bzReadClose(&rc, bz_file);
     fclose(input);
 
 #else
     crm_err("Could not read compressed %s: not built with bzlib support",
             filename);
 #endif
     return buffer;
 }
 
 void
 strip_text_nodes(xmlNode * xml)
 {
     xmlNode *iter = xml->children;
 
     while (iter) {
         xmlNode *next = iter->next;
 
         switch (iter->type) {
             case XML_TEXT_NODE:
                 /* Remove it */
                 pcmk_free_xml_subtree(iter);
                 break;
 
             case XML_ELEMENT_NODE:
                 /* Search it */
                 strip_text_nodes(iter);
                 break;
 
             default:
                 /* Leave it */
                 break;
         }
 
         iter = next;
     }
 }
 
 xmlNode *
 filename2xml(const char *filename)
 {
     xmlNode *xml = NULL;
     xmlDocPtr output = NULL;
     gboolean uncompressed = TRUE;
     xmlParserCtxtPtr ctxt = NULL;
     xmlErrorPtr last_error = NULL;
     static int xml_options = XML_PARSE_NOBLANKS | XML_PARSE_RECOVER;
 
     /* create a parser context */
     ctxt = xmlNewParserCtxt();
     CRM_CHECK(ctxt != NULL, return NULL);
 
     /* xmlCtxtUseOptions(ctxt, XML_PARSE_NOBLANKS|XML_PARSE_RECOVER); */
 
     xmlCtxtResetLastError(ctxt);
     xmlSetGenericErrorFunc(ctxt, crm_xml_err);
     /* initGenericErrorDefaultFunc(crm_xml_err); */
 
     if (filename) {
         uncompressed = !crm_ends_with_ext(filename, ".bz2");
     }
 
     if (filename == NULL) {
         /* STDIN_FILENO == fileno(stdin) */
         output = xmlCtxtReadFd(ctxt, STDIN_FILENO, "unknown.xml", NULL, xml_options);
 
     } else if (uncompressed) {
         output = xmlCtxtReadFile(ctxt, filename, NULL, xml_options);
 
     } else {
         char *input = decompress_file(filename);
 
         output = xmlCtxtReadDoc(ctxt, (pcmkXmlStr) input, NULL, NULL,
                                 xml_options);
         free(input);
     }
 
     if (output && (xml = xmlDocGetRootElement(output))) {
         strip_text_nodes(xml);
     }
 
     last_error = xmlCtxtGetLastError(ctxt);
     if (last_error && last_error->code != XML_ERR_OK) {
         /* crm_abort(__FILE__,__FUNCTION__,__LINE__, "last_error->code != XML_ERR_OK", TRUE, TRUE); */
         /*
          * http://xmlsoft.org/html/libxml-xmlerror.html#xmlErrorLevel
          * http://xmlsoft.org/html/libxml-xmlerror.html#xmlParserErrors
          */
         crm_err("Parsing failed (domain=%d, level=%d, code=%d): %s",
                 last_error->domain, last_error->level, last_error->code, last_error->message);
 
         if (last_error && last_error->code != XML_ERR_OK) {
             crm_err("Couldn't%s parse %s", xml ? " fully" : "", filename);
             if (xml != NULL) {
                 crm_log_xml_err(xml, "Partial");
             }
         }
     }
 
     xmlFreeParserCtxt(ctxt);
     return xml;
 }
 
 /*!
  * \internal
  * \brief Add a "last written" attribute to an XML node, set to current time
  *
  * \param[in] xml_node XML node to get attribute
  *
  * \return Value that was set, or NULL on error
  */
 const char *
 crm_xml_add_last_written(xmlNode *xml_node)
 {
     const char *now_str = crm_now_string();
     return crm_xml_add(xml_node, XML_CIB_ATTR_WRITTEN, now_str);
 }
 
 /*!
  * \brief Sanitize a string so it is usable as an XML ID
  *
  * \param[in,out] id  String to sanitize
  */
 void
 crm_xml_sanitize_id(char *id)
 {
     char *c;
 
     for (c = id; *c; ++c) {
         /* @TODO Sanitize more comprehensively */
         switch (*c) {
             case ':':
             case '#':
                 *c = '.';
         }
     }
 }
 
 /*!
  * \brief Set the ID of an XML element using a format
  *
  * \param[in,out] xml  XML element
  * \param[in]     fmt  printf-style format
  * \param[in]     ...  any arguments required by format
  */
 void
 crm_xml_set_id(xmlNode *xml, const char *format, ...)
 {
     va_list ap;
     int len = 0;
     char *id = NULL;
 
     /* equivalent to crm_strdup_printf() */
     va_start(ap, format);
     len = vasprintf(&id, format, ap);
     va_end(ap);
     CRM_ASSERT(len > 0);
 
     crm_xml_sanitize_id(id);
     crm_xml_add(xml, XML_ATTR_ID, id);
     free(id);
 }
 
 /*!
  * \internal
  * \brief Write XML to a file stream
  *
  * \param[in] xml_node  XML to write
  * \param[in] filename  Name of file being written (for logging only)
  * \param[in] stream    Open file stream corresponding to filename
  * \param[in] compress  Whether to compress XML before writing
  *
  * \return Number of bytes written on success, -errno otherwise
  */
 static int
 write_xml_stream(xmlNode * xml_node, const char *filename, FILE * stream, gboolean compress)
 {
     int res = 0;
     char *buffer = NULL;
     unsigned int out = 0;
 
     crm_log_xml_trace(xml_node, "writing");
 
     buffer = dump_xml_formatted(xml_node);
     CRM_CHECK(buffer && strlen(buffer),
               crm_log_xml_warn(xml_node, "formatting failed");
               res = -pcmk_err_generic;
               goto bail);
 
     if (compress) {
 #if HAVE_BZLIB_H
         int rc = BZ_OK;
         unsigned int in = 0;
         BZFILE *bz_file = NULL;
 
         bz_file = BZ2_bzWriteOpen(&rc, stream, 5, 0, 30);
         if (rc != BZ_OK) {
             crm_warn("Not compressing %s: could not prepare file stream: %s "
                      CRM_XS " bzerror=%d", filename, bz2_strerror(rc), rc);
         } else {
             BZ2_bzWrite(&rc, bz_file, buffer, strlen(buffer));
             if (rc != BZ_OK) {
                 crm_warn("Not compressing %s: could not compress data: %s "
                          CRM_XS " bzerror=%d errno=%d",
                          filename, bz2_strerror(rc), rc, errno);
             }
         }
 
         if (rc == BZ_OK) {
             BZ2_bzWriteClose(&rc, bz_file, 0, &in, &out);
             if (rc != BZ_OK) {
                 crm_warn("Not compressing %s: could not write compressed data: %s "
                          CRM_XS " bzerror=%d errno=%d",
                          filename, bz2_strerror(rc), rc, errno);
                 out = 0; // retry without compression
             } else {
                 res = (int) out;
                 crm_trace("Compressed XML for %s from %u bytes to %u",
                           filename, in, out);
             }
         }
 #else
         crm_warn("Not compressing %s: not built with bzlib support", filename);
 #endif
     }
 
     if (out == 0) {
         res = fprintf(stream, "%s", buffer);
         if (res < 0) {
             res = -errno;
             crm_perror(LOG_ERR, "writing %s", filename);
             goto bail;
         }
     }
 
   bail:
 
     if (fflush(stream) != 0) {
         res = -errno;
         crm_perror(LOG_ERR, "flushing %s", filename);
     }
 
     /* Don't report error if the file does not support synchronization */
     if (fsync(fileno(stream)) < 0 && errno != EROFS  && errno != EINVAL) {
         res = -errno;
         crm_perror(LOG_ERR, "synchronizing %s", filename);
     }
 
     fclose(stream);
 
     crm_trace("Saved %d bytes%s to %s as XML",
               res, ((out > 0)? " (compressed)" : ""), filename);
     free(buffer);
 
     return res;
 }
 
 /*!
  * \brief Write XML to a file descriptor
  *
  * \param[in] xml_node  XML to write
  * \param[in] filename  Name of file being written (for logging only)
  * \param[in] fd        Open file descriptor corresponding to filename
  * \param[in] compress  Whether to compress XML before writing
  *
  * \return Number of bytes written on success, -errno otherwise
  */
 int
 write_xml_fd(xmlNode * xml_node, const char *filename, int fd, gboolean compress)
 {
     FILE *stream = NULL;
 
     CRM_CHECK(xml_node && (fd > 0), return -EINVAL);
     stream = fdopen(fd, "w");
     if (stream == NULL) {
         return -errno;
     }
     return write_xml_stream(xml_node, filename, stream, compress);
 }
 
 /*!
  * \brief Write XML to a file
  *
  * \param[in] xml_node  XML to write
  * \param[in] filename  Name of file to write
  * \param[in] compress  Whether to compress XML before writing
  *
  * \return Number of bytes written on success, -errno otherwise
  */
 int
 write_xml_file(xmlNode * xml_node, const char *filename, gboolean compress)
 {
     FILE *stream = NULL;
 
     CRM_CHECK(xml_node && filename, return -EINVAL);
     stream = fopen(filename, "w");
     if (stream == NULL) {
         return -errno;
     }
     return write_xml_stream(xml_node, filename, stream, compress);
 }
 
 xmlNode *
 get_message_xml(xmlNode * msg, const char *field)
 {
     xmlNode *tmp = first_named_child(msg, field);
 
     return __xml_first_child(tmp);
 }
 
 gboolean
 add_message_xml(xmlNode * msg, const char *field, xmlNode * xml)
 {
     xmlNode *holder = create_xml_node(msg, field);
 
     add_node_copy(holder, xml);
     return TRUE;
 }
 
 static char *
 crm_xml_escape_shuffle(char *text, int start, int *length, const char *replace)
 {
     int lpc;
     int offset = strlen(replace) - 1;   /* We have space for 1 char already */
 
     *length += offset;
     text = realloc_safe(text, *length);
 
     for (lpc = (*length) - 1; lpc > (start + offset); lpc--) {
         text[lpc] = text[lpc - offset];
     }
 
     memcpy(text + start, replace, offset + 1);
     return text;
 }
 
 char *
 crm_xml_escape(const char *text)
 {
     int index;
     int changes = 0;
     int length = 1 + strlen(text);
     char *copy = strdup(text);
 
     /*
      * When xmlCtxtReadDoc() parses &lt; and friends in a
      * value, it converts them to their human readable
      * form.
      *
      * If one uses xmlNodeDump() to convert it back to a
      * string, all is well, because special characters are
      * converted back to their escape sequences.
      *
      * However xmlNodeDump() is randomly dog slow, even with the same
      * input. So we need to replicate the escaping in our custom
      * version so that the result can be re-parsed by xmlCtxtReadDoc()
      * when necessary.
      */
 
     for (index = 0; index < length; index++) {
         switch (copy[index]) {
             case 0:
                 break;
             case '<':
                 copy = crm_xml_escape_shuffle(copy, index, &length, "&lt;");
                 changes++;
                 break;
             case '>':
                 copy = crm_xml_escape_shuffle(copy, index, &length, "&gt;");
                 changes++;
                 break;
             case '"':
                 copy = crm_xml_escape_shuffle(copy, index, &length, "&quot;");
                 changes++;
                 break;
             case '\'':
                 copy = crm_xml_escape_shuffle(copy, index, &length, "&apos;");
                 changes++;
                 break;
             case '&':
                 copy = crm_xml_escape_shuffle(copy, index, &length, "&amp;");
                 changes++;
                 break;
             case '\t':
                 /* Might as well just expand to a few spaces... */
                 copy = crm_xml_escape_shuffle(copy, index, &length, "    ");
                 changes++;
                 break;
             case '\n':
                 /* crm_trace("Convert: \\%.3o", copy[index]); */
                 copy = crm_xml_escape_shuffle(copy, index, &length, "\\n");
                 changes++;
                 break;
             case '\r':
                 copy = crm_xml_escape_shuffle(copy, index, &length, "\\r");
                 changes++;
                 break;
                 /* For debugging...
             case '\\':
                 crm_trace("Passthrough: \\%c", copy[index+1]);
                 break;
                 */
             default:
                 /* Check for and replace non-printing characters with their octal equivalent */
                 if(copy[index] < ' ' || copy[index] > '~') {
                     char *replace = crm_strdup_printf("\\%.3o", copy[index]);
 
                     /* crm_trace("Convert to octal: \\%.3o", copy[index]); */
                     copy = crm_xml_escape_shuffle(copy, index, &length, replace);
                     free(replace);
                     changes++;
                 }
         }
     }
 
     if (changes) {
         crm_trace("Dumped '%s'", copy);
     }
     return copy;
 }
 
 static inline void
 dump_xml_attr(xmlAttrPtr attr, int options, char **buffer, int *offset, int *max)
 {
     char *p_value = NULL;
     const char *p_name = NULL;
     xml_private_t *p = NULL;
 
     CRM_ASSERT(buffer != NULL);
     if (attr == NULL || attr->children == NULL) {
         return;
     }
 
     p = attr->_private;
     if (p && is_set(p->flags, xpf_deleted)) {
         return;
     }
 
     p_name = (const char *)attr->name;
     p_value = crm_xml_escape((const char *)attr->children->content);
     buffer_print(*buffer, *max, *offset, " %s=\"%s\"", p_name, p_value);
     free(p_value);
 }
 
 static void
 __xml_log_element(int log_level, const char *file, const char *function, int line,
                   const char *prefix, xmlNode * data, int depth, int options)
 {
     int max = 0;
     int offset = 0;
     const char *name = NULL;
     const char *hidden = NULL;
 
     xmlNode *child = NULL;
     xmlAttrPtr pIter = NULL;
 
     if(data == NULL) {
         return;
     }
 
     name = crm_element_name(data);
 
     if(is_set(options, xml_log_option_open)) {
         char *buffer = NULL;
 
         insert_prefix(options, &buffer, &offset, &max, depth);
 
         if (data->type == XML_COMMENT_NODE) {
             buffer_print(buffer, max, offset, "<!--%s-->", data->content);
 
         } else {
             buffer_print(buffer, max, offset, "<%s", name);
 
             hidden = crm_element_value(data, "hidden");
             for (pIter = pcmk__first_xml_attr(data); pIter != NULL; pIter = pIter->next) {
                 xml_private_t *p = pIter->_private;
                 const char *p_name = (const char *)pIter->name;
                 const char *p_value = pcmk__xml_attr_value(pIter);
                 char *p_copy = NULL;
 
                 if(is_set(p->flags, xpf_deleted)) {
                     continue;
                 } else if ((is_set(options, xml_log_option_diff_plus)
                      || is_set(options, xml_log_option_diff_minus))
                     && strcmp(XML_DIFF_MARKER, p_name) == 0) {
                     continue;
 
                 } else if (hidden != NULL && p_name[0] != 0 && strstr(hidden, p_name) != NULL) {
                     p_copy = strdup("*****");
 
                 } else {
                     p_copy = crm_xml_escape(p_value);
                 }
 
                 buffer_print(buffer, max, offset, " %s=\"%s\"", p_name, p_copy);
                 free(p_copy);
             }
 
             if(xml_has_children(data) == FALSE) {
                 buffer_print(buffer, max, offset, "/>");
 
             } else if(is_set(options, xml_log_option_children)) {
                 buffer_print(buffer, max, offset, ">");
 
             } else {
                 buffer_print(buffer, max, offset, "/>");
             }
         }
 
         do_crm_log_alias(log_level, file, function, line, "%s %s", prefix, buffer);
         free(buffer);
     }
 
     if(data->type == XML_COMMENT_NODE) {
         return;
 
     } else if(xml_has_children(data) == FALSE) {
         return;
 
     } else if(is_set(options, xml_log_option_children)) {
         offset = 0;
         max = 0;
 
         for (child = __xml_first_child(data); child != NULL; child = __xml_next(child)) {
             __xml_log_element(log_level, file, function, line, prefix, child, depth + 1, options|xml_log_option_open|xml_log_option_close);
         }
     }
 
     if(is_set(options, xml_log_option_close)) {
         char *buffer = NULL;
 
         insert_prefix(options, &buffer, &offset, &max, depth);
         buffer_print(buffer, max, offset, "</%s>", name);
 
         do_crm_log_alias(log_level, file, function, line, "%s %s", prefix, buffer);
         free(buffer);
     }
 }
 
 static void
 __xml_log_change_element(int log_level, const char *file, const char *function, int line,
                          const char *prefix, xmlNode * data, int depth, int options)
 {
     xml_private_t *p;
     char *prefix_m = NULL;
     xmlNode *child = NULL;
     xmlAttrPtr pIter = NULL;
 
     if(data == NULL) {
         return;
     }
 
     p = data->_private;
 
     prefix_m = strdup(prefix);
     prefix_m[1] = '+';
 
     if(is_set(p->flags, xpf_dirty) && is_set(p->flags, xpf_created)) {
         /* Continue and log full subtree */
         __xml_log_element(log_level, file, function, line,
                           prefix_m, data, depth, options|xml_log_option_open|xml_log_option_close|xml_log_option_children);
 
     } else if(is_set(p->flags, xpf_dirty)) {
         char *spaces = calloc(80, 1);
         int s_count = 0, s_max = 80;
         char *prefix_del = NULL;
         char *prefix_moved = NULL;
         const char *flags = prefix;
 
         insert_prefix(options, &spaces, &s_count, &s_max, depth);
         prefix_del = strdup(prefix);
         prefix_del[0] = '-';
         prefix_del[1] = '-';
         prefix_moved = strdup(prefix);
         prefix_moved[1] = '~';
 
         if(is_set(p->flags, xpf_moved)) {
             flags = prefix_moved;
         } else {
             flags = prefix;
         }
 
         __xml_log_element(log_level, file, function, line,
                           flags, data, depth, options|xml_log_option_open);
 
         for (pIter = pcmk__first_xml_attr(data); pIter != NULL; pIter = pIter->next) {
             const char *aname = (const char*)pIter->name;
 
             p = pIter->_private;
             if(is_set(p->flags, xpf_deleted)) {
                 const char *value = crm_element_value(data, aname);
                 flags = prefix_del;
                 do_crm_log_alias(log_level, file, function, line,
                                  "%s %s @%s=%s", flags, spaces, aname, value);
 
             } else if(is_set(p->flags, xpf_dirty)) {
                 const char *value = crm_element_value(data, aname);
 
                 if(is_set(p->flags, xpf_created)) {
                     flags = prefix_m;
 
                 } else if(is_set(p->flags, xpf_modified)) {
                     flags = prefix;
 
                 } else if(is_set(p->flags, xpf_moved)) {
                     flags = prefix_moved;
 
                 } else {
                     flags = prefix;
                 }
                 do_crm_log_alias(log_level, file, function, line,
                                  "%s %s @%s=%s", flags, spaces, aname, value);
             }
         }
         free(prefix_moved);
         free(prefix_del);
         free(spaces);
 
         for (child = __xml_first_child(data); child != NULL; child = __xml_next(child)) {
             __xml_log_change_element(log_level, file, function, line, prefix, child, depth + 1, options);
         }
 
         __xml_log_element(log_level, file, function, line,
                           prefix, data, depth, options|xml_log_option_close);
 
     } else {
         for (child = __xml_first_child(data); child != NULL; child = __xml_next(child)) {
             __xml_log_change_element(log_level, file, function, line, prefix, child, depth + 1, options);
         }
     }
 
     free(prefix_m);
 
 }
 
 void
 log_data_element(int log_level, const char *file, const char *function, int line,
                  const char *prefix, xmlNode * data, int depth, int options)
 {
     xmlNode *a_child = NULL;
 
     char *prefix_m = NULL;
 
     if (prefix == NULL) {
         prefix = "";
     }
 
     /* Since we use the same file and line, to avoid confusing libqb, we need to use the same format strings */
     if (data == NULL) {
         do_crm_log_alias(log_level, file, function, line, "%s: %s", prefix,
                          "No data to dump as XML");
         return;
     }
 
     if(is_set(options, xml_log_option_dirty_add) || is_set(options, xml_log_option_dirty_add)) {
         __xml_log_change_element(log_level, file, function, line, prefix, data, depth, options);
         return;
     }
 
     if (is_set(options, xml_log_option_formatted)) {
         if (is_set(options, xml_log_option_diff_plus)
             && (data->children == NULL || crm_element_value(data, XML_DIFF_MARKER))) {
             options |= xml_log_option_diff_all;
             prefix_m = strdup(prefix);
             prefix_m[1] = '+';
             prefix = prefix_m;
 
         } else if (is_set(options, xml_log_option_diff_minus)
                    && (data->children == NULL || crm_element_value(data, XML_DIFF_MARKER))) {
             options |= xml_log_option_diff_all;
             prefix_m = strdup(prefix);
             prefix_m[1] = '-';
             prefix = prefix_m;
         }
     }
 
     if (is_set(options, xml_log_option_diff_short)
                && is_not_set(options, xml_log_option_diff_all)) {
         /* Still searching for the actual change */
         for (a_child = __xml_first_child(data); a_child != NULL; a_child = __xml_next(a_child)) {
             log_data_element(log_level, file, function, line, prefix, a_child, depth + 1, options);
         }
     } else {
         __xml_log_element(log_level, file, function, line, prefix, data, depth,
                           options|xml_log_option_open|xml_log_option_close|xml_log_option_children);
     }
     free(prefix_m);
 }
 
 static void
 dump_filtered_xml(xmlNode * data, int options, char **buffer, int *offset, int *max)
 {
     int lpc;
     xmlAttrPtr xIter = NULL;
     static int filter_len = DIMOF(filter);
 
     for (lpc = 0; options && lpc < filter_len; lpc++) {
         filter[lpc].found = FALSE;
     }
 
     for (xIter = pcmk__first_xml_attr(data); xIter != NULL; xIter = xIter->next) {
         bool skip = FALSE;
         const char *p_name = (const char *)xIter->name;
 
         for (lpc = 0; skip == FALSE && lpc < filter_len; lpc++) {
             if (filter[lpc].found == FALSE && strcmp(p_name, filter[lpc].string) == 0) {
                 filter[lpc].found = TRUE;
                 skip = TRUE;
                 break;
             }
         }
 
         if (skip == FALSE) {
             dump_xml_attr(xIter, options, buffer, offset, max);
         }
     }
 }
 
 static void
 dump_xml_element(xmlNode * data, int options, char **buffer, int *offset, int *max, int depth)
 {
     const char *name = NULL;
 
     CRM_ASSERT(max != NULL);
     CRM_ASSERT(offset != NULL);
     CRM_ASSERT(buffer != NULL);
 
     if (data == NULL) {
         crm_trace("Nothing to dump");
         return;
     }
 
     if (*buffer == NULL) {
         *offset = 0;
         *max = 0;
     }
 
     name = crm_element_name(data);
     CRM_ASSERT(name != NULL);
 
     insert_prefix(options, buffer, offset, max, depth);
     buffer_print(*buffer, *max, *offset, "<%s", name);
 
     if (options & xml_log_option_filtered) {
         dump_filtered_xml(data, options, buffer, offset, max);
 
     } else {
         xmlAttrPtr xIter = NULL;
 
         for (xIter = pcmk__first_xml_attr(data); xIter != NULL; xIter = xIter->next) {
             dump_xml_attr(xIter, options, buffer, offset, max);
         }
     }
 
     if (data->children == NULL) {
         buffer_print(*buffer, *max, *offset, "/>");
 
     } else {
         buffer_print(*buffer, *max, *offset, ">");
     }
 
     if (options & xml_log_option_formatted) {
         buffer_print(*buffer, *max, *offset, "\n");
     }
 
     if (data->children) {
         xmlNode *xChild = NULL;
         for(xChild = data->children; xChild != NULL; xChild = xChild->next) {
             crm_xml_dump(xChild, options, buffer, offset, max, depth + 1);
         }
 
         insert_prefix(options, buffer, offset, max, depth);
         buffer_print(*buffer, *max, *offset, "</%s>", name);
 
         if (options & xml_log_option_formatted) {
             buffer_print(*buffer, *max, *offset, "\n");
         }
     }
 }
 
 static void
 dump_xml_text(xmlNode * data, int options, char **buffer, int *offset, int *max, int depth)
 {
     CRM_ASSERT(max != NULL);
     CRM_ASSERT(offset != NULL);
     CRM_ASSERT(buffer != NULL);
 
     if (data == NULL) {
         crm_trace("Nothing to dump");
         return;
     }
 
     if (*buffer == NULL) {
         *offset = 0;
         *max = 0;
     }
 
     insert_prefix(options, buffer, offset, max, depth);
 
     buffer_print(*buffer, *max, *offset, "%s", data->content);
 
     if (options & xml_log_option_formatted) {
         buffer_print(*buffer, *max, *offset, "\n");
     }
 }
 
 static void
 dump_xml_cdata(xmlNode * data, int options, char **buffer, int *offset, int *max, int depth)
 {
     CRM_ASSERT(max != NULL);
     CRM_ASSERT(offset != NULL);
     CRM_ASSERT(buffer != NULL);
 
     if (data == NULL) {
         crm_trace("Nothing to dump");
         return;
     }
 
     if (*buffer == NULL) {
         *offset = 0;
         *max = 0;
     }
 
     insert_prefix(options, buffer, offset, max, depth);
 
     buffer_print(*buffer, *max, *offset, "<![CDATA[");
     buffer_print(*buffer, *max, *offset, "%s", data->content);
     buffer_print(*buffer, *max, *offset, "]]>");
 
     if (options & xml_log_option_formatted) {
         buffer_print(*buffer, *max, *offset, "\n");
     }
 }
 
 
 static void
 dump_xml_comment(xmlNode * data, int options, char **buffer, int *offset, int *max, int depth)
 {
     CRM_ASSERT(max != NULL);
     CRM_ASSERT(offset != NULL);
     CRM_ASSERT(buffer != NULL);
 
     if (data == NULL) {
         crm_trace("Nothing to dump");
         return;
     }
 
     if (*buffer == NULL) {
         *offset = 0;
         *max = 0;
     }
 
     insert_prefix(options, buffer, offset, max, depth);
 
     buffer_print(*buffer, *max, *offset, "<!--");
     buffer_print(*buffer, *max, *offset, "%s", data->content);
     buffer_print(*buffer, *max, *offset, "-->");
 
     if (options & xml_log_option_formatted) {
         buffer_print(*buffer, *max, *offset, "\n");
     }
 }
 
 void
 crm_xml_dump(xmlNode * data, int options, char **buffer, int *offset, int *max, int depth)
 {
     if(data == NULL) {
         *offset = 0;
         *max = 0;
         return;
     }
 #if 0
     if (is_not_set(options, xml_log_option_filtered)) {
         /* Turning this code on also changes the scheduler tests for some reason
          * (not just newlines).  Figure out why before considering to
          * enable this permanently.
          *
          * It exists to help debug slowness in xmlNodeDump() and
          * potentially if we ever want to go back to it.
          *
          * In theory it's a good idea (reuse) but our custom version does
          * better for the filtered case and avoids the final strdup() for
          * everything
          */
 
         time_t now, next;
         xmlDoc *doc = NULL;
         xmlBuffer *xml_buffer = NULL;
 
         *buffer = NULL;
         doc = getDocPtr(data);
         /* doc will only be NULL if data is */
         CRM_CHECK(doc != NULL, return);
 
         now = time(NULL);
         xml_buffer = xmlBufferCreate();
         CRM_ASSERT(xml_buffer != NULL);
 
         /* The default allocator XML_BUFFER_ALLOC_EXACT does far too many
          * realloc()s and it can take upwards of 18 seconds (yes, seconds)
          * to dump a 28kb tree which XML_BUFFER_ALLOC_DOUBLEIT can do in
          * less than 1 second.
          *
          * We could also use xmlBufferCreateSize() to start with a
          * sane-ish initial size and avoid the first few doubles.
          */
         xmlBufferSetAllocationScheme(xml_buffer, XML_BUFFER_ALLOC_DOUBLEIT);
 
         *max = xmlNodeDump(xml_buffer, doc, data, 0, (options & xml_log_option_formatted));
         if (*max > 0) {
             *buffer = strdup((char *)xml_buffer->content);
         }
 
         next = time(NULL);
         if ((now + 1) < next) {
             crm_log_xml_trace(data, "Long time");
             crm_err("xmlNodeDump() -> %dbytes took %ds", *max, next - now);
         }
 
         xmlBufferFree(xml_buffer);
         return;
     }
 #endif
 
     switch(data->type) {
         case XML_ELEMENT_NODE:
             /* Handle below */
             dump_xml_element(data, options, buffer, offset, max, depth);
             break;
         case XML_TEXT_NODE:
             /* if option xml_log_option_text is enabled, then dump XML_TEXT_NODE */
             if (options & xml_log_option_text) {
                 dump_xml_text(data, options, buffer, offset, max, depth);
             }
             return;
         case XML_COMMENT_NODE:
             dump_xml_comment(data, options, buffer, offset, max, depth);
             break;
         case XML_CDATA_SECTION_NODE:
             dump_xml_cdata(data, options, buffer, offset, max, depth);
             break;
         default:
             crm_warn("Unhandled type: %d", data->type);
             return;
 
             /*
             XML_ATTRIBUTE_NODE = 2
             XML_ENTITY_REF_NODE = 5
             XML_ENTITY_NODE = 6
             XML_PI_NODE = 7
             XML_DOCUMENT_NODE = 9
             XML_DOCUMENT_TYPE_NODE = 10
             XML_DOCUMENT_FRAG_NODE = 11
             XML_NOTATION_NODE = 12
             XML_HTML_DOCUMENT_NODE = 13
             XML_DTD_NODE = 14
             XML_ELEMENT_DECL = 15
             XML_ATTRIBUTE_DECL = 16
             XML_ENTITY_DECL = 17
             XML_NAMESPACE_DECL = 18
             XML_XINCLUDE_START = 19
             XML_XINCLUDE_END = 20
             XML_DOCB_DOCUMENT_NODE = 21
             */
     }
 
 }
 
 void
 crm_buffer_add_char(char **buffer, int *offset, int *max, char c)
 {
     buffer_print(*buffer, *max, *offset, "%c", c);
 }
 
 char *
 dump_xml_formatted_with_text(xmlNode * an_xml_node)
 {
     char *buffer = NULL;
     int offset = 0, max = 0;
 
     crm_xml_dump(an_xml_node, xml_log_option_formatted|xml_log_option_text, &buffer, &offset, &max, 0);
     return buffer;
 }
 
 char *
 dump_xml_formatted(xmlNode * an_xml_node)
 {
     char *buffer = NULL;
     int offset = 0, max = 0;
 
     crm_xml_dump(an_xml_node, xml_log_option_formatted, &buffer, &offset, &max, 0);
     return buffer;
 }
 
 char *
 dump_xml_unformatted(xmlNode * an_xml_node)
 {
     char *buffer = NULL;
     int offset = 0, max = 0;
 
     crm_xml_dump(an_xml_node, 0, &buffer, &offset, &max, 0);
     return buffer;
 }
 
 gboolean
 xml_has_children(const xmlNode * xml_root)
 {
     if (xml_root != NULL && xml_root->children != NULL) {
         return TRUE;
     }
     return FALSE;
 }
 
 void
 xml_remove_prop(xmlNode * obj, const char *name)
 {
     if (pcmk__check_acl(obj, NULL, xpf_acl_write) == FALSE) {
         crm_trace("Cannot remove %s from %s", name, obj->name);
 
     } else if (pcmk__tracking_xml_changes(obj, FALSE)) {
         /* Leave in place (marked for removal) until after the diff is calculated */
         xml_private_t *p = NULL;
         xmlAttr *attr = xmlHasProp(obj, (pcmkXmlStr) name);
 
         p = attr->_private;
         set_parent_flag(obj, xpf_dirty);
         p->flags |= xpf_deleted;
         /* crm_trace("Setting flag %x due to %s[@id=%s].%s", xpf_dirty, obj->name, ID(obj), name); */
 
     } else {
         xmlUnsetProp(obj, (pcmkXmlStr) name);
     }
 }
 
 void
 purge_diff_markers(xmlNode * a_node)
 {
     xmlNode *child = NULL;
 
     CRM_CHECK(a_node != NULL, return);
 
     xml_remove_prop(a_node, XML_DIFF_MARKER);
     for (child = __xml_first_child(a_node); child != NULL; child = __xml_next(child)) {
         purge_diff_markers(child);
     }
 }
 
 void
 save_xml_to_file(xmlNode * xml, const char *desc, const char *filename)
 {
     char *f = NULL;
 
     if (filename == NULL) {
         char *uuid = crm_generate_uuid();
 
         f = crm_strdup_printf("%s/%s", crm_get_tmpdir(), uuid);
         filename = f;
         free(uuid);
     }
 
     crm_info("Saving %s to %s", desc, filename);
     write_xml_file(xml, filename, FALSE);
     free(f);
 }
 
 gboolean
 apply_xml_diff(xmlNode *old_xml, xmlNode * diff, xmlNode **new_xml)
 {
     gboolean result = TRUE;
     int root_nodes_seen = 0;
     static struct qb_log_callsite *digest_cs = NULL;
     const char *digest = crm_element_value(diff, XML_ATTR_DIGEST);
     const char *version = crm_element_value(diff, XML_ATTR_CRM_VERSION);
 
     xmlNode *child_diff = NULL;
     xmlNode *added = find_xml_node(diff, "diff-added", FALSE);
     xmlNode *removed = find_xml_node(diff, "diff-removed", FALSE);
 
     CRM_CHECK(new_xml != NULL, return FALSE);
     if (digest_cs == NULL) {
         digest_cs =
             qb_log_callsite_get(__func__, __FILE__, "diff-digest", LOG_TRACE, __LINE__,
                                 crm_trace_nonlog);
     }
 
     crm_trace("Subtraction Phase");
     for (child_diff = __xml_first_child(removed); child_diff != NULL;
          child_diff = __xml_next(child_diff)) {
         CRM_CHECK(root_nodes_seen == 0, result = FALSE);
         if (root_nodes_seen == 0) {
             *new_xml = subtract_xml_object(NULL, old_xml, child_diff, FALSE, NULL, NULL);
         }
         root_nodes_seen++;
     }
 
     if (root_nodes_seen == 0) {
         *new_xml = copy_xml(old_xml);
 
     } else if (root_nodes_seen > 1) {
         crm_err("(-) Diffs cannot contain more than one change set..." " saw %d", root_nodes_seen);
         result = FALSE;
     }
 
     root_nodes_seen = 0;
     crm_trace("Addition Phase");
     if (result) {
         xmlNode *child_diff = NULL;
 
         for (child_diff = __xml_first_child(added); child_diff != NULL;
              child_diff = __xml_next(child_diff)) {
             CRM_CHECK(root_nodes_seen == 0, result = FALSE);
             if (root_nodes_seen == 0) {
                 add_xml_object(NULL, *new_xml, child_diff, TRUE);
             }
             root_nodes_seen++;
         }
     }
 
     if (root_nodes_seen > 1) {
         crm_err("(+) Diffs cannot contain more than one change set..." " saw %d", root_nodes_seen);
         result = FALSE;
 
     } else if (result && digest) {
         char *new_digest = NULL;
 
         purge_diff_markers(*new_xml);       /* Purge now so the diff is ok */
         new_digest = calculate_xml_versioned_digest(*new_xml, FALSE, TRUE, version);
         if (safe_str_neq(new_digest, digest)) {
             crm_info("Digest mis-match: expected %s, calculated %s", digest, new_digest);
             result = FALSE;
 
             crm_trace("%p %.6x", digest_cs, digest_cs ? digest_cs->targets : 0);
             if (digest_cs && digest_cs->targets) {
                 save_xml_to_file(old_xml, "diff:original", NULL);
                 save_xml_to_file(diff, "diff:input", NULL);
                 save_xml_to_file(*new_xml, "diff:new", NULL);
             }
 
         } else {
             crm_trace("Digest matched: expected %s, calculated %s", digest, new_digest);
         }
         free(new_digest);
 
     } else if (result) {
         purge_diff_markers(*new_xml);       /* Purge now so the diff is ok */
     }
 
     return result;
 }
 
 static void
 __xml_diff_object(xmlNode *old_xml, xmlNode *new_xml, bool check_top)
 {
     xmlNode *cIter = NULL;
     xmlAttr *pIter = NULL;
 
     CRM_CHECK(new_xml != NULL, return);
     if (old_xml == NULL) {
         crm_node_created(new_xml);
-        pcmk__post_process_acl(new_xml, check_top); // Check creation is allowed
+        pcmk__apply_creation_acl(new_xml, check_top);
         return;
 
     } else {
         xml_private_t *p = new_xml->_private;
 
         if(p->flags & xpf_processed) {
             /* Avoid re-comparing nodes */
             return;
         }
         p->flags |= xpf_processed;
     }
 
     for (pIter = pcmk__first_xml_attr(new_xml); pIter != NULL; pIter = pIter->next) {
         xml_private_t *p = pIter->_private;
 
         /* Assume everything was just created and take it from there */
         p->flags |= xpf_created;
     }
 
     for (pIter = pcmk__first_xml_attr(old_xml); pIter != NULL; ) {
         xmlAttr *prop = pIter;
         xml_private_t *p = NULL;
         const char *name = (const char *)pIter->name;
         const char *old_value = crm_element_value(old_xml, name);
         xmlAttr *exists = xmlHasProp(new_xml, pIter->name);
 
         pIter = pIter->next;
         if(exists == NULL) {
             p = new_xml->doc->_private;
 
             /* Prevent the dirty flag being set recursively upwards */
             clear_bit(p->flags, xpf_tracking);
             exists = xmlSetProp(new_xml, (pcmkXmlStr) name,
                                 (pcmkXmlStr) old_value);
             set_bit(p->flags, xpf_tracking);
 
             p = exists->_private;
             p->flags = 0;
 
             crm_trace("Lost %s@%s=%s", old_xml->name, name, old_value);
             xml_remove_prop(new_xml, name);
 
         } else {
             int p_new = __xml_offset((xmlNode*)exists);
             int p_old = __xml_offset((xmlNode*)prop);
             const char *value = crm_element_value(new_xml, name);
 
             p = exists->_private;
             p->flags = (p->flags & ~xpf_created);
 
             if(strcmp(value, old_value) != 0) {
                 /* Restore the original value, so we can call crm_xml_add(),
                  * which checks ACLs
                  */
                 char *vcopy = crm_element_value_copy(new_xml, name);
 
                 crm_trace("Modified %s@%s %s->%s",
                           old_xml->name, name, old_value, vcopy);
                 xmlSetProp(new_xml, prop->name, (pcmkXmlStr) old_value);
                 crm_xml_add(new_xml, name, vcopy);
                 free(vcopy);
 
             } else if ((p_old != p_new)
                        && !pcmk__tracking_xml_changes(new_xml, TRUE)) {
                 crm_info("Moved %s@%s (%d -> %d)",
                          old_xml->name, name, p_old, p_new);
                 __xml_node_dirty(new_xml);
                 p->flags |= xpf_dirty|xpf_moved;
 
                 if(p_old > p_new) {
                     p = prop->_private;
                     p->flags |= xpf_skip;
 
                 } else {
                     p = exists->_private;
                     p->flags |= xpf_skip;
                 }
             }
         }
     }
 
     for (pIter = pcmk__first_xml_attr(new_xml); pIter != NULL; ) {
         xmlAttr *prop = pIter;
         xml_private_t *p = pIter->_private;
 
         pIter = pIter->next;
         if(is_set(p->flags, xpf_created)) {
             char *name = strdup((const char *)prop->name);
             char *value = crm_element_value_copy(new_xml, name);
 
             crm_trace("Created %s@%s=%s", new_xml->name, name, value);
             /* Remove plus create won't work as it will modify the relative attribute ordering */
             if (pcmk__check_acl(new_xml, name, xpf_acl_write)) {
                 pcmk__mark_xml_attr_dirty(prop);
             } else {
                 xmlUnsetProp(new_xml, prop->name); /* Remove - change not allowed */
             }
 
             free(value);
             free(name);
         }
     }
 
     for (cIter = __xml_first_child(old_xml); cIter != NULL; ) {
         xmlNode *old_child = cIter;
         xmlNode *new_child = find_element(new_xml, cIter, TRUE);
 
         cIter = __xml_next(cIter);
         if(new_child) {
             __xml_diff_object(old_child, new_child, TRUE);
 
         } else {
             /* Create then free (which will check the acls if necessary) */
             xmlNode *candidate = add_node_copy(new_xml, old_child);
             xmlNode *top = xmlDocGetRootElement(candidate->doc);
 
             __xml_node_clean(candidate);
             pcmk__apply_acl(top); /* Make sure any ACLs are applied to 'candidate' */
             /* Record the old position */
             free_xml_with_position(candidate, __xml_offset(old_child));
 
             if (find_element(new_xml, old_child, TRUE) == NULL) {
                 xml_private_t *p = old_child->_private;
 
                 p->flags |= xpf_skip;
             }
         }
     }
 
     for (cIter = __xml_first_child(new_xml); cIter != NULL; ) {
         xmlNode *new_child = cIter;
         xmlNode *old_child = find_element(old_xml, cIter, TRUE);
 
         cIter = __xml_next(cIter);
         if(old_child == NULL) {
             xml_private_t *p = new_child->_private;
             p->flags |= xpf_skip;
             __xml_diff_object(old_child, new_child, TRUE);
 
         } else {
             /* Check for movement, we already checked for differences */
             int p_new = __xml_offset(new_child);
             int p_old = __xml_offset(old_child);
 
             if(p_old != p_new) {
                 xml_private_t *p = new_child->_private;
 
                 crm_info("%s.%s moved from %d to %d",
                          new_child->name, ID(new_child), p_old, p_new);
                 __xml_node_dirty(new_xml);
                 p->flags |= xpf_moved;
 
                 if(p_old > p_new) {
                     p = old_child->_private;
                 } else {
                     p = new_child->_private;
                 }
                 p->flags |= xpf_skip;
             }
         }
     }
 }
 
 void
 xml_calculate_significant_changes(xmlNode *old_xml, xmlNode *new_xml)
 {
     pcmk__set_xml_flag(new_xml, xpf_lazy);
     xml_calculate_changes(old_xml, new_xml);
 }
 
 void
 xml_calculate_changes(xmlNode *old_xml, xmlNode *new_xml)
 {
     CRM_CHECK(safe_str_eq(crm_element_name(old_xml),
                           crm_element_name(new_xml)),
               return);
     CRM_CHECK(safe_str_eq(ID(old_xml), ID(new_xml)), return);
 
     if(xml_tracking_changes(new_xml) == FALSE) {
         xml_track_changes(new_xml, NULL, NULL, FALSE);
     }
 
     __xml_diff_object(old_xml, new_xml, FALSE);
 }
 
 xmlNode *
 diff_xml_object(xmlNode * old, xmlNode * new, gboolean suppress)
 {
     xmlNode *tmp1 = NULL;
     xmlNode *diff = create_xml_node(NULL, "diff");
     xmlNode *removed = create_xml_node(diff, "diff-removed");
     xmlNode *added = create_xml_node(diff, "diff-added");
 
     crm_xml_add(diff, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
 
     tmp1 = subtract_xml_object(removed, old, new, FALSE, NULL, "removed:top");
     if (suppress && tmp1 != NULL && can_prune_leaf(tmp1)) {
         free_xml(tmp1);
     }
 
     tmp1 = subtract_xml_object(added, new, old, TRUE, NULL, "added:top");
     if (suppress && tmp1 != NULL && can_prune_leaf(tmp1)) {
         free_xml(tmp1);
     }
 
     if (added->children == NULL && removed->children == NULL) {
         free_xml(diff);
         diff = NULL;
     }
 
     return diff;
 }
 
 gboolean
 can_prune_leaf(xmlNode * xml_node)
 {
     xmlNode *cIter = NULL;
     xmlAttrPtr pIter = NULL;
     gboolean can_prune = TRUE;
     const char *name = crm_element_name(xml_node);
 
     if (safe_str_eq(name, XML_TAG_RESOURCE_REF)
         || safe_str_eq(name, XML_CIB_TAG_OBJ_REF)
         || safe_str_eq(name, XML_ACL_TAG_ROLE_REF)
         || safe_str_eq(name, XML_ACL_TAG_ROLE_REFv1)) {
         return FALSE;
     }
 
     for (pIter = pcmk__first_xml_attr(xml_node); pIter != NULL; pIter = pIter->next) {
         const char *p_name = (const char *)pIter->name;
 
         if (strcmp(p_name, XML_ATTR_ID) == 0) {
             continue;
         }
         can_prune = FALSE;
     }
 
     cIter = __xml_first_child(xml_node);
     while (cIter) {
         xmlNode *child = cIter;
 
         cIter = __xml_next(cIter);
         if (can_prune_leaf(child)) {
             free_xml(child);
         } else {
             can_prune = FALSE;
         }
     }
     return can_prune;
 }
 
 static xmlNode *
 find_xml_comment(xmlNode * root, xmlNode * search_comment, gboolean exact)
 {
     xmlNode *a_child = NULL;
     int search_offset = __xml_offset(search_comment);
 
     CRM_CHECK(search_comment->type == XML_COMMENT_NODE, return NULL);
 
     for (a_child = __xml_first_child(root); a_child != NULL; a_child = __xml_next(a_child)) {
         if (exact) {
             int offset = __xml_offset(a_child);
             xml_private_t *p = a_child->_private;
 
             if (offset < search_offset) {
                 continue;
 
             } else if (offset > search_offset) {
                 return NULL;
             }
 
             if (is_set(p->flags, xpf_skip)) {
                 continue;
             }
         }
 
         if (a_child->type == XML_COMMENT_NODE
             && safe_str_eq((const char *)a_child->content, (const char *)search_comment->content)) {
             return a_child;
 
         } else if (exact) {
             return NULL;
         }
     }
 
     return NULL;
 }
 
 static xmlNode *
 subtract_xml_comment(xmlNode * parent, xmlNode * left, xmlNode * right,
                      gboolean * changed)
 {
     CRM_CHECK(left != NULL, return NULL);
     CRM_CHECK(left->type == XML_COMMENT_NODE, return NULL);
 
     if (right == NULL
         || safe_str_neq((const char *)left->content, (const char *)right->content)) {
         xmlNode *deleted = NULL;
 
         deleted = add_node_copy(parent, left);
         *changed = TRUE;
 
         return deleted;
     }
 
     return NULL;
 }
 
 xmlNode *
 subtract_xml_object(xmlNode * parent, xmlNode * left, xmlNode * right,
                     gboolean full, gboolean * changed, const char *marker)
 {
     gboolean dummy = FALSE;
     gboolean skip = FALSE;
     xmlNode *diff = NULL;
     xmlNode *right_child = NULL;
     xmlNode *left_child = NULL;
     xmlAttrPtr xIter = NULL;
 
     const char *id = NULL;
     const char *name = NULL;
     const char *value = NULL;
     const char *right_val = NULL;
 
     int lpc = 0;
     static int filter_len = DIMOF(filter);
 
     if (changed == NULL) {
         changed = &dummy;
     }
 
     if (left == NULL) {
         return NULL;
     }
 
     if (left->type == XML_COMMENT_NODE) {
         return subtract_xml_comment(parent, left, right, changed);
     }
 
     id = ID(left);
     if (right == NULL) {
         xmlNode *deleted = NULL;
 
         crm_trace("Processing <%s id=%s> (complete copy)", crm_element_name(left), id);
         deleted = add_node_copy(parent, left);
         crm_xml_add(deleted, XML_DIFF_MARKER, marker);
 
         *changed = TRUE;
         return deleted;
     }
 
     name = crm_element_name(left);
     CRM_CHECK(name != NULL, return NULL);
     CRM_CHECK(safe_str_eq(crm_element_name(left), crm_element_name(right)), return NULL);
 
     /* check for XML_DIFF_MARKER in a child */
     value = crm_element_value(right, XML_DIFF_MARKER);
     if (value != NULL && strcmp(value, "removed:top") == 0) {
         crm_trace("We are the root of the deletion: %s.id=%s", name, id);
         *changed = TRUE;
         return NULL;
     }
 
     /* Avoiding creating the full heirarchy would save even more work here */
     diff = create_xml_node(parent, name);
 
     /* Reset filter */
     for (lpc = 0; lpc < filter_len; lpc++) {
         filter[lpc].found = FALSE;
     }
 
     /* changes to child objects */
     for (left_child = __xml_first_child(left); left_child != NULL;
          left_child = __xml_next(left_child)) {
         gboolean child_changed = FALSE;
 
         right_child = find_element(right, left_child, FALSE);
         subtract_xml_object(diff, left_child, right_child, full, &child_changed, marker);
         if (child_changed) {
             *changed = TRUE;
         }
     }
 
     if (*changed == FALSE) {
         /* Nothing to do */
 
     } else if (full) {
         xmlAttrPtr pIter = NULL;
 
         for (pIter = pcmk__first_xml_attr(left); pIter != NULL; pIter = pIter->next) {
             const char *p_name = (const char *)pIter->name;
             const char *p_value = pcmk__xml_attr_value(pIter);
 
             xmlSetProp(diff, (pcmkXmlStr) p_name, (pcmkXmlStr) p_value);
         }
 
         /* We already have everything we need... */
         goto done;
     }
 
     /* changes to name/value pairs */
     for (xIter = pcmk__first_xml_attr(left); xIter != NULL; xIter = xIter->next) {
         const char *prop_name = (const char *)xIter->name;
         xmlAttrPtr right_attr = NULL;
         xml_private_t *p = NULL;
 
         if (strcmp(prop_name, XML_ATTR_ID) == 0) {
             /* id already obtained when present ~ this case, so just reuse */
             xmlSetProp(diff, (pcmkXmlStr) XML_ATTR_ID, (pcmkXmlStr) id);
             continue;
         }
 
         skip = FALSE;
         for (lpc = 0; skip == FALSE && lpc < filter_len; lpc++) {
             if (filter[lpc].found == FALSE && strcmp(prop_name, filter[lpc].string) == 0) {
                 filter[lpc].found = TRUE;
                 skip = TRUE;
                 break;
             }
         }
 
         if (skip) {
             continue;
         }
 
         right_attr = xmlHasProp(right, (pcmkXmlStr) prop_name);
         if (right_attr) {
             p = right_attr->_private;
         }
 
         right_val = crm_element_value(right, prop_name);
         if (right_val == NULL || (p && is_set(p->flags, xpf_deleted))) {
             /* new */
             *changed = TRUE;
             if (full) {
                 xmlAttrPtr pIter = NULL;
 
                 for (pIter = pcmk__first_xml_attr(left); pIter != NULL; pIter = pIter->next) {
                     const char *p_name = (const char *)pIter->name;
                     const char *p_value = pcmk__xml_attr_value(pIter);
 
                     xmlSetProp(diff, (pcmkXmlStr) p_name, (pcmkXmlStr) p_value);
                 }
                 break;
 
             } else {
                 const char *left_value = crm_element_value(left, prop_name);
 
                 xmlSetProp(diff, (pcmkXmlStr) prop_name, (pcmkXmlStr) value);
                 crm_xml_add(diff, prop_name, left_value);
             }
 
         } else {
             /* Only now do we need the left value */
             const char *left_value = crm_element_value(left, prop_name);
 
             if (strcmp(left_value, right_val) == 0) {
                 /* unchanged */
 
             } else {
                 *changed = TRUE;
                 if (full) {
                     xmlAttrPtr pIter = NULL;
 
                     crm_trace("Changes detected to %s in <%s id=%s>", prop_name,
                               crm_element_name(left), id);
                     for (pIter = pcmk__first_xml_attr(left); pIter != NULL; pIter = pIter->next) {
                         const char *p_name = (const char *)pIter->name;
                         const char *p_value = pcmk__xml_attr_value(pIter);
 
                         xmlSetProp(diff, (pcmkXmlStr) p_name, (pcmkXmlStr) p_value);
                     }
                     break;
 
                 } else {
                     crm_trace("Changes detected to %s (%s -> %s) in <%s id=%s>",
                               prop_name, left_value, right_val, crm_element_name(left), id);
                     crm_xml_add(diff, prop_name, left_value);
                 }
             }
         }
     }
 
     if (*changed == FALSE) {
         free_xml(diff);
         return NULL;
 
     } else if (full == FALSE && id) {
         crm_xml_add(diff, XML_ATTR_ID, id);
     }
   done:
     return diff;
 }
 
 static int
 add_xml_comment(xmlNode * parent, xmlNode * target, xmlNode * update)
 {
     CRM_CHECK(update != NULL, return 0);
     CRM_CHECK(update->type == XML_COMMENT_NODE, return 0);
 
     if (target == NULL) {
         target = find_xml_comment(parent, update, FALSE);
     }
 
     if (target == NULL) {
         add_node_copy(parent, update);
 
     /* We won't reach here currently */
     } else if (safe_str_neq((const char *)target->content, (const char *)update->content)) {
         xmlFree(target->content);
         target->content = xmlStrdup(update->content);
     }
 
     return 0;
 }
 
 static int
 add_xml_object(xmlNode * parent, xmlNode * target, xmlNode * update, gboolean as_diff)
 {
     xmlNode *a_child = NULL;
     const char *object_name = NULL,
                *object_href = NULL,
                *object_href_val = NULL;
 
 #if XML_PARSE_DEBUG
     crm_log_xml_trace("update:", update);
     crm_log_xml_trace("target:", target);
 #endif
 
     CRM_CHECK(update != NULL, return 0);
 
     if (update->type == XML_COMMENT_NODE) {
         return add_xml_comment(parent, target, update);
     }
 
     object_name = crm_element_name(update);
     object_href_val = ID(update);
     if (object_href_val != NULL) {
         object_href = XML_ATTR_ID;
     } else {
         object_href_val = crm_element_value(update, XML_ATTR_IDREF);
         object_href = (object_href_val == NULL) ? NULL : XML_ATTR_IDREF;
     }
 
     CRM_CHECK(object_name != NULL, return 0);
     CRM_CHECK(target != NULL || parent != NULL, return 0);
 
     if (target == NULL) {
         target = find_entity_by_attr_or_just_name(parent, object_name,
                                                   object_href, object_href_val);
     }
 
     if (target == NULL) {
         target = create_xml_node(parent, object_name);
         CRM_CHECK(target != NULL, return 0);
 #if XML_PARSER_DEBUG
         crm_trace("Added  <%s%s%s%s%s/>", crm_str(object_name),
                   object_href ? " " : "",
                   object_href ? object_href : "",
                   object_href ? "=" : "",
                   object_href ? object_href_val : "");
 
     } else {
         crm_trace("Found node <%s%s%s%s%s/> to update", crm_str(object_name),
                   object_href ? " " : "",
                   object_href ? object_href : "",
                   object_href ? "=" : "",
                   object_href ? object_href_val : "");
 #endif
     }
 
     CRM_CHECK(safe_str_eq(crm_element_name(target), crm_element_name(update)), return 0);
 
     if (as_diff == FALSE) {
         /* So that expand_plus_plus() gets called */
         copy_in_properties(target, update);
 
     } else {
         /* No need for expand_plus_plus(), just raw speed */
         xmlAttrPtr pIter = NULL;
 
         for (pIter = pcmk__first_xml_attr(update); pIter != NULL; pIter = pIter->next) {
             const char *p_name = (const char *)pIter->name;
             const char *p_value = pcmk__xml_attr_value(pIter);
 
             /* Remove it first so the ordering of the update is preserved */
             xmlUnsetProp(target, (pcmkXmlStr) p_name);
             xmlSetProp(target, (pcmkXmlStr) p_name, (pcmkXmlStr) p_value);
         }
     }
 
     for (a_child = __xml_first_child(update); a_child != NULL; a_child = __xml_next(a_child)) {
 #if XML_PARSER_DEBUG
         crm_trace("Updating child <%s%s%s%s%s/>", crm_str(object_name),
                   object_href ? " " : "",
                   object_href ? object_href : "",
                   object_href ? "=" : "",
                   object_href ? object_href_val : "");
 #endif
         add_xml_object(target, NULL, a_child, as_diff);
     }
 
 #if XML_PARSER_DEBUG
     crm_trace("Finished with <%s%s%s%s%s/>", crm_str(object_name),
               object_href ? " " : "",
               object_href ? object_href : "",
               object_href ? "=" : "",
               object_href ? object_href_val : "");
 #endif
     return 0;
 }
 
 gboolean
 update_xml_child(xmlNode * child, xmlNode * to_update)
 {
     gboolean can_update = TRUE;
     xmlNode *child_of_child = NULL;
 
     CRM_CHECK(child != NULL, return FALSE);
     CRM_CHECK(to_update != NULL, return FALSE);
 
     if (safe_str_neq(crm_element_name(to_update), crm_element_name(child))) {
         can_update = FALSE;
 
     } else if (safe_str_neq(ID(to_update), ID(child))) {
         can_update = FALSE;
 
     } else if (can_update) {
 #if XML_PARSER_DEBUG
         crm_log_xml_trace(child, "Update match found...");
 #endif
         add_xml_object(NULL, child, to_update, FALSE);
     }
 
     for (child_of_child = __xml_first_child(child); child_of_child != NULL;
          child_of_child = __xml_next(child_of_child)) {
         /* only update the first one */
         if (can_update) {
             break;
         }
         can_update = update_xml_child(child_of_child, to_update);
     }
 
     return can_update;
 }
 
 int
 find_xml_children(xmlNode ** children, xmlNode * root,
                   const char *tag, const char *field, const char *value, gboolean search_matches)
 {
     int match_found = 0;
 
     CRM_CHECK(root != NULL, return FALSE);
     CRM_CHECK(children != NULL, return FALSE);
 
     if (tag != NULL && safe_str_neq(tag, crm_element_name(root))) {
 
     } else if (value != NULL && safe_str_neq(value, crm_element_value(root, field))) {
 
     } else {
         if (*children == NULL) {
             *children = create_xml_node(NULL, __FUNCTION__);
         }
         add_node_copy(*children, root);
         match_found = 1;
     }
 
     if (search_matches || match_found == 0) {
         xmlNode *child = NULL;
 
         for (child = __xml_first_child(root); child != NULL; child = __xml_next(child)) {
             match_found += find_xml_children(children, child, tag, field, value, search_matches);
         }
     }
 
     return match_found;
 }
 
 gboolean
 replace_xml_child(xmlNode * parent, xmlNode * child, xmlNode * update, gboolean delete_only)
 {
     gboolean can_delete = FALSE;
     xmlNode *child_of_child = NULL;
 
     const char *up_id = NULL;
     const char *child_id = NULL;
     const char *right_val = NULL;
 
     CRM_CHECK(child != NULL, return FALSE);
     CRM_CHECK(update != NULL, return FALSE);
 
     up_id = ID(update);
     child_id = ID(child);
 
     if (up_id == NULL || (child_id && strcmp(child_id, up_id) == 0)) {
         can_delete = TRUE;
     }
     if (safe_str_neq(crm_element_name(update), crm_element_name(child))) {
         can_delete = FALSE;
     }
     if (can_delete && delete_only) {
         xmlAttrPtr pIter = NULL;
 
         for (pIter = pcmk__first_xml_attr(update); pIter != NULL; pIter = pIter->next) {
             const char *p_name = (const char *)pIter->name;
             const char *p_value = pcmk__xml_attr_value(pIter);
 
             right_val = crm_element_value(child, p_name);
             if (safe_str_neq(p_value, right_val)) {
                 can_delete = FALSE;
             }
         }
     }
 
     if (can_delete && parent != NULL) {
         crm_log_xml_trace(child, "Delete match found...");
         if (delete_only || update == NULL) {
             free_xml(child);
 
         } else {
             xmlNode *tmp = copy_xml(update);
             xmlDoc *doc = tmp->doc;
             xmlNode *old = NULL;
 
             xml_accept_changes(tmp);
             old = xmlReplaceNode(child, tmp);
 
             if(xml_tracking_changes(tmp)) {
                 /* Replaced sections may have included relevant ACLs */
                 pcmk__apply_acl(tmp);
             }
 
             xml_calculate_changes(old, tmp);
             xmlDocSetRootElement(doc, old);
             free_xml(old);
         }
         child = NULL;
         return TRUE;
 
     } else if (can_delete) {
         crm_log_xml_debug(child, "Cannot delete the search root");
         can_delete = FALSE;
     }
 
     child_of_child = __xml_first_child(child);
     while (child_of_child) {
         xmlNode *next = __xml_next(child_of_child);
 
         can_delete = replace_xml_child(child, child_of_child, update, delete_only);
 
         /* only delete the first one */
         if (can_delete) {
             child_of_child = NULL;
         } else {
             child_of_child = next;
         }
     }
 
     return can_delete;
 }
 
 xmlNode *
 sorted_xml(xmlNode *input, xmlNode *parent, gboolean recursive)
 {
     xmlNode *child = NULL;
     GSList *nvpairs = NULL;
     xmlNode *result = NULL;
     const char *name = NULL;
 
     CRM_CHECK(input != NULL, return NULL);
 
     name = crm_element_name(input);
     CRM_CHECK(name != NULL, return NULL);
 
     result = create_xml_node(parent, name);
     nvpairs = pcmk_xml_attrs2nvpairs(input);
     nvpairs = pcmk_sort_nvpairs(nvpairs);
     pcmk_nvpairs2xml_attrs(nvpairs, result);
     pcmk_free_nvpairs(nvpairs);
 
     for (child = __xml_first_child(input); child != NULL;
          child = __xml_next(child)) {
 
         if (recursive) {
             sorted_xml(child, result, recursive);
         } else {
             add_node_copy(result, child);
         }
     }
 
     return result;
 }
 
 xmlNode *
 first_named_child(const xmlNode *parent, const char *name)
 {
     xmlNode *match = NULL;
 
     for (match = __xml_first_child(parent); match != NULL; match = __xml_next(match)) {
         /*
          * name == NULL gives first child regardless of name; this is
          * semantically incorrect in this function, but may be necessary
          * due to prior use of xml_child_iter_filter
          */
         if (name == NULL || strcmp((const char *)match->name, name) == 0) {
             return match;
         }
     }
     return NULL;
 }
 
 /*!
  * \brief Get next instance of same XML tag
  *
  * \param[in] sibling  XML tag to start from
  *
  * \return Next sibling XML tag with same name
  */
 xmlNode *
 crm_next_same_xml(const xmlNode *sibling)
 {
     xmlNode *match = __xml_next(sibling);
     const char *name = crm_element_name(sibling);
 
     while (match != NULL) {
         if (!strcmp(crm_element_name(match), name)) {
             return match;
         }
         match = __xml_next(match);
     }
     return NULL;
 }
 
 void
 crm_xml_init(void)
 {
     static bool init = TRUE;
 
     if(init) {
         init = FALSE;
         /* The default allocator XML_BUFFER_ALLOC_EXACT does far too many
          * realloc_safe()s and it can take upwards of 18 seconds (yes, seconds)
          * to dump a 28kb tree which XML_BUFFER_ALLOC_DOUBLEIT can do in
          * less than 1 second.
          */
         xmlSetBufferAllocationScheme(XML_BUFFER_ALLOC_DOUBLEIT);
 
         /* Populate and free the _private field when nodes are created and destroyed */
         xmlDeregisterNodeDefault(pcmkDeregisterNode);
         xmlRegisterNodeDefault(pcmkRegisterNode);
 
         crm_schema_init();
     }
 }
 
 void
 crm_xml_cleanup(void)
 {
     crm_info("Cleaning up memory from libxml2");
     crm_schema_cleanup();
     xmlCleanupParser();
 }
 
 #define XPATH_MAX 512
 
 xmlNode *
 expand_idref(xmlNode * input, xmlNode * top)
 {
     const char *tag = NULL;
     const char *ref = NULL;
     xmlNode *result = input;
 
     if (result == NULL) {
         return NULL;
 
     } else if (top == NULL) {
         top = input;
     }
 
     tag = crm_element_name(result);
     ref = crm_element_value(result, XML_ATTR_IDREF);
 
     if (ref != NULL) {
         char *xpath_string = crm_strdup_printf("//%s[@id='%s']", tag, ref);
 
         result = get_xpath_object(xpath_string, top, LOG_ERR);
         if (result == NULL) {
             char *nodePath = (char *)xmlGetNodePath(top);
 
             crm_err("No match for %s found in %s: Invalid configuration", xpath_string,
                     crm_str(nodePath));
             free(nodePath);
         }
         free(xpath_string);
     }
     return result;
 }
 
 void
 crm_destroy_xml(gpointer data)
 {
     free_xml(data);
 }