Coverage Report

Created: 2026-07-12 06:15

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