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