diff --git a/daemons/controld/controld_execd_state.c b/daemons/controld/controld_execd_state.c
index c3e5200c06..7f6b8d9fa4 100644
--- a/daemons/controld/controld_execd_state.c
+++ b/daemons/controld/controld_execd_state.c
@@ -1,820 +1,825 @@
 /*
  * Copyright 2012-2024 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.
  */
 
 #include <crm_internal.h>
 
 #include <errno.h>
 
 #include <crm/crm.h>
 #include <crm/common/iso8601.h>
 #include <crm/common/xml.h>
 #include <crm/pengine/rules.h>
 #include <crm/pengine/rules_internal.h>
 #include <crm/lrmd_internal.h>
 
 #include <pacemaker-internal.h>
 #include <pacemaker-controld.h>
 
 static GHashTable *lrm_state_table = NULL;
 extern GHashTable *proxy_table;
 int lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg);
 void lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg));
 
 static void
 free_rsc_info(gpointer value)
 {
     lrmd_rsc_info_t *rsc_info = value;
 
     lrmd_free_rsc_info(rsc_info);
 }
 
 static void
 free_deletion_op(gpointer value)
 {
     struct pending_deletion_op_s *op = value;
 
     free(op->rsc);
     delete_ha_msg_input(op->input);
     free(op);
 }
 
 static void
 free_recurring_op(gpointer value)
 {
     active_op_t *op = value;
 
     free(op->user_data);
     free(op->rsc_id);
     free(op->op_type);
     free(op->op_key);
     if (op->params) {
         g_hash_table_destroy(op->params);
     }
     free(op);
 }
 
 static gboolean
 fail_pending_op(gpointer key, gpointer value, gpointer user_data)
 {
     lrmd_event_data_t event = { 0, };
     lrm_state_t *lrm_state = user_data;
     active_op_t *op = value;
 
     crm_trace("Pre-emptively failing " PCMK__OP_FMT " on %s (call=%s, %s)",
               op->rsc_id, op->op_type, op->interval_ms,
               lrm_state->node_name, (char*)key, op->user_data);
 
     event.type = lrmd_event_exec_complete;
     event.rsc_id = op->rsc_id;
     event.op_type = op->op_type;
     event.user_data = op->user_data;
     event.timeout = 0;
     event.interval_ms = op->interval_ms;
     lrmd__set_result(&event, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_NOT_CONNECTED,
                      "Action was pending when executor connection was dropped");
     event.t_run = op->start_time;
     event.t_rcchange = op->start_time;
 
     event.call_id = op->call_id;
     event.remote_nodename = lrm_state->node_name;
     event.params = op->params;
 
     process_lrm_event(lrm_state, &event, op, NULL);
     lrmd__reset_result(&event);
     return TRUE;
 }
 
 gboolean
 lrm_state_is_local(lrm_state_t *lrm_state)
 {
     return (lrm_state != NULL) && controld_is_local_node(lrm_state->node_name);
 }
 
 /*!
  * \internal
  * \brief Create executor state entry for a node and add it to the state table
  *
  * \param[in]  node_name  Node to create entry for
  *
  * \return Newly allocated executor state object initialized for \p node_name
  */
 static lrm_state_t *
 lrm_state_create(const char *node_name)
 {
     lrm_state_t *state = NULL;
 
     if (!node_name) {
         crm_err("No node name given for lrm state object");
         return NULL;
     }
 
     state = pcmk__assert_alloc(1, sizeof(lrm_state_t));
 
     state->node_name = pcmk__str_copy(node_name);
     state->rsc_info_cache = pcmk__strkey_table(NULL, free_rsc_info);
     state->deletion_ops = pcmk__strkey_table(free, free_deletion_op);
     state->active_ops = pcmk__strkey_table(free, free_recurring_op);
     state->resource_history = pcmk__strkey_table(NULL, history_free);
     state->metadata_cache = metadata_cache_new();
 
     g_hash_table_insert(lrm_state_table, (char *)state->node_name, state);
     return state;
 }
 
 static gboolean
 remote_proxy_remove_by_node(gpointer key, gpointer value, gpointer user_data)
 {
     remote_proxy_t *proxy = value;
     const char *node_name = user_data;
 
     if (pcmk__str_eq(node_name, proxy->node_name, pcmk__str_casei)) {
         return TRUE;
     }
 
     return FALSE;
 }
 
 static remote_proxy_t *
 find_connected_proxy_by_node(const char * node_name)
 {
     GHashTableIter gIter;
     remote_proxy_t *proxy = NULL;
 
     CRM_CHECK(proxy_table != NULL, return NULL);
 
     g_hash_table_iter_init(&gIter, proxy_table);
 
     while (g_hash_table_iter_next(&gIter, NULL, (gpointer *) &proxy)) {
         if (proxy->source
             && pcmk__str_eq(node_name, proxy->node_name, pcmk__str_casei)) {
             return proxy;
         }
     }
 
     return NULL;
 }
 
 static void
 remote_proxy_disconnect_by_node(const char * node_name)
 {
     remote_proxy_t *proxy = NULL;
 
     CRM_CHECK(proxy_table != NULL, return);
 
     while ((proxy = find_connected_proxy_by_node(node_name)) != NULL) {
         /* mainloop_del_ipc_client() eventually calls remote_proxy_disconnected()
          * , which removes the entry from proxy_table.
          * Do not do this in a g_hash_table_iter_next() loop. */
         if (proxy->source) {
             mainloop_del_ipc_client(proxy->source);
         }
     }
 
     return;
 }
 
 static void
 internal_lrm_state_destroy(gpointer data)
 {
     lrm_state_t *lrm_state = data;
 
     if (!lrm_state) {
         return;
     }
 
     /* Rather than directly remove the recorded proxy entries from proxy_table,
      * make sure any connected proxies get disconnected. So that
      * remote_proxy_disconnected() will be called and as well remove the
      * entries from proxy_table.
      */
     remote_proxy_disconnect_by_node(lrm_state->node_name);
 
     crm_trace("Destroying proxy table %s with %u members",
               lrm_state->node_name, g_hash_table_size(proxy_table));
     // Just in case there's still any leftovers in proxy_table
     g_hash_table_foreach_remove(proxy_table, remote_proxy_remove_by_node, (char *) lrm_state->node_name);
     remote_ra_cleanup(lrm_state);
     lrmd_api_delete(lrm_state->conn);
 
     if (lrm_state->rsc_info_cache) {
         crm_trace("Destroying rsc info cache with %u members",
                   g_hash_table_size(lrm_state->rsc_info_cache));
         g_hash_table_destroy(lrm_state->rsc_info_cache);
     }
     if (lrm_state->resource_history) {
         crm_trace("Destroying history op cache with %u members",
                   g_hash_table_size(lrm_state->resource_history));
         g_hash_table_destroy(lrm_state->resource_history);
     }
     if (lrm_state->deletion_ops) {
         crm_trace("Destroying deletion op cache with %u members",
                   g_hash_table_size(lrm_state->deletion_ops));
         g_hash_table_destroy(lrm_state->deletion_ops);
     }
     if (lrm_state->active_ops != NULL) {
         crm_trace("Destroying pending op cache with %u members",
                   g_hash_table_size(lrm_state->active_ops));
         g_hash_table_destroy(lrm_state->active_ops);
     }
     metadata_cache_free(lrm_state->metadata_cache);
 
     free((char *)lrm_state->node_name);
     free(lrm_state);
 }
 
 void
 lrm_state_reset_tables(lrm_state_t * lrm_state, gboolean reset_metadata)
 {
     if (lrm_state->resource_history) {
         crm_trace("Resetting resource history cache with %u members",
                   g_hash_table_size(lrm_state->resource_history));
         g_hash_table_remove_all(lrm_state->resource_history);
     }
     if (lrm_state->deletion_ops) {
         crm_trace("Resetting deletion operations cache with %u members",
                   g_hash_table_size(lrm_state->deletion_ops));
         g_hash_table_remove_all(lrm_state->deletion_ops);
     }
     if (lrm_state->active_ops != NULL) {
         crm_trace("Resetting active operations cache with %u members",
                   g_hash_table_size(lrm_state->active_ops));
         g_hash_table_remove_all(lrm_state->active_ops);
     }
     if (lrm_state->rsc_info_cache) {
         crm_trace("Resetting resource information cache with %u members",
                   g_hash_table_size(lrm_state->rsc_info_cache));
         g_hash_table_remove_all(lrm_state->rsc_info_cache);
     }
     if (reset_metadata) {
         metadata_cache_reset(lrm_state->metadata_cache);
     }
 }
 
 gboolean
 lrm_state_init_local(void)
 {
     if (lrm_state_table) {
         return TRUE;
     }
 
     lrm_state_table = pcmk__strikey_table(NULL, internal_lrm_state_destroy);
     if (!lrm_state_table) {
         return FALSE;
     }
 
     proxy_table = pcmk__strikey_table(NULL, remote_proxy_free);
     if (!proxy_table) {
         g_hash_table_destroy(lrm_state_table);
         lrm_state_table = NULL;
         return FALSE;
     }
 
     return TRUE;
 }
 
 void
 lrm_state_destroy_all(void)
 {
     if (lrm_state_table) {
         crm_trace("Destroying state table with %u members",
                   g_hash_table_size(lrm_state_table));
         g_hash_table_destroy(lrm_state_table); lrm_state_table = NULL;
     }
     if(proxy_table) {
         crm_trace("Destroying proxy table with %u members",
                   g_hash_table_size(proxy_table));
         g_hash_table_destroy(proxy_table); proxy_table = NULL;
     }
 }
 
 /*!
  * \internal
  * \brief Get executor state object
  *
  * \param[in] node_name  Get executor state for this node (local node if NULL)
  * \param[in] create     If true, create executor state if it doesn't exist
  *
  * \return Executor state object for \p node_name
  */
 lrm_state_t *
 controld_get_executor_state(const char *node_name, bool create)
 {
     lrm_state_t *state = NULL;
 
     if ((node_name == NULL) && (controld_globals.cluster != NULL)) {
         node_name = controld_globals.cluster->priv->node_name;
     }
     if ((node_name == NULL) || (lrm_state_table == NULL)) {
         return NULL;
     }
 
     state = g_hash_table_lookup(lrm_state_table, node_name);
     if ((state == NULL) && create) {
         state = lrm_state_create(node_name);
     }
     return state;
 }
 
 GList *
 lrm_state_get_list(void)
 {
     if (lrm_state_table == NULL) {
         return NULL;
     }
     return g_hash_table_get_values(lrm_state_table);
 }
 
 void
 lrm_state_disconnect_only(lrm_state_t * lrm_state)
 {
     int removed = 0;
 
     if (!lrm_state->conn) {
         return;
     }
     crm_trace("Disconnecting %s", lrm_state->node_name);
 
     remote_proxy_disconnect_by_node(lrm_state->node_name);
 
     ((lrmd_t *) lrm_state->conn)->cmds->disconnect(lrm_state->conn);
 
     if (!pcmk_is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
         removed = g_hash_table_foreach_remove(lrm_state->active_ops,
                                               fail_pending_op, lrm_state);
         crm_trace("Synthesized %d operation failures for %s", removed, lrm_state->node_name);
     }
 }
 
 void
 lrm_state_disconnect(lrm_state_t * lrm_state)
 {
     if (!lrm_state->conn) {
         return;
     }
 
     lrm_state_disconnect_only(lrm_state);
 
     lrmd_api_delete(lrm_state->conn);
     lrm_state->conn = NULL;
 }
 
 int
 lrm_state_is_connected(lrm_state_t * lrm_state)
 {
     if (!lrm_state->conn) {
         return FALSE;
     }
     return ((lrmd_t *) lrm_state->conn)->cmds->is_connected(lrm_state->conn);
 }
 
 int
 lrm_state_poke_connection(lrm_state_t * lrm_state)
 {
 
     if (!lrm_state->conn) {
         return -ENOTCONN;
     }
     return ((lrmd_t *) lrm_state->conn)->cmds->poke_connection(lrm_state->conn);
 }
 
 // \return Standard Pacemaker return code
 int
 controld_connect_local_executor(lrm_state_t *lrm_state)
 {
     int rc = pcmk_rc_ok;
 
     if (lrm_state->conn == NULL) {
         lrmd_t *api = NULL;
 
         rc = lrmd__new(&api, NULL, NULL, 0);
         if (rc != pcmk_rc_ok) {
             return rc;
         }
         api->cmds->set_callback(api, lrm_op_callback);
         lrm_state->conn = api;
     }
 
     rc = ((lrmd_t *) lrm_state->conn)->cmds->connect(lrm_state->conn,
                                                      CRM_SYSTEM_CRMD, NULL);
     rc = pcmk_legacy2rc(rc);
 
     if (rc == pcmk_rc_ok) {
         lrm_state->num_lrm_register_fails = 0;
     } else {
         lrm_state->num_lrm_register_fails++;
     }
     return rc;
 }
 
 static remote_proxy_t *
 crmd_remote_proxy_new(lrmd_t *lrmd, const char *node_name, const char *session_id, const char *channel)
 {
     struct ipc_client_callbacks proxy_callbacks = {
         .dispatch = remote_proxy_dispatch,
         .destroy = remote_proxy_disconnected
     };
     remote_proxy_t *proxy = remote_proxy_new(lrmd, &proxy_callbacks, node_name,
                                              session_id, channel);
     return proxy;
 }
 
 gboolean
 crmd_is_proxy_session(const char *session)
 {
     return g_hash_table_lookup(proxy_table, session) ? TRUE : FALSE;
 }
 
 void
 crmd_proxy_send(const char *session, xmlNode *msg)
 {
     remote_proxy_t *proxy = g_hash_table_lookup(proxy_table, session);
     lrm_state_t *lrm_state = NULL;
 
     if (!proxy) {
         return;
     }
     crm_log_xml_trace(msg, "to-proxy");
     lrm_state = controld_get_executor_state(proxy->node_name, false);
     if (lrm_state) {
         crm_trace("Sending event to %.8s on %s", proxy->session_id, proxy->node_name);
         remote_proxy_relay_event(proxy, msg);
     }
 }
 
 static void
 crmd_proxy_dispatch(const char *session, xmlNode *msg)
 {
     crm_trace("Processing proxied IPC message from session %s", session);
     crm_log_xml_trace(msg, "controller[inbound]");
     crm_xml_add(msg, PCMK__XA_CRM_SYS_FROM, session);
     if (controld_authorize_ipc_message(msg, NULL, session)) {
         route_message(C_IPC_MESSAGE, msg);
     }
     controld_trigger_fsa();
 }
 
 static void
 remote_config_check(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
 {
     if (rc != pcmk_ok) {
         crm_err("Query resulted in an error: %s", pcmk_strerror(rc));
 
         if (rc == -EACCES || rc == -pcmk_err_schema_validation) {
             crm_err("The cluster is mis-configured - shutting down and staying down");
         }
 
     } else {
         lrmd_t * lrmd = (lrmd_t *)user_data;
         crm_time_t *now = crm_time_new(NULL);
         GHashTable *config_hash = pcmk__strkey_table(free, free);
 
         crm_debug("Call %d : Parsing CIB options", call_id);
 
         pe_unpack_nvpairs(output, output, PCMK_XE_CLUSTER_PROPERTY_SET, NULL,
                           config_hash, PCMK_VALUE_CIB_BOOTSTRAP_OPTIONS, FALSE,
                           now, NULL);
 
         /* Now send it to the remote peer */
         lrmd__validate_remote_settings(lrmd, config_hash);
 
         g_hash_table_destroy(config_hash);
         crm_time_free(now);
     }
 }
 
 static void
 crmd_remote_proxy_cb(lrmd_t *lrmd, void *userdata, xmlNode *msg)
 {
     lrm_state_t *lrm_state = userdata;
     const char *session = crm_element_value(msg, PCMK__XA_LRMD_IPC_SESSION);
     remote_proxy_t *proxy = g_hash_table_lookup(proxy_table, session);
 
     const char *op = crm_element_value(msg, PCMK__XA_LRMD_IPC_OP);
     if (pcmk__str_eq(op, LRMD_IPC_OP_NEW, pcmk__str_casei)) {
         const char *channel = crm_element_value(msg, PCMK__XA_LRMD_IPC_SERVER);
 
         proxy = crmd_remote_proxy_new(lrmd, lrm_state->node_name, session, channel);
         if (!remote_ra_controlling_guest(lrm_state)) {
             if (proxy != NULL) {
                 cib_t *cib_conn = controld_globals.cib_conn;
 
                 /* Look up PCMK_OPT_STONITH_WATCHDOG_TIMEOUT and send to the
                  * remote peer for validation
                  */
                 int rc = cib_conn->cmds->query(cib_conn, PCMK_XE_CRM_CONFIG,
                                                NULL, cib_none);
                 cib_conn->cmds->register_callback_full(cib_conn, rc, 10, FALSE,
                                                        lrmd,
                                                        "remote_config_check",
                                                        remote_config_check,
                                                        NULL);
             }
         } else {
             crm_debug("Skipping remote_config_check for guest-nodes");
         }
 
     } else if (pcmk__str_eq(op, LRMD_IPC_OP_SHUTDOWN_REQ, pcmk__str_casei)) {
         char *now_s = NULL;
 
         crm_notice("%s requested shutdown of its remote connection",
                    lrm_state->node_name);
 
         if (!remote_ra_is_in_maintenance(lrm_state)) {
             now_s = pcmk__ttoa(time(NULL));
             update_attrd(lrm_state->node_name, PCMK__NODE_ATTR_SHUTDOWN, now_s,
                          NULL, TRUE);
             free(now_s);
 
             remote_proxy_ack_shutdown(lrmd);
 
             crm_warn("Reconnection attempts to %s may result in failures that must be cleared",
                     lrm_state->node_name);
         } else {
             remote_proxy_nack_shutdown(lrmd);
 
             crm_notice("Remote resource for %s is not managed so no ordered shutdown happening",
                     lrm_state->node_name);
         }
         return;
 
     } else if (pcmk__str_eq(op, LRMD_IPC_OP_REQUEST, pcmk__str_casei) && proxy && proxy->is_local) {
         /* This is for the controller, which we are, so don't try
          * to send to ourselves over IPC -- do it directly.
          */
-        int flags = 0;
+        uint32_t flags = 0U;
+        int rc = pcmk_rc_ok;
         xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_LRMD_IPC_MSG,
                                                 NULL, NULL);
         xmlNode *request = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
 
         CRM_CHECK(request != NULL, return);
         CRM_CHECK(lrm_state->node_name, return);
         crm_xml_add(request, PCMK_XE_ACL_ROLE, "pacemaker-remote");
         pcmk__update_acl_user(request, PCMK__XA_LRMD_IPC_USER,
                               lrm_state->node_name);
 
         /* Pacemaker Remote nodes don't know their own names (as known to the
          * cluster). When getting a node info request with no name or ID, add
          * the name, so we don't return info for ourselves instead of the
          * Pacemaker Remote node.
          */
         if (pcmk__str_eq(crm_element_value(request, PCMK__XA_CRM_TASK),
                          CRM_OP_NODE_INFO, pcmk__str_none)) {
             int node_id = 0;
 
             crm_element_value_int(request, PCMK_XA_ID, &node_id);
             if ((node_id <= 0)
                 && (crm_element_value(request, PCMK_XA_UNAME) == NULL)) {
                 crm_xml_add(request, PCMK_XA_UNAME, lrm_state->node_name);
             }
         }
 
         crmd_proxy_dispatch(session, request);
 
-        crm_element_value_int(msg, PCMK__XA_LRMD_IPC_MSG_FLAGS, &flags);
-        if (flags & crm_ipc_client_response) {
+        rc = pcmk__xe_get_flags(msg, PCMK__XA_LRMD_IPC_MSG_FLAGS, &flags, 0U);
+        if (rc != pcmk_rc_ok) {
+            crm_warn("Couldn't parse controller flags from remote request: %s",
+                     pcmk_rc_str(rc));
+        }
+        if (pcmk_is_set(flags, crm_ipc_client_response)) {
             int msg_id = 0;
             xmlNode *op_reply = pcmk__xe_create(NULL, PCMK__XE_ACK);
 
             crm_xml_add(op_reply, PCMK_XA_FUNCTION, __func__);
             crm_xml_add_int(op_reply, PCMK__XA_LINE, __LINE__);
 
             crm_element_value_int(msg, PCMK__XA_LRMD_IPC_MSG_ID, &msg_id);
             remote_proxy_relay_response(proxy, op_reply, msg_id);
 
             pcmk__xml_free(op_reply);
         }
 
     } else {
         remote_proxy_cb(lrmd, lrm_state->node_name, msg);
     }
 }
 
 
 // \return Standard Pacemaker return code
 int
 controld_connect_remote_executor(lrm_state_t *lrm_state, const char *server,
                                  int port, int timeout_ms)
 {
     int rc = pcmk_rc_ok;
 
     if (lrm_state->conn == NULL) {
         lrmd_t *api = NULL;
 
         rc = lrmd__new(&api, lrm_state->node_name, server, port);
         if (rc != pcmk_rc_ok) {
             crm_warn("Pacemaker Remote connection to %s:%s failed: %s "
                      QB_XS " rc=%d", server, port, pcmk_rc_str(rc), rc);
 
             return rc;
         }
         lrm_state->conn = api;
         api->cmds->set_callback(api, remote_lrm_op_callback);
         lrmd_internal_set_proxy_callback(api, lrm_state, crmd_remote_proxy_cb);
     }
 
     crm_trace("Initiating remote connection to %s:%d with timeout %dms",
               server, port, timeout_ms);
     rc = ((lrmd_t *) lrm_state->conn)->cmds->connect_async(lrm_state->conn,
                                                            lrm_state->node_name,
                                                            timeout_ms);
     if (rc == pcmk_ok) {
         lrm_state->num_lrm_register_fails = 0;
     } else {
         lrm_state->num_lrm_register_fails++; // Ignored for remote connections
     }
     return pcmk_legacy2rc(rc);
 }
 
 int
 lrm_state_get_metadata(lrm_state_t * lrm_state,
                        const char *class,
                        const char *provider,
                        const char *agent, char **output, enum lrmd_call_options options)
 {
     lrmd_key_value_t *params = NULL;
 
     if (!lrm_state->conn) {
         return -ENOTCONN;
     }
 
     /* Add the node name to the environment, as is done with normal resource
      * action calls. Meta-data calls shouldn't need it, but some agents are
      * written with an ocf_local_nodename call at the beginning regardless of
      * action. Without the environment variable, the agent would try to contact
      * the controller to get the node name -- but the controller would be
      * blocking on the synchronous meta-data call.
      *
      * At this point, we have to assume that agents are unlikely to make other
      * calls that require the controller, such as crm_node --quorum or
      * --cluster-id.
      *
      * @TODO Make meta-data calls asynchronous. (This will be part of a larger
      * project to make meta-data calls via the executor rather than directly.)
      */
     params = lrmd_key_value_add(params, CRM_META "_" PCMK__META_ON_NODE,
                                 lrm_state->node_name);
 
     return ((lrmd_t *) lrm_state->conn)->cmds->get_metadata_params(lrm_state->conn,
             class, provider, agent, output, options, params);
 }
 
 int
 lrm_state_cancel(lrm_state_t *lrm_state, const char *rsc_id, const char *action,
                  guint interval_ms)
 {
     if (!lrm_state->conn) {
         return -ENOTCONN;
     }
 
     /* Figure out a way to make this async?
      * NOTICE: Currently it's synced and directly acknowledged in do_lrm_invoke(). */
     if (is_remote_lrmd_ra(NULL, NULL, rsc_id)) {
         return remote_ra_cancel(lrm_state, rsc_id, action, interval_ms);
     }
     return ((lrmd_t *) lrm_state->conn)->cmds->cancel(lrm_state->conn, rsc_id,
                                                       action, interval_ms);
 }
 
 lrmd_rsc_info_t *
 lrm_state_get_rsc_info(lrm_state_t * lrm_state, const char *rsc_id, enum lrmd_call_options options)
 {
     lrmd_rsc_info_t *rsc = NULL;
 
     if (!lrm_state->conn) {
         return NULL;
     }
     if (is_remote_lrmd_ra(NULL, NULL, rsc_id)) {
         return remote_ra_get_rsc_info(lrm_state, rsc_id);
     }
 
     rsc = g_hash_table_lookup(lrm_state->rsc_info_cache, rsc_id);
     if (rsc == NULL) {
         /* only contact the lrmd if we don't already have a cached rsc info */
         rsc = ((lrmd_t *) lrm_state->conn)->cmds->get_rsc_info(lrm_state->conn, rsc_id, options);
         if (rsc == NULL) {
 		    return NULL;
         }
         /* cache the result */
         g_hash_table_insert(lrm_state->rsc_info_cache, rsc->id, rsc);
     }
 
     return lrmd_copy_rsc_info(rsc);
 
 }
 
 /*!
  * \internal
  * \brief Initiate a resource agent action
  *
  * \param[in,out] lrm_state       Executor state object
  * \param[in]     rsc_id          ID of resource for action
  * \param[in]     action          Action to execute
  * \param[in]     userdata        String to copy and pass to execution callback
  * \param[in]     interval_ms     Action interval (in milliseconds)
  * \param[in]     timeout_ms      Action timeout (in milliseconds)
  * \param[in]     start_delay_ms  Delay (in ms) before initiating action
  * \param[in]     parameters      Hash table of resource parameters
  * \param[out]    call_id         Where to store call ID on success
  *
  * \return Standard Pacemaker return code
  */
 int
 controld_execute_resource_agent(lrm_state_t *lrm_state, const char *rsc_id,
                                 const char *action, const char *userdata,
                                 guint interval_ms, int timeout_ms,
                                 int start_delay_ms, GHashTable *parameters,
                                 int *call_id)
 {
     int rc = pcmk_rc_ok;
     lrmd_key_value_t *params = NULL;
 
     if (lrm_state->conn == NULL) {
         return ENOTCONN;
     }
 
     // Convert parameters from hash table to list
     if (parameters != NULL) {
         const char *key = NULL;
         const char *value = NULL;
         GHashTableIter iter;
 
         g_hash_table_iter_init(&iter, parameters);
         while (g_hash_table_iter_next(&iter, (gpointer *) &key,
                                       (gpointer *) &value)) {
             params = lrmd_key_value_add(params, key, value);
         }
     }
 
     if (is_remote_lrmd_ra(NULL, NULL, rsc_id)) {
         rc = controld_execute_remote_agent(lrm_state, rsc_id, action,
                                            userdata, interval_ms, timeout_ms,
                                            start_delay_ms, params, call_id);
 
     } else {
         rc = ((lrmd_t *) lrm_state->conn)->cmds->exec(lrm_state->conn, rsc_id,
                                                       action, userdata,
                                                       interval_ms, timeout_ms,
                                                       start_delay_ms,
                                                       lrmd_opt_notify_changes_only,
                                                       params);
         if (rc < 0) {
             rc = pcmk_legacy2rc(rc);
         } else {
             *call_id = rc;
             rc = pcmk_rc_ok;
         }
     }
     return rc;
 }
 
 int
 lrm_state_register_rsc(lrm_state_t * lrm_state,
                        const char *rsc_id,
                        const char *class,
                        const char *provider, const char *agent, enum lrmd_call_options options)
 {
     lrmd_t *conn = (lrmd_t *) lrm_state->conn;
 
     if (conn == NULL) {
         return -ENOTCONN;
     }
 
     if (is_remote_lrmd_ra(agent, provider, NULL)) {
         return controld_get_executor_state(rsc_id, true)? pcmk_ok : -EINVAL;
     }
 
     /* @TODO Implement an asynchronous version of this (currently a blocking
      * call to the lrmd).
      */
     return conn->cmds->register_rsc(lrm_state->conn, rsc_id, class, provider,
                                     agent, options);
 }
 
 int
 lrm_state_unregister_rsc(lrm_state_t * lrm_state,
                          const char *rsc_id, enum lrmd_call_options options)
 {
     if (!lrm_state->conn) {
         return -ENOTCONN;
     }
 
     if (is_remote_lrmd_ra(NULL, NULL, rsc_id)) {
         g_hash_table_remove(lrm_state_table, rsc_id);
         return pcmk_ok;
     }
 
     g_hash_table_remove(lrm_state->rsc_info_cache, rsc_id);
 
     /* @TODO Optimize this ... this function is a blocking round trip from
      * client to daemon. The controld_execd_state.c code path that uses this
      * function should always treat it as an async operation. The executor API
      * should make an async version available.
      */
     return ((lrmd_t *) lrm_state->conn)->cmds->unregister_rsc(lrm_state->conn, rsc_id, options);
 }
diff --git a/lib/lrmd/proxy_common.c b/lib/lrmd/proxy_common.c
index 6d5f1b6030..19183918a0 100644
--- a/lib/lrmd/proxy_common.c
+++ b/lib/lrmd/proxy_common.c
@@ -1,327 +1,333 @@
 /*
  * Copyright 2015-2024 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 <glib.h>
 #include <unistd.h>
 
 #include <crm/crm.h>
 #include <crm/common/xml.h>
 #include <crm/services.h>
 #include <crm/common/mainloop.h>
 
 #include <crm/pengine/status.h>
 #include <crm/cib.h>
 #include <crm/lrmd.h>
 #include <crm/lrmd_internal.h>
 
 int lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg);
 GHashTable *proxy_table = NULL;
 
 static void
 remote_proxy_notify_destroy(lrmd_t *lrmd, const char *session_id)
 {
     /* sending to the remote node that an ipc connection has been destroyed */
     xmlNode *msg = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
     crm_xml_add(msg, PCMK__XA_LRMD_IPC_OP, LRMD_IPC_OP_DESTROY);
     crm_xml_add(msg, PCMK__XA_LRMD_IPC_SESSION, session_id);
     lrmd_internal_proxy_send(lrmd, msg);
     pcmk__xml_free(msg);
 }
 
 /*!
  * \internal
  * \brief Acknowledge a remote proxy shutdown request
  *
  * \param[in,out] lrmd  Connection to proxy
  */
 void
 remote_proxy_ack_shutdown(lrmd_t *lrmd)
 {
     xmlNode *msg = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
     crm_xml_add(msg, PCMK__XA_LRMD_IPC_OP, LRMD_IPC_OP_SHUTDOWN_ACK);
     lrmd_internal_proxy_send(lrmd, msg);
     pcmk__xml_free(msg);
 }
 
 /*!
  * \internal
  * \brief Reject a remote proxy shutdown request
  *
  * \param[in,out] lrmd  Connection to proxy
  */
 void
 remote_proxy_nack_shutdown(lrmd_t *lrmd)
 {
     xmlNode *msg = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
     crm_xml_add(msg, PCMK__XA_LRMD_IPC_OP, LRMD_IPC_OP_SHUTDOWN_NACK);
     lrmd_internal_proxy_send(lrmd, msg);
     pcmk__xml_free(msg);
 }
 
 void
 remote_proxy_relay_event(remote_proxy_t *proxy, xmlNode *msg)
 {
     /* sending to the remote node an event msg. */
     xmlNode *event = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
     xmlNode *wrapper = NULL;
 
     crm_xml_add(event, PCMK__XA_LRMD_IPC_OP, LRMD_IPC_OP_EVENT);
     crm_xml_add(event, PCMK__XA_LRMD_IPC_SESSION, proxy->session_id);
 
     wrapper = pcmk__xe_create(event, PCMK__XE_LRMD_IPC_MSG);
     pcmk__xml_copy(wrapper, msg);
 
     crm_log_xml_explicit(event, "EventForProxy");
     lrmd_internal_proxy_send(proxy->lrm, event);
     pcmk__xml_free(event);
 }
 
 void
 remote_proxy_relay_response(remote_proxy_t *proxy, xmlNode *msg, int msg_id)
 {
     /* sending to the remote node a response msg. */
     xmlNode *response = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
     xmlNode *wrapper = NULL;
 
     crm_xml_add(response, PCMK__XA_LRMD_IPC_OP, LRMD_IPC_OP_RESPONSE);
     crm_xml_add(response, PCMK__XA_LRMD_IPC_SESSION, proxy->session_id);
     crm_xml_add_int(response, PCMK__XA_LRMD_IPC_MSG_ID, msg_id);
 
     wrapper = pcmk__xe_create(response, PCMK__XE_LRMD_IPC_MSG);
     pcmk__xml_copy(wrapper, msg);
 
     lrmd_internal_proxy_send(proxy->lrm, response);
     pcmk__xml_free(response);
 }
 
 static void
 remote_proxy_end_session(remote_proxy_t *proxy)
 {
     if (proxy == NULL) {
         return;
     }
     crm_trace("ending session ID %s", proxy->session_id);
 
     if (proxy->source) {
         mainloop_del_ipc_client(proxy->source);
     }
 }
 
 void
 remote_proxy_free(gpointer data)
 {
     remote_proxy_t *proxy = data;
 
     crm_trace("freed proxy session ID %s", proxy->session_id);
     free(proxy->node_name);
     free(proxy->session_id);
     free(proxy);
 }
 
 int
 remote_proxy_dispatch(const char *buffer, ssize_t length, gpointer userdata)
 {
     // Async responses from servers to clients via the remote executor
     xmlNode *xml = NULL;
     uint32_t flags = 0;
     remote_proxy_t *proxy = userdata;
 
     xml = pcmk__xml_parse(buffer);
     if (xml == NULL) {
         crm_warn("Received a NULL msg from IPC service.");
         return 1;
     }
 
     flags = crm_ipc_buffer_flags(proxy->ipc);
     if (flags & crm_ipc_proxied_relay_response) {
         crm_trace("Passing response back to %.8s on %s: %.200s - request id: %d", proxy->session_id, proxy->node_name, buffer, proxy->last_request_id);
         remote_proxy_relay_response(proxy, xml, proxy->last_request_id);
         proxy->last_request_id = 0;
 
     } else {
         crm_trace("Passing event back to %.8s on %s: %.200s", proxy->session_id, proxy->node_name, buffer);
         remote_proxy_relay_event(proxy, xml);
     }
     pcmk__xml_free(xml);
     return 1;
 }
 
 
 void
 remote_proxy_disconnected(gpointer userdata)
 {
     remote_proxy_t *proxy = userdata;
 
     crm_trace("destroying %p", proxy);
 
     proxy->source = NULL;
     proxy->ipc = NULL;
 
     if(proxy->lrm) {
         remote_proxy_notify_destroy(proxy->lrm, proxy->session_id);
         proxy->lrm = NULL;
     }
 
     g_hash_table_remove(proxy_table, proxy->session_id);
 }
 
 remote_proxy_t *
 remote_proxy_new(lrmd_t *lrmd, struct ipc_client_callbacks *proxy_callbacks,
                  const char *node_name, const char *session_id, const char *channel)
 {
     remote_proxy_t *proxy = NULL;
 
     if(channel == NULL) {
         crm_err("No channel specified to proxy");
         remote_proxy_notify_destroy(lrmd, session_id);
         return NULL;
     }
 
     proxy = pcmk__assert_alloc(1, sizeof(remote_proxy_t));
 
     proxy->node_name = strdup(node_name);
     proxy->session_id = strdup(session_id);
     proxy->lrm = lrmd;
 
     if ((pcmk__parse_server(crm_system_name) == pcmk_ipc_controld)
         && (pcmk__parse_server(channel) == pcmk_ipc_controld)) {
         // The controller doesn't need to connect to itself
         proxy->is_local = TRUE;
 
     } else {
         proxy->source = mainloop_add_ipc_client(channel, G_PRIORITY_LOW, 0, proxy, proxy_callbacks);
         proxy->ipc = mainloop_get_ipc_client(proxy->source);
         if (proxy->source == NULL) {
             remote_proxy_free(proxy);
             remote_proxy_notify_destroy(lrmd, session_id);
             return NULL;
         }
     }
 
     crm_trace("new remote proxy client established to %s on %s, session id %s",
               channel, node_name, session_id);
     g_hash_table_insert(proxy_table, proxy->session_id, proxy);
 
     return proxy;
 }
 
 void
 remote_proxy_cb(lrmd_t *lrmd, const char *node_name, xmlNode *msg)
 {
     const char *op = crm_element_value(msg, PCMK__XA_LRMD_IPC_OP);
     const char *session = crm_element_value(msg, PCMK__XA_LRMD_IPC_SESSION);
     remote_proxy_t *proxy = g_hash_table_lookup(proxy_table, session);
     int msg_id = 0;
 
     /* sessions are raw ipc connections to IPC,
      * all we do is proxy requests/responses exactly
      * like they are given to us at the ipc level. */
 
     CRM_CHECK(op != NULL, return);
     CRM_CHECK(session != NULL, return);
 
     crm_element_value_int(msg, PCMK__XA_LRMD_IPC_MSG_ID, &msg_id);
     /* This is msg from remote ipc client going to real ipc server */
 
     if (pcmk__str_eq(op, LRMD_IPC_OP_DESTROY, pcmk__str_casei)) {
         remote_proxy_end_session(proxy);
 
     } else if (pcmk__str_eq(op, LRMD_IPC_OP_REQUEST, pcmk__str_casei)) {
-        int flags = 0;
+        uint32_t flags = 0U;
+        int rc = pcmk_rc_ok;
         const char *name = crm_element_value(msg, PCMK__XA_LRMD_IPC_CLIENT);
 
         xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_LRMD_IPC_MSG,
                                                 NULL, NULL);
         xmlNode *request = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
 
         CRM_CHECK(request != NULL, return);
 
         if (proxy == NULL) {
             /* proxy connection no longer exists */
             remote_proxy_notify_destroy(lrmd, session);
             return;
         }
 
         // Controller requests MUST be handled by the controller, not us
         CRM_CHECK(proxy->is_local == FALSE,
                   remote_proxy_end_session(proxy); return);
 
         if (!crm_ipc_connected(proxy->ipc)) {
             remote_proxy_end_session(proxy);
             return;
         }
         proxy->last_request_id = 0;
-        crm_element_value_int(msg, PCMK__XA_LRMD_IPC_MSG_FLAGS, &flags);
         crm_xml_add(request, PCMK_XE_ACL_ROLE, "pacemaker-remote");
 
+        rc = pcmk__xe_get_flags(msg, PCMK__XA_LRMD_IPC_MSG_FLAGS, &flags, 0U);
+        if (rc != pcmk_rc_ok) {
+            crm_warn("Couldn't parse controller flags from remote request: %s",
+                     pcmk_rc_str(rc));
+        }
+
         pcmk__assert(node_name != NULL);
         pcmk__update_acl_user(request, PCMK__XA_LRMD_IPC_USER, node_name);
 
         if (pcmk_is_set(flags, crm_ipc_proxied)) {
             const char *type = crm_element_value(request, PCMK__XA_T);
             int rc = 0;
 
             if (pcmk__str_eq(type, PCMK__VALUE_ATTRD, pcmk__str_none)
                 && (crm_element_value(request, PCMK__XA_ATTR_HOST) == NULL)
                 && pcmk__str_any_of(crm_element_value(request, PCMK_XA_TASK),
                                     PCMK__ATTRD_CMD_UPDATE,
                                     PCMK__ATTRD_CMD_UPDATE_BOTH,
                                     PCMK__ATTRD_CMD_UPDATE_DELAY, NULL)) {
                 pcmk__xe_add_node(request, proxy->node_name, 0);
             }
 
             rc = crm_ipc_send(proxy->ipc, request, flags, 5000, NULL);
 
             if(rc < 0) {
                 xmlNode *op_reply = pcmk__xe_create(NULL, PCMK__XE_NACK);
 
                 crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
                          op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
 
                 /* Send a n'ack so the caller doesn't block */
                 crm_xml_add(op_reply, PCMK_XA_FUNCTION, __func__);
                 crm_xml_add_int(op_reply, PCMK__XA_LINE, __LINE__);
                 crm_xml_add_int(op_reply, PCMK_XA_RC, rc);
                 remote_proxy_relay_response(proxy, op_reply, msg_id);
                 pcmk__xml_free(op_reply);
 
             } else {
                 crm_trace("Relayed %s request %d from %s to %s for %s",
                           op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
                 proxy->last_request_id = msg_id;
             }
 
         } else {
             int rc = pcmk_ok;
             xmlNode *op_reply = NULL;
             // @COMPAT pacemaker_remoted <= 1.1.10
 
             crm_trace("Relaying %s request %d from %s to %s for %s",
                       op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
 
             rc = crm_ipc_send(proxy->ipc, request, flags, 10000, &op_reply);
             if(rc < 0) {
                 crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
                          op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
             } else {
                 crm_trace("Relayed %s request %d from %s to %s for %s",
                           op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
             }
 
             if(op_reply) {
                 remote_proxy_relay_response(proxy, op_reply, msg_id);
                 pcmk__xml_free(op_reply);
             }
         }
     } else {
         crm_err("Unknown proxy operation: %s", op);
     }
 }