1 /*
2 * Copyright 2004-2019 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10 #include <crm_internal.h>
11
12 #if defined(US_AUTH_PEERCRED_UCRED) || defined(US_AUTH_PEERCRED_SOCKPEERCRED)
13 # ifdef US_AUTH_PEERCRED_UCRED
14 # ifndef _GNU_SOURCE
15 # define _GNU_SOURCE
16 # endif
17 # endif
18 # include <sys/socket.h>
19 #elif defined(US_AUTH_GETPEERUCRED)
20 # include <ucred.h>
21 #endif
22
23 #include <sys/param.h>
24
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <grp.h>
30
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <bzlib.h>
34
35 #include <crm/crm.h> /* indirectly: pcmk_err_generic */
36 #include <crm/msg_xml.h>
37 #include <crm/common/ipc.h>
38 #include <crm/common/ipcs.h>
39
40 #include <crm/common/ipc_internal.h> /* PCMK__SPECIAL_PID* */
41
42 #define PCMK_IPC_VERSION 1
43
44 /* Evict clients whose event queue grows this large (by default) */
45 #define PCMK_IPC_DEFAULT_QUEUE_MAX 500
46
47 struct crm_ipc_response_header {
48 struct qb_ipc_response_header qb;
49 uint32_t size_uncompressed;
50 uint32_t size_compressed;
51 uint32_t flags;
52 uint8_t version; /* Protect against version changes for anyone that might bother to statically link us */
53 };
54
55 static int hdr_offset = 0;
56 static unsigned int ipc_buffer_max = 0;
57 static unsigned int pick_ipc_buffer(unsigned int max);
58
59 static inline void
crm_ipc_init(void)60 crm_ipc_init(void)
61 {
62 if (hdr_offset == 0) {
63 hdr_offset = sizeof(struct crm_ipc_response_header);
64 }
65 if (ipc_buffer_max == 0) {
66 ipc_buffer_max = pick_ipc_buffer(0);
67 }
68 }
69
70 unsigned int
crm_ipc_default_buffer_size(void)71 crm_ipc_default_buffer_size(void)
72 {
73 return pick_ipc_buffer(0);
74 }
75
76 static char *
generateReference(const char * custom1,const char * custom2)77 generateReference(const char *custom1, const char *custom2)
78 {
79 static uint ref_counter = 0;
80 const char *local_cust1 = custom1;
81 const char *local_cust2 = custom2;
82 int reference_len = 4;
83 char *since_epoch = NULL;
84
85 reference_len += 20; /* too big */
86 reference_len += 40; /* too big */
87
88 if (local_cust1 == NULL) {
89 local_cust1 = "_empty_";
90 }
91 reference_len += strlen(local_cust1);
92
93 if (local_cust2 == NULL) {
94 local_cust2 = "_empty_";
95 }
96 reference_len += strlen(local_cust2);
97
98 since_epoch = calloc(1, reference_len);
99
100 if (since_epoch != NULL) {
101 sprintf(since_epoch, "%s-%s-%lu-%u",
102 local_cust1, local_cust2, (unsigned long)time(NULL), ref_counter++);
103 }
104
105 return since_epoch;
106 }
107
108 xmlNode *
create_request_adv(const char * task,xmlNode * msg_data,const char * host_to,const char * sys_to,const char * sys_from,const char * uuid_from,const char * origin)109 create_request_adv(const char *task, xmlNode * msg_data,
110 const char *host_to, const char *sys_to,
111 const char *sys_from, const char *uuid_from, const char *origin)
112 {
113 char *true_from = NULL;
114 xmlNode *request = NULL;
115 char *reference = generateReference(task, sys_from);
116
117 if (uuid_from != NULL) {
118 true_from = generate_hash_key(sys_from, uuid_from);
119 } else if (sys_from != NULL) {
120 true_from = strdup(sys_from);
121 } else {
122 crm_err("No sys from specified");
123 }
124
125 /* host_from will get set for us if necessary by CRMd when routed */
126 request = create_xml_node(NULL, __FUNCTION__);
127 crm_xml_add(request, F_CRM_ORIGIN, origin);
128 crm_xml_add(request, F_TYPE, T_CRM);
129 crm_xml_add(request, F_CRM_VERSION, CRM_FEATURE_SET);
130 crm_xml_add(request, F_CRM_MSG_TYPE, XML_ATTR_REQUEST);
131 crm_xml_add(request, F_CRM_REFERENCE, reference);
132 crm_xml_add(request, F_CRM_TASK, task);
133 crm_xml_add(request, F_CRM_SYS_TO, sys_to);
134 crm_xml_add(request, F_CRM_SYS_FROM, true_from);
135
136 /* HOSTTO will be ignored if it is to the DC anyway. */
137 if (host_to != NULL && strlen(host_to) > 0) {
138 crm_xml_add(request, F_CRM_HOST_TO, host_to);
139 }
140
141 if (msg_data != NULL) {
142 add_message_xml(request, F_CRM_DATA, msg_data);
143 }
144 free(reference);
145 free(true_from);
146
147 return request;
148 }
149
150 /*
151 * This method adds a copy of xml_response_data
152 */
153 xmlNode *
create_reply_adv(xmlNode * original_request,xmlNode * xml_response_data,const char * origin)154 create_reply_adv(xmlNode * original_request, xmlNode * xml_response_data, const char *origin)
155 {
156 xmlNode *reply = NULL;
157
158 const char *host_from = crm_element_value(original_request, F_CRM_HOST_FROM);
159 const char *sys_from = crm_element_value(original_request, F_CRM_SYS_FROM);
160 const char *sys_to = crm_element_value(original_request, F_CRM_SYS_TO);
161 const char *type = crm_element_value(original_request, F_CRM_MSG_TYPE);
162 const char *operation = crm_element_value(original_request, F_CRM_TASK);
163 const char *crm_msg_reference = crm_element_value(original_request, F_CRM_REFERENCE);
164
165 if (type == NULL) {
166 crm_err("Cannot create new_message, no message type in original message");
167 CRM_ASSERT(type != NULL);
168 return NULL;
169 #if 0
170 } else if (strcasecmp(XML_ATTR_REQUEST, type) != 0) {
171 crm_err("Cannot create new_message, original message was not a request");
172 return NULL;
173 #endif
174 }
175 reply = create_xml_node(NULL, __FUNCTION__);
176 if (reply == NULL) {
177 crm_err("Cannot create new_message, malloc failed");
178 return NULL;
179 }
180
181 crm_xml_add(reply, F_CRM_ORIGIN, origin);
182 crm_xml_add(reply, F_TYPE, T_CRM);
183 crm_xml_add(reply, F_CRM_VERSION, CRM_FEATURE_SET);
184 crm_xml_add(reply, F_CRM_MSG_TYPE, XML_ATTR_RESPONSE);
185 crm_xml_add(reply, F_CRM_REFERENCE, crm_msg_reference);
186 crm_xml_add(reply, F_CRM_TASK, operation);
187
188 /* since this is a reply, we reverse the from and to */
189 crm_xml_add(reply, F_CRM_SYS_TO, sys_from);
190 crm_xml_add(reply, F_CRM_SYS_FROM, sys_to);
191
192 /* HOSTTO will be ignored if it is to the DC anyway. */
193 if (host_from != NULL && strlen(host_from) > 0) {
194 crm_xml_add(reply, F_CRM_HOST_TO, host_from);
195 }
196
197 if (xml_response_data != NULL) {
198 add_message_xml(reply, F_CRM_DATA, xml_response_data);
199 }
200
201 return reply;
202 }
203
204 /* Libqb based IPC */
205
206 /* Server... */
207
208 GHashTable *client_connections = NULL;
209
210 crm_client_t *
crm_client_get(qb_ipcs_connection_t * c)211 crm_client_get(qb_ipcs_connection_t * c)
212 {
213 if (client_connections) {
214 return g_hash_table_lookup(client_connections, c);
215 }
216
217 crm_trace("No client found for %p", c);
218 return NULL;
219 }
220
221 crm_client_t *
crm_client_get_by_id(const char * id)222 crm_client_get_by_id(const char *id)
223 {
224 gpointer key;
225 crm_client_t *client;
226 GHashTableIter iter;
227
228 if (client_connections && id) {
229 g_hash_table_iter_init(&iter, client_connections);
230 while (g_hash_table_iter_next(&iter, &key, (gpointer *) & client)) {
231 if (strcmp(client->id, id) == 0) {
232 return client;
233 }
234 }
235 }
236
237 crm_trace("No client found with id=%s", id);
238 return NULL;
239 }
240
241 const char *
crm_client_name(crm_client_t * c)242 crm_client_name(crm_client_t * c)
243 {
244 if (c == NULL) {
245 return "null";
246 } else if (c->name == NULL && c->id == NULL) {
247 return "unknown";
248 } else if (c->name == NULL) {
249 return c->id;
250 } else {
251 return c->name;
252 }
253 }
254
255 void
crm_client_init(void)256 crm_client_init(void)
257 {
258 if (client_connections == NULL) {
259 crm_trace("Creating client hash table");
260 client_connections = g_hash_table_new(g_direct_hash, g_direct_equal);
261 }
262 }
263
264 void
crm_client_cleanup(void)265 crm_client_cleanup(void)
266 {
267 if (client_connections != NULL) {
268 int active = g_hash_table_size(client_connections);
269
270 if (active) {
271 crm_err("Exiting with %d active connections", active);
272 }
273 g_hash_table_destroy(client_connections); client_connections = NULL;
274 }
275 }
276
277 void
crm_client_disconnect_all(qb_ipcs_service_t * service)278 crm_client_disconnect_all(qb_ipcs_service_t *service)
279 {
280 qb_ipcs_connection_t *c = NULL;
281
282 if (service == NULL) {
283 return;
284 }
285
286 c = qb_ipcs_connection_first_get(service);
287
288 while (c != NULL) {
289 qb_ipcs_connection_t *last = c;
290
291 c = qb_ipcs_connection_next_get(service, last);
292
293 /* There really shouldn't be anyone connected at this point */
294 crm_notice("Disconnecting client %p, pid=%d...", last, crm_ipcs_client_pid(last));
295 qb_ipcs_disconnect(last);
296 qb_ipcs_connection_unref(last);
297 }
298 }
299
300 /*!
301 * \internal
302 * \brief Allocate a new crm_client_t object based on an IPC connection
303 *
304 * \param[in] c IPC connection (or NULL to allocate generic client)
305 * \param[in] key Connection table key (or NULL to use sane default)
306 * \param[in] uid_client UID corresponding to c (ignored if c is NULL)
307 *
308 * \return Pointer to new crm_client_t (or NULL on error)
309 */
310 static crm_client_t *
client_from_connection(qb_ipcs_connection_t * c,void * key,uid_t uid_client)311 client_from_connection(qb_ipcs_connection_t *c, void *key, uid_t uid_client)
312 {
313 crm_client_t *client = calloc(1, sizeof(crm_client_t));
314
315 if (client == NULL) {
316 crm_perror(LOG_ERR, "Allocating client");
317 return NULL;
318 }
319
320 if (c) {
321 #if ENABLE_ACL
322 client->user = uid2username(uid_client);
323 if (client->user == NULL) {
324 client->user = strdup("#unprivileged");
325 CRM_CHECK(client->user != NULL, free(client); return NULL);
326 crm_err("Unable to enforce ACLs for user ID %d, assuming unprivileged",
327 uid_client);
328 }
329 #endif
330 client->ipcs = c;
331 client->kind = CRM_CLIENT_IPC;
332 client->pid = crm_ipcs_client_pid(c);
333 if (key == NULL) {
334 key = c;
335 }
336 }
337
338 client->id = crm_generate_uuid();
339 if (client->id == NULL) {
340 crm_err("Could not generate UUID for client");
341 free(client->user);
342 free(client);
343 return NULL;
344 }
345 if (key == NULL) {
346 key = client->id;
347 }
348 g_hash_table_insert(client_connections, key, client);
349 return client;
350 }
351
352 /*!
353 * \brief Allocate a new crm_client_t object and generate its ID
354 *
355 * \param[in] key What to use as connections hash table key (NULL to use ID)
356 *
357 * \return Pointer to new crm_client_t (asserts on failure)
358 */
359 crm_client_t *
crm_client_alloc(void * key)360 crm_client_alloc(void *key)
361 {
362 crm_client_t *client = client_from_connection(NULL, key, 0);
363
364 CRM_ASSERT(client != NULL);
365 return client;
366 }
367
368 crm_client_t *
crm_client_new(qb_ipcs_connection_t * c,uid_t uid_client,gid_t gid_client)369 crm_client_new(qb_ipcs_connection_t * c, uid_t uid_client, gid_t gid_client)
370 {
371 static gid_t uid_cluster = 0;
372 static gid_t gid_cluster = 0;
373
374 crm_client_t *client = NULL;
375
376 CRM_CHECK(c != NULL, return NULL);
377
378 if (uid_cluster == 0) {
379 if (crm_user_lookup(CRM_DAEMON_USER, &uid_cluster, &gid_cluster) < 0) {
380 static bool need_log = TRUE;
381
382 if (need_log) {
383 crm_warn("Could not find user and group IDs for user %s",
384 CRM_DAEMON_USER);
385 need_log = FALSE;
386 }
387 }
388 }
389
390 if (uid_client != 0) {
391 crm_trace("Giving access to group %u", gid_cluster);
392 /* Passing -1 to chown(2) means don't change */
393 qb_ipcs_connection_auth_set(c, -1, gid_cluster, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
394 }
395
396 crm_client_init();
397
398 /* TODO: Do our own auth checking, return NULL if unauthorized */
399 client = client_from_connection(c, NULL, uid_client);
400 if (client == NULL) {
401 return NULL;
402 }
403
404 if ((uid_client == 0) || (uid_client == uid_cluster)) {
405 /* Remember when a connection came from root or hacluster */
406 set_bit(client->flags, crm_client_flag_ipc_privileged);
407 }
408
409 crm_debug("Connecting %p for uid=%d gid=%d pid=%u id=%s", c, uid_client, gid_client, client->pid, client->id);
410
411 return client;
412 }
413
414 void
crm_client_destroy(crm_client_t * c)415 crm_client_destroy(crm_client_t * c)
416 {
417 if (c == NULL) {
418 return;
419 }
420
421 if (client_connections) {
422 if (c->ipcs) {
423 crm_trace("Destroying %p/%p (%d remaining)",
424 c, c->ipcs, crm_hash_table_size(client_connections) - 1);
425 g_hash_table_remove(client_connections, c->ipcs);
426
427 } else {
428 crm_trace("Destroying remote connection %p (%d remaining)",
429 c, crm_hash_table_size(client_connections) - 1);
430 g_hash_table_remove(client_connections, c->id);
431 }
432 }
433
434 if (c->event_timer) {
435 g_source_remove(c->event_timer);
436 }
437
438 crm_debug("Destroying %d events", g_list_length(c->event_queue));
439 while (c->event_queue) {
440 struct iovec *event = c->event_queue->data;
441
442 c->event_queue = g_list_remove(c->event_queue, event);
443 free(event[0].iov_base);
444 free(event[1].iov_base);
445 free(event);
446 }
447
448 free(c->id);
449 free(c->name);
450 free(c->user);
451 if (c->remote) {
452 if (c->remote->auth_timeout) {
453 g_source_remove(c->remote->auth_timeout);
454 }
455 free(c->remote->buffer);
456 free(c->remote);
457 }
458 free(c);
459 }
460
461 /*!
462 * \brief Raise IPC eviction threshold for a client, if allowed
463 *
464 * \param[in,out] client Client to modify
465 * \param[in] queue_max New threshold (as string)
466 *
467 * \return TRUE if change was allowed, FALSE otherwise
468 */
469 bool
crm_set_client_queue_max(crm_client_t * client,const char * qmax)470 crm_set_client_queue_max(crm_client_t *client, const char *qmax)
471 {
472 if (is_set(client->flags, crm_client_flag_ipc_privileged)) {
473 int qmax_int = crm_int_helper(qmax, NULL);
474
475 if ((errno == 0) && (qmax_int > 0)) {
476 client->queue_max = qmax_int;
477 return TRUE;
478 }
479 }
480 return FALSE;
481 }
482
483 int
crm_ipcs_client_pid(qb_ipcs_connection_t * c)484 crm_ipcs_client_pid(qb_ipcs_connection_t * c)
485 {
486 struct qb_ipcs_connection_stats stats;
487
488 stats.client_pid = 0;
489 qb_ipcs_connection_stats_get(c, &stats, 0);
490 return stats.client_pid;
491 }
492
493 xmlNode *
crm_ipcs_recv(crm_client_t * c,void * data,size_t size,uint32_t * id,uint32_t * flags)494 crm_ipcs_recv(crm_client_t * c, void *data, size_t size, uint32_t * id, uint32_t * flags)
495 {
496 xmlNode *xml = NULL;
497 char *uncompressed = NULL;
498 char *text = ((char *)data) + sizeof(struct crm_ipc_response_header);
499 struct crm_ipc_response_header *header = data;
500
501 if (id) {
502 *id = ((struct qb_ipc_response_header *)data)->id;
503 }
504 if (flags) {
505 *flags = header->flags;
506 }
507
508 if (is_set(header->flags, crm_ipc_proxied)) {
509 /* mark this client as being the endpoint of a proxy connection.
510 * Proxy connections responses are sent on the event channel to avoid
511 * blocking the proxy daemon (crmd) */
512 c->flags |= crm_client_flag_ipc_proxied;
513 }
514
515 if(header->version > PCMK_IPC_VERSION) {
516 crm_err("Filtering incompatible v%d IPC message, we only support versions <= %d",
517 header->version, PCMK_IPC_VERSION);
518 return NULL;
519 }
520
521 if (header->size_compressed) {
522 int rc = 0;
523 unsigned int size_u = 1 + header->size_uncompressed;
524 uncompressed = calloc(1, size_u);
525
526 crm_trace("Decompressing message data %u bytes into %u bytes",
527 header->size_compressed, size_u);
528
529 rc = BZ2_bzBuffToBuffDecompress(uncompressed, &size_u, text, header->size_compressed, 1, 0);
530 text = uncompressed;
531
532 if (rc != BZ_OK) {
533 crm_err("Decompression failed: %s (%d)", bz2_strerror(rc), rc);
534 free(uncompressed);
535 return NULL;
536 }
537 }
538
539 CRM_ASSERT(text[header->size_uncompressed - 1] == 0);
540
541 crm_trace("Received %.200s", text);
542 xml = string2xml(text);
543
544 free(uncompressed);
545 return xml;
546 }
547
548 ssize_t crm_ipcs_flush_events(crm_client_t * c);
549
550 static gboolean
crm_ipcs_flush_events_cb(gpointer data)551 crm_ipcs_flush_events_cb(gpointer data)
552 {
553 crm_client_t *c = data;
554
555 c->event_timer = 0;
556 crm_ipcs_flush_events(c);
557 return FALSE;
558 }
559
560 /*!
561 * \internal
562 * \brief Add progressive delay before next event queue flush
563 *
564 * \param[in,out] c Client connection to add delay to
565 * \param[in] queue_len Current event queue length
566 */
567 static inline void
delay_next_flush(crm_client_t * c,unsigned int queue_len)568 delay_next_flush(crm_client_t *c, unsigned int queue_len)
569 {
570 /* Delay a maximum of 5 seconds */
571 guint delay = (queue_len < 40)? (1000 + 100 * queue_len) : 5000;
572
573 c->event_timer = g_timeout_add(delay, crm_ipcs_flush_events_cb, c);
574 }
575
576 ssize_t
crm_ipcs_flush_events(crm_client_t * c)577 crm_ipcs_flush_events(crm_client_t * c)
578 {
579 ssize_t rc = 0;
580 unsigned int sent = 0;
581 unsigned int queue_len = 0;
582
583 if (c == NULL) {
584 return pcmk_ok;
585
586 } else if (c->event_timer) {
587 /* There is already a timer, wait until it goes off */
588 crm_trace("Timer active for %p - %d", c->ipcs, c->event_timer);
589 return pcmk_ok;
590 }
591
592 queue_len = g_list_length(c->event_queue);
593 while (c->event_queue && sent < 100) {
594 struct crm_ipc_response_header *header = NULL;
595 struct iovec *event = c->event_queue->data;
596
597 rc = qb_ipcs_event_sendv(c->ipcs, event, 2);
598 if (rc < 0) {
599 break;
600 }
601
602 sent++;
603 header = event[0].iov_base;
604 if (header->size_compressed) {
605 crm_trace("Event %d to %p[%d] (%lld compressed bytes) sent",
606 header->qb.id, c->ipcs, c->pid, (long long) rc);
607 } else {
608 crm_trace("Event %d to %p[%d] (%lld bytes) sent: %.120s",
609 header->qb.id, c->ipcs, c->pid, (long long) rc,
610 (char *) (event[1].iov_base));
611 }
612
613 c->event_queue = g_list_remove(c->event_queue, event);
614 free(event[0].iov_base);
615 free(event[1].iov_base);
616 free(event);
617 }
618
619 queue_len -= sent;
620 if (sent > 0 || queue_len) {
621 crm_trace("Sent %d events (%d remaining) for %p[%d]: %s (%lld)",
622 sent, queue_len, c->ipcs, c->pid,
623 pcmk_strerror(rc < 0 ? rc : 0), (long long) rc);
624 }
625
626 if (queue_len) {
627
628 /* Allow clients to briefly fall behind on processing incoming messages,
629 * but drop completely unresponsive clients so the connection doesn't
630 * consume resources indefinitely.
631 */
632 if (queue_len > QB_MAX(c->queue_max, PCMK_IPC_DEFAULT_QUEUE_MAX)) {
633 if ((c->queue_backlog <= 1) || (queue_len < c->queue_backlog)) {
634 /* Don't evict for a new or shrinking backlog */
635 crm_warn("Client with process ID %u has a backlog of %u messages "
636 CRM_XS " %p", c->pid, queue_len, c->ipcs);
637 } else {
638 crm_err("Evicting client with process ID %u due to backlog of %u messages "
639 CRM_XS " %p", c->pid, queue_len, c->ipcs);
640 c->queue_backlog = 0;
641 qb_ipcs_disconnect(c->ipcs);
642 return rc;
643 }
644 }
645
646 c->queue_backlog = queue_len;
647 delay_next_flush(c, queue_len);
648
649 } else {
650 /* Event queue is empty, there is no backlog */
651 c->queue_backlog = 0;
652 }
653
654 return rc;
655 }
656
657 ssize_t
crm_ipc_prepare(uint32_t request,xmlNode * message,struct iovec ** result,uint32_t max_send_size)658 crm_ipc_prepare(uint32_t request, xmlNode * message, struct iovec ** result, uint32_t max_send_size)
659 {
660 static unsigned int biggest = 0;
661 struct iovec *iov;
662 unsigned int total = 0;
663 char *compressed = NULL;
664 char *buffer = dump_xml_unformatted(message);
665 struct crm_ipc_response_header *header = calloc(1, sizeof(struct crm_ipc_response_header));
666
667 CRM_ASSERT(result != NULL);
668
669 crm_ipc_init();
670
671 if (max_send_size == 0) {
672 max_send_size = ipc_buffer_max;
673 }
674
675 CRM_LOG_ASSERT(max_send_size != 0);
676
677 *result = NULL;
678 iov = calloc(2, sizeof(struct iovec));
679
680
681 iov[0].iov_len = hdr_offset;
682 iov[0].iov_base = header;
683
684 header->version = PCMK_IPC_VERSION;
685 header->size_uncompressed = 1 + strlen(buffer);
686 total = iov[0].iov_len + header->size_uncompressed;
687
688 if (total < max_send_size) {
689 iov[1].iov_base = buffer;
690 iov[1].iov_len = header->size_uncompressed;
691
692 } else {
693 unsigned int new_size = 0;
694
695 if (crm_compress_string
696 (buffer, header->size_uncompressed, max_send_size, &compressed, &new_size)) {
697
698 header->flags |= crm_ipc_compressed;
699 header->size_compressed = new_size;
700
701 iov[1].iov_len = header->size_compressed;
702 iov[1].iov_base = compressed;
703
704 free(buffer);
705
706 biggest = QB_MAX(header->size_compressed, biggest);
707
708 } else {
709 ssize_t rc = -EMSGSIZE;
710
711 crm_log_xml_trace(message, "EMSGSIZE");
712 biggest = QB_MAX(header->size_uncompressed, biggest);
713
714 crm_err
715 ("Could not compress the message (%u bytes) into less than the configured ipc limit (%u bytes). "
716 "Set PCMK_ipc_buffer to a higher value (%u bytes suggested)",
717 header->size_uncompressed, max_send_size, 4 * biggest);
718
719 free(compressed);
720 free(buffer);
721 free(header);
722 free(iov);
723
724 return rc;
725 }
726 }
727
728 header->qb.size = iov[0].iov_len + iov[1].iov_len;
729 header->qb.id = (int32_t)request; /* Replying to a specific request */
730
731 *result = iov;
732 CRM_ASSERT(header->qb.size > 0);
733 return header->qb.size;
734 }
735
736 ssize_t
crm_ipcs_sendv(crm_client_t * c,struct iovec * iov,enum crm_ipc_flags flags)737 crm_ipcs_sendv(crm_client_t * c, struct iovec * iov, enum crm_ipc_flags flags)
738 {
739 ssize_t rc;
740 static uint32_t id = 1;
741 struct crm_ipc_response_header *header = iov[0].iov_base;
742
743 if (c->flags & crm_client_flag_ipc_proxied) {
744 /* _ALL_ replies to proxied connections need to be sent as events */
745 if (is_not_set(flags, crm_ipc_server_event)) {
746 flags |= crm_ipc_server_event;
747 /* this flag lets us know this was originally meant to be a response.
748 * even though we're sending it over the event channel. */
749 flags |= crm_ipc_proxied_relay_response;
750 }
751 }
752
753 header->flags |= flags;
754 if (flags & crm_ipc_server_event) {
755 header->qb.id = id++; /* We don't really use it, but doesn't hurt to set one */
756
757 if (flags & crm_ipc_server_free) {
758 crm_trace("Sending the original to %p[%d]", c->ipcs, c->pid);
759 c->event_queue = g_list_append(c->event_queue, iov);
760
761 } else {
762 struct iovec *iov_copy = calloc(2, sizeof(struct iovec));
763
764 crm_trace("Sending a copy to %p[%d]", c->ipcs, c->pid);
765 iov_copy[0].iov_len = iov[0].iov_len;
766 iov_copy[0].iov_base = malloc(iov[0].iov_len);
767 memcpy(iov_copy[0].iov_base, iov[0].iov_base, iov[0].iov_len);
768
769 iov_copy[1].iov_len = iov[1].iov_len;
770 iov_copy[1].iov_base = malloc(iov[1].iov_len);
771 memcpy(iov_copy[1].iov_base, iov[1].iov_base, iov[1].iov_len);
772
773 c->event_queue = g_list_append(c->event_queue, iov_copy);
774 }
775
776 } else {
777 CRM_LOG_ASSERT(header->qb.id != 0); /* Replying to a specific request */
778
779 rc = qb_ipcs_response_sendv(c->ipcs, iov, 2);
780 if (rc < header->qb.size) {
781 crm_notice("Response %d to %p[%d] (%u bytes) failed: %s (%d)",
782 header->qb.id, c->ipcs, c->pid, header->qb.size, pcmk_strerror(rc), rc);
783
784 } else {
785 crm_trace("Response %d sent, %lld bytes to %p[%d]",
786 header->qb.id, (long long) rc, c->ipcs, c->pid);
787 }
788
789 if (flags & crm_ipc_server_free) {
790 free(iov[0].iov_base);
791 free(iov[1].iov_base);
792 free(iov);
793 }
794 }
795
796 if (flags & crm_ipc_server_event) {
797 rc = crm_ipcs_flush_events(c);
798 } else {
799 crm_ipcs_flush_events(c);
800 }
801
802 if (rc == -EPIPE || rc == -ENOTCONN) {
803 crm_trace("Client %p disconnected", c->ipcs);
804 }
805
806 return rc;
807 }
808
809 ssize_t
crm_ipcs_send(crm_client_t * c,uint32_t request,xmlNode * message,enum crm_ipc_flags flags)810 crm_ipcs_send(crm_client_t * c, uint32_t request, xmlNode * message,
811 enum crm_ipc_flags flags)
812 {
813 struct iovec *iov = NULL;
814 ssize_t rc = 0;
815
816 if(c == NULL) {
817 return -EDESTADDRREQ;
818 }
819 crm_ipc_init();
820
821 rc = crm_ipc_prepare(request, message, &iov, ipc_buffer_max);
822 if (rc > 0) {
823 rc = crm_ipcs_sendv(c, iov, flags | crm_ipc_server_free);
824
825 } else {
826 free(iov);
827 crm_notice("Message to %p[%d] failed: %s (%d)",
828 c->ipcs, c->pid, pcmk_strerror(rc), rc);
829 }
830
831 return rc;
832 }
833
834 void
crm_ipcs_send_ack(crm_client_t * c,uint32_t request,uint32_t flags,const char * tag,const char * function,int line)835 crm_ipcs_send_ack(crm_client_t * c, uint32_t request, uint32_t flags, const char *tag, const char *function,
836 int line)
837 {
838 if (flags & crm_ipc_client_response) {
839 xmlNode *ack = create_xml_node(NULL, tag);
840
841 crm_trace("Ack'ing msg from %s (%p)", crm_client_name(c), c);
842 c->request_id = 0;
843 crm_xml_add(ack, "function", function);
844 crm_xml_add_int(ack, "line", line);
845 crm_ipcs_send(c, request, ack, flags);
846 free_xml(ack);
847 }
848 }
849
850 /* Client... */
851
852 #define MIN_MSG_SIZE 12336 /* sizeof(struct qb_ipc_connection_response) */
853 #define MAX_MSG_SIZE 128*1024 /* 128k default */
854
855 struct crm_ipc_s {
856 struct pollfd pfd;
857
858 /* the max size we can send/receive over ipc */
859 unsigned int max_buf_size;
860 /* Size of the allocated 'buffer' */
861 unsigned int buf_size;
862 int msg_size;
863 int need_reply;
864 char *buffer;
865 char *name;
866 uint32_t buffer_flags;
867
868 qb_ipcc_connection_t *ipc;
869
870 };
871
872 static unsigned int
pick_ipc_buffer(unsigned int max)873 pick_ipc_buffer(unsigned int max)
874 {
875 static unsigned int global_max = 0;
876
877 if (global_max == 0) {
878 const char *env = getenv("PCMK_ipc_buffer");
879
880 if (env) {
881 int env_max = crm_parse_int(env, "0");
882
883 global_max = (env_max > 0)? QB_MAX(MIN_MSG_SIZE, env_max) : MAX_MSG_SIZE;
884
885 } else {
886 global_max = MAX_MSG_SIZE;
887 }
888 }
889
890 return QB_MAX(max, global_max);
891 }
892
893 crm_ipc_t *
crm_ipc_new(const char * name,size_t max_size)894 crm_ipc_new(const char *name, size_t max_size)
895 {
896 crm_ipc_t *client = NULL;
897
898 client = calloc(1, sizeof(crm_ipc_t));
899
900 client->name = strdup(name);
901 client->buf_size = pick_ipc_buffer(max_size);
902 client->buffer = malloc(client->buf_size);
903
904 /* Clients initiating connection pick the max buf size */
905 client->max_buf_size = client->buf_size;
906
907 client->pfd.fd = -1;
908 client->pfd.events = POLLIN;
909 client->pfd.revents = 0;
910
911 return client;
912 }
913
914 /*!
915 * \brief Establish an IPC connection to a Pacemaker component
916 *
917 * \param[in] client Connection instance obtained from crm_ipc_new()
918 *
919 * \return TRUE on success, FALSE otherwise (in which case errno will be set;
920 * specifically, in case of discovering the remote side is not
921 * authentic, its value is set to ECONNABORTED).
922 */
923 bool
crm_ipc_connect(crm_ipc_t * client)924 crm_ipc_connect(crm_ipc_t * client)
925 {
926 static uid_t cl_uid = 0;
927 static gid_t cl_gid = 0;
928 pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
929 int rv;
930
931 client->need_reply = FALSE;
932 client->ipc = qb_ipcc_connect(client->name, client->buf_size);
933
934 if (client->ipc == NULL) {
935 crm_debug("Could not establish %s connection: %s (%d)", client->name, pcmk_strerror(errno), errno);
936 return FALSE;
937 }
938
939 client->pfd.fd = crm_ipc_get_fd(client);
940 if (client->pfd.fd < 0) {
941 rv = errno;
942 /* message already omitted */
943 crm_ipc_close(client);
944 errno = rv;
945 return FALSE;
946 }
947
948 if (!cl_uid && !cl_gid
949 && (rv = crm_user_lookup(CRM_DAEMON_USER, &cl_uid, &cl_gid)) < 0) {
950 errno = -rv;
951 /* message already omitted */
952 crm_ipc_close(client);
953 errno = -rv;
954 return FALSE;
955 }
956
957 if (!(rv = crm_ipc_is_authentic_process(client->pfd.fd, cl_uid, cl_gid,
958 &found_pid, &found_uid,
959 &found_gid))) {
960 crm_err("Daemon (IPC %s) is not authentic:"
961 " process %lld (uid: %lld, gid: %lld)",
962 client->name, (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
963 (long long) found_uid, (long long) found_gid);
964 crm_ipc_close(client);
965 errno = ECONNABORTED;
966 return FALSE;
967
968 } else if (rv < 0) {
969 errno = -rv;
970 crm_perror(LOG_ERR, "Could not verify authenticity of daemon (IPC %s)",
971 client->name);
972 crm_ipc_close(client);
973 errno = -rv;
974 return FALSE;
975 }
976
977 qb_ipcc_context_set(client->ipc, client);
978
979 #ifdef HAVE_IPCS_GET_BUFFER_SIZE
980 client->max_buf_size = qb_ipcc_get_buffer_size(client->ipc);
981 if (client->max_buf_size > client->buf_size) {
982 free(client->buffer);
983 client->buffer = calloc(1, client->max_buf_size);
984 client->buf_size = client->max_buf_size;
985 }
986 #endif
987
988 return TRUE;
989 }
990
991 void
crm_ipc_close(crm_ipc_t * client)992 crm_ipc_close(crm_ipc_t * client)
993 {
994 if (client) {
995 crm_trace("Disconnecting %s IPC connection %p (%p)", client->name, client, client->ipc);
996
997 if (client->ipc) {
998 qb_ipcc_connection_t *ipc = client->ipc;
999
1000 client->ipc = NULL;
1001 qb_ipcc_disconnect(ipc);
1002 }
1003 }
1004 }
1005
1006 void
crm_ipc_destroy(crm_ipc_t * client)1007 crm_ipc_destroy(crm_ipc_t * client)
1008 {
1009 if (client) {
1010 if (client->ipc && qb_ipcc_is_connected(client->ipc)) {
1011 crm_notice("Destroying an active IPC connection to %s", client->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 }
1022 crm_trace("Destroying IPC connection to %s: %p", client->name, client);
1023 free(client->buffer);
1024 free(client->name);
1025 free(client);
1026 }
1027 }
1028
1029 int
crm_ipc_get_fd(crm_ipc_t * client)1030 crm_ipc_get_fd(crm_ipc_t * client)
1031 {
1032 int fd = 0;
1033
1034 if (client && client->ipc && (qb_ipcc_fd_get(client->ipc, &fd) == 0)) {
1035 return fd;
1036 }
1037 errno = EINVAL;
1038 crm_perror(LOG_ERR, "Could not obtain file IPC descriptor for %s",
1039 (client? client->name : "unspecified client"));
1040 return -errno;
1041 }
1042
1043 bool
crm_ipc_connected(crm_ipc_t * client)1044 crm_ipc_connected(crm_ipc_t * client)
1045 {
1046 bool rc = FALSE;
1047
1048 if (client == NULL) {
1049 crm_trace("No client");
1050 return FALSE;
1051
1052 } else if (client->ipc == NULL) {
1053 crm_trace("No connection");
1054 return FALSE;
1055
1056 } else if (client->pfd.fd < 0) {
1057 crm_trace("Bad descriptor");
1058 return FALSE;
1059 }
1060
1061 rc = qb_ipcc_is_connected(client->ipc);
1062 if (rc == FALSE) {
1063 client->pfd.fd = -EINVAL;
1064 }
1065 return rc;
1066 }
1067
1068 /*!
1069 * \brief Check whether an IPC connection is ready to be read
1070 *
1071 * \param[in] client Connection to check
1072 *
1073 * \return Positive value if ready to be read, 0 if not ready, -errno on error
1074 */
1075 int
crm_ipc_ready(crm_ipc_t * client)1076 crm_ipc_ready(crm_ipc_t *client)
1077 {
1078 int rc;
1079
1080 CRM_ASSERT(client != NULL);
1081
1082 if (crm_ipc_connected(client) == FALSE) {
1083 return -ENOTCONN;
1084 }
1085
1086 client->pfd.revents = 0;
1087 rc = poll(&(client->pfd), 1, 0);
1088 return (rc < 0)? -errno : rc;
1089 }
1090
1091 static int
crm_ipc_decompress(crm_ipc_t * client)1092 crm_ipc_decompress(crm_ipc_t * client)
1093 {
1094 struct crm_ipc_response_header *header = (struct crm_ipc_response_header *)(void*)client->buffer;
1095
1096 if (header->size_compressed) {
1097 int rc = 0;
1098 unsigned int size_u = 1 + header->size_uncompressed;
1099 /* never let buf size fall below our max size required for ipc reads. */
1100 unsigned int new_buf_size = QB_MAX((hdr_offset + size_u), client->max_buf_size);
1101 char *uncompressed = calloc(1, new_buf_size);
1102
1103 crm_trace("Decompressing message data %u bytes into %u bytes",
1104 header->size_compressed, size_u);
1105
1106 rc = BZ2_bzBuffToBuffDecompress(uncompressed + hdr_offset, &size_u,
1107 client->buffer + hdr_offset, header->size_compressed, 1, 0);
1108
1109 if (rc != BZ_OK) {
1110 crm_err("Decompression failed: %s (%d)", bz2_strerror(rc), rc);
1111 free(uncompressed);
1112 return -EILSEQ;
1113 }
1114
1115 /*
1116 * This assert no longer holds true. For an identical msg, some clients may
1117 * require compression, and others may not. If that same msg (event) is sent
1118 * to multiple clients, it could result in some clients receiving a compressed
1119 * msg even though compression was not explicitly required for them.
1120 *
1121 * CRM_ASSERT((header->size_uncompressed + hdr_offset) >= ipc_buffer_max);
1122 */
1123 CRM_ASSERT(size_u == header->size_uncompressed);
1124
1125 memcpy(uncompressed, client->buffer, hdr_offset); /* Preserve the header */
1126 header = (struct crm_ipc_response_header *)(void*)uncompressed;
1127
1128 free(client->buffer);
1129 client->buf_size = new_buf_size;
1130 client->buffer = uncompressed;
1131 }
1132
1133 CRM_ASSERT(client->buffer[hdr_offset + header->size_uncompressed - 1] == 0);
1134 return pcmk_ok;
1135 }
1136
1137 long
crm_ipc_read(crm_ipc_t * client)1138 crm_ipc_read(crm_ipc_t * client)
1139 {
1140 struct crm_ipc_response_header *header = NULL;
1141
1142 CRM_ASSERT(client != NULL);
1143 CRM_ASSERT(client->ipc != NULL);
1144 CRM_ASSERT(client->buffer != NULL);
1145
1146 crm_ipc_init();
1147
1148 client->buffer[0] = 0;
1149 client->msg_size = qb_ipcc_event_recv(client->ipc, client->buffer,
1150 client->buf_size, 0);
1151 if (client->msg_size >= 0) {
1152 int rc = crm_ipc_decompress(client);
1153
1154 if (rc != pcmk_ok) {
1155 return rc;
1156 }
1157
1158 header = (struct crm_ipc_response_header *)(void*)client->buffer;
1159 if(header->version > PCMK_IPC_VERSION) {
1160 crm_err("Filtering incompatible v%d IPC message, we only support versions <= %d",
1161 header->version, PCMK_IPC_VERSION);
1162 return -EBADMSG;
1163 }
1164
1165 crm_trace("Received %s event %d, size=%u, rc=%d, text: %.100s",
1166 client->name, header->qb.id, header->qb.size, client->msg_size,
1167 client->buffer + hdr_offset);
1168
1169 } else {
1170 crm_trace("No message from %s received: %s", client->name, pcmk_strerror(client->msg_size));
1171 }
1172
1173 if (crm_ipc_connected(client) == FALSE || client->msg_size == -ENOTCONN) {
1174 crm_err("Connection to %s failed", client->name);
1175 }
1176
1177 if (header) {
1178 /* Data excluding the header */
1179 return header->size_uncompressed;
1180 }
1181 return -ENOMSG;
1182 }
1183
1184 const char *
crm_ipc_buffer(crm_ipc_t * client)1185 crm_ipc_buffer(crm_ipc_t * client)
1186 {
1187 CRM_ASSERT(client != NULL);
1188 return client->buffer + sizeof(struct crm_ipc_response_header);
1189 }
1190
1191 uint32_t
crm_ipc_buffer_flags(crm_ipc_t * client)1192 crm_ipc_buffer_flags(crm_ipc_t * client)
1193 {
1194 struct crm_ipc_response_header *header = NULL;
1195
1196 CRM_ASSERT(client != NULL);
1197 if (client->buffer == NULL) {
1198 return 0;
1199 }
1200
1201 header = (struct crm_ipc_response_header *)(void*)client->buffer;
1202 return header->flags;
1203 }
1204
1205 const char *
crm_ipc_name(crm_ipc_t * client)1206 crm_ipc_name(crm_ipc_t * client)
1207 {
1208 CRM_ASSERT(client != NULL);
1209 return client->name;
1210 }
1211
1212 static int
internal_ipc_send_recv(crm_ipc_t * client,const void * iov)1213 internal_ipc_send_recv(crm_ipc_t * client, const void *iov)
1214 {
1215 int rc = 0;
1216
1217 do {
1218 rc = qb_ipcc_sendv_recv(client->ipc, iov, 2, client->buffer, client->buf_size, -1);
1219 } while (rc == -EAGAIN && crm_ipc_connected(client));
1220
1221 return rc;
1222 }
1223
1224 static int
internal_ipc_send_request(crm_ipc_t * client,const void * iov,int ms_timeout)1225 internal_ipc_send_request(crm_ipc_t * client, const void *iov, int ms_timeout)
1226 {
1227 int rc = 0;
1228 time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1229
1230 do {
1231 rc = qb_ipcc_sendv(client->ipc, iov, 2);
1232 } while (rc == -EAGAIN && time(NULL) < timeout && crm_ipc_connected(client));
1233
1234 return rc;
1235 }
1236
1237 static int
internal_ipc_get_reply(crm_ipc_t * client,int request_id,int ms_timeout)1238 internal_ipc_get_reply(crm_ipc_t * client, int request_id, int ms_timeout)
1239 {
1240 time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1241 int rc = 0;
1242
1243 crm_ipc_init();
1244
1245 /* get the reply */
1246 crm_trace("client %s waiting on reply to msg id %d", client->name, request_id);
1247 do {
1248
1249 rc = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, 1000);
1250 if (rc > 0) {
1251 struct crm_ipc_response_header *hdr = NULL;
1252
1253 int rc = crm_ipc_decompress(client);
1254
1255 if (rc != pcmk_ok) {
1256 return rc;
1257 }
1258
1259 hdr = (struct crm_ipc_response_header *)(void*)client->buffer;
1260 if (hdr->qb.id == request_id) {
1261 /* Got it */
1262 break;
1263 } else if (hdr->qb.id < request_id) {
1264 xmlNode *bad = string2xml(crm_ipc_buffer(client));
1265
1266 crm_err("Discarding old reply %d (need %d)", hdr->qb.id, request_id);
1267 crm_log_xml_notice(bad, "OldIpcReply");
1268
1269 } else {
1270 xmlNode *bad = string2xml(crm_ipc_buffer(client));
1271
1272 crm_err("Discarding newer reply %d (need %d)", hdr->qb.id, request_id);
1273 crm_log_xml_notice(bad, "ImpossibleReply");
1274 CRM_ASSERT(hdr->qb.id <= request_id);
1275 }
1276 } else if (crm_ipc_connected(client) == FALSE) {
1277 crm_err("Server disconnected client %s while waiting for msg id %d", client->name,
1278 request_id);
1279 break;
1280 }
1281
1282 } while (time(NULL) < timeout);
1283
1284 return rc;
1285 }
1286
1287 int
crm_ipc_send(crm_ipc_t * client,xmlNode * message,enum crm_ipc_flags flags,int32_t ms_timeout,xmlNode ** reply)1288 crm_ipc_send(crm_ipc_t * client, xmlNode * message, enum crm_ipc_flags flags, int32_t ms_timeout,
1289 xmlNode ** reply)
1290 {
1291 long rc = 0;
1292 struct iovec *iov;
1293 static uint32_t id = 0;
1294 static int factor = 8;
1295 struct crm_ipc_response_header *header;
1296
1297 crm_ipc_init();
1298
1299 if (client == NULL) {
1300 crm_notice("Invalid connection");
1301 return -ENOTCONN;
1302
1303 } else if (crm_ipc_connected(client) == FALSE) {
1304 /* Don't even bother */
1305 crm_notice("Connection to %s closed", client->name);
1306 return -ENOTCONN;
1307 }
1308
1309 if (ms_timeout == 0) {
1310 ms_timeout = 5000;
1311 }
1312
1313 if (client->need_reply) {
1314 crm_trace("Trying again to obtain pending reply from %s", client->name);
1315 rc = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, ms_timeout);
1316 if (rc < 0) {
1317 crm_warn("Sending to %s (%p) is disabled until pending reply is received", client->name,
1318 client->ipc);
1319 return -EALREADY;
1320
1321 } else {
1322 crm_notice("Lost reply from %s (%p) finally arrived, sending re-enabled", client->name,
1323 client->ipc);
1324 client->need_reply = FALSE;
1325 }
1326 }
1327
1328 id++;
1329 CRM_LOG_ASSERT(id != 0); /* Crude wrap-around detection */
1330 rc = crm_ipc_prepare(id, message, &iov, client->max_buf_size);
1331 if(rc < 0) {
1332 return rc;
1333 }
1334
1335 header = iov[0].iov_base;
1336 header->flags |= flags;
1337
1338 if(is_set(flags, crm_ipc_proxied)) {
1339 /* Don't look for a synchronous response */
1340 clear_bit(flags, crm_ipc_client_response);
1341 }
1342
1343 if(header->size_compressed) {
1344 if(factor < 10 && (client->max_buf_size / 10) < (rc / factor)) {
1345 crm_notice("Compressed message exceeds %d0%% of the configured ipc limit (%u bytes), "
1346 "consider setting PCMK_ipc_buffer to %u or higher",
1347 factor, client->max_buf_size, 2 * client->max_buf_size);
1348 factor++;
1349 }
1350 }
1351
1352 crm_trace("Sending from client: %s request id: %d bytes: %u timeout:%d msg...",
1353 client->name, header->qb.id, header->qb.size, ms_timeout);
1354
1355 if (ms_timeout > 0 || is_not_set(flags, crm_ipc_client_response)) {
1356
1357 rc = internal_ipc_send_request(client, iov, ms_timeout);
1358
1359 if (rc <= 0) {
1360 crm_trace("Failed to send from client %s request %d with %u bytes...",
1361 client->name, header->qb.id, header->qb.size);
1362 goto send_cleanup;
1363
1364 } else if (is_not_set(flags, crm_ipc_client_response)) {
1365 crm_trace("Message sent, not waiting for reply to %d from %s to %u bytes...",
1366 header->qb.id, client->name, header->qb.size);
1367
1368 goto send_cleanup;
1369 }
1370
1371 rc = internal_ipc_get_reply(client, header->qb.id, ms_timeout);
1372 if (rc < 0) {
1373 /* No reply, for now, disable sending
1374 *
1375 * The alternative is to close the connection since we don't know
1376 * how to detect and discard out-of-sequence replies
1377 *
1378 * TODO - implement the above
1379 */
1380 client->need_reply = TRUE;
1381 }
1382
1383 } else {
1384 rc = internal_ipc_send_recv(client, iov);
1385 }
1386
1387 if (rc > 0) {
1388 struct crm_ipc_response_header *hdr = (struct crm_ipc_response_header *)(void*)client->buffer;
1389
1390 crm_trace("Received response %d, size=%u, rc=%ld, text: %.200s", hdr->qb.id, hdr->qb.size,
1391 rc, crm_ipc_buffer(client));
1392
1393 if (reply) {
1394 *reply = string2xml(crm_ipc_buffer(client));
1395 }
1396
1397 } else {
1398 crm_trace("Response not received: rc=%ld, errno=%d", rc, errno);
1399 }
1400
1401 send_cleanup:
1402 if (crm_ipc_connected(client) == FALSE) {
1403 crm_notice("Connection to %s closed: %s (%ld)", client->name, pcmk_strerror(rc), rc);
1404
1405 } else if (rc == -ETIMEDOUT) {
1406 crm_warn("Request %d to %s (%p) failed: %s (%ld) after %dms",
1407 header->qb.id, client->name, client->ipc, pcmk_strerror(rc), rc, ms_timeout);
1408 crm_write_blackbox(0, NULL);
1409
1410 } else if (rc <= 0) {
1411 crm_warn("Request %d to %s (%p) failed: %s (%ld)",
1412 header->qb.id, client->name, client->ipc, pcmk_strerror(rc), rc);
1413 }
1414
1415 free(header);
1416 free(iov[1].iov_base);
1417 free(iov);
1418 return rc;
1419 }
1420
1421 int
crm_ipc_is_authentic_process(int sock,uid_t refuid,gid_t refgid,pid_t * gotpid,uid_t * gotuid,gid_t * gotgid)1422 crm_ipc_is_authentic_process(int sock, uid_t refuid, gid_t refgid,
1423 pid_t *gotpid, uid_t *gotuid, gid_t *gotgid) {
1424 int ret = 0;
1425 pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
1426 #if defined(US_AUTH_PEERCRED_UCRED)
1427 struct ucred ucred;
1428 socklen_t ucred_len = sizeof(ucred);
1429
1430 if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
1431 &ucred, &ucred_len)
1432 && ucred_len == sizeof(ucred)) {
1433 found_pid = ucred.pid; found_uid = ucred.uid; found_gid = ucred.gid;
1434
1435 #elif defined(US_AUTH_PEERCRED_SOCKPEERCRED)
1436 struct sockpeercred sockpeercred;
1437 socklen_t sockpeercred_len = sizeof(sockpeercred);
1438
1439 if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
1440 &sockpeercred, &sockpeercred_len)
1441 && sockpeercred_len == sizeof(sockpeercred_len)) {
1442 found_pid = sockpeercred.pid;
1443 found_uid = sockpeercred.uid; found_gid = sockpeercred.gid;
1444
1445 #elif defined(US_AUTH_GETPEEREID)
1446 if (!getpeereid(sock, &found_uid, &found_gid)) {
1447 found_pid = PCMK__SPECIAL_PID; /* cannot obtain PID (FreeBSD) */
1448
1449 #elif defined(US_AUTH_GETPEERUCRED)
1450 ucred_t *ucred;
1451 if (!getpeerucred(sock, &ucred)) {
1452 errno = 0;
1453 found_pid = ucred_getpid(ucred);
1454 found_uid = ucred_geteuid(ucred); found_gid = ucred_getegid(ucred);
1455 ret = -errno;
1456 ucred_free(ucred);
1457 if (ret) {
1458 return (ret < 0) ? ret : -pcmk_err_generic;
1459 }
1460
1461 #else
1462 # error "No way to authenticate a Unix socket peer"
1463 errno = 0;
1464 if (0) {
1465 #endif
1466 if (gotpid != NULL) {
1467 *gotpid = found_pid;
1468 }
1469 if (gotuid != NULL) {
1470 *gotuid = found_uid;
1471 }
1472 if (gotgid != NULL) {
1473 *gotgid = found_gid;
1474 }
1475 ret = (found_uid == 0 || found_uid == refuid || found_gid == refgid);
1476 } else {
1477 ret = (errno > 0) ? -errno : -pcmk_err_generic;
1478 }
1479
1480 return ret;
1481 }
1482
1483 int
1484 pcmk__ipc_is_authentic_process_active(const char *name, uid_t refuid,
1485 gid_t refgid, pid_t *gotpid) {
1486 static char last_asked_name[PATH_MAX / 2] = ""; /* log spam prevention */
1487 int fd, ret = 0;
1488 pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
1489 qb_ipcc_connection_t *c;
1490
1491 if ((c = qb_ipcc_connect(name, 0)) == NULL) {
1492 crm_info("Could not connect to %s IPC: %s", name, strerror(errno));
1493
1494 } else if ((ret = qb_ipcc_fd_get(c, &fd))) {
1495 crm_err("Could not get fd from %s IPC: %s (%d)", name,
1496 strerror(-ret), -ret);
1497 ret = -1;
1498
1499 } else if ((ret = crm_ipc_is_authentic_process(fd, refuid, refgid,
1500 &found_pid, &found_uid,
1501 &found_gid)) < 0) {
1502 if (ret == -pcmk_err_generic) {
1503 crm_err("Could not get peer credentials from %s IPC", name);
1504 } else {
1505 crm_err("Could not get peer credentials from %s IPC: %s (%d)",
1506 name, strerror(-ret), -ret);
1507 }
1508 ret = -1;
1509
1510 } else {
1511 if (gotpid != NULL) {
1512 *gotpid = found_pid;
1513 }
1514
1515 if (!ret) {
1516 crm_err("Daemon (IPC %s) effectively blocked with unauthorized"
1517 " process %lld (uid: %lld, gid: %lld)",
1518 name, (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
1519 (long long) found_uid, (long long) found_gid);
1520 ret = -2;
1521 } else if ((found_uid != refuid || found_gid != refgid)
1522 && strncmp(last_asked_name, name, sizeof(last_asked_name))) {
1523 if (!found_uid && refuid) {
1524 crm_warn("Daemon (IPC %s) runs as root, whereas the expected"
1525 " credentials are %lld:%lld, hazard of violating"
1526 " the least privilege principle",
1527 name, (long long) refuid, (long long) refgid);
1528 } else {
1529 crm_notice("Daemon (IPC %s) runs as %lld:%lld, whereas the"
1530 " expected credentials are %lld:%lld, which may"
1531 " mean a different set of privileges than expected",
1532 name, (long long) found_uid, (long long) found_gid,
1533 (long long) refuid, (long long) refgid);
1534 }
1535 memccpy(last_asked_name, name, '\0', sizeof(last_asked_name));
1536 }
1537 }
1538
1539 if (ret) { /* here, !ret only when we could not initially connect */
1540 qb_ipcc_disconnect(c);
1541 }
1542
1543 return ret;
1544 }
1545
1546
1547 /* Utils */
1548
1549 xmlNode *
1550 create_hello_message(const char *uuid,
1551 const char *client_name, const char *major_version, const char *minor_version)
1552 {
1553 xmlNode *hello_node = NULL;
1554 xmlNode *hello = NULL;
1555
1556 if (uuid == NULL || strlen(uuid) == 0
1557 || client_name == NULL || strlen(client_name) == 0
1558 || major_version == NULL || strlen(major_version) == 0
1559 || minor_version == NULL || strlen(minor_version) == 0) {
1560 crm_err("Missing fields, Hello message will not be valid.");
1561 return NULL;
1562 }
1563
1564 hello_node = create_xml_node(NULL, XML_TAG_OPTIONS);
1565 crm_xml_add(hello_node, "major_version", major_version);
1566 crm_xml_add(hello_node, "minor_version", minor_version);
1567 crm_xml_add(hello_node, "client_name", client_name);
1568 crm_xml_add(hello_node, "client_uuid", uuid);
1569
1570 crm_trace("creating hello message");
1571 hello = create_request(CRM_OP_HELLO, hello_node, NULL, NULL, client_name, uuid);
1572 free_xml(hello_node);
1573
1574 return hello;
1575 }
1576