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

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