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