root/lib/common/ipc_client.c

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

DEFINITIONS

This source file includes following definitions.
  1. pcmk_new_ipc_api
  2. free_daemon_specific_data
  3. pcmk__call_ipc_callback
  4. ipc_post_disconnect
  5. pcmk_free_ipc_api
  6. pcmk_ipc_name
  7. pcmk_ipc_is_connected
  8. call_api_dispatch
  9. dispatch_ipc_data
  10. dispatch_ipc_source_data
  11. pcmk_poll_ipc
  12. pcmk_dispatch_ipc
  13. connect_with_main_loop
  14. connect_without_main_loop
  15. pcmk__connect_ipc_retry_conrefused
  16. pcmk__connect_ipc
  17. pcmk_connect_ipc
  18. pcmk_disconnect_ipc
  19. pcmk_register_ipc_callback
  20. pcmk__send_ipc_request
  21. create_purge_node_request
  22. pcmk_ipc_purge_node
  23. crm_ipc_new
  24. pcmk__connect_generic_ipc
  25. crm_ipc_close
  26. crm_ipc_destroy
  27. pcmk__ipc_fd
  28. crm_ipc_get_fd
  29. crm_ipc_connected
  30. crm_ipc_ready
  31. crm_ipc_read
  32. pcmk__ipc_free_client_buffer
  33. crm_ipc_buffer
  34. crm_ipc_buffer_flags
  35. crm_ipc_name
  36. internal_ipc_get_reply
  37. discard_old_replies
  38. crm_ipc_send
  39. is_ipc_provider_expected
  40. crm_ipc_is_authentic_process
  41. pcmk__ipc_is_authentic_process_active
  42. crm_ipc_connect

   1 /*
   2  * Copyright 2004-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 #include <crm_internal.h>
  11 
  12 #if defined(HAVE_UCRED) || defined(HAVE_SOCKPEERCRED)
  13 #include <sys/socket.h>
  14 #elif defined(HAVE_GETPEERUCRED)
  15 #include <ucred.h>
  16 #endif
  17 
  18 #include <stdio.h>
  19 #include <sys/types.h>
  20 #include <errno.h>
  21 #include <bzlib.h>
  22 
  23 #include <crm/crm.h>   /* indirectly: pcmk_err_generic */
  24 #include <crm/common/xml.h>
  25 #include <crm/common/ipc.h>
  26 #include <crm/common/ipc_internal.h>
  27 #include "crmcommon_private.h"
  28 
  29 static int is_ipc_provider_expected(qb_ipcc_connection_t *qb_ipc, int sock,
  30                                     uid_t refuid, gid_t refgid, pid_t *gotpid,
  31                                     uid_t *gotuid, gid_t *gotgid);
  32 
  33 /*!
  34  * \brief Create a new object for using Pacemaker daemon IPC
  35  *
  36  * \param[out] api     Where to store new IPC object
  37  * \param[in]  server  Which Pacemaker daemon the object is for
  38  *
  39  * \return Standard Pacemaker result code
  40  *
  41  * \note The caller is responsible for freeing *api using pcmk_free_ipc_api().
  42  * \note This is intended to supersede crm_ipc_new() but currently only
  43  *       supports the controller, pacemakerd, and schedulerd IPC API.
  44  */
  45 int
  46 pcmk_new_ipc_api(pcmk_ipc_api_t **api, enum pcmk_ipc_server server)
     /* [previous][next][first][last][top][bottom][index][help] */
  47 {
  48     if (api == NULL) {
  49         return EINVAL;
  50     }
  51 
  52     *api = calloc(1, sizeof(pcmk_ipc_api_t));
  53     if (*api == NULL) {
  54         return errno;
  55     }
  56 
  57     (*api)->server = server;
  58     if (pcmk_ipc_name(*api, false) == NULL) {
  59         pcmk_free_ipc_api(*api);
  60         *api = NULL;
  61         return EOPNOTSUPP;
  62     }
  63 
  64     // Set server methods
  65     switch (server) {
  66         case pcmk_ipc_attrd:
  67             (*api)->cmds = pcmk__attrd_api_methods();
  68             break;
  69 
  70         case pcmk_ipc_based:
  71             break;
  72 
  73         case pcmk_ipc_controld:
  74             (*api)->cmds = pcmk__controld_api_methods();
  75             break;
  76 
  77         case pcmk_ipc_execd:
  78             break;
  79 
  80         case pcmk_ipc_fenced:
  81             break;
  82 
  83         case pcmk_ipc_pacemakerd:
  84             (*api)->cmds = pcmk__pacemakerd_api_methods();
  85             break;
  86 
  87         case pcmk_ipc_schedulerd:
  88             (*api)->cmds = pcmk__schedulerd_api_methods();
  89             break;
  90 
  91         default: // pcmk_ipc_unknown
  92             pcmk_free_ipc_api(*api);
  93             *api = NULL;
  94             return EINVAL;
  95     }
  96     if ((*api)->cmds == NULL) {
  97         pcmk_free_ipc_api(*api);
  98         *api = NULL;
  99         return ENOMEM;
 100     }
 101 
 102     (*api)->ipc = crm_ipc_new(pcmk_ipc_name(*api, false), 0);
 103     if ((*api)->ipc == NULL) {
 104         pcmk_free_ipc_api(*api);
 105         *api = NULL;
 106         return ENOMEM;
 107     }
 108 
 109     // If daemon API has its own data to track, allocate it
 110     if ((*api)->cmds->new_data != NULL) {
 111         if ((*api)->cmds->new_data(*api) != pcmk_rc_ok) {
 112             pcmk_free_ipc_api(*api);
 113             *api = NULL;
 114             return ENOMEM;
 115         }
 116     }
 117     crm_trace("Created %s API IPC object", pcmk_ipc_name(*api, true));
 118     return pcmk_rc_ok;
 119 }
 120 
 121 static void
 122 free_daemon_specific_data(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 123 {
 124     if ((api != NULL) && (api->cmds != NULL)) {
 125         if ((api->cmds->free_data != NULL) && (api->api_data != NULL)) {
 126             api->cmds->free_data(api->api_data);
 127             api->api_data = NULL;
 128         }
 129         free(api->cmds);
 130         api->cmds = NULL;
 131     }
 132 }
 133 
 134 /*!
 135  * \internal
 136  * \brief Call an IPC API event callback, if one is registed
 137  *
 138  * \param[in,out] api         IPC API connection
 139  * \param[in]     event_type  The type of event that occurred
 140  * \param[in]     status      Event status
 141  * \param[in,out] event_data  Event-specific data
 142  */
 143 void
 144 pcmk__call_ipc_callback(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type,
     /* [previous][next][first][last][top][bottom][index][help] */
 145                         crm_exit_t status, void *event_data)
 146 {
 147     if ((api != NULL) && (api->cb != NULL)) {
 148         api->cb(api, event_type, status, event_data, api->user_data);
 149     }
 150 }
 151 
 152 /*!
 153  * \internal
 154  * \brief Clean up after an IPC disconnect
 155  *
 156  * \param[in,out] user_data  IPC API connection that disconnected
 157  *
 158  * \note This function can be used as a main loop IPC destroy callback.
 159  */
 160 static void
 161 ipc_post_disconnect(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 162 {
 163     pcmk_ipc_api_t *api = user_data;
 164 
 165     crm_info("Disconnected from %s", pcmk_ipc_name(api, true));
 166 
 167     // Perform any daemon-specific handling needed
 168     if ((api->cmds != NULL) && (api->cmds->post_disconnect != NULL)) {
 169         api->cmds->post_disconnect(api);
 170     }
 171 
 172     // Call client's registered event callback
 173     pcmk__call_ipc_callback(api, pcmk_ipc_event_disconnect, CRM_EX_DISCONNECT,
 174                             NULL);
 175 
 176     /* If this is being called from a running main loop, mainloop_gio_destroy()
 177      * will free ipc and mainloop_io immediately after calling this function.
 178      * If this is called from a stopped main loop, these will leak, so the best
 179      * practice is to close the connection before stopping the main loop.
 180      */
 181     api->ipc = NULL;
 182     api->mainloop_io = NULL;
 183 
 184     if (api->free_on_disconnect) {
 185         /* pcmk_free_ipc_api() has already been called, but did not free api
 186          * or api->cmds because this function needed them. Do that now.
 187          */
 188         free_daemon_specific_data(api);
 189         crm_trace("Freeing IPC API object after disconnect");
 190         free(api);
 191     }
 192 }
 193 
 194 /*!
 195  * \brief Free the contents of an IPC API object
 196  *
 197  * \param[in,out] api  IPC API object to free
 198  */
 199 void
 200 pcmk_free_ipc_api(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 201 {
 202     bool free_on_disconnect = false;
 203 
 204     if (api == NULL) {
 205         return;
 206     }
 207     crm_debug("Releasing %s IPC API", pcmk_ipc_name(api, true));
 208 
 209     if (api->ipc != NULL) {
 210         if (api->mainloop_io != NULL) {
 211             /* We need to keep the api pointer itself around, because it is the
 212              * user data for the IPC client destroy callback. That will be
 213              * triggered by the pcmk_disconnect_ipc() call below, but it might
 214              * happen later in the main loop (if still running).
 215              *
 216              * This flag tells the destroy callback to free the object. It can't
 217              * do that unconditionally, because the application might call this
 218              * function after a disconnect that happened by other means.
 219              */
 220             free_on_disconnect = api->free_on_disconnect = true;
 221         }
 222         pcmk_disconnect_ipc(api); // Frees api if free_on_disconnect is true
 223     }
 224     if (!free_on_disconnect) {
 225         free_daemon_specific_data(api);
 226         crm_trace("Freeing IPC API object");
 227         free(api);
 228     }
 229 }
 230 
 231 /*!
 232  * \brief Get the IPC name used with an IPC API connection
 233  *
 234  * \param[in] api      IPC API connection
 235  * \param[in] for_log  If true, return human-friendly name instead of IPC name
 236  *
 237  * \return IPC API's human-friendly or connection name, or if none is available,
 238  *         "Pacemaker" if for_log is true and NULL if for_log is false
 239  */
 240 const char *
 241 pcmk_ipc_name(const pcmk_ipc_api_t *api, bool for_log)
     /* [previous][next][first][last][top][bottom][index][help] */
 242 {
 243     if (api == NULL) {
 244         return for_log? "Pacemaker" : NULL;
 245     }
 246     if (for_log) {
 247         const char *name = pcmk__server_log_name(api->server);
 248 
 249         return pcmk__s(name, "Pacemaker");
 250     }
 251     switch (api->server) {
 252         // These servers do not have pcmk_ipc_api_t implementations yet
 253         case pcmk_ipc_based:
 254         case pcmk_ipc_execd:
 255         case pcmk_ipc_fenced:
 256             return NULL;
 257 
 258         default:
 259             return pcmk__server_ipc_name(api->server);
 260     }
 261 }
 262 
 263 /*!
 264  * \brief Check whether an IPC API connection is active
 265  *
 266  * \param[in,out] api  IPC API connection
 267  *
 268  * \return true if IPC is connected, false otherwise
 269  */
 270 bool
 271 pcmk_ipc_is_connected(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 272 {
 273     return (api != NULL) && crm_ipc_connected(api->ipc);
 274 }
 275 
 276 /*!
 277  * \internal
 278  * \brief Call the daemon-specific API's dispatch function
 279  *
 280  * Perform daemon-specific handling of IPC reply dispatch. It is the daemon
 281  * method's responsibility to call the client's registered event callback, as
 282  * well as allocate and free any event data.
 283  *
 284  * \param[in,out] api      IPC API connection
 285  * \param[in,out] message  IPC reply XML to dispatch
 286  */
 287 static bool
 288 call_api_dispatch(pcmk_ipc_api_t *api, xmlNode *message)
     /* [previous][next][first][last][top][bottom][index][help] */
 289 {
 290     crm_log_xml_trace(message, "ipc-received");
 291     if ((api->cmds != NULL) && (api->cmds->dispatch != NULL)) {
 292         return api->cmds->dispatch(api, message);
 293     }
 294 
 295     return false;
 296 }
 297 
 298 /*!
 299  * \internal
 300  * \brief Dispatch previously read IPC data
 301  *
 302  * \param[in]     buffer  Data read from IPC
 303  * \param[in,out] api     IPC object
 304  *
 305  * \return Standard Pacemaker return code.  In particular:
 306  *
 307  * pcmk_rc_ok: There are no more messages expected from the server.  Quit
 308  *             reading.
 309  * EINPROGRESS: There are more messages expected from the server.  Keep reading.
 310  *
 311  * All other values indicate an error.
 312  */
 313 static int
 314 dispatch_ipc_data(const char *buffer, pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 315 {
 316     bool more = false;
 317     xmlNode *msg;
 318 
 319     if (buffer == NULL) {
 320         crm_warn("Empty message received from %s IPC",
 321                  pcmk_ipc_name(api, true));
 322         return ENOMSG;
 323     }
 324 
 325     msg = pcmk__xml_parse(buffer);
 326     if (msg == NULL) {
 327         crm_warn("Malformed message received from %s IPC",
 328                  pcmk_ipc_name(api, true));
 329         return EPROTO;
 330     }
 331 
 332     more = call_api_dispatch(api, msg);
 333     pcmk__xml_free(msg);
 334 
 335     if (more) {
 336         return EINPROGRESS;
 337     } else {
 338         return pcmk_rc_ok;
 339     }
 340 }
 341 
 342 /*!
 343  * \internal
 344  * \brief Dispatch data read from IPC source
 345  *
 346  * \param[in]     buffer     Data read from IPC
 347  * \param[in]     length     Number of bytes of data in buffer (ignored)
 348  * \param[in,out] user_data  IPC object
 349  *
 350  * \return Always 0 (meaning connection is still required)
 351  *
 352  * \note This function can be used as a main loop IPC dispatch callback.
 353  */
 354 static int
 355 dispatch_ipc_source_data(const char *buffer, ssize_t length, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 356 {
 357     pcmk_ipc_api_t *api = user_data;
 358 
 359     CRM_CHECK(api != NULL, return 0);
 360     dispatch_ipc_data(buffer, api);
 361     return 0;
 362 }
 363 
 364 /*!
 365  * \brief Check whether an IPC connection has data available (without main loop)
 366  *
 367  * \param[in]  api         IPC API connection
 368  * \param[in]  timeout_ms  If less than 0, poll indefinitely; if 0, poll once
 369  *                         and return immediately; otherwise, poll for up to
 370  *                         this many milliseconds
 371  *
 372  * \return Standard Pacemaker return code
 373  *
 374  * \note Callers of pcmk_connect_ipc() using pcmk_ipc_dispatch_poll should call
 375  *       this function to check whether IPC data is available. Return values of
 376  *       interest include pcmk_rc_ok meaning data is available, and EAGAIN
 377  *       meaning no data is available; all other values indicate errors.
 378  * \todo This does not allow the caller to poll multiple file descriptors at
 379  *       once. If there is demand for that, we could add a wrapper for
 380  *       pcmk__ipc_fd(api->ipc), so the caller can call poll() themselves.
 381  */
 382 int
 383 pcmk_poll_ipc(const pcmk_ipc_api_t *api, int timeout_ms)
     /* [previous][next][first][last][top][bottom][index][help] */
 384 {
 385     int rc;
 386     struct pollfd pollfd = { 0, };
 387 
 388     if ((api == NULL) || (api->dispatch_type != pcmk_ipc_dispatch_poll)) {
 389         return EINVAL;
 390     }
 391 
 392     rc = pcmk__ipc_fd(api->ipc, &(pollfd.fd));
 393     if (rc != pcmk_rc_ok) {
 394         crm_debug("Could not obtain file descriptor for %s IPC: %s",
 395                   pcmk_ipc_name(api, true), pcmk_rc_str(rc));
 396         return rc;
 397     }
 398 
 399     pollfd.events = POLLIN;
 400     rc = poll(&pollfd, 1, timeout_ms);
 401     if (rc < 0) {
 402         /* Some UNIX systems return negative and set EAGAIN for failure to
 403          * allocate memory; standardize the return code in that case
 404          */
 405         return (errno == EAGAIN)? ENOMEM : errno;
 406     } else if (rc == 0) {
 407         return EAGAIN;
 408     }
 409     return pcmk_rc_ok;
 410 }
 411 
 412 /*!
 413  * \brief Dispatch available messages on an IPC connection (without main loop)
 414  *
 415  * \param[in,out] api  IPC API connection
 416  *
 417  * \return Standard Pacemaker return code
 418  *
 419  * \note Callers of pcmk_connect_ipc() using pcmk_ipc_dispatch_poll should call
 420  *       this function when IPC data is available.
 421  */
 422 void
 423 pcmk_dispatch_ipc(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 424 {
 425     if (api == NULL) {
 426         return;
 427     }
 428     while (crm_ipc_ready(api->ipc) > 0) {
 429         if (crm_ipc_read(api->ipc) > 0) {
 430             dispatch_ipc_data(crm_ipc_buffer(api->ipc), api);
 431             pcmk__ipc_free_client_buffer(api->ipc);
 432         }
 433     }
 434 }
 435 
 436 // \return Standard Pacemaker return code
 437 static int
 438 connect_with_main_loop(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 439 {
 440     int rc;
 441 
 442     struct ipc_client_callbacks callbacks = {
 443         .dispatch = dispatch_ipc_source_data,
 444         .destroy = ipc_post_disconnect,
 445     };
 446 
 447     rc = pcmk__add_mainloop_ipc(api->ipc, G_PRIORITY_DEFAULT, api,
 448                                 &callbacks, &(api->mainloop_io));
 449     if (rc != pcmk_rc_ok) {
 450         return rc;
 451     }
 452     crm_debug("Connected to %s IPC (attached to main loop)",
 453               pcmk_ipc_name(api, true));
 454     /* After this point, api->mainloop_io owns api->ipc, so api->ipc
 455      * should not be explicitly freed.
 456      */
 457     return pcmk_rc_ok;
 458 }
 459 
 460 // \return Standard Pacemaker return code
 461 static int
 462 connect_without_main_loop(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 463 {
 464     int rc = pcmk__connect_generic_ipc(api->ipc);
 465 
 466     if (rc != pcmk_rc_ok) {
 467         crm_ipc_close(api->ipc);
 468     } else {
 469         crm_debug("Connected to %s IPC (without main loop)",
 470                   pcmk_ipc_name(api, true));
 471     }
 472     return rc;
 473 }
 474 
 475 /*!
 476  * \internal
 477  * \brief Connect to a Pacemaker daemon via IPC (retrying after soft errors
 478  *        and ECONNREFUSED)
 479  *
 480  * \param[in,out] api            IPC API instance
 481  * \param[in]     dispatch_type  How IPC replies should be dispatched
 482  * \param[in]     attempts       How many times to try (in case of soft error)
 483  *
 484  * \return Standard Pacemaker return code
 485  */
 486 int
 487 pcmk__connect_ipc_retry_conrefused(pcmk_ipc_api_t *api,
     /* [previous][next][first][last][top][bottom][index][help] */
 488                                    enum pcmk_ipc_dispatch dispatch_type,
 489                                    int attempts)
 490 {
 491     int remaining = attempts;
 492     int rc = pcmk_rc_ok;
 493 
 494     do {
 495         if (rc == ECONNREFUSED) {
 496             pcmk__sleep_ms((attempts - remaining) * 500);
 497         }
 498         rc = pcmk__connect_ipc(api, dispatch_type, remaining);
 499         remaining--;
 500     } while (rc == ECONNREFUSED && remaining >= 0);
 501 
 502     return rc;
 503 }
 504 
 505 
 506 /*!
 507  * \internal
 508  * \brief Connect to a Pacemaker daemon via IPC (retrying after soft errors)
 509  *
 510  * \param[in,out] api            IPC API instance
 511  * \param[in]     dispatch_type  How IPC replies should be dispatched
 512  * \param[in]     attempts       How many times to try (in case of soft error)
 513  *
 514  * \return Standard Pacemaker return code
 515  */
 516 int
 517 pcmk__connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type,
     /* [previous][next][first][last][top][bottom][index][help] */
 518                   int attempts)
 519 {
 520     int rc = pcmk_rc_ok;
 521 
 522     if ((api == NULL) || (attempts < 1)) {
 523         return EINVAL;
 524     }
 525 
 526     if (api->ipc == NULL) {
 527         api->ipc = crm_ipc_new(pcmk_ipc_name(api, false), 0);
 528         if (api->ipc == NULL) {
 529             return ENOMEM;
 530         }
 531     }
 532 
 533     if (crm_ipc_connected(api->ipc)) {
 534         crm_trace("Already connected to %s", pcmk_ipc_name(api, true));
 535         return pcmk_rc_ok;
 536     }
 537 
 538     api->dispatch_type = dispatch_type;
 539 
 540     crm_debug("Attempting connection to %s (up to %d time%s)",
 541               pcmk_ipc_name(api, true), attempts, pcmk__plural_s(attempts));
 542     for (int remaining = attempts - 1; remaining >= 0; --remaining) {
 543         switch (dispatch_type) {
 544             case pcmk_ipc_dispatch_main:
 545                 rc = connect_with_main_loop(api);
 546                 break;
 547 
 548             case pcmk_ipc_dispatch_sync:
 549             case pcmk_ipc_dispatch_poll:
 550                 rc = connect_without_main_loop(api);
 551                 break;
 552         }
 553 
 554         if ((remaining == 0) || ((rc != EAGAIN) && (rc != EALREADY))) {
 555             break; // Result is final
 556         }
 557 
 558         // Retry after soft error (interrupted by signal, etc.)
 559         pcmk__sleep_ms((attempts - remaining) * 500);
 560         crm_debug("Re-attempting connection to %s (%d attempt%s remaining)",
 561                   pcmk_ipc_name(api, true), remaining,
 562                   pcmk__plural_s(remaining));
 563     }
 564 
 565     if (rc != pcmk_rc_ok) {
 566         return rc;
 567     }
 568 
 569     if ((api->cmds != NULL) && (api->cmds->post_connect != NULL)) {
 570         rc = api->cmds->post_connect(api);
 571         if (rc != pcmk_rc_ok) {
 572             crm_ipc_close(api->ipc);
 573         }
 574     }
 575     return rc;
 576 }
 577 
 578 /*!
 579  * \brief Connect to a Pacemaker daemon via IPC
 580  *
 581  * \param[in,out] api            IPC API instance
 582  * \param[in]     dispatch_type  How IPC replies should be dispatched
 583  *
 584  * \return Standard Pacemaker return code
 585  */
 586 int
 587 pcmk_connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type)
     /* [previous][next][first][last][top][bottom][index][help] */
 588 {
 589     int rc = pcmk__connect_ipc(api, dispatch_type, 2);
 590 
 591     if (rc != pcmk_rc_ok) {
 592         crm_err("Connection to %s failed: %s",
 593                 pcmk_ipc_name(api, true), pcmk_rc_str(rc));
 594     }
 595     return rc;
 596 }
 597 
 598 /*!
 599  * \brief Disconnect an IPC API instance
 600  *
 601  * \param[in,out] api  IPC API connection
 602  *
 603  * \return Standard Pacemaker return code
 604  *
 605  * \note If the connection is attached to a main loop, this function should be
 606  *       called before quitting the main loop, to ensure that all memory is
 607  *       freed.
 608  */
 609 void
 610 pcmk_disconnect_ipc(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 611 {
 612     if ((api == NULL) || (api->ipc == NULL)) {
 613         return;
 614     }
 615     switch (api->dispatch_type) {
 616         case pcmk_ipc_dispatch_main:
 617             {
 618                 mainloop_io_t *mainloop_io = api->mainloop_io;
 619 
 620                 // Make sure no code with access to api can use these again
 621                 api->mainloop_io = NULL;
 622                 api->ipc = NULL;
 623 
 624                 mainloop_del_ipc_client(mainloop_io);
 625                 // After this point api might have already been freed
 626             }
 627             break;
 628 
 629         case pcmk_ipc_dispatch_poll:
 630         case pcmk_ipc_dispatch_sync:
 631             {
 632                 crm_ipc_t *ipc = api->ipc;
 633 
 634                 // Make sure no code with access to api can use ipc again
 635                 api->ipc = NULL;
 636 
 637                 // This should always be the case already, but to be safe
 638                 api->free_on_disconnect = false;
 639 
 640                 crm_ipc_close(ipc);
 641                 crm_ipc_destroy(ipc);
 642                 ipc_post_disconnect(api);
 643             }
 644             break;
 645     }
 646 }
 647 
 648 /*!
 649  * \brief Register a callback for IPC API events
 650  *
 651  * \param[in,out] api       IPC API connection
 652  * \param[in]     callback  Callback to register
 653  * \param[in]     userdata  Caller data to pass to callback
 654  *
 655  * \note This function may be called multiple times to update the callback
 656  *       and/or user data. The caller remains responsible for freeing
 657  *       userdata in any case (after the IPC is disconnected, if the
 658  *       user data is still registered with the IPC).
 659  */
 660 void
 661 pcmk_register_ipc_callback(pcmk_ipc_api_t *api, pcmk_ipc_callback_t cb,
     /* [previous][next][first][last][top][bottom][index][help] */
 662                            void *user_data)
 663 {
 664     if (api == NULL) {
 665         return;
 666     }
 667     api->cb = cb;
 668     api->user_data = user_data;
 669 }
 670 
 671 /*!
 672  * \internal
 673  * \brief Send an XML request across an IPC API connection
 674  *
 675  * \param[in,out] api      IPC API connection
 676  * \param[in]     request  XML request to send
 677  *
 678  * \return Standard Pacemaker return code
 679  *
 680  * \note Daemon-specific IPC API functions should call this function to send
 681  *       requests, because it handles different dispatch types appropriately.
 682  */
 683 int
 684 pcmk__send_ipc_request(pcmk_ipc_api_t *api, const xmlNode *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 685 {
 686     int rc;
 687     xmlNode *reply = NULL;
 688     enum crm_ipc_flags flags = crm_ipc_flags_none;
 689 
 690     if ((api == NULL) || (api->ipc == NULL) || (request == NULL)) {
 691         return EINVAL;
 692     }
 693     crm_log_xml_trace(request, "ipc-sent");
 694 
 695     // Synchronous dispatch requires waiting for a reply
 696     if ((api->dispatch_type == pcmk_ipc_dispatch_sync)
 697         && (api->cmds != NULL)
 698         && (api->cmds->reply_expected != NULL)
 699         && (api->cmds->reply_expected(api, request))) {
 700         flags = crm_ipc_client_response;
 701     }
 702 
 703     /* The 0 here means a default timeout of 5 seconds
 704      *
 705      * @TODO Maybe add a timeout_ms member to pcmk_ipc_api_t and a
 706      * pcmk_set_ipc_timeout() setter for it, then use it here.
 707      */
 708     rc = crm_ipc_send(api->ipc, request, flags, 0, &reply);
 709 
 710     if (rc < 0) {
 711         return pcmk_legacy2rc(rc);
 712     } else if (rc == 0) {
 713         return ENODATA;
 714     }
 715 
 716     // With synchronous dispatch, we dispatch any reply now
 717     if (reply != NULL) {
 718         bool more = call_api_dispatch(api, reply);
 719 
 720         pcmk__xml_free(reply);
 721 
 722         while (more) {
 723             rc = crm_ipc_read(api->ipc);
 724 
 725             if (rc == -EAGAIN) {
 726                 continue;
 727             } else if (rc == -ENOMSG || rc == pcmk_ok) {
 728                 return pcmk_rc_ok;
 729             } else if (rc < 0) {
 730                 return -rc;
 731             }
 732 
 733             rc = dispatch_ipc_data(crm_ipc_buffer(api->ipc), api);
 734             pcmk__ipc_free_client_buffer(api->ipc);
 735 
 736             if (rc == pcmk_rc_ok) {
 737                 more = false;
 738             } else if (rc == EINPROGRESS) {
 739                 more = true;
 740             } else {
 741                 continue;
 742             }
 743         }
 744     }
 745     return pcmk_rc_ok;
 746 }
 747 
 748 /*!
 749  * \internal
 750  * \brief Create the XML for an IPC request to purge a node from the peer cache
 751  *
 752  * \param[in]  api        IPC API connection
 753  * \param[in]  node_name  If not NULL, name of node to purge
 754  * \param[in]  nodeid     If not 0, node ID of node to purge
 755  *
 756  * \return Newly allocated IPC request XML
 757  *
 758  * \note The controller, fencer, and pacemakerd use the same request syntax, but
 759  *       the attribute manager uses a different one. The CIB manager doesn't
 760  *       have any syntax for it. The executor and scheduler don't connect to the
 761  *       cluster layer and thus don't have or need any syntax for it.
 762  *
 763  * \todo Modify the attribute manager to accept the common syntax (as well
 764  *       as its current one, for compatibility with older clients). Modify
 765  *       the CIB manager to accept and honor the common syntax. Modify the
 766  *       executor and scheduler to accept the syntax (immediately returning
 767  *       success), just for consistency. Modify this function to use the
 768  *       common syntax with all daemons if their version supports it.
 769  */
 770 static xmlNode *
 771 create_purge_node_request(const pcmk_ipc_api_t *api, const char *node_name,
     /* [previous][next][first][last][top][bottom][index][help] */
 772                           uint32_t nodeid)
 773 {
 774     xmlNode *request = NULL;
 775     const char *client = crm_system_name? crm_system_name : "client";
 776 
 777     switch (api->server) {
 778         case pcmk_ipc_attrd:
 779             request = pcmk__xe_create(NULL, __func__);
 780             crm_xml_add(request, PCMK__XA_T, PCMK__VALUE_ATTRD);
 781             crm_xml_add(request, PCMK__XA_SRC, crm_system_name);
 782             crm_xml_add(request, PCMK_XA_TASK, PCMK__ATTRD_CMD_PEER_REMOVE);
 783             pcmk__xe_set_bool_attr(request, PCMK__XA_REAP, true);
 784             crm_xml_add(request, PCMK__XA_ATTR_HOST, node_name);
 785             if (nodeid > 0) {
 786                 crm_xml_add_int(request, PCMK__XA_ATTR_HOST_ID, nodeid);
 787             }
 788             break;
 789 
 790         case pcmk_ipc_controld:
 791         case pcmk_ipc_fenced:
 792         case pcmk_ipc_pacemakerd:
 793             request = pcmk__new_request(api->server, client, NULL,
 794                                         pcmk_ipc_name(api, false),
 795                                         CRM_OP_RM_NODE_CACHE, NULL);
 796             if (nodeid > 0) {
 797                 crm_xml_add_ll(request, PCMK_XA_ID, (long long) nodeid);
 798             }
 799             crm_xml_add(request, PCMK_XA_UNAME, node_name);
 800             break;
 801 
 802         case pcmk_ipc_based:
 803         case pcmk_ipc_execd:
 804         case pcmk_ipc_schedulerd:
 805             break;
 806 
 807         default: // pcmk_ipc_unknown (shouldn't be possible)
 808             return NULL;
 809     }
 810     return request;
 811 }
 812 
 813 /*!
 814  * \brief Ask a Pacemaker daemon to purge a node from its peer cache
 815  *
 816  * \param[in,out] api        IPC API connection
 817  * \param[in]     node_name  If not NULL, name of node to purge
 818  * \param[in]     nodeid     If not 0, node ID of node to purge
 819  *
 820  * \return Standard Pacemaker return code
 821  *
 822  * \note At least one of node_name or nodeid must be specified.
 823  */
 824 int
 825 pcmk_ipc_purge_node(pcmk_ipc_api_t *api, const char *node_name, uint32_t nodeid)
     /* [previous][next][first][last][top][bottom][index][help] */
 826 {
 827     int rc = 0;
 828     xmlNode *request = NULL;
 829 
 830     if (api == NULL) {
 831         return EINVAL;
 832     }
 833     if ((node_name == NULL) && (nodeid == 0)) {
 834         return EINVAL;
 835     }
 836 
 837     request = create_purge_node_request(api, node_name, nodeid);
 838     if (request == NULL) {
 839         return EOPNOTSUPP;
 840     }
 841     rc = pcmk__send_ipc_request(api, request);
 842     pcmk__xml_free(request);
 843 
 844     crm_debug("%s peer cache purge of node %s[%lu]: rc=%d",
 845               pcmk_ipc_name(api, true), node_name, (unsigned long) nodeid, rc);
 846     return rc;
 847 }
 848 
 849 /*
 850  * Generic IPC API (to eventually be deprecated as public API and made internal)
 851  */
 852 
 853 struct crm_ipc_s {
 854     struct pollfd pfd;
 855     int need_reply;
 856     GByteArray *buffer;
 857     char *server_name;          // server IPC name being connected to
 858     qb_ipcc_connection_t *ipc;
 859 };
 860 
 861 /*!
 862  * \brief Create a new (legacy) object for using Pacemaker daemon IPC
 863  *
 864  * \param[in] name      IPC system name to connect to
 865  * \param[in] max_size  Use a maximum IPC buffer size of at least this size
 866  *
 867  * \return Newly allocated IPC object on success, NULL otherwise
 868  *
 869  * \note The caller is responsible for freeing the result using
 870  *       crm_ipc_destroy().
 871  * \note This should be considered deprecated for use with daemons supported by
 872  *       pcmk_new_ipc_api().
 873  * \note @COMPAT Since 3.0.1, \p max_size is ignored and the default given by
 874  *       \c crm_ipc_default_buffer_size() will be used instead.
 875  */
 876 crm_ipc_t *
 877 crm_ipc_new(const char *name, size_t max_size)
     /* [previous][next][first][last][top][bottom][index][help] */
 878 {
 879     crm_ipc_t *client = NULL;
 880 
 881     client = calloc(1, sizeof(crm_ipc_t));
 882     if (client == NULL) {
 883         crm_err("Could not create IPC connection: %s", strerror(errno));
 884         return NULL;
 885     }
 886 
 887     client->server_name = strdup(name);
 888     if (client->server_name == NULL) {
 889         crm_err("Could not create %s IPC connection: %s",
 890                 name, strerror(errno));
 891         free(client);
 892         return NULL;
 893     }
 894 
 895     client->buffer = NULL;
 896     client->pfd.fd = -1;
 897     client->pfd.events = POLLIN;
 898     client->pfd.revents = 0;
 899 
 900     return client;
 901 }
 902 
 903 /*!
 904  * \internal
 905  * \brief Connect a generic (not daemon-specific) IPC object
 906  *
 907  * \param[in,out] ipc  Generic IPC object to connect
 908  *
 909  * \return Standard Pacemaker return code
 910  */
 911 int
 912 pcmk__connect_generic_ipc(crm_ipc_t *ipc)
     /* [previous][next][first][last][top][bottom][index][help] */
 913 {
 914     uid_t cl_uid = 0;
 915     gid_t cl_gid = 0;
 916     pid_t found_pid = 0;
 917     uid_t found_uid = 0;
 918     gid_t found_gid = 0;
 919     int rc = pcmk_rc_ok;
 920 
 921     if (ipc == NULL) {
 922         return EINVAL;
 923     }
 924 
 925     ipc->need_reply = FALSE;
 926     ipc->ipc = qb_ipcc_connect(ipc->server_name, crm_ipc_default_buffer_size());
 927     if (ipc->ipc == NULL) {
 928         return errno;
 929     }
 930 
 931     rc = qb_ipcc_fd_get(ipc->ipc, &ipc->pfd.fd);
 932     if (rc < 0) { // -errno
 933         crm_ipc_close(ipc);
 934         return -rc;
 935     }
 936 
 937     rc = pcmk_daemon_user(&cl_uid, &cl_gid);
 938     rc = pcmk_legacy2rc(rc);
 939     if (rc != pcmk_rc_ok) {
 940         crm_ipc_close(ipc);
 941         return rc;
 942     }
 943 
 944     rc = is_ipc_provider_expected(ipc->ipc, ipc->pfd.fd, cl_uid, cl_gid,
 945                                   &found_pid, &found_uid, &found_gid);
 946     if (rc != pcmk_rc_ok) {
 947         if (rc == pcmk_rc_ipc_unauthorized) {
 948             crm_info("%s IPC provider authentication failed: process %lld has "
 949                      "uid %lld (expected %lld) and gid %lld (expected %lld)",
 950                      ipc->server_name,
 951                      (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 952                      (long long) found_uid, (long long) cl_uid,
 953                      (long long) found_gid, (long long) cl_gid);
 954         }
 955         crm_ipc_close(ipc);
 956         return rc;
 957     }
 958 
 959     return pcmk_rc_ok;
 960 }
 961 
 962 void
 963 crm_ipc_close(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
 964 {
 965     if (client) {
 966         if (client->ipc) {
 967             qb_ipcc_connection_t *ipc = client->ipc;
 968 
 969             client->ipc = NULL;
 970             qb_ipcc_disconnect(ipc);
 971         }
 972     }
 973 }
 974 
 975 void
 976 crm_ipc_destroy(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
 977 {
 978     if (client) {
 979         if (client->ipc && qb_ipcc_is_connected(client->ipc)) {
 980             crm_notice("Destroying active %s IPC connection",
 981                        client->server_name);
 982             /* The next line is basically unsafe
 983              *
 984              * If this connection was attached to mainloop and mainloop is active,
 985              *   the 'disconnected' callback will end up back here and we'll end
 986              *   up free'ing the memory twice - something that can still happen
 987              *   even without this if we destroy a connection and it closes before
 988              *   we call exit
 989              */
 990             /* crm_ipc_close(client); */
 991         } else {
 992             crm_trace("Destroying inactive %s IPC connection",
 993                       client->server_name);
 994         }
 995 
 996         if (client->buffer != NULL) {
 997             pcmk__ipc_free_client_buffer(client);
 998         }
 999 
1000         free(client->server_name);
1001         free(client);
1002     }
1003 }
1004 
1005 /*!
1006  * \internal
1007  * \brief Get the file descriptor for a generic IPC object
1008  *
1009  * \param[in,out] ipc  Generic IPC object to get file descriptor for
1010  * \param[out]    fd   Where to store file descriptor
1011  *
1012  * \return Standard Pacemaker return code
1013  */
1014 int
1015 pcmk__ipc_fd(crm_ipc_t *ipc, int *fd)
     /* [previous][next][first][last][top][bottom][index][help] */
1016 {
1017     if ((ipc == NULL) || (fd == NULL)) {
1018         return EINVAL;
1019     }
1020     if ((ipc->ipc == NULL) || (ipc->pfd.fd < 0)) {
1021         return ENOTCONN;
1022     }
1023     *fd = ipc->pfd.fd;
1024     return pcmk_rc_ok;
1025 }
1026 
1027 int
1028 crm_ipc_get_fd(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
1029 {
1030     int fd = -1;
1031 
1032     if (pcmk__ipc_fd(client, &fd) != pcmk_rc_ok) {
1033         crm_err("Could not obtain file descriptor for %s IPC",
1034                 ((client == NULL)? "unspecified" : client->server_name));
1035         errno = EINVAL;
1036         return -EINVAL;
1037     }
1038     return fd;
1039 }
1040 
1041 bool
1042 crm_ipc_connected(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
1043 {
1044     bool rc = FALSE;
1045 
1046     if (client == NULL) {
1047         crm_trace("No client");
1048         return FALSE;
1049 
1050     } else if (client->ipc == NULL) {
1051         crm_trace("No connection");
1052         return FALSE;
1053 
1054     } else if (client->pfd.fd < 0) {
1055         crm_trace("Bad descriptor");
1056         return FALSE;
1057     }
1058 
1059     rc = qb_ipcc_is_connected(client->ipc);
1060     if (rc == FALSE) {
1061         client->pfd.fd = -EINVAL;
1062     }
1063     return rc;
1064 }
1065 
1066 /*!
1067  * \brief Check whether an IPC connection is ready to be read
1068  *
1069  * \param[in,out] client  Connection to check
1070  *
1071  * \return Positive value if ready to be read, 0 if not ready, -errno on error
1072  */
1073 int
1074 crm_ipc_ready(crm_ipc_t *client)
     /* [previous][next][first][last][top][bottom][index][help] */
1075 {
1076     int rc;
1077 
1078     pcmk__assert(client != NULL);
1079 
1080     if (!crm_ipc_connected(client)) {
1081         return -ENOTCONN;
1082     }
1083 
1084     client->pfd.revents = 0;
1085     rc = poll(&(client->pfd), 1, 0);
1086     return (rc < 0)? -errno : rc;
1087 }
1088 
1089 long
1090 crm_ipc_read(crm_ipc_t *client)
     /* [previous][next][first][last][top][bottom][index][help] */
1091 {
1092     guint8 *buffer = NULL;
1093     long rc = -ENOMSG;
1094 
1095     pcmk__assert((client != NULL) && (client->ipc != NULL));
1096     buffer = g_malloc0(crm_ipc_default_buffer_size());
1097 
1098     do {
1099         pcmk__ipc_header_t *header = NULL;
1100         ssize_t bytes = qb_ipcc_event_recv(client->ipc, buffer,
1101                                            crm_ipc_default_buffer_size(), 0);
1102 
1103         header = (pcmk__ipc_header_t *)(void *) buffer;
1104 
1105         if (bytes <= 0) {
1106             crm_trace("No message received from %s IPC: %s",
1107                       client->server_name, strerror(-bytes));
1108 
1109             if (!crm_ipc_connected(client) || bytes == -ENOTCONN) {
1110                 crm_err("Connection to %s IPC failed", client->server_name);
1111                 rc = -ENOTCONN;
1112                 pcmk__ipc_free_client_buffer(client);
1113             } else if (bytes == -EAGAIN) {
1114                 rc = -EAGAIN;
1115             }
1116 
1117             goto done;
1118 
1119         } else if (bytes != header->size + sizeof(pcmk__ipc_header_t)) {
1120             crm_trace("Message size does not match header");
1121             rc = -EBADMSG;
1122             pcmk__ipc_free_client_buffer(client);
1123             goto done;
1124         }
1125 
1126         crm_trace("Received %s IPC event %" PRId32 " size=%" PRIu32 " rc=%zu",
1127                   client->server_name, header->qb.id, header->qb.size,
1128                   bytes);
1129 
1130         rc = pcmk__ipc_msg_append(&client->buffer, buffer);
1131 
1132         if (rc == pcmk_rc_ok) {
1133             break;
1134         } else if (rc == pcmk_rc_ipc_more) {
1135             continue;
1136         } else {
1137             pcmk__ipc_free_client_buffer(client);
1138             rc = pcmk_rc2legacy(rc);
1139             goto done;
1140         }
1141     } while (true);
1142 
1143     if (client->buffer->len > 0) {
1144         /* Data length excluding the header */
1145         rc = client->buffer->len - sizeof(pcmk__ipc_header_t);
1146     }
1147 
1148 done:
1149     g_free(buffer);
1150     return rc;
1151 }
1152 
1153 void
1154 pcmk__ipc_free_client_buffer(crm_ipc_t *client)
     /* [previous][next][first][last][top][bottom][index][help] */
1155 {
1156     pcmk__assert(client != NULL);
1157 
1158     if (client->buffer != NULL) {
1159         g_byte_array_free(client->buffer, TRUE);
1160         client->buffer = NULL;
1161     }
1162 }
1163 
1164 const char *
1165 crm_ipc_buffer(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
1166 {
1167     pcmk__assert(client != NULL);
1168     CRM_CHECK(client->buffer != NULL, return NULL);
1169     return (const char *) (client->buffer->data + sizeof(pcmk__ipc_header_t));
1170 }
1171 
1172 uint32_t
1173 crm_ipc_buffer_flags(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
1174 {
1175     pcmk__ipc_header_t *header = NULL;
1176 
1177     pcmk__assert(client != NULL);
1178     if (client->buffer == NULL) {
1179         return 0;
1180     }
1181 
1182     header = (pcmk__ipc_header_t *)(void*) client->buffer->data;
1183     return header->flags;
1184 }
1185 
1186 const char *
1187 crm_ipc_name(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
1188 {
1189     pcmk__assert(client != NULL);
1190     return client->server_name;
1191 }
1192 
1193 // \return Standard Pacemaker return code
1194 static int
1195 internal_ipc_get_reply(crm_ipc_t *client, int request_id, int ms_timeout,
     /* [previous][next][first][last][top][bottom][index][help] */
1196                        ssize_t *bytes, xmlNode **reply)
1197 {
1198     guint8 *buffer = NULL;
1199     pcmk__ipc_header_t *hdr = NULL;
1200     time_t timeout = 0;
1201     int32_t qb_timeout = -1;
1202     int rc = pcmk_rc_ok;
1203     int reply_id = 0;
1204 
1205     if (ms_timeout > 0) {
1206         timeout = time(NULL) + 1 + pcmk__timeout_ms2s(ms_timeout);
1207         qb_timeout = 1000;
1208     }
1209 
1210     /* get the reply */
1211     crm_trace("Expecting reply to %s IPC message %d", client->server_name,
1212               request_id);
1213 
1214     buffer = g_malloc0(crm_ipc_default_buffer_size());
1215 
1216     do {
1217         guint8 *data = NULL;
1218         xmlNode *xml = NULL;
1219 
1220         *bytes = qb_ipcc_recv(client->ipc, buffer, crm_ipc_default_buffer_size(),
1221                               qb_timeout);
1222 
1223         hdr = (pcmk__ipc_header_t *) (void *) buffer;
1224 
1225         if (*bytes <= 0) {
1226             if (!crm_ipc_connected(client)) {
1227                 crm_err("%s IPC provider disconnected while waiting for message %d",
1228                         client->server_name, request_id);
1229                 break;
1230             }
1231 
1232             continue;
1233 
1234         } else if (*bytes != hdr->size + sizeof(pcmk__ipc_header_t)) {
1235             crm_trace("Message size does not match header");
1236             rc = -EBADMSG;
1237             break;
1238         }
1239 
1240         reply_id = hdr->qb.id;
1241 
1242         if (reply_id == request_id) {
1243             /* Got the reply we were expecting. */
1244             rc = pcmk__ipc_msg_append(&client->buffer, buffer);
1245 
1246             if (rc == pcmk_rc_ok) {
1247                 break;
1248             } else if (rc == pcmk_rc_ipc_more) {
1249                 continue;
1250             } else {
1251                 goto done;
1252             }
1253         }
1254 
1255         data = buffer + sizeof(pcmk__ipc_header_t);
1256         xml = pcmk__xml_parse((const char *) data);
1257 
1258         if (reply_id < request_id) {
1259             crm_err("Discarding old reply %d (need %d)", reply_id, request_id);
1260             crm_log_xml_notice(xml, "OldIpcReply");
1261         } else if (reply_id > request_id) {
1262             crm_err("Discarding newer reply %d (need %d)", reply_id, request_id);
1263             crm_log_xml_notice(xml, "ImpossibleReply");
1264             pcmk__assert(hdr->qb.id <= request_id);
1265         }
1266     } while (time(NULL) < timeout || (timeout == 0 && *bytes == -EAGAIN));
1267 
1268     if (client->buffer->len > 0) {
1269         crm_trace("Received %u-byte reply %d to %s IPC %d: %.100s",
1270                   client->buffer->len, reply_id, client->server_name,
1271                   request_id, crm_ipc_buffer(client));
1272 
1273         if (reply != NULL) {
1274             *reply = pcmk__xml_parse(crm_ipc_buffer(client));
1275         }
1276     } else if (*bytes < 0) {
1277         rc = (int) -*bytes; // System errno
1278         crm_trace("No reply to %s IPC %d: %s " QB_XS " rc=%d",
1279                   client->server_name, request_id, pcmk_rc_str(rc), rc);
1280     }
1281     /* If bytes == 0, we'll return that to crm_ipc_send which will interpret
1282      * that as pcmk_rc_ok, log that the IPC request failed (since we did not
1283      * give it a valid reply), and return that 0 to its callers.  It's up to
1284      * the callers to take appropriate action after that.
1285      */
1286 
1287     /* Once we've parsed the client buffer as XML and saved it to reply,
1288      * there's no need to keep the client buffer around anymore.  Free it here
1289      * to avoid having to do this anywhere crm_ipc_send is called.
1290      */
1291 done:
1292     pcmk__ipc_free_client_buffer(client);
1293     g_free(buffer);
1294     return rc;
1295 }
1296 
1297 static int
1298 discard_old_replies(crm_ipc_t *client, int32_t ms_timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
1299 {
1300     pcmk__ipc_header_t *header = NULL;
1301     int rc = pcmk_rc_ok;
1302     ssize_t qb_rc = 0;
1303     char *buffer = pcmk__assert_alloc(crm_ipc_default_buffer_size(),
1304                                       sizeof(char));
1305 
1306     qb_rc = qb_ipcc_recv(client->ipc, buffer, crm_ipc_default_buffer_size(),
1307                          ms_timeout);
1308 
1309     if (qb_rc < 0) {
1310         crm_warn("Sending %s IPC disabled until pending reply received",
1311                  client->server_name);
1312         rc = EALREADY;
1313         goto done;
1314     }
1315 
1316     header = (pcmk__ipc_header_t *)(void *) buffer;
1317 
1318     if (!pcmk__valid_ipc_header(header)) {
1319         rc = EBADMSG;
1320 
1321     } else if (!pcmk_is_set(header->flags, crm_ipc_multipart)
1322                || pcmk_is_set(header->flags, crm_ipc_multipart_end)) {
1323         crm_notice("Sending %s IPC re-enabled after pending reply received",
1324                    client->server_name);
1325         client->need_reply = FALSE;
1326 
1327     } else {
1328         crm_warn("Sending %s IPC disabled until multipart IPC message "
1329                  "reply received", client->server_name);
1330         rc = EALREADY;
1331     }
1332 
1333 done:
1334     free(buffer);
1335     return rc;
1336 }
1337 
1338 /*!
1339  * \brief Send an IPC XML message
1340  *
1341  * \param[in,out] client      Connection to IPC server
1342  * \param[in]     message     XML message to send
1343  * \param[in]     flags       Bitmask of crm_ipc_flags
1344  * \param[in]     ms_timeout  Give up if not sent within this much time
1345  *                            (5 seconds if 0, or no timeout if negative)
1346  * \param[out]    reply       Reply from server (or NULL if none)
1347  *
1348  * \return Negative errno on error, otherwise size of reply received in bytes
1349  *         if reply was needed, otherwise number of bytes sent
1350  */
1351 int
1352 crm_ipc_send(crm_ipc_t *client, const xmlNode *message,
     /* [previous][next][first][last][top][bottom][index][help] */
1353              enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
1354 {
1355     int rc = 0;
1356     ssize_t bytes = 0;
1357     ssize_t sent_bytes = 0;
1358     struct iovec *iov = NULL;
1359     static uint32_t id = 0;
1360     pcmk__ipc_header_t *header;
1361     GString *iov_buffer = NULL;
1362     uint16_t index = 0;
1363 
1364     if (client == NULL) {
1365         crm_notice("Can't send IPC request without connection (bug?): %.100s",
1366                    message);
1367         return -ENOTCONN;
1368 
1369     } else if (!crm_ipc_connected(client)) {
1370         /* Don't even bother */
1371         crm_notice("Can't send %s IPC requests: Connection closed",
1372                    client->server_name);
1373         return -ENOTCONN;
1374     }
1375 
1376     if (ms_timeout == 0) {
1377         ms_timeout = 5000;
1378     }
1379 
1380     /* This block exists only to clear out any old replies that we haven't
1381      * yet read.  We don't care about their contents since it's too late to
1382      * do anything with them, so we just read and throw them away.
1383      */
1384     if (client->need_reply) {
1385         int discard_rc = discard_old_replies(client, ms_timeout);
1386 
1387         if (discard_rc != pcmk_rc_ok) {
1388             return pcmk_rc2legacy(discard_rc);
1389         }
1390     }
1391 
1392     id++;
1393     CRM_LOG_ASSERT(id != 0); /* Crude wrap-around detection */
1394 
1395     iov_buffer = g_string_sized_new(1024);
1396     pcmk__xml_string(message, 0, iov_buffer, 0);
1397 
1398     do {
1399         ssize_t qb_rc = 0;
1400         time_t timeout = 0;
1401 
1402         rc = pcmk__ipc_prepare_iov(id, iov_buffer, index, &iov, &bytes);
1403 
1404         if ((rc != pcmk_rc_ok) && (rc != pcmk_rc_ipc_more)) {
1405             crm_warn("Couldn't prepare %s IPC request: %s " QB_XS " rc=%d",
1406                      client->server_name, pcmk_rc_str(rc), rc);
1407             g_string_free(iov_buffer, TRUE);
1408             return pcmk_rc2legacy(rc);
1409         }
1410 
1411         header = iov[0].iov_base;
1412         pcmk__set_ipc_flags(header->flags, client->server_name, flags);
1413 
1414         if (pcmk_is_set(flags, crm_ipc_proxied)) {
1415             /* Don't look for a synchronous response */
1416             pcmk__clear_ipc_flags(flags, "client", crm_ipc_client_response);
1417         }
1418 
1419         if (pcmk_is_set(header->flags, crm_ipc_multipart)) {
1420             bool is_end = pcmk_is_set(header->flags, crm_ipc_multipart_end);
1421             crm_trace("Sending %s IPC request %" PRId32 " (%spart %" PRIu16 ") of "
1422                       "%" PRId32 " bytes using %dms timeout",
1423                       client->server_name, header->qb.id, is_end ? "final " : "",
1424                       index, header->qb.size, ms_timeout);
1425             crm_trace("Text = %s", (char *) iov[1].iov_base);
1426         } else {
1427             crm_trace("Sending %s IPC request %" PRId32 " of %" PRId32 " bytes "
1428                       "using %dms timeout",
1429                       client->server_name, header->qb.id, header->qb.size,
1430                       ms_timeout);
1431             crm_trace("Text = %s", (char *) iov[1].iov_base);
1432         }
1433 
1434         /* Send the IPC request, respecting any timeout we were passed */
1435         if (ms_timeout > 0) {
1436             timeout = time(NULL) + 1 + pcmk__timeout_ms2s(ms_timeout);
1437         }
1438 
1439         do {
1440             qb_rc = qb_ipcc_sendv(client->ipc, iov, 2);
1441         } while ((qb_rc == -EAGAIN) && ((timeout == 0) || (time(NULL) < timeout)));
1442 
1443         /* An error occurred when sending. */
1444         if (qb_rc <= 0) {
1445             rc = (int) qb_rc;   // Negative of system errno
1446             goto send_cleanup;
1447         }
1448 
1449         /* Sending succeeded.  The next action depends on whether this was a
1450          * multipart IPC message or not.
1451          */
1452         if (rc == pcmk_rc_ok) {
1453             /* This was either a standalone IPC message or the last part of
1454              * a multipart message.  Set the return value and break out of
1455              * this processing loop.
1456              */
1457             sent_bytes += qb_rc;
1458             rc = (int) sent_bytes;
1459             break;
1460         } else {
1461             /* There's no way to get here for any value other than rc == pcmk_rc_more
1462              * given the check right after pcmk__ipc_prepare_iov.
1463              *
1464              * This was a multipart message, loop to process the next chunk.
1465              */
1466             sent_bytes += qb_rc;
1467             index++;
1468         }
1469 
1470         pcmk_free_ipc_event(iov);
1471         iov = NULL;
1472     } while (true);
1473 
1474     /* If we should not wait for a response, bail now */
1475     if (!pcmk_is_set(flags, crm_ipc_client_response)) {
1476         crm_trace("Not waiting for reply to %s IPC request %d",
1477                   client->server_name, header->qb.id);
1478         goto send_cleanup;
1479     }
1480 
1481     pcmk__ipc_free_client_buffer(client);
1482     rc = internal_ipc_get_reply(client, header->qb.id, ms_timeout, &bytes, reply);
1483     if (rc == pcmk_rc_ok) {
1484         rc = (int) bytes; // Size of reply received
1485     } else {
1486         /* rc is either a positive system errno or a negative standard Pacemaker
1487          * return code.  If it's an errno, we need to convert it back to a
1488          * negative number for comparison and return at the end of this function.
1489          */
1490         rc = pcmk_rc2legacy(rc);
1491 
1492         if (ms_timeout > 0) {
1493             /* We didn't get the reply in time, so disable future sends for now.
1494              * The only alternative would be to close the connection since we
1495              * don't know how to detect and discard out-of-sequence replies.
1496              *
1497              * @TODO Implement out-of-sequence detection
1498              */
1499             client->need_reply = TRUE;
1500         }
1501     }
1502 
1503   send_cleanup:
1504     if (!crm_ipc_connected(client)) {
1505         crm_notice("Couldn't send %s IPC request %d: Connection closed "
1506                    QB_XS " rc=%d", client->server_name, header->qb.id, rc);
1507 
1508     } else if (rc == -ETIMEDOUT) {
1509         crm_warn("%s IPC request %d failed: %s after %dms " QB_XS " rc=%d",
1510                  client->server_name, header->qb.id, pcmk_strerror(rc),
1511                  ms_timeout, rc);
1512         crm_write_blackbox(0, NULL);
1513 
1514     } else if (rc <= 0) {
1515         crm_warn("%s IPC request %d failed: %s " QB_XS " rc=%d",
1516                  client->server_name, header->qb.id,
1517                  ((rc == 0)? "No bytes sent" : pcmk_strerror(rc)), rc);
1518     }
1519 
1520     g_string_free(iov_buffer, TRUE);
1521     pcmk_free_ipc_event(iov);
1522     // coverity[return_overflow]
1523     return rc;
1524 }
1525 
1526 /*!
1527  * \brief Ensure an IPC provider has expected user or group
1528  *
1529  * \param[in]  qb_ipc  libqb client connection if available
1530  * \param[in]  sock    Connected Unix socket for IPC
1531  * \param[in]  refuid  Expected user ID
1532  * \param[in]  refgid  Expected group ID
1533  * \param[out] gotpid  If not NULL, where to store provider's actual process ID
1534  *                     (or 1 on platforms where ID is not available)
1535  * \param[out] gotuid  If not NULL, where to store provider's actual user ID
1536  * \param[out] gotgid  If not NULL, where to store provider's actual group ID
1537  *
1538  * \return Standard Pacemaker return code
1539  * \note An actual user ID of 0 (root) will always be considered authorized,
1540  *       regardless of the expected values provided. The caller can use the
1541  *       output arguments to be stricter than this function.
1542  */
1543 static int
1544 is_ipc_provider_expected(qb_ipcc_connection_t *qb_ipc, int sock,
     /* [previous][next][first][last][top][bottom][index][help] */
1545                          uid_t refuid, gid_t refgid,
1546                          pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1547 {
1548     int rc = EOPNOTSUPP;
1549     pid_t found_pid = 0;
1550     uid_t found_uid = 0;
1551     gid_t found_gid = 0;
1552 
1553 #ifdef HAVE_QB_IPCC_AUTH_GET
1554     if (qb_ipc != NULL) {
1555         rc = qb_ipcc_auth_get(qb_ipc, &found_pid, &found_uid, &found_gid);
1556         rc = -rc; // libqb returns 0 or -errno
1557         if (rc == pcmk_rc_ok) {
1558             goto found;
1559         }
1560     }
1561 #endif
1562 
1563 #ifdef HAVE_UCRED
1564     {
1565         struct ucred ucred;
1566         socklen_t ucred_len = sizeof(ucred);
1567 
1568         if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &ucred_len) < 0) {
1569             rc = errno;
1570         } else if (ucred_len != sizeof(ucred)) {
1571             rc = EOPNOTSUPP;
1572         } else {
1573             found_pid = ucred.pid;
1574             found_uid = ucred.uid;
1575             found_gid = ucred.gid;
1576             goto found;
1577         }
1578     }
1579 #endif
1580 
1581 #ifdef HAVE_SOCKPEERCRED
1582     {
1583         struct sockpeercred sockpeercred;
1584         socklen_t sockpeercred_len = sizeof(sockpeercred);
1585 
1586         if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
1587                        &sockpeercred, &sockpeercred_len) < 0) {
1588             rc = errno;
1589         } else if (sockpeercred_len != sizeof(sockpeercred)) {
1590             rc = EOPNOTSUPP;
1591         } else {
1592             found_pid = sockpeercred.pid;
1593             found_uid = sockpeercred.uid;
1594             found_gid = sockpeercred.gid;
1595             goto found;
1596         }
1597     }
1598 #endif
1599 
1600 #ifdef HAVE_GETPEEREID // For example, FreeBSD
1601     if (getpeereid(sock, &found_uid, &found_gid) < 0) {
1602         rc = errno;
1603     } else {
1604         found_pid = PCMK__SPECIAL_PID;
1605         goto found;
1606     }
1607 #endif
1608 
1609 #ifdef HAVE_GETPEERUCRED
1610     {
1611         ucred_t *ucred = NULL;
1612 
1613         if (getpeerucred(sock, &ucred) < 0) {
1614             rc = errno;
1615         } else {
1616             found_pid = ucred_getpid(ucred);
1617             found_uid = ucred_geteuid(ucred);
1618             found_gid = ucred_getegid(ucred);
1619             ucred_free(ucred);
1620             goto found;
1621         }
1622     }
1623 #endif
1624 
1625     return rc; // If we get here, nothing succeeded
1626 
1627 found:
1628     if (gotpid != NULL) {
1629         *gotpid = found_pid;
1630     }
1631     if (gotuid != NULL) {
1632         *gotuid = found_uid;
1633     }
1634     if (gotgid != NULL) {
1635         *gotgid = found_gid;
1636     }
1637     if ((found_uid != 0) && (found_uid != refuid) && (found_gid != refgid)) {
1638         return pcmk_rc_ipc_unauthorized;
1639     }
1640     return pcmk_rc_ok;
1641 }
1642 
1643 int
1644 crm_ipc_is_authentic_process(int sock, uid_t refuid, gid_t refgid,
     /* [previous][next][first][last][top][bottom][index][help] */
1645                              pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1646 {
1647     int ret = is_ipc_provider_expected(NULL, sock, refuid, refgid,
1648                                        gotpid, gotuid, gotgid);
1649 
1650     /* The old function had some very odd return codes*/
1651     if (ret == 0) {
1652         return 1;
1653     } else if (ret == pcmk_rc_ipc_unauthorized) {
1654         return 0;
1655     } else {
1656         return pcmk_rc2legacy(ret);
1657     }
1658 }
1659 
1660 int
1661 pcmk__ipc_is_authentic_process_active(const char *name, uid_t refuid,
     /* [previous][next][first][last][top][bottom][index][help] */
1662                                       gid_t refgid, pid_t *gotpid)
1663 {
1664     static char last_asked_name[PATH_MAX / 2] = "";  /* log spam prevention */
1665     int fd;
1666     int rc = pcmk_rc_ipc_unresponsive;
1667     int auth_rc = 0;
1668     int32_t qb_rc;
1669     pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
1670     qb_ipcc_connection_t *c;
1671 #ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1672     struct pollfd pollfd = { 0, };
1673     int poll_rc;
1674 
1675     c = qb_ipcc_connect_async(name, 0,
1676                               &(pollfd.fd));
1677 #else
1678     c = qb_ipcc_connect(name, 0);
1679 #endif
1680     if (c == NULL) {
1681         crm_info("Could not connect to %s IPC: %s", name, strerror(errno));
1682         rc = pcmk_rc_ipc_unresponsive;
1683         goto bail;
1684     }
1685 #ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1686     pollfd.events = POLLIN;
1687     do {
1688         poll_rc = poll(&pollfd, 1, 2000);
1689     } while ((poll_rc == -1) && (errno == EINTR));
1690 
1691     /* If poll() failed, given that disconnect function is not registered yet,
1692      * qb_ipcc_disconnect() won't clean up the socket. In any case, call
1693      * qb_ipcc_connect_continue() here so that it may fail and do the cleanup
1694      * for us.
1695      */
1696     if (qb_ipcc_connect_continue(c) != 0) {
1697         crm_info("Could not connect to %s IPC: %s", name,
1698                  (poll_rc == 0)?"timeout":strerror(errno));
1699         rc = pcmk_rc_ipc_unresponsive;
1700         c = NULL; // qb_ipcc_connect_continue cleaned up for us
1701         goto bail;
1702     }
1703 #endif
1704 
1705     qb_rc = qb_ipcc_fd_get(c, &fd);
1706     if (qb_rc != 0) {
1707         rc = (int) -qb_rc; // System errno
1708         crm_err("Could not get fd from %s IPC: %s " QB_XS " rc=%d",
1709                 name, pcmk_rc_str(rc), rc);
1710         goto bail;
1711     }
1712 
1713     auth_rc = is_ipc_provider_expected(c, fd, refuid, refgid,
1714                                        &found_pid, &found_uid, &found_gid);
1715     if (auth_rc == pcmk_rc_ipc_unauthorized) {
1716         crm_err("Daemon (IPC %s) effectively blocked with unauthorized"
1717                 " process %lld (uid: %lld, gid: %lld)",
1718                 name, (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
1719                 (long long) found_uid, (long long) found_gid);
1720         rc = pcmk_rc_ipc_unauthorized;
1721         goto bail;
1722     }
1723 
1724     if (auth_rc != pcmk_rc_ok) {
1725         rc = auth_rc;
1726         crm_err("Could not get peer credentials from %s IPC: %s "
1727                 QB_XS " rc=%d", name, pcmk_rc_str(rc), rc);
1728         goto bail;
1729     }
1730 
1731     if (gotpid != NULL) {
1732         *gotpid = found_pid;
1733     }
1734 
1735     rc = pcmk_rc_ok;
1736     if ((found_uid != refuid || found_gid != refgid)
1737             && strncmp(last_asked_name, name, sizeof(last_asked_name))) {
1738         if ((found_uid == 0) && (refuid != 0)) {
1739             crm_warn("Daemon (IPC %s) runs as root, whereas the expected"
1740                      " credentials are %lld:%lld, hazard of violating"
1741                      " the least privilege principle",
1742                      name, (long long) refuid, (long long) refgid);
1743         } else {
1744             crm_notice("Daemon (IPC %s) runs as %lld:%lld, whereas the"
1745                        " expected credentials are %lld:%lld, which may"
1746                        " mean a different set of privileges than expected",
1747                        name, (long long) found_uid, (long long) found_gid,
1748                        (long long) refuid, (long long) refgid);
1749         }
1750         memccpy(last_asked_name, name, '\0', sizeof(last_asked_name));
1751     }
1752 
1753 bail:
1754     if (c != NULL) {
1755         qb_ipcc_disconnect(c);
1756     }
1757     return rc;
1758 }
1759 
1760 // Deprecated functions kept only for backward API compatibility
1761 // LCOV_EXCL_START
1762 
1763 #include <crm/common/ipc_client_compat.h>
1764 
1765 bool
1766 crm_ipc_connect(crm_ipc_t *client)
     /* [previous][next][first][last][top][bottom][index][help] */
1767 {
1768     int rc = pcmk__connect_generic_ipc(client);
1769 
1770     if (rc == pcmk_rc_ok) {
1771         return true;
1772     }
1773     if ((client != NULL) && (client->ipc == NULL)) {
1774         errno = (rc > 0)? rc : ENOTCONN;
1775         crm_debug("Could not establish %s IPC connection: %s (%d)",
1776                   client->server_name, pcmk_rc_str(errno), errno);
1777     } else if (rc == pcmk_rc_ipc_unauthorized) {
1778         crm_err("%s IPC provider authentication failed",
1779                 (client == NULL)? "Pacemaker" : client->server_name);
1780         errno = ECONNABORTED;
1781     } else {
1782         crm_err("Could not verify authenticity of %s IPC provider",
1783                 (client == NULL)? "Pacemaker" : client->server_name);
1784         errno = ENOTCONN;
1785     }
1786     return false;
1787 }
1788 
1789 // LCOV_EXCL_STOP
1790 // End deprecated API

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