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. pcmk_poll_ipc
  11. pcmk_dispatch_ipc
  12. connect_with_main_loop
  13. connect_without_main_loop
  14. pcmk_connect_ipc
  15. pcmk_disconnect_ipc
  16. pcmk_register_ipc_callback
  17. pcmk__send_ipc_request
  18. create_purge_node_request
  19. pcmk_ipc_purge_node
  20. crm_ipc_new
  21. crm_ipc_connect
  22. crm_ipc_close
  23. crm_ipc_destroy
  24. crm_ipc_get_fd
  25. crm_ipc_connected
  26. crm_ipc_ready
  27. crm_ipc_decompress
  28. crm_ipc_read
  29. crm_ipc_buffer
  30. crm_ipc_buffer_flags
  31. crm_ipc_name
  32. internal_ipc_get_reply
  33. crm_ipc_send
  34. crm_ipc_is_authentic_process
  35. pcmk__ipc_is_authentic_process_active

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

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