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

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