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 int pcmk__connect_generic_ipc(crm_ipc_t *ipc);
 100 int pcmk__ipc_fd(crm_ipc_t *ipc, int *fd);
 101 int pcmk__connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type,
 102                       int attempts);
 103 
 104 /*
 105  * Server-related
 106  */
 107 
 108 typedef struct pcmk__client_s pcmk__client_t;
 109 
 110 struct pcmk__remote_s {
 111     /* Shared */
 112     char *buffer;
 113     size_t buffer_size;
 114     size_t buffer_offset;
 115     int auth_timeout;
 116     int tcp_socket;
 117     mainloop_io_t *source;
 118     time_t uptime;
 119     char *start_state;
 120 
 121     /* CIB-only */
 122     char *token;
 123 
 124     /* TLS only */
 125 #  ifdef HAVE_GNUTLS_GNUTLS_H
 126     gnutls_session_t *tls_session;
 127 #  endif
 128 };
 129 
 130 enum pcmk__client_flags {
 131     // Lower 32 bits are reserved for server (not library) use
 132 
 133     // Next 8 bits are reserved for client type (sort of a cheap enum)
 134 
 135     //! Client uses plain IPC
 136     pcmk__client_ipc                    = (UINT64_C(1) << 32),
 137 
 138     //! Client uses TCP connection
 139     pcmk__client_tcp                    = (UINT64_C(1) << 33),
 140 
 141 #  ifdef HAVE_GNUTLS_GNUTLS_H
 142     //! Client uses TCP with TLS
 143     pcmk__client_tls                    = (UINT64_C(1) << 34),
 144 #  endif
 145 
 146     // The rest are client attributes
 147 
 148     //! Client IPC is proxied
 149     pcmk__client_proxied                = (UINT64_C(1) << 40),
 150 
 151     //! Client is run by root or cluster user
 152     pcmk__client_privileged             = (UINT64_C(1) << 41),
 153 
 154     //! Local client to be proxied
 155     pcmk__client_to_proxy               = (UINT64_C(1) << 42),
 156 
 157     /*!
 158      * \brief Client IPC connection accepted
 159      *
 160      * Used only for remote CIB connections via \c remote-tls-port.
 161      */
 162     pcmk__client_authenticated          = (UINT64_C(1) << 43),
 163 
 164 #  ifdef HAVE_GNUTLS_GNUTLS_H
 165     //! Client TLS handshake is complete
 166     pcmk__client_tls_handshake_complete = (UINT64_C(1) << 44),
 167 #  endif
 168 };
 169 
 170 #define PCMK__CLIENT_TYPE(client) ((client)->flags & UINT64_C(0xff00000000))
 171 
 172 struct pcmk__client_s {
 173     unsigned int pid;
 174 
 175     char *id;
 176     char *name;
 177     char *user;
 178     uint64_t flags; // Group of pcmk__client_flags
 179 
 180     int request_id;
 181     void *userdata;
 182 
 183     int event_timer;
 184     GQueue *event_queue;
 185 
 186     /* Depending on the client type, only some of the following will be
 187      * populated/valid. @TODO Maybe convert to a union.
 188      */
 189 
 190     qb_ipcs_connection_t *ipcs; /* IPC */
 191 
 192     struct pcmk__remote_s *remote;        /* TCP/TLS */
 193 
 194     unsigned int queue_backlog; /* IPC queue length after last flush */
 195     unsigned int queue_max;     /* Evict client whose queue grows this big */
 196 };
 197 
 198 #define pcmk__set_client_flags(client, flags_to_set) do {               \
 199         (client)->flags = pcmk__set_flags_as(__func__, __LINE__,        \
 200             LOG_TRACE,                                                  \
 201             "Client", pcmk__client_name(client),                        \
 202             (client)->flags, (flags_to_set), #flags_to_set);            \
 203     } while (0)
 204 
 205 #define pcmk__clear_client_flags(client, flags_to_clear) do {           \
 206         (client)->flags = pcmk__clear_flags_as(__func__, __LINE__,      \
 207             LOG_TRACE,                                                  \
 208             "Client", pcmk__client_name(client),                        \
 209             (client)->flags, (flags_to_clear), #flags_to_clear);        \
 210     } while (0)
 211 
 212 #define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set) do {         \
 213         ipc_flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE,       \
 214                                        "IPC", (ipc_name),                   \
 215                                        (ipc_flags), (flags_to_set),         \
 216                                        #flags_to_set);                      \
 217     } while (0)
 218 
 219 #define pcmk__clear_ipc_flags(ipc_flags, ipc_name, flags_to_clear) do {     \
 220         ipc_flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE,     \
 221                                          "IPC", (ipc_name),                 \
 222                                          (ipc_flags), (flags_to_clear),     \
 223                                          #flags_to_clear);                  \
 224     } while (0)
 225 
 226 guint pcmk__ipc_client_count(void);
 227 void pcmk__foreach_ipc_client(GHFunc func, gpointer user_data);
 228 
 229 void pcmk__client_cleanup(void);
 230 
 231 pcmk__client_t *pcmk__find_client(const qb_ipcs_connection_t *c);
 232 pcmk__client_t *pcmk__find_client_by_id(const char *id);
 233 const char *pcmk__client_name(const pcmk__client_t *c);
 234 const char *pcmk__client_type_str(uint64_t client_type);
 235 
 236 pcmk__client_t *pcmk__new_unauth_client(void *key);
 237 pcmk__client_t *pcmk__new_client(qb_ipcs_connection_t *c, uid_t uid, gid_t gid);
 238 void pcmk__free_client(pcmk__client_t *c);
 239 void pcmk__drop_all_clients(qb_ipcs_service_t *s);
 240 bool pcmk__set_client_queue_max(pcmk__client_t *client, const char *qmax);
 241 
 242 xmlNode *pcmk__ipc_create_ack_as(const char *function, int line, uint32_t flags,
 243                                  const char *tag, const char *ver, crm_exit_t status);
 244 #define pcmk__ipc_create_ack(flags, tag, ver, st) \
 245     pcmk__ipc_create_ack_as(__func__, __LINE__, (flags), (tag), (ver), (st))
 246 
 247 int pcmk__ipc_send_ack_as(const char *function, int line, pcmk__client_t *c,
 248                           uint32_t request, uint32_t flags, const char *tag,
 249                           const char *ver, crm_exit_t status);
 250 #define pcmk__ipc_send_ack(c, req, flags, tag, ver, st) \
 251     pcmk__ipc_send_ack_as(__func__, __LINE__, (c), (req), (flags), (tag), (ver), (st))
 252 
 253 int pcmk__ipc_prepare_iov(uint32_t request, const xmlNode *message,
 254                           uint32_t max_send_size,
 255                           struct iovec **result, ssize_t *bytes);
 256 int pcmk__ipc_send_xml(pcmk__client_t *c, uint32_t request,
 257                        const xmlNode *message, uint32_t flags);
 258 int pcmk__ipc_send_iov(pcmk__client_t *c, struct iovec *iov, uint32_t flags);
 259 xmlNode *pcmk__client_data2xml(pcmk__client_t *c, void *data,
 260                                uint32_t *id, uint32_t *flags);
 261 
 262 int pcmk__client_pid(qb_ipcs_connection_t *c);
 263 
 264 void pcmk__serve_attrd_ipc(qb_ipcs_service_t **ipcs,
 265                            struct qb_ipcs_service_handlers *cb);
 266 void pcmk__serve_fenced_ipc(qb_ipcs_service_t **ipcs,
 267                             struct qb_ipcs_service_handlers *cb);
 268 void pcmk__serve_pacemakerd_ipc(qb_ipcs_service_t **ipcs,
 269                                 struct qb_ipcs_service_handlers *cb);
 270 qb_ipcs_service_t *pcmk__serve_schedulerd_ipc(struct qb_ipcs_service_handlers *cb);
 271 qb_ipcs_service_t *pcmk__serve_controld_ipc(struct qb_ipcs_service_handlers *cb);
 272 
 273 void pcmk__serve_based_ipc(qb_ipcs_service_t **ipcs_ro,
 274                            qb_ipcs_service_t **ipcs_rw,
 275                            qb_ipcs_service_t **ipcs_shm,
 276                            struct qb_ipcs_service_handlers *ro_cb,
 277                            struct qb_ipcs_service_handlers *rw_cb);
 278 
 279 void pcmk__stop_based_ipc(qb_ipcs_service_t *ipcs_ro,
 280         qb_ipcs_service_t *ipcs_rw,
 281         qb_ipcs_service_t *ipcs_shm);
 282 
 283 static inline const char *
 284 pcmk__ipc_sys_name(const char *ipc_name, const char *fallback)
     /* [previous][next][first][last][top][bottom][index][help] */
 285 {
 286     return ipc_name ? ipc_name : ((crm_system_name ? crm_system_name : fallback));
 287 }
 288 
 289 const char *pcmk__pcmkd_state_enum2friendly(enum pcmk_pacemakerd_state state);
 290 
 291 const char *pcmk__controld_api_reply2str(enum pcmk_controld_api_reply reply);
 292 const char *pcmk__pcmkd_api_reply2str(enum pcmk_pacemakerd_api_reply reply);
 293 
 294 #ifdef __cplusplus
 295 }
 296 #endif
 297 
 298 #endif

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