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

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