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_connect
  25. crm_ipc_close
  26. crm_ipc_destroy
  27. pcmk__ipc_fd
  28. crm_ipc_get_fd
  29. crm_ipc_connected
  30. crm_ipc_ready
  31. crm_ipc_decompress
  32. crm_ipc_read
  33. crm_ipc_buffer
  34. crm_ipc_buffer_flags
  35. crm_ipc_name
  36. internal_ipc_get_reply
  37. crm_ipc_send
  38. is_ipc_provider_expected
  39. crm_ipc_is_authentic_process
  40. pcmk__ipc_is_authentic_process_active

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

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