diff --git a/daemons/based/based_common.c b/daemons/based/based_common.c index 5ae4a20a30..5f0b7a5dbd 100644 --- a/daemons/based/based_common.c +++ b/daemons/based/based_common.c @@ -1,335 +1,356 @@ /* * Copyright 2008-2023 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include gboolean stand_alone = FALSE; extern int cib_perform_command(xmlNode * request, xmlNode ** reply, xmlNode ** cib_diff, gboolean privileged); static xmlNode * cib_prepare_common(xmlNode * root, const char *section) { xmlNode *data = NULL; /* extract the CIB from the fragment */ if (root == NULL) { return NULL; } else if (pcmk__strcase_any_of(crm_element_name(root), XML_TAG_FRAGMENT, F_CRM_DATA, F_CIB_CALLDATA, NULL)) { data = first_named_child(root, XML_TAG_CIB); } else { data = root; } /* grab the section specified for the command */ if (section != NULL && data != NULL && pcmk__str_eq(crm_element_name(data), XML_TAG_CIB, pcmk__str_none)) { data = pcmk_find_cib_element(data, section); } /* crm_log_xml_trace(root, "cib:input"); */ return data; } static int cib_prepare_none(xmlNode * request, xmlNode ** data, const char **section) { *data = NULL; *section = crm_element_value(request, F_CIB_SECTION); return pcmk_ok; } static int cib_prepare_data(xmlNode * request, xmlNode ** data, const char **section) { xmlNode *input_fragment = get_message_xml(request, F_CIB_CALLDATA); *section = crm_element_value(request, F_CIB_SECTION); *data = cib_prepare_common(input_fragment, *section); /* crm_log_xml_debug(*data, "data"); */ return pcmk_ok; } static int cib_prepare_sync(xmlNode * request, xmlNode ** data, const char **section) { *data = NULL; *section = crm_element_value(request, F_CIB_SECTION); return pcmk_ok; } static int cib_prepare_diff(xmlNode * request, xmlNode ** data, const char **section) { xmlNode *input_fragment = NULL; *data = NULL; *section = NULL; if (pcmk__xe_attr_is_true(request, F_CIB_GLOBAL_UPDATE)) { input_fragment = get_message_xml(request, F_CIB_UPDATE_DIFF); } else { input_fragment = get_message_xml(request, F_CIB_CALLDATA); } CRM_CHECK(input_fragment != NULL, crm_log_xml_warn(request, "no input")); *data = cib_prepare_common(input_fragment, NULL); return pcmk_ok; } static int cib_cleanup_query(int options, xmlNode ** data, xmlNode ** output) { CRM_LOG_ASSERT(*data == NULL); if ((options & cib_no_children) || pcmk__str_eq(crm_element_name(*output), "xpath-query", pcmk__str_casei)) { free_xml(*output); } return pcmk_ok; } static int cib_cleanup_data(int options, xmlNode ** data, xmlNode ** output) { free_xml(*output); *data = NULL; return pcmk_ok; } static int cib_cleanup_output(int options, xmlNode ** data, xmlNode ** output) { free_xml(*output); return pcmk_ok; } static int cib_cleanup_none(int options, xmlNode ** data, xmlNode ** output) { CRM_LOG_ASSERT(*data == NULL); CRM_LOG_ASSERT(*output == NULL); return pcmk_ok; } static cib_operation_t cib_server_ops[] = { - // Booleans are modifies_cib, needs_privileges { - NULL, FALSE, FALSE, + NULL, + cib_op_attr_none, cib_prepare_none, cib_cleanup_none, cib_process_default }, { - PCMK__CIB_REQUEST_QUERY, FALSE, FALSE, + PCMK__CIB_REQUEST_QUERY, + cib_op_attr_none, cib_prepare_none, cib_cleanup_query, cib_process_query }, { - PCMK__CIB_REQUEST_MODIFY, TRUE, TRUE, + PCMK__CIB_REQUEST_MODIFY, + cib_op_attr_modifies|cib_op_attr_privileged, cib_prepare_data, cib_cleanup_data, cib_process_modify }, { - PCMK__CIB_REQUEST_APPLY_PATCH, TRUE, TRUE, + PCMK__CIB_REQUEST_APPLY_PATCH, + cib_op_attr_modifies|cib_op_attr_privileged, cib_prepare_diff, cib_cleanup_data, cib_server_process_diff }, { - PCMK__CIB_REQUEST_REPLACE, TRUE, TRUE, + PCMK__CIB_REQUEST_REPLACE, + cib_op_attr_modifies|cib_op_attr_privileged, cib_prepare_data, cib_cleanup_data, cib_process_replace_svr }, { - PCMK__CIB_REQUEST_CREATE, TRUE, TRUE, + PCMK__CIB_REQUEST_CREATE, + cib_op_attr_modifies|cib_op_attr_privileged, cib_prepare_data, cib_cleanup_data, cib_process_create }, { - PCMK__CIB_REQUEST_DELETE, TRUE, TRUE, + PCMK__CIB_REQUEST_DELETE, + cib_op_attr_modifies|cib_op_attr_privileged, cib_prepare_data, cib_cleanup_data, cib_process_delete }, { - PCMK__CIB_REQUEST_SYNC_TO_ALL, FALSE, TRUE, + PCMK__CIB_REQUEST_SYNC_TO_ALL, + cib_op_attr_privileged, cib_prepare_sync, cib_cleanup_none, cib_process_sync }, { - PCMK__CIB_REQUEST_BUMP, TRUE, TRUE, + PCMK__CIB_REQUEST_BUMP, + cib_op_attr_modifies|cib_op_attr_privileged, cib_prepare_none, cib_cleanup_output, cib_process_bump }, { - PCMK__CIB_REQUEST_ERASE, TRUE, TRUE, + PCMK__CIB_REQUEST_ERASE, + cib_op_attr_modifies|cib_op_attr_privileged, cib_prepare_none, cib_cleanup_output, cib_process_erase }, { - PCMK__CIB_REQUEST_NOOP, FALSE, FALSE, + PCMK__CIB_REQUEST_NOOP, + cib_op_attr_none, cib_prepare_none, cib_cleanup_none, cib_process_default }, { - PCMK__CIB_REQUEST_ABS_DELETE, TRUE, TRUE, + PCMK__CIB_REQUEST_ABS_DELETE, + cib_op_attr_modifies|cib_op_attr_privileged, cib_prepare_data, cib_cleanup_data, cib_process_delete_absolute }, { - PCMK__CIB_REQUEST_UPGRADE, TRUE, TRUE, + PCMK__CIB_REQUEST_UPGRADE, + cib_op_attr_modifies|cib_op_attr_privileged, cib_prepare_none, cib_cleanup_output, cib_process_upgrade_server }, { - PCMK__CIB_REQUEST_SECONDARY, FALSE, TRUE, + PCMK__CIB_REQUEST_SECONDARY, + cib_op_attr_privileged, cib_prepare_none, cib_cleanup_none, cib_process_readwrite }, { - PCMK__CIB_REQUEST_ALL_SECONDARY, FALSE, TRUE, + PCMK__CIB_REQUEST_ALL_SECONDARY, + cib_op_attr_privileged, cib_prepare_none, cib_cleanup_none, cib_process_readwrite }, { - PCMK__CIB_REQUEST_SYNC_TO_ONE, FALSE, TRUE, + PCMK__CIB_REQUEST_SYNC_TO_ONE, + cib_op_attr_privileged, cib_prepare_sync, cib_cleanup_none, cib_process_sync_one }, { - PCMK__CIB_REQUEST_PRIMARY, TRUE, TRUE, + PCMK__CIB_REQUEST_PRIMARY, + cib_op_attr_modifies|cib_op_attr_privileged, cib_prepare_data, cib_cleanup_data, cib_process_readwrite }, { - PCMK__CIB_REQUEST_IS_PRIMARY, FALSE, TRUE, + PCMK__CIB_REQUEST_IS_PRIMARY, + cib_op_attr_privileged, cib_prepare_none, cib_cleanup_none, cib_process_readwrite }, { - PCMK__CIB_REQUEST_SHUTDOWN, FALSE, TRUE, + PCMK__CIB_REQUEST_SHUTDOWN, + cib_op_attr_privileged, cib_prepare_sync, cib_cleanup_none, cib_process_shutdown_req }, { - CRM_OP_PING, FALSE, FALSE, + CRM_OP_PING, + cib_op_attr_none, cib_prepare_none, cib_cleanup_output, cib_process_ping }, }; int cib_get_operation_id(const char *op, int *operation) { static GHashTable *operation_hash = NULL; if (operation_hash == NULL) { int lpc = 0; int max_msg_types = PCMK__NELEM(cib_server_ops); operation_hash = pcmk__strkey_table(NULL, free); for (lpc = 1; lpc < max_msg_types; lpc++) { int *value = malloc(sizeof(int)); if(value) { *value = lpc; g_hash_table_insert(operation_hash, (gpointer) cib_server_ops[lpc].operation, value); } } } if (op != NULL) { int *value = g_hash_table_lookup(operation_hash, op); if (value) { *operation = *value; return pcmk_ok; } } crm_err("Operation %s is not valid", op); *operation = -1; return -EINVAL; } xmlNode * cib_msg_copy(xmlNode *msg) { static const char *field_list[] = { F_XML_TAGNAME, F_TYPE, F_CIB_CLIENTID, F_CIB_CALLOPTS, F_CIB_CALLID, F_CIB_OPERATION, F_CIB_ISREPLY, F_CIB_SECTION, F_CIB_HOST, F_CIB_RC, F_CIB_DELEGATED, F_CIB_OBJID, F_CIB_OBJTYPE, F_CIB_EXISTING, F_CIB_SEENCOUNT, F_CIB_TIMEOUT, F_CIB_GLOBAL_UPDATE, F_CIB_CLIENTNAME, F_CIB_USER, F_CIB_NOTIFY_TYPE, F_CIB_NOTIFY_ACTIVATE }; xmlNode *copy = create_xml_node(NULL, "copy"); CRM_ASSERT(copy != NULL); for (int lpc = 0; lpc < PCMK__NELEM(field_list); lpc++) { const char *field = field_list[lpc]; const char *value = crm_element_value(msg, field); if (value != NULL) { crm_xml_add(copy, field, value); } } return copy; } cib_op_t * cib_op_func(int call_type) { return &(cib_server_ops[call_type].fn); } gboolean cib_op_modifies(int call_type) { - return cib_server_ops[call_type].modifies_cib; + return pcmk_is_set(cib_server_ops[call_type].flags, cib_op_attr_modifies); } int cib_op_can_run(int call_type, int call_options, bool privileged) { - if (!privileged && cib_server_ops[call_type].needs_privileges) { + if (!privileged + && pcmk_is_set(cib_server_ops[call_type].flags, + cib_op_attr_privileged)) { return -EACCES; } return pcmk_ok; } int cib_op_prepare(int call_type, xmlNode * request, xmlNode ** input, const char **section) { crm_trace("Prepare %d", call_type); return cib_server_ops[call_type].prepare(request, input, section); } int cib_op_cleanup(int call_type, int options, xmlNode ** input, xmlNode ** output) { crm_trace("Cleanup %d", call_type); return cib_server_ops[call_type].cleanup(options, input, output); } diff --git a/daemons/based/pacemaker-based.h b/daemons/based/pacemaker-based.h index 56057ea3e0..a741d0ce85 100644 --- a/daemons/based/pacemaker-based.h +++ b/daemons/based/pacemaker-based.h @@ -1,150 +1,160 @@ /* * Copyright 2004-2023 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 PACEMAKER_BASED__H # define PACEMAKER_BASED__H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_GNUTLS_GNUTLS_H # include #endif // CIB-specific client flags enum cib_client_flags { // Notifications cib_notify_pre = (UINT64_C(1) << 0), cib_notify_post = (UINT64_C(1) << 1), cib_notify_replace = (UINT64_C(1) << 2), cib_notify_confirm = (UINT64_C(1) << 3), cib_notify_diff = (UINT64_C(1) << 4), // Whether client is another cluster daemon cib_is_daemon = (UINT64_C(1) << 12), }; +/*! + * \internal + * \enum cib_op_attr + * \brief Bit flags for CIB operation attributes + */ +enum cib_op_attr { + cib_op_attr_none = 0, //!< No special attributes + cib_op_attr_modifies = (1 << 1), //!< Modifies CIB + cib_op_attr_privileged = (1 << 2), //!< Requires privileges +}; + typedef struct cib_operation_s { const char *operation; - gboolean modifies_cib; - gboolean needs_privileges; + uint32_t flags; //!< Group of enum cib_op_attr flags int (*prepare) (xmlNode *, xmlNode **, const char **); int (*cleanup) (int, xmlNode **, xmlNode **); int (*fn) (const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **); } cib_operation_t; extern bool based_is_primary; extern GHashTable *config_hash; extern xmlNode *the_cib; extern crm_trigger_t *cib_writer; extern gboolean cib_writes_enabled; extern GMainLoop *mainloop; extern crm_cluster_t *crm_cluster; extern GHashTable *local_notify_queue; extern gboolean legacy_mode; extern gboolean stand_alone; extern gboolean cib_shutdown_flag; extern gchar *cib_root; extern int cib_status; extern pcmk__output_t *logger_out; extern struct qb_ipcs_service_handlers ipc_ro_callbacks; extern struct qb_ipcs_service_handlers ipc_rw_callbacks; extern qb_ipcs_service_t *ipcs_ro; extern qb_ipcs_service_t *ipcs_rw; extern qb_ipcs_service_t *ipcs_shm; void cib_peer_callback(xmlNode *msg, void *private_data); void cib_common_callback_worker(uint32_t id, uint32_t flags, xmlNode *op_request, pcmk__client_t *cib_client, gboolean privileged); void cib_shutdown(int nsig); void terminate_cib(const char *caller, int fast); gboolean cib_legacy_mode(void); gboolean uninitializeCib(void); xmlNode *readCibXmlFile(const char *dir, const char *file, gboolean discard_status); int activateCibXml(xmlNode *doc, gboolean to_disk, const char *op); int cib_process_shutdown_req(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); int cib_process_default(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); int cib_process_ping(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); int cib_process_readwrite(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); int cib_process_replace_svr(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); int cib_server_process_diff(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); int cib_process_sync(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); int cib_process_sync_one(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); int cib_process_delete_absolute(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); int cib_process_upgrade_server(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer); void send_sync_request(const char *host); int sync_our_cib(xmlNode *request, gboolean all); xmlNode *cib_msg_copy(xmlNode *msg); int cib_get_operation_id(const char *op, int *operation); cib_op_t *cib_op_func(int call_type); gboolean cib_op_modifies(int call_type); int cib_op_prepare(int call_type, xmlNode *request, xmlNode **input, const char **section); int cib_op_cleanup(int call_type, int options, xmlNode **input, xmlNode **output); int cib_op_can_run(int call_type, int call_options, bool privileged); void cib_diff_notify(const char *op, int result, const char *call_id, const char *client_id, const char *client_name, const char *origin, xmlNode *update, xmlNode *diff); void cib_replace_notify(const char *op, int result, const char *call_id, const char *client_id, const char *client_name, const char *origin, xmlNode *update, xmlNode *diff, uint32_t change_section); static inline const char * cib_config_lookup(const char *opt) { return g_hash_table_lookup(config_hash, opt); } #endif // PACEMAKER_BASED__H