/src/pacemaker/include/crm/common/ipc_internal.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2013-2026 the Pacemaker project contributors |
3 | | * |
4 | | * The version control history for this file may have further details. |
5 | | * |
6 | | * This source code is licensed under the GNU Lesser General Public License |
7 | | * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. |
8 | | */ |
9 | | |
10 | | #ifndef PCMK__INCLUDED_CRM_COMMON_INTERNAL_H |
11 | | #error "Include <crm/common/internal.h> instead of <ipc_internal.h> directly" |
12 | | #endif |
13 | | |
14 | | #ifndef PCMK__CRM_COMMON_IPC_INTERNAL__H |
15 | | #define PCMK__CRM_COMMON_IPC_INTERNAL__H |
16 | | |
17 | | #include <stdbool.h> // bool |
18 | | #include <stdint.h> // uint32_t, uint64_t, UINT64_C() |
19 | | #include <sys/uio.h> // struct iovec |
20 | | #include <sys/types.h> // uid_t, gid_t, pid_t, size_t |
21 | | |
22 | | #include <glib.h> // GQueue, ... |
23 | | #include <libxml/tree.h> // xmlNode |
24 | | #include <qb/qbipcs.h> // qb_ipcs_connection_t, ... |
25 | | |
26 | | #include <crm_config.h> // HAVE_GETPEEREID |
27 | | #include <crm/crm.h> // crm_system_name |
28 | | #include <crm/common/ipc.h> |
29 | | #include <crm/common/ipc_controld.h> // pcmk_controld_api_reply |
30 | | #include <crm/common/ipc_pacemakerd.h> // pcmk_pacemakerd_{api_reply,state} |
31 | | #include <crm/common/remote_internal.h> // pcmk__remote_t |
32 | | |
33 | | #ifdef __cplusplus |
34 | | extern "C" { |
35 | | #endif |
36 | | |
37 | | /* denotes "non yieldable PID" on FreeBSD, or actual PID1 in scenarios that |
38 | | require a delicate handling anyway (socket-based activation with systemd); |
39 | | we can be reasonably sure that this PID is never possessed by the actual |
40 | | child daemon, as it gets taken either by the proper init, or by pacemakerd |
41 | | itself (i.e. this precludes anything else); note that value of zero |
42 | | is meant to carry "unset" meaning, and better not to bet on/conditionalize |
43 | | over signedness of pid_t */ |
44 | | #define PCMK__SPECIAL_PID 1 |
45 | | |
46 | | // Timeout (in seconds) to use for IPC client sends, reply waits, etc. |
47 | 0 | #define PCMK__IPC_TIMEOUT 120 |
48 | | |
49 | | #if defined(HAVE_GETPEEREID) |
50 | | /* on FreeBSD, we don't want to expose "non-yieldable PID" (leading to |
51 | | "IPC liveness check only") as its nominal representation, which could |
52 | | cause confusion -- this is unambiguous as long as there's no |
53 | | socket-based activation like with systemd (very improbable) */ |
54 | | #define PCMK__SPECIAL_PID_AS_0(p) (((p) == PCMK__SPECIAL_PID) ? 0 : (p)) |
55 | | #else |
56 | 0 | #define PCMK__SPECIAL_PID_AS_0(p) (p) |
57 | | #endif |
58 | | |
59 | | /*! |
60 | | * \internal |
61 | | * \brief Check the authenticity and liveness of the process via IPC end-point |
62 | | * |
63 | | * When IPC daemon under given IPC end-point (name) detected, its authenticity |
64 | | * is verified by the means of comparing against provided referential UID and |
65 | | * GID, and the result of this check can be deduced from the return value. |
66 | | * As an exception, referential UID of 0 (~ root) satisfies arbitrary |
67 | | * detected daemon's credentials. |
68 | | * |
69 | | * \param[in] name IPC name to base the search on |
70 | | * \param[in] refuid referential UID to check against |
71 | | * \param[in] refgid referential GID to check against |
72 | | * \param[out] gotpid to optionally store obtained PID of the found process |
73 | | * upon returning 1 or -2 |
74 | | * (not available on FreeBSD, special value of 1, |
75 | | * see PCMK__SPECIAL_PID, used instead, and the caller |
76 | | * is required to special case this value respectively) |
77 | | * |
78 | | * \return Standard Pacemaker return code |
79 | | * |
80 | | * \note Return codes of particular interest include pcmk_rc_ipc_unresponsive |
81 | | * indicating that no trace of IPC liveness was detected, and |
82 | | * pcmk_rc_ipc_unauthorized indicating that the IPC endpoint is blocked by |
83 | | * an unauthorized process. |
84 | | * \note This function emits a log message for return codes other than |
85 | | * pcmk_rc_ok and pcmk_rc_ipc_unresponsive, and when there isn't a perfect |
86 | | * match in respect to \p reguid and/or \p refgid, for a possible |
87 | | * least privilege principle violation. |
88 | | * |
89 | | * \see crm_ipc_is_authentic_process |
90 | | */ |
91 | | int pcmk__ipc_is_authentic_process_active(const char *name, uid_t refuid, |
92 | | gid_t refgid, pid_t *gotpid); |
93 | | |
94 | | int pcmk__connect_generic_ipc(crm_ipc_t *ipc); |
95 | | int pcmk__ipc_fd(crm_ipc_t *ipc, int *fd); |
96 | | int pcmk__connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type, |
97 | | int attempts); |
98 | | int pcmk__connect_ipc_retry_conrefused(pcmk_ipc_api_t *api, |
99 | | enum pcmk_ipc_dispatch dispatch_type, |
100 | | int attempts); |
101 | | /* |
102 | | * Server-related |
103 | | */ |
104 | | |
105 | | enum pcmk__client_flags { |
106 | | // Lower 32 bits are reserved for server (not library) use |
107 | | |
108 | | // Next 8 bits are reserved for client type (sort of a cheap enum) |
109 | | |
110 | | //! Client uses plain IPC |
111 | | pcmk__client_ipc = (UINT64_C(1) << 32), |
112 | | |
113 | | //! Client uses TCP connection |
114 | | pcmk__client_tcp = (UINT64_C(1) << 33), |
115 | | |
116 | | //! Client uses TCP with TLS |
117 | | pcmk__client_tls = (UINT64_C(1) << 34), |
118 | | |
119 | | // The rest are client attributes |
120 | | |
121 | | //! Client IPC is proxied |
122 | | pcmk__client_proxied = (UINT64_C(1) << 40), |
123 | | |
124 | | //! Client is run by root or cluster user |
125 | | pcmk__client_privileged = (UINT64_C(1) << 41), |
126 | | |
127 | | //! Local client to be proxied |
128 | | pcmk__client_to_proxy = (UINT64_C(1) << 42), |
129 | | |
130 | | /*! |
131 | | * \brief Client IPC connection accepted |
132 | | * |
133 | | * Used only for remote CIB connections via \c PCMK_XA_REMOTE_TLS_PORT. |
134 | | */ |
135 | | pcmk__client_authenticated = (UINT64_C(1) << 43), |
136 | | |
137 | | //! Client TLS handshake is complete |
138 | | pcmk__client_tls_handshake_complete = (UINT64_C(1) << 44), |
139 | | }; |
140 | | |
141 | | #define PCMK__CLIENT_TYPE(client) ((client)->flags & UINT64_C(0xff00000000)) |
142 | | |
143 | | typedef struct { |
144 | | unsigned int pid; |
145 | | |
146 | | char *id; |
147 | | char *name; |
148 | | char *user; |
149 | | uint64_t flags; // Group of pcmk__client_flags |
150 | | |
151 | | int request_id; |
152 | | void *userdata; |
153 | | |
154 | | int event_timer; |
155 | | GQueue *event_queue; |
156 | | |
157 | | /* Buffer used to store a multipart IPC message when we are building it |
158 | | * up over multiple reads. |
159 | | */ |
160 | | GByteArray *buffer; |
161 | | |
162 | | /* Depending on the client type, only some of the following will be |
163 | | * populated/valid. @TODO Maybe convert to a union. |
164 | | */ |
165 | | |
166 | | qb_ipcs_connection_t *ipcs; /* IPC */ |
167 | | |
168 | | pcmk__remote_t *remote; /* TCP/TLS */ |
169 | | |
170 | | unsigned int queue_backlog; /* IPC queue length after last flush */ |
171 | | } pcmk__client_t; |
172 | | |
173 | 0 | #define pcmk__set_client_flags(client, flags_to_set) do { \ |
174 | 0 | (client)->flags = pcmk__set_flags_as(__func__, __LINE__, \ |
175 | 0 | LOG_TRACE, \ |
176 | 0 | "Client", pcmk__client_name(client), \ |
177 | 0 | (client)->flags, (flags_to_set), #flags_to_set); \ |
178 | 0 | } while (0) |
179 | | |
180 | | #define pcmk__clear_client_flags(client, flags_to_clear) do { \ |
181 | | (client)->flags = pcmk__clear_flags_as(__func__, __LINE__, \ |
182 | | LOG_TRACE, \ |
183 | | "Client", pcmk__client_name(client), \ |
184 | | (client)->flags, (flags_to_clear), #flags_to_clear); \ |
185 | | } while (0) |
186 | | |
187 | 0 | #define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set) do { \ |
188 | 0 | ipc_flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, \ |
189 | 0 | "IPC", (ipc_name), \ |
190 | 0 | (ipc_flags), (flags_to_set), \ |
191 | 0 | #flags_to_set); \ |
192 | 0 | } while (0) |
193 | | |
194 | 0 | #define pcmk__clear_ipc_flags(ipc_flags, ipc_name, flags_to_clear) do { \ |
195 | 0 | ipc_flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, \ |
196 | 0 | "IPC", (ipc_name), \ |
197 | 0 | (ipc_flags), (flags_to_clear), \ |
198 | 0 | #flags_to_clear); \ |
199 | 0 | } while (0) |
200 | | |
201 | | unsigned int pcmk__ipc_client_count(void); |
202 | | void pcmk__foreach_ipc_client(GHFunc func, void *user_data); |
203 | | |
204 | | void pcmk__client_cleanup(void); |
205 | | |
206 | | pcmk__client_t *pcmk__find_client(const qb_ipcs_connection_t *c); |
207 | | pcmk__client_t *pcmk__find_client_by_id(const char *id); |
208 | | const char *pcmk__client_name(const pcmk__client_t *c); |
209 | | const char *pcmk__client_type_str(uint64_t client_type); |
210 | | |
211 | | pcmk__client_t *pcmk__new_unauth_client(void); |
212 | | pcmk__client_t *pcmk__new_client(qb_ipcs_connection_t *c, uid_t uid); |
213 | | void pcmk__free_client(pcmk__client_t *c); |
214 | | void pcmk__drop_all_clients(qb_ipcs_service_t *s); |
215 | | |
216 | | xmlNode *pcmk__ipc_create_ack_as(const char *function, int line, uint32_t flags, |
217 | | const char *ver, crm_exit_t status); |
218 | | #define pcmk__ipc_create_ack(flags, ver, st) \ |
219 | | pcmk__ipc_create_ack_as(__func__, __LINE__, (flags), (ver), (st)) |
220 | | |
221 | | int pcmk__ipc_send_ack_as(const char *function, int line, pcmk__client_t *c, |
222 | | uint32_t request, uint32_t flags, const char *ver, |
223 | | crm_exit_t status); |
224 | | #define pcmk__ipc_send_ack(c, req, flags, ver, st) \ |
225 | | pcmk__ipc_send_ack_as(__func__, __LINE__, (c), (req), (flags), (ver), (st)) |
226 | | |
227 | | int pcmk__ipc_prepare_iov(uint32_t request, const GString *message, |
228 | | uint16_t index, struct iovec **result, ssize_t *bytes); |
229 | | int pcmk__ipc_send_xml(pcmk__client_t *c, uint32_t request, |
230 | | const xmlNode *message, uint32_t flags); |
231 | | int pcmk__ipc_send_iov(pcmk__client_t *c, struct iovec *iov, uint32_t flags); |
232 | | void pcmk__ipc_free_client_buffer(crm_ipc_t *client); |
233 | | int pcmk__ipc_msg_append(GByteArray **buffer, guint8 *data); |
234 | | xmlNode *pcmk__client_data2xml(pcmk__client_t *c, uint32_t *id, uint32_t *flags); |
235 | | |
236 | | int pcmk__client_pid(qb_ipcs_connection_t *c); |
237 | | |
238 | | void pcmk__serve_attrd_ipc(qb_ipcs_service_t **ipcs, |
239 | | struct qb_ipcs_service_handlers *cb); |
240 | | void pcmk__serve_controld_ipc(qb_ipcs_service_t **ipcs, |
241 | | struct qb_ipcs_service_handlers *cb); |
242 | | void pcmk__serve_execd_ipc(qb_ipcs_service_t **ipcs, |
243 | | struct qb_ipcs_service_handlers *cb); |
244 | | void pcmk__serve_fenced_ipc(qb_ipcs_service_t **ipcs, |
245 | | struct qb_ipcs_service_handlers *cb); |
246 | | void pcmk__serve_pacemakerd_ipc(qb_ipcs_service_t **ipcs, |
247 | | struct qb_ipcs_service_handlers *cb); |
248 | | void pcmk__serve_schedulerd_ipc(qb_ipcs_service_t **ipcs, |
249 | | struct qb_ipcs_service_handlers *cb); |
250 | | |
251 | | void pcmk__serve_based_ipc(qb_ipcs_service_t **ipcs_ro, |
252 | | qb_ipcs_service_t **ipcs_rw, |
253 | | struct qb_ipcs_service_handlers *ro_cb, |
254 | | struct qb_ipcs_service_handlers *rw_cb); |
255 | | |
256 | | static inline const char * |
257 | | pcmk__ipc_sys_name(const char *ipc_name, const char *fallback) |
258 | 0 | { |
259 | 0 | return ipc_name ? ipc_name : ((crm_system_name ? crm_system_name : fallback)); |
260 | 0 | } Unexecuted instantiation: scores_fuzzer.c:pcmk__ipc_sys_name Unexecuted instantiation: results.c:pcmk__ipc_sys_name Unexecuted instantiation: scores.c:pcmk__ipc_sys_name Unexecuted instantiation: strings.c:pcmk__ipc_sys_name Unexecuted instantiation: utils.c:pcmk__ipc_sys_name Unexecuted instantiation: iso8601.c:pcmk__ipc_sys_name Unexecuted instantiation: logging.c:pcmk__ipc_sys_name Unexecuted instantiation: mainloop.c:pcmk__ipc_sys_name Unexecuted instantiation: options.c:pcmk__ipc_sys_name Unexecuted instantiation: output.c:pcmk__ipc_sys_name Unexecuted instantiation: output_log.c:pcmk__ipc_sys_name Unexecuted instantiation: output_none.c:pcmk__ipc_sys_name Unexecuted instantiation: output_text.c:pcmk__ipc_sys_name Unexecuted instantiation: output_xml.c:pcmk__ipc_sys_name Unexecuted instantiation: patchset_display.c:pcmk__ipc_sys_name Unexecuted instantiation: schemas.c:pcmk__ipc_sys_name Unexecuted instantiation: xml.c:pcmk__ipc_sys_name Unexecuted instantiation: xml_display.c:pcmk__ipc_sys_name Unexecuted instantiation: xml_element.c:pcmk__ipc_sys_name Unexecuted instantiation: xml_idref.c:pcmk__ipc_sys_name Unexecuted instantiation: xml_io.c:pcmk__ipc_sys_name Unexecuted instantiation: xml_tracking.c:pcmk__ipc_sys_name Unexecuted instantiation: xpath.c:pcmk__ipc_sys_name Unexecuted instantiation: acl.c:pcmk__ipc_sys_name Unexecuted instantiation: actions.c:pcmk__ipc_sys_name Unexecuted instantiation: agents.c:pcmk__ipc_sys_name Unexecuted instantiation: cmdline.c:pcmk__ipc_sys_name Unexecuted instantiation: digest.c:pcmk__ipc_sys_name Unexecuted instantiation: health.c:pcmk__ipc_sys_name Unexecuted instantiation: io.c:pcmk__ipc_sys_name Unexecuted instantiation: ipc_client.c:pcmk__ipc_sys_name Unexecuted instantiation: ipc_common.c:pcmk__ipc_sys_name Unexecuted instantiation: ipc_controld.c:pcmk__ipc_sys_name Unexecuted instantiation: ipc_pacemakerd.c:pcmk__ipc_sys_name Unexecuted instantiation: ipc_schedulerd.c:pcmk__ipc_sys_name Unexecuted instantiation: ipc_server.c:pcmk__ipc_sys_name Unexecuted instantiation: messages.c:pcmk__ipc_sys_name Unexecuted instantiation: nodes.c:pcmk__ipc_sys_name Unexecuted instantiation: nvpair.c:pcmk__ipc_sys_name Unexecuted instantiation: options_display.c:pcmk__ipc_sys_name Unexecuted instantiation: patchset.c:pcmk__ipc_sys_name Unexecuted instantiation: procfs.c:pcmk__ipc_sys_name Unexecuted instantiation: rules.c:pcmk__ipc_sys_name Unexecuted instantiation: servers.c:pcmk__ipc_sys_name Unexecuted instantiation: xml_attr.c:pcmk__ipc_sys_name Unexecuted instantiation: xml_comment.c:pcmk__ipc_sys_name Unexecuted instantiation: cib.c:pcmk__ipc_sys_name Unexecuted instantiation: ipc_attrd.c:pcmk__ipc_sys_name Unexecuted instantiation: pid.c:pcmk__ipc_sys_name Unexecuted instantiation: attrs.c:pcmk__ipc_sys_name Unexecuted instantiation: xml_fuzzer.c:pcmk__ipc_sys_name Unexecuted instantiation: strings_fuzzer.c:pcmk__ipc_sys_name Unexecuted instantiation: cib_file_fuzzer.c:pcmk__ipc_sys_name Unexecuted instantiation: cib_client.c:pcmk__ipc_sys_name Unexecuted instantiation: cib_file.c:pcmk__ipc_sys_name Unexecuted instantiation: cib_native.c:pcmk__ipc_sys_name Unexecuted instantiation: cib_ops.c:pcmk__ipc_sys_name Unexecuted instantiation: cib_remote.c:pcmk__ipc_sys_name Unexecuted instantiation: cib_utils.c:pcmk__ipc_sys_name Unexecuted instantiation: remote.c:pcmk__ipc_sys_name Unexecuted instantiation: tls.c:pcmk__ipc_sys_name Unexecuted instantiation: watchdog.c:pcmk__ipc_sys_name Unexecuted instantiation: iso8601_fuzzer.c:pcmk__ipc_sys_name |
261 | | |
262 | | const char *pcmk__pcmkd_state_enum2friendly(enum pcmk_pacemakerd_state state); |
263 | | |
264 | | const char *pcmk__controld_api_reply2str(enum pcmk_controld_api_reply reply); |
265 | | const char *pcmk__pcmkd_api_reply2str(enum pcmk_pacemakerd_api_reply reply); |
266 | | |
267 | | #ifdef __cplusplus |
268 | | } |
269 | | #endif |
270 | | |
271 | | #endif // PCMK__CRM_COMMON_IPC_INTERNAL__H |