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
  16. pcmk_disconnect_ipc
  17. pcmk_register_ipc_callback
  18. pcmk__send_ipc_request
  19. create_purge_node_request
  20. pcmk_ipc_purge_node
  21. crm_ipc_new
  22. crm_ipc_connect
  23. crm_ipc_close
  24. crm_ipc_destroy
  25. crm_ipc_get_fd
  26. crm_ipc_connected
  27. crm_ipc_ready
  28. crm_ipc_decompress
  29. crm_ipc_read
  30. crm_ipc_buffer
  31. crm_ipc_buffer_flags
  32. crm_ipc_name
  33. internal_ipc_get_reply
  34. crm_ipc_send
  35. pcmk__crm_ipc_is_authentic_process
  36. crm_ipc_is_authentic_process
  37. pcmk__ipc_is_authentic_process_active

   1 /*
   2  * Copyright 2004-2022 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #if defined(US_AUTH_PEERCRED_UCRED) || defined(US_AUTH_PEERCRED_SOCKPEERCRED)
  13 #  ifdef US_AUTH_PEERCRED_UCRED
  14 #    ifndef _GNU_SOURCE
  15 #      define _GNU_SOURCE
  16 #    endif
  17 #  endif
  18 #  include <sys/socket.h>
  19 #elif defined(US_AUTH_GETPEERUCRED)
  20 #  include <ucred.h>
  21 #endif
  22 
  23 #include <stdio.h>
  24 #include <sys/types.h>
  25 #include <errno.h>
  26 #include <bzlib.h>
  27 
  28 #include <crm/crm.h>   /* indirectly: pcmk_err_generic */
  29 #include <crm/msg_xml.h>
  30 #include <crm/common/ipc.h>
  31 #include <crm/common/ipc_internal.h>
  32 #include "crmcommon_private.h"
  33 
  34 /*!
  35  * \brief Create a new object for using Pacemaker daemon IPC
  36  *
  37  * \param[out] api     Where to store new IPC object
  38  * \param[in]  server  Which Pacemaker daemon the object is for
  39  *
  40  * \return Standard Pacemaker result code
  41  *
  42  * \note The caller is responsible for freeing *api using pcmk_free_ipc_api().
  43  * \note This is intended to supersede crm_ipc_new() but currently only
  44  *       supports the controller, pacemakerd, and schedulerd IPC API.
  45  */
  46 int
  47 pcmk_new_ipc_api(pcmk_ipc_api_t **api, enum pcmk_ipc_server server)
     /* [previous][next][first][last][top][bottom][index][help] */
  48 {
  49     if (api == NULL) {
  50         return EINVAL;
  51     }
  52 
  53     *api = calloc(1, sizeof(pcmk_ipc_api_t));
  54     if (*api == NULL) {
  55         return errno;
  56     }
  57 
  58     (*api)->server = server;
  59     if (pcmk_ipc_name(*api, false) == NULL) {
  60         pcmk_free_ipc_api(*api);
  61         *api = NULL;
  62         return EOPNOTSUPP;
  63     }
  64 
  65     (*api)->ipc_size_max = 0;
  66 
  67     // Set server methods and max_size (if not default)
  68     switch (server) {
  69         case pcmk_ipc_attrd:
  70             break;
  71 
  72         case pcmk_ipc_based:
  73             (*api)->ipc_size_max = 512 * 1024; // 512KB
  74             break;
  75 
  76         case pcmk_ipc_controld:
  77             (*api)->cmds = pcmk__controld_api_methods();
  78             break;
  79 
  80         case pcmk_ipc_execd:
  81             break;
  82 
  83         case pcmk_ipc_fenced:
  84             break;
  85 
  86         case pcmk_ipc_pacemakerd:
  87             (*api)->cmds = pcmk__pacemakerd_api_methods();
  88             break;
  89 
  90         case pcmk_ipc_schedulerd:
  91             (*api)->cmds = pcmk__schedulerd_api_methods();
  92             // @TODO max_size could vary by client, maybe take as argument?
  93             (*api)->ipc_size_max = 5 * 1024 * 1024; // 5MB
  94             break;
  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),
 103                               (*api)->ipc_size_max);
 104     if ((*api)->ipc == NULL) {
 105         pcmk_free_ipc_api(*api);
 106         *api = NULL;
 107         return ENOMEM;
 108     }
 109 
 110     // If daemon API has its own data to track, allocate it
 111     if ((*api)->cmds->new_data != NULL) {
 112         if ((*api)->cmds->new_data(*api) != pcmk_rc_ok) {
 113             pcmk_free_ipc_api(*api);
 114             *api = NULL;
 115             return ENOMEM;
 116         }
 117     }
 118     crm_trace("Created %s API IPC object", pcmk_ipc_name(*api, true));
 119     return pcmk_rc_ok;
 120 }
 121 
 122 static void
 123 free_daemon_specific_data(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125     if ((api != NULL) && (api->cmds != NULL)) {
 126         if ((api->cmds->free_data != NULL) && (api->api_data != NULL)) {
 127             api->cmds->free_data(api->api_data);
 128             api->api_data = NULL;
 129         }
 130         free(api->cmds);
 131         api->cmds = NULL;
 132     }
 133 }
 134 
 135 /*!
 136  * \internal
 137  * \brief Call an IPC API event callback, if one is registed
 138  *
 139  * \param[in] api         IPC API connection
 140  * \param[in] event_type  The type of event that occurred
 141  * \param[in] status      Event status
 142  * \param[in] event_data  Event-specific data
 143  */
 144 void
 145 pcmk__call_ipc_callback(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type,
     /* [previous][next][first][last][top][bottom][index][help] */
 146                         crm_exit_t status, void *event_data)
 147 {
 148     if ((api != NULL) && (api->cb != NULL)) {
 149         api->cb(api, event_type, status, event_data, api->user_data);
 150     }
 151 }
 152 
 153 /*!
 154  * \internal
 155  * \brief Clean up after an IPC disconnect
 156  *
 157  * \param[in]  user_data  IPC API connection that disconnected
 158  *
 159  * \note This function can be used as a main loop IPC destroy callback.
 160  */
 161 static void
 162 ipc_post_disconnect(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 163 {
 164     pcmk_ipc_api_t *api = user_data;
 165 
 166     crm_info("Disconnected from %s IPC API", pcmk_ipc_name(api, true));
 167 
 168     // Perform any daemon-specific handling needed
 169     if ((api->cmds != NULL) && (api->cmds->post_disconnect != NULL)) {
 170         api->cmds->post_disconnect(api);
 171     }
 172 
 173     // Call client's registered event callback
 174     pcmk__call_ipc_callback(api, pcmk_ipc_event_disconnect, CRM_EX_DISCONNECT,
 175                             NULL);
 176 
 177     /* If this is being called from a running main loop, mainloop_gio_destroy()
 178      * will free ipc and mainloop_io immediately after calling this function.
 179      * If this is called from a stopped main loop, these will leak, so the best
 180      * practice is to close the connection before stopping the main loop.
 181      */
 182     api->ipc = NULL;
 183     api->mainloop_io = NULL;
 184 
 185     if (api->free_on_disconnect) {
 186         /* pcmk_free_ipc_api() has already been called, but did not free api
 187          * or api->cmds because this function needed them. Do that now.
 188          */
 189         free_daemon_specific_data(api);
 190         crm_trace("Freeing IPC API object after disconnect");
 191         free(api);
 192     }
 193 }
 194 
 195 /*!
 196  * \brief Free the contents of an IPC API object
 197  *
 198  * \param[in] api  IPC API object to free
 199  */
 200 void
 201 pcmk_free_ipc_api(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 202 {
 203     bool free_on_disconnect = false;
 204 
 205     if (api == NULL) {
 206         return;
 207     }
 208     crm_debug("Releasing %s IPC API", pcmk_ipc_name(api, true));
 209 
 210     if (api->ipc != NULL) {
 211         if (api->mainloop_io != NULL) {
 212             /* We need to keep the api pointer itself around, because it is the
 213              * user data for the IPC client destroy callback. That will be
 214              * triggered by the pcmk_disconnect_ipc() call below, but it might
 215              * happen later in the main loop (if still running).
 216              *
 217              * This flag tells the destroy callback to free the object. It can't
 218              * do that unconditionally, because the application might call this
 219              * function after a disconnect that happened by other means.
 220              */
 221             free_on_disconnect = api->free_on_disconnect = true;
 222         }
 223         pcmk_disconnect_ipc(api); // Frees api if free_on_disconnect is true
 224     }
 225     if (!free_on_disconnect) {
 226         free_daemon_specific_data(api);
 227         crm_trace("Freeing IPC API object");
 228         free(api);
 229     }
 230 }
 231 
 232 /*!
 233  * \brief Get the IPC name used with an IPC API connection
 234  *
 235  * \param[in] api      IPC API connection
 236  * \param[in] for_log  If true, return human-friendly name instead of IPC name
 237  *
 238  * \return IPC API's human-friendly or connection name, or if none is available,
 239  *         "Pacemaker" if for_log is true and NULL if for_log is false
 240  */
 241 const char *
 242 pcmk_ipc_name(pcmk_ipc_api_t *api, bool for_log)
     /* [previous][next][first][last][top][bottom][index][help] */
 243 {
 244     if (api == NULL) {
 245         return for_log? "Pacemaker" : NULL;
 246     }
 247     switch (api->server) {
 248         case pcmk_ipc_attrd:
 249             return for_log? "attribute manager" : NULL /* T_ATTRD */;
 250 
 251         case pcmk_ipc_based:
 252             return for_log? "CIB manager" : NULL /* PCMK__SERVER_BASED_RW */;
 253 
 254         case pcmk_ipc_controld:
 255             return for_log? "controller" : CRM_SYSTEM_CRMD;
 256 
 257         case pcmk_ipc_execd:
 258             return for_log? "executor" : NULL /* CRM_SYSTEM_LRMD */;
 259 
 260         case pcmk_ipc_fenced:
 261             return for_log? "fencer" : NULL /* "stonith-ng" */;
 262 
 263         case pcmk_ipc_pacemakerd:
 264             return for_log? "launcher" : CRM_SYSTEM_MCP;
 265 
 266         case pcmk_ipc_schedulerd:
 267             return for_log? "scheduler" : CRM_SYSTEM_PENGINE;
 268 
 269         default:
 270             return for_log? "Pacemaker" : NULL;
 271     }
 272 }
 273 
 274 /*!
 275  * \brief Check whether an IPC API connection is active
 276  *
 277  * \param[in] api  IPC API connection
 278  *
 279  * \return true if IPC is connected, false otherwise
 280  */
 281 bool
 282 pcmk_ipc_is_connected(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 283 {
 284     return (api != NULL) && crm_ipc_connected(api->ipc);
 285 }
 286 
 287 /*!
 288  * \internal
 289  * \brief Call the daemon-specific API's dispatch function
 290  *
 291  * Perform daemon-specific handling of IPC reply dispatch. It is the daemon
 292  * method's responsibility to call the client's registered event callback, as
 293  * well as allocate and free any event data.
 294  *
 295  * \param[in] api  IPC API connection
 296  */
 297 static bool
 298 call_api_dispatch(pcmk_ipc_api_t *api, xmlNode *message)
     /* [previous][next][first][last][top][bottom][index][help] */
 299 {
 300     crm_log_xml_trace(message, "ipc-received");
 301     if ((api->cmds != NULL) && (api->cmds->dispatch != NULL)) {
 302         return api->cmds->dispatch(api, message);
 303     }
 304 
 305     return false;
 306 }
 307 
 308 /*!
 309  * \internal
 310  * \brief Dispatch previously read IPC data
 311  *
 312  * \param[in] buffer Data read from IPC
 313  * \param[in] api    IPC object
 314  *
 315  * \return Standard Pacemaker return code.  In particular:
 316  *
 317  * pcmk_rc_ok: There are no more messages expected from the server.  Quit
 318  *             reading.
 319  * EINPROGRESS: There are more messages expected from the server.  Keep reading.
 320  *
 321  * All other values indicate an error.
 322  */
 323 static int
 324 dispatch_ipc_data(const char *buffer, pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 325 {
 326     bool more = false;
 327     xmlNode *msg;
 328 
 329     if (buffer == NULL) {
 330         crm_warn("Empty message received from %s IPC",
 331                  pcmk_ipc_name(api, true));
 332         return ENOMSG;
 333     }
 334 
 335     msg = string2xml(buffer);
 336     if (msg == NULL) {
 337         crm_warn("Malformed message received from %s IPC",
 338                  pcmk_ipc_name(api, true));
 339         return EPROTO;
 340     }
 341 
 342     more = call_api_dispatch(api, msg);
 343     free_xml(msg);
 344 
 345     if (more) {
 346         return EINPROGRESS;
 347     } else {
 348         return pcmk_rc_ok;
 349     }
 350 }
 351 
 352 /*!
 353  * \internal
 354  * \brief Dispatch data read from IPC source
 355  *
 356  * \param[in] buffer     Data read from IPC
 357  * \param[in] length     Number of bytes of data in buffer (ignored)
 358  * \param[in] user_data  IPC object
 359  *
 360  * \return Always 0 (meaning connection is still required)
 361  *
 362  * \note This function can be used as a main loop IPC dispatch callback.
 363  */
 364 static int
 365 dispatch_ipc_source_data(const char *buffer, ssize_t length, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 366 {
 367     pcmk_ipc_api_t *api = user_data;
 368 
 369     CRM_CHECK(api != NULL, return 0);
 370     dispatch_ipc_data(buffer, api);
 371     return 0;
 372 }
 373 
 374 /*!
 375  * \brief Check whether an IPC connection has data available (without main loop)
 376  *
 377  * \param[in]  api         IPC API connection
 378  * \param[in]  timeout_ms  If less than 0, poll indefinitely; if 0, poll once
 379  *                         and return immediately; otherwise, poll for up to
 380  *                         this many milliseconds
 381  *
 382  * \return Standard Pacemaker return code
 383  *
 384  * \note Callers of pcmk_connect_ipc() using pcmk_ipc_dispatch_poll should call
 385  *       this function to check whether IPC data is available. Return values of
 386  *       interest include pcmk_rc_ok meaning data is available, and EAGAIN
 387  *       meaning no data is available; all other values indicate errors.
 388  * \todo This does not allow the caller to poll multiple file descriptors at
 389  *       once. If there is demand for that, we could add a wrapper for
 390  *       crm_ipc_get_fd(api->ipc), so the caller can call poll() themselves.
 391  */
 392 int
 393 pcmk_poll_ipc(pcmk_ipc_api_t *api, int timeout_ms)
     /* [previous][next][first][last][top][bottom][index][help] */
 394 {
 395     int rc;
 396     struct pollfd pollfd = { 0, };
 397 
 398     if ((api == NULL) || (api->dispatch_type != pcmk_ipc_dispatch_poll)) {
 399         return EINVAL;
 400     }
 401     pollfd.fd = crm_ipc_get_fd(api->ipc);
 402     pollfd.events = POLLIN;
 403     rc = poll(&pollfd, 1, timeout_ms);
 404     if (rc < 0) {
 405         return 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]  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         }
 432     }
 433 }
 434 
 435 // \return Standard Pacemaker return code
 436 static int
 437 connect_with_main_loop(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 438 {
 439     int rc;
 440 
 441     struct ipc_client_callbacks callbacks = {
 442         .dispatch = dispatch_ipc_source_data,
 443         .destroy = ipc_post_disconnect,
 444     };
 445 
 446     rc = pcmk__add_mainloop_ipc(api->ipc, G_PRIORITY_DEFAULT, api,
 447                                 &callbacks, &(api->mainloop_io));
 448     if (rc != pcmk_rc_ok) {
 449         return rc;
 450     }
 451     crm_debug("Connected to %s IPC (attached to main loop)",
 452               pcmk_ipc_name(api, true));
 453     /* After this point, api->mainloop_io owns api->ipc, so api->ipc
 454      * should not be explicitly freed.
 455      */
 456     return pcmk_rc_ok;
 457 }
 458 
 459 // \return Standard Pacemaker return code
 460 static int
 461 connect_without_main_loop(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 462 {
 463     int rc;
 464 
 465     if (!crm_ipc_connect(api->ipc)) {
 466         rc = errno;
 467         crm_ipc_close(api->ipc);
 468         return rc;
 469     }
 470     crm_debug("Connected to %s IPC (without main loop)",
 471               pcmk_ipc_name(api, true));
 472     return pcmk_rc_ok;
 473 }
 474 
 475 /*!
 476  * \brief Connect to a Pacemaker daemon via IPC
 477  *
 478  * \param[in]  api            IPC API instance
 479  * \param[out] dispatch_type  How IPC replies should be dispatched
 480  *
 481  * \return Standard Pacemaker return code
 482  */
 483 int
 484 pcmk_connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type)
     /* [previous][next][first][last][top][bottom][index][help] */
 485 {
 486     int rc = pcmk_rc_ok;
 487 
 488     if (api == NULL) {
 489         crm_err("Cannot connect to uninitialized API object");
 490         return EINVAL;
 491     }
 492 
 493     if (api->ipc == NULL) {
 494         api->ipc = crm_ipc_new(pcmk_ipc_name(api, false),
 495                                   api->ipc_size_max);
 496         if (api->ipc == NULL) {
 497             crm_err("Failed to re-create IPC API");
 498             return ENOMEM;
 499         }
 500     }
 501 
 502     if (crm_ipc_connected(api->ipc)) {
 503         crm_trace("Already connected to %s IPC API", pcmk_ipc_name(api, true));
 504         return pcmk_rc_ok;
 505     }
 506 
 507     api->dispatch_type = dispatch_type;
 508     switch (dispatch_type) {
 509         case pcmk_ipc_dispatch_main:
 510             rc = connect_with_main_loop(api);
 511             break;
 512 
 513         case pcmk_ipc_dispatch_sync:
 514         case pcmk_ipc_dispatch_poll:
 515             rc = connect_without_main_loop(api);
 516             break;
 517     }
 518     if (rc != pcmk_rc_ok) {
 519         return rc;
 520     }
 521 
 522     if ((api->cmds != NULL) && (api->cmds->post_connect != NULL)) {
 523         rc = api->cmds->post_connect(api);
 524         if (rc != pcmk_rc_ok) {
 525             crm_ipc_close(api->ipc);
 526         }
 527     }
 528     return rc;
 529 }
 530 
 531 /*!
 532  * \brief Disconnect an IPC API instance
 533  *
 534  * \param[in]  api  IPC API connection
 535  *
 536  * \return Standard Pacemaker return code
 537  *
 538  * \note If the connection is attached to a main loop, this function should be
 539  *       called before quitting the main loop, to ensure that all memory is
 540  *       freed.
 541  */
 542 void
 543 pcmk_disconnect_ipc(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 544 {
 545     if ((api == NULL) || (api->ipc == NULL)) {
 546         return;
 547     }
 548     switch (api->dispatch_type) {
 549         case pcmk_ipc_dispatch_main:
 550             {
 551                 mainloop_io_t *mainloop_io = api->mainloop_io;
 552 
 553                 // Make sure no code with access to api can use these again
 554                 api->mainloop_io = NULL;
 555                 api->ipc = NULL;
 556 
 557                 mainloop_del_ipc_client(mainloop_io);
 558                 // After this point api might have already been freed
 559             }
 560             break;
 561 
 562         case pcmk_ipc_dispatch_poll:
 563         case pcmk_ipc_dispatch_sync:
 564             {
 565                 crm_ipc_t *ipc = api->ipc;
 566 
 567                 // Make sure no code with access to api can use ipc again
 568                 api->ipc = NULL;
 569 
 570                 // This should always be the case already, but to be safe
 571                 api->free_on_disconnect = false;
 572 
 573                 crm_ipc_destroy(ipc);
 574                 ipc_post_disconnect(api);
 575             }
 576             break;
 577     }
 578 }
 579 
 580 /*!
 581  * \brief Register a callback for IPC API events
 582  *
 583  * \param[in] api          IPC API connection
 584  * \param[in] callback     Callback to register
 585  * \param[in] userdata     Caller data to pass to callback
 586  *
 587  * \note This function may be called multiple times to update the callback
 588  *       and/or user data. The caller remains responsible for freeing
 589  *       userdata in any case (after the IPC is disconnected, if the
 590  *       user data is still registered with the IPC).
 591  */
 592 void
 593 pcmk_register_ipc_callback(pcmk_ipc_api_t *api, pcmk_ipc_callback_t cb,
     /* [previous][next][first][last][top][bottom][index][help] */
 594                            void *user_data)
 595 {
 596     if (api == NULL) {
 597         return;
 598     }
 599     api->cb = cb;
 600     api->user_data = user_data;
 601 }
 602 
 603 /*!
 604  * \internal
 605  * \brief Send an XML request across an IPC API connection
 606  *
 607  * \param[in] api          IPC API connection
 608  * \param[in] request      XML request to send
 609  *
 610  * \return Standard Pacemaker return code
 611  *
 612  * \note Daemon-specific IPC API functions should call this function to send
 613  *       requests, because it handles different dispatch types appropriately.
 614  */
 615 int
 616 pcmk__send_ipc_request(pcmk_ipc_api_t *api, xmlNode *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 617 {
 618     int rc;
 619     xmlNode *reply = NULL;
 620     enum crm_ipc_flags flags = crm_ipc_flags_none;
 621 
 622     if ((api == NULL) || (api->ipc == NULL) || (request == NULL)) {
 623         return EINVAL;
 624     }
 625     crm_log_xml_trace(request, "ipc-sent");
 626 
 627     // Synchronous dispatch requires waiting for a reply
 628     if ((api->dispatch_type == pcmk_ipc_dispatch_sync)
 629         && (api->cmds != NULL)
 630         && (api->cmds->reply_expected != NULL)
 631         && (api->cmds->reply_expected(api, request))) {
 632         flags = crm_ipc_client_response;
 633     }
 634 
 635     // The 0 here means a default timeout of 5 seconds
 636     rc = crm_ipc_send(api->ipc, request, flags, 0, &reply);
 637 
 638     if (rc < 0) {
 639         return pcmk_legacy2rc(rc);
 640     } else if (rc == 0) {
 641         return ENODATA;
 642     }
 643 
 644     // With synchronous dispatch, we dispatch any reply now
 645     if (reply != NULL) {
 646         bool more = call_api_dispatch(api, reply);
 647 
 648         free_xml(reply);
 649 
 650         while (more) {
 651             rc = crm_ipc_read(api->ipc);
 652 
 653             if (rc == -EAGAIN) {
 654                 continue;
 655             } else if (rc == -ENOMSG || rc == pcmk_ok) {
 656                 return pcmk_rc_ok;
 657             } else if (rc < 0) {
 658                 return -rc;
 659             }
 660 
 661             rc = dispatch_ipc_data(crm_ipc_buffer(api->ipc), api);
 662 
 663             if (rc == pcmk_rc_ok) {
 664                 more = false;
 665             } else if (rc == EINPROGRESS) {
 666                 more = true;
 667             } else {
 668                 continue;
 669             }
 670         }
 671     }
 672     return pcmk_rc_ok;
 673 }
 674 
 675 /*!
 676  * \internal
 677  * \brief Create the XML for an IPC request to purge a node from the peer cache
 678  *
 679  * \param[in]  api        IPC API connection
 680  * \param[in]  node_name  If not NULL, name of node to purge
 681  * \param[in]  nodeid     If not 0, node ID of node to purge
 682  *
 683  * \return Newly allocated IPC request XML
 684  *
 685  * \note The controller, fencer, and pacemakerd use the same request syntax, but
 686  *       the attribute manager uses a different one. The CIB manager doesn't
 687  *       have any syntax for it. The executor and scheduler don't connect to the
 688  *       cluster layer and thus don't have or need any syntax for it.
 689  *
 690  * \todo Modify the attribute manager to accept the common syntax (as well
 691  *       as its current one, for compatibility with older clients). Modify
 692  *       the CIB manager to accept and honor the common syntax. Modify the
 693  *       executor and scheduler to accept the syntax (immediately returning
 694  *       success), just for consistency. Modify this function to use the
 695  *       common syntax with all daemons if their version supports it.
 696  */
 697 static xmlNode *
 698 create_purge_node_request(pcmk_ipc_api_t *api, const char *node_name,
     /* [previous][next][first][last][top][bottom][index][help] */
 699                           uint32_t nodeid)
 700 {
 701     xmlNode *request = NULL;
 702     const char *client = crm_system_name? crm_system_name : "client";
 703 
 704     switch (api->server) {
 705         case pcmk_ipc_attrd:
 706             request = create_xml_node(NULL, __func__);
 707             crm_xml_add(request, F_TYPE, T_ATTRD);
 708             crm_xml_add(request, F_ORIG, crm_system_name);
 709             crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_PEER_REMOVE);
 710             crm_xml_add(request, PCMK__XA_ATTR_NODE_NAME, node_name);
 711             if (nodeid > 0) {
 712                 crm_xml_add_int(request, PCMK__XA_ATTR_NODE_ID, (int) nodeid);
 713             }
 714             break;
 715 
 716         case pcmk_ipc_controld:
 717         case pcmk_ipc_fenced:
 718         case pcmk_ipc_pacemakerd:
 719             request = create_request(CRM_OP_RM_NODE_CACHE, NULL, NULL,
 720                                      pcmk_ipc_name(api, false), client, NULL);
 721             if (nodeid > 0) {
 722                 crm_xml_set_id(request, "%lu", (unsigned long) nodeid);
 723             }
 724             crm_xml_add(request, XML_ATTR_UNAME, node_name);
 725             break;
 726 
 727         case pcmk_ipc_based:
 728         case pcmk_ipc_execd:
 729         case pcmk_ipc_schedulerd:
 730             break;
 731     }
 732     return request;
 733 }
 734 
 735 /*!
 736  * \brief Ask a Pacemaker daemon to purge a node from its peer cache
 737  *
 738  * \param[in]  api        IPC API connection
 739  * \param[in]  node_name  If not NULL, name of node to purge
 740  * \param[in]  nodeid     If not 0, node ID of node to purge
 741  *
 742  * \return Standard Pacemaker return code
 743  *
 744  * \note At least one of node_name or nodeid must be specified.
 745  */
 746 int
 747 pcmk_ipc_purge_node(pcmk_ipc_api_t *api, const char *node_name, uint32_t nodeid)
     /* [previous][next][first][last][top][bottom][index][help] */
 748 {
 749     int rc = 0;
 750     xmlNode *request = NULL;
 751 
 752     if (api == NULL) {
 753         return EINVAL;
 754     }
 755     if ((node_name == NULL) && (nodeid == 0)) {
 756         return EINVAL;
 757     }
 758 
 759     request = create_purge_node_request(api, node_name, nodeid);
 760     if (request == NULL) {
 761         return EOPNOTSUPP;
 762     }
 763     rc = pcmk__send_ipc_request(api, request);
 764     free_xml(request);
 765 
 766     crm_debug("%s peer cache purge of node %s[%lu]: rc=%d",
 767               pcmk_ipc_name(api, true), node_name, (unsigned long) nodeid, rc);
 768     return rc;
 769 }
 770 
 771 /*
 772  * Generic IPC API (to eventually be deprecated as public API and made internal)
 773  */
 774 
 775 struct crm_ipc_s {
 776     struct pollfd pfd;
 777     unsigned int max_buf_size; // maximum bytes we can send or receive over IPC
 778     unsigned int buf_size;     // size of allocated buffer
 779     int msg_size;
 780     int need_reply;
 781     char *buffer;
 782     char *server_name;          // server IPC name being connected to
 783     qb_ipcc_connection_t *ipc;
 784 };
 785 
 786 /*!
 787  * \brief Create a new (legacy) object for using Pacemaker daemon IPC
 788  *
 789  * \param[in] name      IPC system name to connect to
 790  * \param[in] max_size  Use a maximum IPC buffer size of at least this size
 791  *
 792  * \return Newly allocated IPC object on success, NULL otherwise
 793  *
 794  * \note The caller is responsible for freeing the result using
 795  *       crm_ipc_destroy().
 796  * \note This should be considered deprecated for use with daemons supported by
 797  *       pcmk_new_ipc_api().
 798  */
 799 crm_ipc_t *
 800 crm_ipc_new(const char *name, size_t max_size)
     /* [previous][next][first][last][top][bottom][index][help] */
 801 {
 802     crm_ipc_t *client = NULL;
 803 
 804     client = calloc(1, sizeof(crm_ipc_t));
 805     if (client == NULL) {
 806         crm_err("Could not create IPC connection: %s", strerror(errno));
 807         return NULL;
 808     }
 809 
 810     client->server_name = strdup(name);
 811     if (client->server_name == NULL) {
 812         crm_err("Could not create %s IPC connection: %s",
 813                 name, strerror(errno));
 814         free(client);
 815         return NULL;
 816     }
 817     client->buf_size = pcmk__ipc_buffer_size(max_size);
 818     client->buffer = malloc(client->buf_size);
 819     if (client->buffer == NULL) {
 820         crm_err("Could not create %s IPC connection: %s",
 821                 name, strerror(errno));
 822         free(client->server_name);
 823         free(client);
 824         return NULL;
 825     }
 826 
 827     /* Clients initiating connection pick the max buf size */
 828     client->max_buf_size = client->buf_size;
 829 
 830     client->pfd.fd = -1;
 831     client->pfd.events = POLLIN;
 832     client->pfd.revents = 0;
 833 
 834     return client;
 835 }
 836 
 837 /*!
 838  * \brief Establish an IPC connection to a Pacemaker component
 839  *
 840  * \param[in] client  Connection instance obtained from crm_ipc_new()
 841  *
 842  * \return TRUE on success, FALSE otherwise (in which case errno will be set;
 843  *         specifically, in case of discovering the remote side is not
 844  *         authentic, its value is set to ECONNABORTED).
 845  */
 846 bool
 847 crm_ipc_connect(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
 848 {
 849     uid_t cl_uid = 0;
 850     gid_t cl_gid = 0;
 851     pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
 852     int rv;
 853 
 854     client->need_reply = FALSE;
 855     client->ipc = qb_ipcc_connect(client->server_name, client->buf_size);
 856 
 857     if (client->ipc == NULL) {
 858         crm_debug("Could not establish %s IPC connection: %s (%d)",
 859                   client->server_name, pcmk_rc_str(errno), errno);
 860         return FALSE;
 861     }
 862 
 863     client->pfd.fd = crm_ipc_get_fd(client);
 864     if (client->pfd.fd < 0) {
 865         rv = errno;
 866         /* message already omitted */
 867         crm_ipc_close(client);
 868         errno = rv;
 869         return FALSE;
 870     }
 871 
 872     rv = pcmk_daemon_user(&cl_uid, &cl_gid);
 873     if (rv < 0) {
 874         /* message already omitted */
 875         crm_ipc_close(client);
 876         errno = -rv;
 877         return FALSE;
 878     }
 879 
 880     if ((rv = pcmk__crm_ipc_is_authentic_process(client->ipc, client->pfd.fd, cl_uid, cl_gid,
 881                                                   &found_pid, &found_uid,
 882                                                   &found_gid)) == pcmk_rc_ipc_unauthorized) {
 883         crm_err("%s IPC provider authentication failed: process %lld has "
 884                 "uid %lld (expected %lld) and gid %lld (expected %lld)",
 885                 client->server_name,
 886                 (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 887                 (long long) found_uid, (long long) cl_uid,
 888                 (long long) found_gid, (long long) cl_gid);
 889         crm_ipc_close(client);
 890         errno = ECONNABORTED;
 891         return FALSE;
 892 
 893     } else if (rv != pcmk_rc_ok) {
 894         crm_perror(LOG_ERR, "Could not verify authenticity of %s IPC provider",
 895                    client->server_name);
 896         crm_ipc_close(client);
 897         if (rv > 0) {
 898             errno = rv;
 899         } else {
 900             errno = ENOTCONN;
 901         }
 902         return FALSE;
 903     }
 904 
 905     qb_ipcc_context_set(client->ipc, client);
 906 
 907     client->max_buf_size = qb_ipcc_get_buffer_size(client->ipc);
 908     if (client->max_buf_size > client->buf_size) {
 909         free(client->buffer);
 910         client->buffer = calloc(1, client->max_buf_size);
 911         client->buf_size = client->max_buf_size;
 912     }
 913     return TRUE;
 914 }
 915 
 916 void
 917 crm_ipc_close(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
 918 {
 919     if (client) {
 920         if (client->ipc) {
 921             qb_ipcc_connection_t *ipc = client->ipc;
 922 
 923             client->ipc = NULL;
 924             qb_ipcc_disconnect(ipc);
 925         }
 926     }
 927 }
 928 
 929 void
 930 crm_ipc_destroy(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
 931 {
 932     if (client) {
 933         if (client->ipc && qb_ipcc_is_connected(client->ipc)) {
 934             crm_notice("Destroying active %s IPC connection",
 935                        client->server_name);
 936             /* The next line is basically unsafe
 937              *
 938              * If this connection was attached to mainloop and mainloop is active,
 939              *   the 'disconnected' callback will end up back here and we'll end
 940              *   up free'ing the memory twice - something that can still happen
 941              *   even without this if we destroy a connection and it closes before
 942              *   we call exit
 943              */
 944             /* crm_ipc_close(client); */
 945         } else {
 946             crm_trace("Destroying inactive %s IPC connection",
 947                       client->server_name);
 948         }
 949         free(client->buffer);
 950         free(client->server_name);
 951         free(client);
 952     }
 953 }
 954 
 955 int
 956 crm_ipc_get_fd(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
 957 {
 958     int fd = 0;
 959 
 960     if (client && client->ipc && (qb_ipcc_fd_get(client->ipc, &fd) == 0)) {
 961         return fd;
 962     }
 963     errno = EINVAL;
 964     crm_perror(LOG_ERR, "Could not obtain file descriptor for %s IPC",
 965                (client? client->server_name : "unspecified"));
 966     return -errno;
 967 }
 968 
 969 bool
 970 crm_ipc_connected(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
 971 {
 972     bool rc = FALSE;
 973 
 974     if (client == NULL) {
 975         crm_trace("No client");
 976         return FALSE;
 977 
 978     } else if (client->ipc == NULL) {
 979         crm_trace("No connection");
 980         return FALSE;
 981 
 982     } else if (client->pfd.fd < 0) {
 983         crm_trace("Bad descriptor");
 984         return FALSE;
 985     }
 986 
 987     rc = qb_ipcc_is_connected(client->ipc);
 988     if (rc == FALSE) {
 989         client->pfd.fd = -EINVAL;
 990     }
 991     return rc;
 992 }
 993 
 994 /*!
 995  * \brief Check whether an IPC connection is ready to be read
 996  *
 997  * \param[in] client  Connection to check
 998  *
 999  * \return Positive value if ready to be read, 0 if not ready, -errno on error
1000  */
1001 int
1002 crm_ipc_ready(crm_ipc_t *client)
     /* [previous][next][first][last][top][bottom][index][help] */
1003 {
1004     int rc;
1005 
1006     CRM_ASSERT(client != NULL);
1007 
1008     if (crm_ipc_connected(client) == FALSE) {
1009         return -ENOTCONN;
1010     }
1011 
1012     client->pfd.revents = 0;
1013     rc = poll(&(client->pfd), 1, 0);
1014     return (rc < 0)? -errno : rc;
1015 }
1016 
1017 // \return Standard Pacemaker return code
1018 static int
1019 crm_ipc_decompress(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
1020 {
1021     pcmk__ipc_header_t *header = (pcmk__ipc_header_t *)(void*)client->buffer;
1022 
1023     if (header->size_compressed) {
1024         int rc = 0;
1025         unsigned int size_u = 1 + header->size_uncompressed;
1026         /* never let buf size fall below our max size required for ipc reads. */
1027         unsigned int new_buf_size = QB_MAX((sizeof(pcmk__ipc_header_t) + size_u), client->max_buf_size);
1028         char *uncompressed = calloc(1, new_buf_size);
1029 
1030         crm_trace("Decompressing message data %u bytes into %u bytes",
1031                  header->size_compressed, size_u);
1032 
1033         rc = BZ2_bzBuffToBuffDecompress(uncompressed + sizeof(pcmk__ipc_header_t), &size_u,
1034                                         client->buffer + sizeof(pcmk__ipc_header_t), header->size_compressed, 1, 0);
1035 
1036         if (rc != BZ_OK) {
1037             crm_err("Decompression failed: %s " CRM_XS " bzerror=%d",
1038                     bz2_strerror(rc), rc);
1039             free(uncompressed);
1040             return EILSEQ;
1041         }
1042 
1043         /*
1044          * This assert no longer holds true.  For an identical msg, some clients may
1045          * require compression, and others may not. If that same msg (event) is sent
1046          * to multiple clients, it could result in some clients receiving a compressed
1047          * msg even though compression was not explicitly required for them.
1048          *
1049          * CRM_ASSERT((header->size_uncompressed + sizeof(pcmk__ipc_header_t)) >= ipc_buffer_max);
1050          */
1051         CRM_ASSERT(size_u == header->size_uncompressed);
1052 
1053         memcpy(uncompressed, client->buffer, sizeof(pcmk__ipc_header_t));       /* Preserve the header */
1054         header = (pcmk__ipc_header_t *)(void*)uncompressed;
1055 
1056         free(client->buffer);
1057         client->buf_size = new_buf_size;
1058         client->buffer = uncompressed;
1059     }
1060 
1061     CRM_ASSERT(client->buffer[sizeof(pcmk__ipc_header_t) + header->size_uncompressed - 1] == 0);
1062     return pcmk_rc_ok;
1063 }
1064 
1065 long
1066 crm_ipc_read(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
1067 {
1068     pcmk__ipc_header_t *header = NULL;
1069 
1070     CRM_ASSERT(client != NULL);
1071     CRM_ASSERT(client->ipc != NULL);
1072     CRM_ASSERT(client->buffer != NULL);
1073 
1074     client->buffer[0] = 0;
1075     client->msg_size = qb_ipcc_event_recv(client->ipc, client->buffer,
1076                                           client->buf_size, 0);
1077     if (client->msg_size >= 0) {
1078         int rc = crm_ipc_decompress(client);
1079 
1080         if (rc != pcmk_rc_ok) {
1081             return pcmk_rc2legacy(rc);
1082         }
1083 
1084         header = (pcmk__ipc_header_t *)(void*)client->buffer;
1085         if (!pcmk__valid_ipc_header(header)) {
1086             return -EBADMSG;
1087         }
1088 
1089         crm_trace("Received %s IPC event %d size=%u rc=%d text='%.100s'",
1090                   client->server_name, header->qb.id, header->qb.size,
1091                   client->msg_size,
1092                   client->buffer + sizeof(pcmk__ipc_header_t));
1093 
1094     } else {
1095         crm_trace("No message received from %s IPC: %s",
1096                   client->server_name, pcmk_strerror(client->msg_size));
1097 
1098         if (client->msg_size == -EAGAIN) {
1099             return -EAGAIN;
1100         }
1101     }
1102 
1103     if (crm_ipc_connected(client) == FALSE || client->msg_size == -ENOTCONN) {
1104         crm_err("Connection to %s IPC failed", client->server_name);
1105     }
1106 
1107     if (header) {
1108         /* Data excluding the header */
1109         return header->size_uncompressed;
1110     }
1111     return -ENOMSG;
1112 }
1113 
1114 const char *
1115 crm_ipc_buffer(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
1116 {
1117     CRM_ASSERT(client != NULL);
1118     return client->buffer + sizeof(pcmk__ipc_header_t);
1119 }
1120 
1121 uint32_t
1122 crm_ipc_buffer_flags(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
1123 {
1124     pcmk__ipc_header_t *header = NULL;
1125 
1126     CRM_ASSERT(client != NULL);
1127     if (client->buffer == NULL) {
1128         return 0;
1129     }
1130 
1131     header = (pcmk__ipc_header_t *)(void*)client->buffer;
1132     return header->flags;
1133 }
1134 
1135 const char *
1136 crm_ipc_name(crm_ipc_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
1137 {
1138     CRM_ASSERT(client != NULL);
1139     return client->server_name;
1140 }
1141 
1142 // \return Standard Pacemaker return code
1143 static int
1144 internal_ipc_get_reply(crm_ipc_t *client, int request_id, int ms_timeout,
     /* [previous][next][first][last][top][bottom][index][help] */
1145                        ssize_t *bytes)
1146 {
1147     time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1148     int rc = pcmk_rc_ok;
1149 
1150     /* get the reply */
1151     crm_trace("Waiting on reply to %s IPC message %d",
1152               client->server_name, request_id);
1153     do {
1154 
1155         *bytes = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, 1000);
1156         if (*bytes > 0) {
1157             pcmk__ipc_header_t *hdr = NULL;
1158 
1159             rc = crm_ipc_decompress(client);
1160             if (rc != pcmk_rc_ok) {
1161                 return rc;
1162             }
1163 
1164             hdr = (pcmk__ipc_header_t *)(void*)client->buffer;
1165             if (hdr->qb.id == request_id) {
1166                 /* Got it */
1167                 break;
1168             } else if (hdr->qb.id < request_id) {
1169                 xmlNode *bad = string2xml(crm_ipc_buffer(client));
1170 
1171                 crm_err("Discarding old reply %d (need %d)", hdr->qb.id, request_id);
1172                 crm_log_xml_notice(bad, "OldIpcReply");
1173 
1174             } else {
1175                 xmlNode *bad = string2xml(crm_ipc_buffer(client));
1176 
1177                 crm_err("Discarding newer reply %d (need %d)", hdr->qb.id, request_id);
1178                 crm_log_xml_notice(bad, "ImpossibleReply");
1179                 CRM_ASSERT(hdr->qb.id <= request_id);
1180             }
1181         } else if (crm_ipc_connected(client) == FALSE) {
1182             crm_err("%s IPC provider disconnected while waiting for message %d",
1183                     client->server_name, request_id);
1184             break;
1185         }
1186 
1187     } while (time(NULL) < timeout);
1188 
1189     if (*bytes < 0) {
1190         rc = (int) -*bytes; // System errno
1191     }
1192     return rc;
1193 }
1194 
1195 /*!
1196  * \brief Send an IPC XML message
1197  *
1198  * \param[in]  client      Connection to IPC server
1199  * \param[in]  message     XML message to send
1200  * \param[in]  flags       Bitmask of crm_ipc_flags
1201  * \param[in]  ms_timeout  Give up if not sent within this much time
1202  *                         (5 seconds if 0, or no timeout if negative)
1203  * \param[out] reply       Reply from server (or NULL if none)
1204  *
1205  * \return Negative errno on error, otherwise size of reply received in bytes
1206  *         if reply was needed, otherwise number of bytes sent
1207  */
1208 int
1209 crm_ipc_send(crm_ipc_t * client, xmlNode * message, enum crm_ipc_flags flags, int32_t ms_timeout,
     /* [previous][next][first][last][top][bottom][index][help] */
1210              xmlNode ** reply)
1211 {
1212     int rc = 0;
1213     ssize_t qb_rc = 0;
1214     ssize_t bytes = 0;
1215     struct iovec *iov;
1216     static uint32_t id = 0;
1217     static int factor = 8;
1218     pcmk__ipc_header_t *header;
1219 
1220     if (client == NULL) {
1221         crm_notice("Can't send IPC request without connection (bug?): %.100s",
1222                    message);
1223         return -ENOTCONN;
1224 
1225     } else if (crm_ipc_connected(client) == FALSE) {
1226         /* Don't even bother */
1227         crm_notice("Can't send %s IPC requests: Connection closed",
1228                    client->server_name);
1229         return -ENOTCONN;
1230     }
1231 
1232     if (ms_timeout == 0) {
1233         ms_timeout = 5000;
1234     }
1235 
1236     if (client->need_reply) {
1237         qb_rc = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, ms_timeout);
1238         if (qb_rc < 0) {
1239             crm_warn("Sending %s IPC disabled until pending reply received",
1240                      client->server_name);
1241             return -EALREADY;
1242 
1243         } else {
1244             crm_notice("Sending %s IPC re-enabled after pending reply received",
1245                        client->server_name);
1246             client->need_reply = FALSE;
1247         }
1248     }
1249 
1250     id++;
1251     CRM_LOG_ASSERT(id != 0); /* Crude wrap-around detection */
1252     rc = pcmk__ipc_prepare_iov(id, message, client->max_buf_size, &iov, &bytes);
1253     if (rc != pcmk_rc_ok) {
1254         crm_warn("Couldn't prepare %s IPC request: %s " CRM_XS " rc=%d",
1255                  client->server_name, pcmk_rc_str(rc), rc);
1256         return pcmk_rc2legacy(rc);
1257     }
1258 
1259     header = iov[0].iov_base;
1260     pcmk__set_ipc_flags(header->flags, client->server_name, flags);
1261 
1262     if (pcmk_is_set(flags, crm_ipc_proxied)) {
1263         /* Don't look for a synchronous response */
1264         pcmk__clear_ipc_flags(flags, "client", crm_ipc_client_response);
1265     }
1266 
1267     if(header->size_compressed) {
1268         if(factor < 10 && (client->max_buf_size / 10) < (bytes / factor)) {
1269             crm_notice("Compressed message exceeds %d0%% of configured IPC "
1270                        "limit (%u bytes); consider setting PCMK_ipc_buffer to "
1271                        "%u or higher",
1272                        factor, client->max_buf_size, 2 * client->max_buf_size);
1273             factor++;
1274         }
1275     }
1276 
1277     crm_trace("Sending %s IPC request %d of %u bytes using %dms timeout",
1278               client->server_name, header->qb.id, header->qb.size, ms_timeout);
1279 
1280     if ((ms_timeout > 0) || !pcmk_is_set(flags, crm_ipc_client_response)) {
1281 
1282         time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1283 
1284         do {
1285             /* @TODO Is this check really needed? Won't qb_ipcc_sendv() return
1286              * an error if it's not connected?
1287              */
1288             if (!crm_ipc_connected(client)) {
1289                 goto send_cleanup;
1290             }
1291 
1292             qb_rc = qb_ipcc_sendv(client->ipc, iov, 2);
1293         } while ((qb_rc == -EAGAIN) && (time(NULL) < timeout));
1294 
1295         rc = (int) qb_rc; // Negative of system errno, or bytes sent
1296         if (qb_rc <= 0) {
1297             goto send_cleanup;
1298 
1299         } else if (!pcmk_is_set(flags, crm_ipc_client_response)) {
1300             crm_trace("Not waiting for reply to %s IPC request %d",
1301                       client->server_name, header->qb.id);
1302             goto send_cleanup;
1303         }
1304 
1305         rc = internal_ipc_get_reply(client, header->qb.id, ms_timeout, &bytes);
1306         if (rc != pcmk_rc_ok) {
1307             /* We didn't get the reply in time, so disable future sends for now.
1308              * The only alternative would be to close the connection since we
1309              * don't know how to detect and discard out-of-sequence replies.
1310              *
1311              * @TODO Implement out-of-sequence detection
1312              */
1313             client->need_reply = TRUE;
1314         }
1315         rc = (int) bytes; // Negative system errno, or size of reply received
1316 
1317     } else {
1318         // No timeout, and client response needed
1319         do {
1320             qb_rc = qb_ipcc_sendv_recv(client->ipc, iov, 2, client->buffer,
1321                                        client->buf_size, -1);
1322         } while ((qb_rc == -EAGAIN) && crm_ipc_connected(client));
1323         rc = (int) qb_rc; // Negative system errno, or size of reply received
1324     }
1325 
1326     if (rc > 0) {
1327         pcmk__ipc_header_t *hdr = (pcmk__ipc_header_t *)(void*)client->buffer;
1328 
1329         crm_trace("Received %d-byte reply %d to %s IPC %d: %.100s",
1330                   rc, hdr->qb.id, client->server_name, header->qb.id,
1331                   crm_ipc_buffer(client));
1332 
1333         if (reply) {
1334             *reply = string2xml(crm_ipc_buffer(client));
1335         }
1336 
1337     } else {
1338         crm_trace("No reply to %s IPC %d: rc=%d",
1339                   client->server_name, header->qb.id, rc);
1340     }
1341 
1342   send_cleanup:
1343     if (crm_ipc_connected(client) == FALSE) {
1344         crm_notice("Couldn't send %s IPC request %d: Connection closed "
1345                    CRM_XS " rc=%d", client->server_name, header->qb.id, rc);
1346 
1347     } else if (rc == -ETIMEDOUT) {
1348         crm_warn("%s IPC request %d failed: %s after %dms " CRM_XS " rc=%d",
1349                  client->server_name, header->qb.id, pcmk_strerror(rc),
1350                  ms_timeout, rc);
1351         crm_write_blackbox(0, NULL);
1352 
1353     } else if (rc <= 0) {
1354         crm_warn("%s IPC request %d failed: %s " CRM_XS " rc=%d",
1355                  client->server_name, header->qb.id,
1356                  ((rc == 0)? "No bytes sent" : pcmk_strerror(rc)), rc);
1357     }
1358 
1359     pcmk_free_ipc_event(iov);
1360     return rc;
1361 }
1362 
1363 int
1364 pcmk__crm_ipc_is_authentic_process(qb_ipcc_connection_t *qb_ipc, int sock, uid_t refuid, gid_t refgid,
     /* [previous][next][first][last][top][bottom][index][help] */
1365                                    pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1366 {
1367     int ret = 0;
1368     pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
1369 #if defined(US_AUTH_PEERCRED_UCRED)
1370     struct ucred ucred;
1371     socklen_t ucred_len = sizeof(ucred);
1372 #endif
1373 
1374 #ifdef HAVE_QB_IPCC_AUTH_GET
1375     if (qb_ipc && !qb_ipcc_auth_get(qb_ipc, &found_pid, &found_uid, &found_gid)) {
1376         goto do_checks;
1377     }
1378 #endif
1379 
1380 #if defined(US_AUTH_PEERCRED_UCRED)
1381     if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
1382                     &ucred, &ucred_len)
1383                 && ucred_len == sizeof(ucred)) {
1384         found_pid = ucred.pid; found_uid = ucred.uid; found_gid = ucred.gid;
1385 
1386 #elif defined(US_AUTH_PEERCRED_SOCKPEERCRED)
1387     struct sockpeercred sockpeercred;
1388     socklen_t sockpeercred_len = sizeof(sockpeercred);
1389 
1390     if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
1391                     &sockpeercred, &sockpeercred_len)
1392                 && sockpeercred_len == sizeof(sockpeercred_len)) {
1393         found_pid = sockpeercred.pid;
1394         found_uid = sockpeercred.uid; found_gid = sockpeercred.gid;
1395 
1396 #elif defined(US_AUTH_GETPEEREID)
1397     if (!getpeereid(sock, &found_uid, &found_gid)) {
1398         found_pid = PCMK__SPECIAL_PID;  /* cannot obtain PID (FreeBSD) */
1399 
1400 #elif defined(US_AUTH_GETPEERUCRED)
1401     ucred_t *ucred;
1402     if (!getpeerucred(sock, &ucred)) {
1403         errno = 0;
1404         found_pid = ucred_getpid(ucred);
1405         found_uid = ucred_geteuid(ucred); found_gid = ucred_getegid(ucred);
1406         ret = -errno;
1407         ucred_free(ucred);
1408         if (ret) {
1409             return (ret < 0) ? ret : -pcmk_err_generic;
1410         }
1411 
1412 #else
1413 #  error "No way to authenticate a Unix socket peer"
1414     errno = 0;
1415     if (0) {
1416 #endif
1417 #ifdef HAVE_QB_IPCC_AUTH_GET
1418     do_checks:
1419 #endif
1420         if (gotpid != NULL) {
1421             *gotpid = found_pid;
1422         }
1423         if (gotuid != NULL) {
1424             *gotuid = found_uid;
1425         }
1426         if (gotgid != NULL) {
1427             *gotgid = found_gid;
1428         }
1429         if (found_uid == 0 || found_uid == refuid || found_gid == refgid) {
1430                 ret = 0;
1431         } else {
1432                 ret = pcmk_rc_ipc_unauthorized;
1433         }
1434     } else {
1435         ret = (errno > 0) ? errno : pcmk_rc_error;
1436     }
1437     return ret;
1438 }
1439 
1440 int
1441 crm_ipc_is_authentic_process(int sock, uid_t refuid, gid_t refgid,
     /* [previous][next][first][last][top][bottom][index][help] */
1442                              pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1443 {
1444     int ret  = pcmk__crm_ipc_is_authentic_process(NULL, sock, refuid, refgid,
1445                                                   gotpid, gotuid, gotgid);
1446 
1447     /* The old function had some very odd return codes*/
1448     if (ret == 0) {
1449         return 1;
1450     } else if (ret == pcmk_rc_ipc_unauthorized) {
1451         return 0;
1452     } else {
1453         return pcmk_rc2legacy(ret);
1454     }
1455 }
1456 
1457 int
1458 pcmk__ipc_is_authentic_process_active(const char *name, uid_t refuid,
     /* [previous][next][first][last][top][bottom][index][help] */
1459                                       gid_t refgid, pid_t *gotpid)
1460 {
1461     static char last_asked_name[PATH_MAX / 2] = "";  /* log spam prevention */
1462     int fd;
1463     int rc = pcmk_rc_ipc_unresponsive;
1464     int auth_rc = 0;
1465     int32_t qb_rc;
1466     pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
1467     qb_ipcc_connection_t *c;
1468 #ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1469     struct pollfd pollfd = { 0, };
1470     int poll_rc;
1471 
1472     c = qb_ipcc_connect_async(name, 0,
1473                               &(pollfd.fd));
1474 #else
1475     c = qb_ipcc_connect(name, 0);
1476 #endif
1477     if (c == NULL) {
1478         crm_info("Could not connect to %s IPC: %s", name, strerror(errno));
1479         rc = pcmk_rc_ipc_unresponsive;
1480         goto bail;
1481     }
1482 #ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1483     pollfd.events = POLLIN;
1484     do {
1485         poll_rc = poll(&pollfd, 1, 2000);
1486     } while ((poll_rc == -1) && (errno == EINTR));
1487     if ((poll_rc <= 0) || (qb_ipcc_connect_continue(c) != 0)) {
1488         crm_info("Could not connect to %s IPC: %s", name,
1489                  (poll_rc == 0)?"timeout":strerror(errno));
1490         rc = pcmk_rc_ipc_unresponsive;
1491         if (poll_rc > 0) {
1492             c = NULL; // qb_ipcc_connect_continue cleaned up for us
1493         }
1494         goto bail;
1495     }
1496 #endif
1497 
1498     qb_rc = qb_ipcc_fd_get(c, &fd);
1499     if (qb_rc != 0) {
1500         rc = (int) -qb_rc; // System errno
1501         crm_err("Could not get fd from %s IPC: %s " CRM_XS " rc=%d",
1502                 name, pcmk_rc_str(rc), rc);
1503         goto bail;
1504     }
1505 
1506     auth_rc = pcmk__crm_ipc_is_authentic_process(c, fd, refuid, refgid, &found_pid,
1507                                                  &found_uid, &found_gid);
1508     if (auth_rc == pcmk_rc_ipc_unauthorized) {
1509         crm_err("Daemon (IPC %s) effectively blocked with unauthorized"
1510                 " process %lld (uid: %lld, gid: %lld)",
1511                 name, (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
1512                 (long long) found_uid, (long long) found_gid);
1513         rc = pcmk_rc_ipc_unauthorized;
1514         goto bail;
1515     }
1516 
1517     if (auth_rc != pcmk_rc_ok) {
1518         rc = auth_rc;
1519         crm_err("Could not get peer credentials from %s IPC: %s "
1520                 CRM_XS " rc=%d", name, pcmk_rc_str(rc), rc);
1521         goto bail;
1522     }
1523 
1524     if (gotpid != NULL) {
1525         *gotpid = found_pid;
1526     }
1527 
1528     rc = pcmk_rc_ok;
1529     if ((found_uid != refuid || found_gid != refgid)
1530             && strncmp(last_asked_name, name, sizeof(last_asked_name))) {
1531         if ((found_uid == 0) && (refuid != 0)) {
1532             crm_warn("Daemon (IPC %s) runs as root, whereas the expected"
1533                      " credentials are %lld:%lld, hazard of violating"
1534                      " the least privilege principle",
1535                      name, (long long) refuid, (long long) refgid);
1536         } else {
1537             crm_notice("Daemon (IPC %s) runs as %lld:%lld, whereas the"
1538                        " expected credentials are %lld:%lld, which may"
1539                        " mean a different set of privileges than expected",
1540                        name, (long long) found_uid, (long long) found_gid,
1541                        (long long) refuid, (long long) refgid);
1542         }
1543         memccpy(last_asked_name, name, '\0', sizeof(last_asked_name));
1544     }
1545 
1546 bail:
1547     if (c != NULL) {
1548         qb_ipcc_disconnect(c);
1549     }
1550     return rc;
1551 }

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