root/include/crm/common/ipc_internal.h

/* [previous][next][first][last][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. pcmk__ipc_sys_name

   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 #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 #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 #define pcmk__set_client_flags(client, flags_to_set) do {               \
 195         (client)->flags = pcmk__set_flags_as(__func__, __LINE__,        \
 196             LOG_TRACE,                                                  \
 197             "Client", pcmk__client_name(client),                        \
 198             (client)->flags, (flags_to_set), #flags_to_set);            \
 199     } 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 #define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set) do {         \
 209         ipc_flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,       \
 210                                        "IPC", (ipc_name),                   \
 211                                        (ipc_flags), (flags_to_set),         \
 212                                        #flags_to_set);                      \
 213     } while (0)
 214 
 215 #define pcmk__clear_ipc_flags(ipc_flags, ipc_name, flags_to_clear) do {     \
 216         ipc_flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE,     \
 217                                          "IPC", (ipc_name),                 \
 218                                          (ipc_flags), (flags_to_clear),     \
 219                                          #flags_to_clear);                  \
 220     } 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 qb_ipcs_service_t *pcmk__serve_schedulerd_ipc(struct qb_ipcs_service_handlers *cb);
 267 qb_ipcs_service_t *pcmk__serve_controld_ipc(struct qb_ipcs_service_handlers *cb);
 268 
 269 void pcmk__serve_based_ipc(qb_ipcs_service_t **ipcs_ro,
 270                            qb_ipcs_service_t **ipcs_rw,
 271                            qb_ipcs_service_t **ipcs_shm,
 272                            struct qb_ipcs_service_handlers *ro_cb,
 273                            struct qb_ipcs_service_handlers *rw_cb);
 274 
 275 void pcmk__stop_based_ipc(qb_ipcs_service_t *ipcs_ro,
 276         qb_ipcs_service_t *ipcs_rw,
 277         qb_ipcs_service_t *ipcs_shm);
 278 
 279 static inline const char *
 280 pcmk__ipc_sys_name(const char *ipc_name, const char *fallback)
     /* [previous][next][first][last][top][bottom][index][help] */
 281 {
 282     return ipc_name ? ipc_name : ((crm_system_name ? crm_system_name : fallback));
 283 }
 284 
 285 const char *pcmk__pcmkd_state_enum2friendly(enum pcmk_pacemakerd_state state);
 286 
 287 const char *pcmk__controld_api_reply2str(enum pcmk_controld_api_reply reply);
 288 const char *pcmk__pcmkd_api_reply2str(enum pcmk_pacemakerd_api_reply reply);
 289 
 290 #ifdef __cplusplus
 291 }
 292 #endif
 293 
 294 #endif // PCMK__CRM_COMMON_IPC_INTERNAL__H

/* [previous][next][first][last][top][bottom][index][help] */