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

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

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