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