Coverage Report

Created: 2026-01-03 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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