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