root/lib/common/ipc_client.c

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

DEFINITIONS

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

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

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