Coverage Report

Created: 2026-10-30 06:56

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-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