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