pacemaker  2.1.2-ada5c3b36e2
Scalable High-Availability cluster resource manager
lrmd_client.c
Go to the documentation of this file.
1 /*
2  * Copyright 2012-2021 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 #include <unistd.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <stdint.h> // uint32_t, uint64_t
16 #include <stdarg.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <errno.h>
20 
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 
24 #include <glib.h>
25 #include <dirent.h>
26 
27 #include <crm/crm.h>
28 #include <crm/lrmd.h>
29 #include <crm/lrmd_internal.h>
30 #include <crm/services.h>
31 #include <crm/services_internal.h>
32 #include <crm/common/mainloop.h>
35 #include <crm/msg_xml.h>
36 
37 #include <crm/stonith-ng.h>
38 #include <crm/fencing/internal.h>
39 
40 #ifdef HAVE_GNUTLS_GNUTLS_H
41 # undef KEYFILE
42 # include <gnutls/gnutls.h>
43 #endif
44 
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <netinet/ip.h>
48 #include <arpa/inet.h>
49 #include <netdb.h>
50 
51 #define MAX_TLS_RECV_WAIT 10000
52 
54 
55 static int lrmd_api_disconnect(lrmd_t * lrmd);
56 static int lrmd_api_is_connected(lrmd_t * lrmd);
57 
58 /* IPC proxy functions */
59 int lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg);
60 static void lrmd_internal_proxy_dispatch(lrmd_t *lrmd, xmlNode *msg);
61 void lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg));
62 
63 #ifdef HAVE_GNUTLS_GNUTLS_H
64 # define LRMD_CLIENT_HANDSHAKE_TIMEOUT 5000 /* 5 seconds */
65 gnutls_psk_client_credentials_t psk_cred_s;
66 static void lrmd_tls_disconnect(lrmd_t * lrmd);
67 static int global_remote_msg_id = 0;
68 static void lrmd_tls_connection_destroy(gpointer userdata);
69 #endif
70 
71 typedef struct lrmd_private_s {
72  uint64_t type;
73  char *token;
74  mainloop_io_t *source;
75 
76  /* IPC parameters */
77  crm_ipc_t *ipc;
78 
79  pcmk__remote_t *remote;
80 
81  /* Extra TLS parameters */
82  char *remote_nodename;
83 #ifdef HAVE_GNUTLS_GNUTLS_H
84  char *server;
85  int port;
86  gnutls_psk_client_credentials_t psk_cred_c;
87 
88  /* while the async connection is occurring, this is the id
89  * of the connection timeout timer. */
90  int async_timer;
91  int sock;
92  /* since tls requires a round trip across the network for a
93  * request/reply, there are times where we just want to be able
94  * to send a request from the client and not wait around (or even care
95  * about) what the reply is. */
96  int expected_late_replies;
97  GList *pending_notify;
98  crm_trigger_t *process_notify;
99 #endif
100 
101  lrmd_event_callback callback;
102 
103  /* Internal IPC proxy msg passing for remote guests */
104  void (*proxy_callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg);
105  void *proxy_callback_userdata;
106  char *peer_version;
108 
109 static lrmd_list_t *
110 lrmd_list_add(lrmd_list_t * head, const char *value)
111 {
112  lrmd_list_t *p, *end;
113 
114  p = calloc(1, sizeof(lrmd_list_t));
115  p->val = strdup(value);
116 
117  end = head;
118  while (end && end->next) {
119  end = end->next;
120  }
121 
122  if (end) {
123  end->next = p;
124  } else {
125  head = p;
126  }
127 
128  return head;
129 }
130 
131 void
133 {
134  lrmd_list_t *p;
135 
136  while (head) {
137  char *val = (char *)head->val;
138 
139  p = head->next;
140  free(val);
141  free(head);
142  head = p;
143  }
144 }
145 
147 lrmd_key_value_add(lrmd_key_value_t * head, const char *key, const char *value)
148 {
149  lrmd_key_value_t *p, *end;
150 
151  p = calloc(1, sizeof(lrmd_key_value_t));
152  p->key = strdup(key);
153  p->value = strdup(value);
154 
155  end = head;
156  while (end && end->next) {
157  end = end->next;
158  }
159 
160  if (end) {
161  end->next = p;
162  } else {
163  head = p;
164  }
165 
166  return head;
167 }
168 
169 void
171 {
172  lrmd_key_value_t *p;
173 
174  while (head) {
175  p = head->next;
176  free(head->key);
177  free(head->value);
178  free(head);
179  head = p;
180  }
181 }
182 
196 lrmd_new_event(const char *rsc_id, const char *task, guint interval_ms)
197 {
198  lrmd_event_data_t *event = calloc(1, sizeof(lrmd_event_data_t));
199 
200  CRM_ASSERT(event != NULL);
201  if (rsc_id != NULL) {
202  event->rsc_id = strdup(rsc_id);
203  CRM_ASSERT(event->rsc_id != NULL);
204  }
205  if (task != NULL) {
206  event->op_type = strdup(task);
207  CRM_ASSERT(event->op_type != NULL);
208  }
209  event->interval_ms = interval_ms;
210  return event;
211 }
212 
215 {
216  lrmd_event_data_t *copy = NULL;
217 
218  copy = calloc(1, sizeof(lrmd_event_data_t));
219 
220  /* This will get all the int values.
221  * we just have to be careful not to leave any
222  * dangling pointers to strings. */
223  memcpy(copy, event, sizeof(lrmd_event_data_t));
224 
225  copy->rsc_id = event->rsc_id ? strdup(event->rsc_id) : NULL;
226  copy->op_type = event->op_type ? strdup(event->op_type) : NULL;
227  copy->user_data = event->user_data ? strdup(event->user_data) : NULL;
228  copy->output = event->output ? strdup(event->output) : NULL;
229  copy->exit_reason = event->exit_reason ? strdup(event->exit_reason) : NULL;
230  copy->remote_nodename = event->remote_nodename ? strdup(event->remote_nodename) : NULL;
231  copy->params = pcmk__str_table_dup(event->params);
232 
233  return copy;
234 }
235 
241 void
243 {
244  if (event == NULL) {
245  return;
246  }
247  // @TODO Why are these const char *?
248  free((void *) event->rsc_id);
249  free((void *) event->op_type);
250  free((void *) event->user_data);
251  free((void *) event->remote_nodename);
252  lrmd__reset_result(event);
253  if (event->params != NULL) {
254  g_hash_table_destroy(event->params);
255  }
256  free(event);
257 }
258 
259 static void
260 lrmd_dispatch_internal(lrmd_t * lrmd, xmlNode * msg)
261 {
262  const char *type;
263  const char *proxy_session = crm_element_value(msg, F_LRMD_IPC_SESSION);
264  lrmd_private_t *native = lrmd->lrmd_private;
265  lrmd_event_data_t event = { 0, };
266 
267  if (proxy_session != NULL) {
268  /* this is proxy business */
269  lrmd_internal_proxy_dispatch(lrmd, msg);
270  return;
271  } else if (!native->callback) {
272  /* no callback set */
273  crm_trace("notify event received but client has not set callback");
274  return;
275  }
276 
277  event.remote_nodename = native->remote_nodename;
279  crm_element_value_int(msg, F_LRMD_CALLID, &event.call_id);
280  event.rsc_id = crm_element_value(msg, F_LRMD_RSC_ID);
281 
282  if (pcmk__str_eq(type, LRMD_OP_RSC_REG, pcmk__str_none)) {
283  event.type = lrmd_event_register;
284  } else if (pcmk__str_eq(type, LRMD_OP_RSC_UNREG, pcmk__str_none)) {
285  event.type = lrmd_event_unregister;
286  } else if (pcmk__str_eq(type, LRMD_OP_RSC_EXEC, pcmk__str_none)) {
287  time_t epoch = 0;
288 
289  crm_element_value_int(msg, F_LRMD_TIMEOUT, &event.timeout);
290  crm_element_value_ms(msg, F_LRMD_RSC_INTERVAL, &event.interval_ms);
291  crm_element_value_int(msg, F_LRMD_RSC_START_DELAY, &event.start_delay);
292  crm_element_value_int(msg, F_LRMD_EXEC_RC, (int *)&event.rc);
293  crm_element_value_int(msg, F_LRMD_OP_STATUS, &event.op_status);
294  crm_element_value_int(msg, F_LRMD_RSC_DELETED, &event.rsc_deleted);
295 
297  event.t_run = (unsigned int) epoch;
298 
300  event.t_rcchange = (unsigned int) epoch;
301 
302  crm_element_value_int(msg, F_LRMD_RSC_EXEC_TIME, (int *)&event.exec_time);
303  crm_element_value_int(msg, F_LRMD_RSC_QUEUE_TIME, (int *)&event.queue_time);
304 
305  event.op_type = crm_element_value(msg, F_LRMD_RSC_ACTION);
306  event.user_data = crm_element_value(msg, F_LRMD_RSC_USERDATA_STR);
307  event.type = lrmd_event_exec_complete;
308 
309  /* output and exit_reason may be freed by a callback */
310  event.output = crm_element_value_copy(msg, F_LRMD_RSC_OUTPUT);
311  lrmd__set_result(&event, event.rc, event.op_status,
313 
314  event.params = xml2list(msg);
315  } else if (pcmk__str_eq(type, LRMD_OP_NEW_CLIENT, pcmk__str_none)) {
316  event.type = lrmd_event_new_client;
317  } else if (pcmk__str_eq(type, LRMD_OP_POKE, pcmk__str_none)) {
318  event.type = lrmd_event_poke;
319  } else {
320  return;
321  }
322 
323  crm_trace("op %s notify event received", type);
324  native->callback(&event);
325 
326  if (event.params) {
327  g_hash_table_destroy(event.params);
328  }
329  lrmd__reset_result(&event);
330 }
331 
332 // \return Always 0, to indicate that IPC mainloop source should be kept
333 static int
334 lrmd_ipc_dispatch(const char *buffer, ssize_t length, gpointer userdata)
335 {
336  lrmd_t *lrmd = userdata;
337  lrmd_private_t *native = lrmd->lrmd_private;
338 
339  if (native->callback != NULL) {
340  xmlNode *msg = string2xml(buffer);
341 
342  lrmd_dispatch_internal(lrmd, msg);
343  free_xml(msg);
344  }
345  return 0;
346 }
347 
348 #ifdef HAVE_GNUTLS_GNUTLS_H
349 static void
350 lrmd_free_xml(gpointer userdata)
351 {
352  free_xml((xmlNode *) userdata);
353 }
354 
355 static bool
356 remote_executor_connected(lrmd_t * lrmd)
357 {
358  lrmd_private_t *native = lrmd->lrmd_private;
359 
360  return (native->remote->tls_session != NULL);
361 }
362 
374 static int
375 lrmd_tls_dispatch(gpointer userdata)
376 {
377  lrmd_t *lrmd = userdata;
378  lrmd_private_t *native = lrmd->lrmd_private;
379  xmlNode *xml = NULL;
380  int rc = pcmk_rc_ok;
381 
382  if (!remote_executor_connected(lrmd)) {
383  crm_trace("TLS dispatch triggered after disconnect");
384  return 0;
385  }
386 
387  crm_trace("TLS dispatch triggered");
388 
389  /* First check if there are any pending notifies to process that came
390  * while we were waiting for replies earlier. */
391  if (native->pending_notify) {
392  GList *iter = NULL;
393 
394  crm_trace("Processing pending notifies");
395  for (iter = native->pending_notify; iter; iter = iter->next) {
396  lrmd_dispatch_internal(lrmd, iter->data);
397  }
398  g_list_free_full(native->pending_notify, lrmd_free_xml);
399  native->pending_notify = NULL;
400  }
401 
402  /* Next read the current buffer and see if there are any messages to handle. */
403  switch (pcmk__remote_ready(native->remote, 0)) {
404  case pcmk_rc_ok:
405  rc = pcmk__read_remote_message(native->remote, -1);
406  xml = pcmk__remote_message_xml(native->remote);
407  break;
408  case ETIME:
409  // Nothing to read, check if a full message is already in buffer
410  xml = pcmk__remote_message_xml(native->remote);
411  break;
412  default:
413  rc = ENOTCONN;
414  break;
415  }
416  while (xml) {
417  const char *msg_type = crm_element_value(xml, F_LRMD_REMOTE_MSG_TYPE);
418  if (pcmk__str_eq(msg_type, "notify", pcmk__str_casei)) {
419  lrmd_dispatch_internal(lrmd, xml);
420  } else if (pcmk__str_eq(msg_type, "reply", pcmk__str_casei)) {
421  if (native->expected_late_replies > 0) {
422  native->expected_late_replies--;
423  } else {
424  int reply_id = 0;
425  crm_element_value_int(xml, F_LRMD_CALLID, &reply_id);
426  /* if this happens, we want to know about it */
427  crm_err("Got outdated Pacemaker Remote reply %d", reply_id);
428  }
429  }
430  free_xml(xml);
431  xml = pcmk__remote_message_xml(native->remote);
432  }
433 
434  if (rc == ENOTCONN) {
435  crm_info("Lost %s executor connection while reading data",
436  (native->remote_nodename? native->remote_nodename : "local"));
437  lrmd_tls_disconnect(lrmd);
438  return 0;
439  }
440  return 1;
441 }
442 #endif
443 
444 /* Not used with mainloop */
445 int
447 {
448  lrmd_private_t *native = lrmd->lrmd_private;
449 
450  switch (native->type) {
451  case pcmk__client_ipc:
452  return crm_ipc_ready(native->ipc);
453 
454 #ifdef HAVE_GNUTLS_GNUTLS_H
455  case pcmk__client_tls:
456  if (native->pending_notify) {
457  return 1;
458  } else {
459  int rc = pcmk__remote_ready(native->remote, 0);
460 
461  switch (rc) {
462  case pcmk_rc_ok:
463  return 1;
464  case ETIME:
465  return 0;
466  default:
467  return pcmk_rc2legacy(rc);
468  }
469  }
470 #endif
471  default:
472  crm_err("Unsupported executor connection type (bug?): %d",
473  native->type);
474  return -EPROTONOSUPPORT;
475  }
476 }
477 
478 /* Not used with mainloop */
479 bool
481 {
482  lrmd_private_t *private = NULL;
483 
484  CRM_ASSERT(lrmd != NULL);
485 
486  private = lrmd->lrmd_private;
487  switch (private->type) {
488  case pcmk__client_ipc:
489  while (crm_ipc_ready(private->ipc)) {
490  if (crm_ipc_read(private->ipc) > 0) {
491  const char *msg = crm_ipc_buffer(private->ipc);
492 
493  lrmd_ipc_dispatch(msg, strlen(msg), lrmd);
494  }
495  }
496  break;
497 #ifdef HAVE_GNUTLS_GNUTLS_H
498  case pcmk__client_tls:
499  lrmd_tls_dispatch(lrmd);
500  break;
501 #endif
502  default:
503  crm_err("Unsupported executor connection type (bug?): %d",
504  private->type);
505  }
506 
507  if (lrmd_api_is_connected(lrmd) == FALSE) {
508  crm_err("Connection closed");
509  return FALSE;
510  }
511 
512  return TRUE;
513 }
514 
515 static xmlNode *
516 lrmd_create_op(const char *token, const char *op, xmlNode *data, int timeout,
517  enum lrmd_call_options options)
518 {
519  xmlNode *op_msg = create_xml_node(NULL, "lrmd_command");
520 
521  CRM_CHECK(op_msg != NULL, return NULL);
522  CRM_CHECK(token != NULL, return NULL);
523 
524  crm_xml_add(op_msg, F_XML_TAGNAME, "lrmd_command");
525  crm_xml_add(op_msg, F_TYPE, T_LRMD);
526  crm_xml_add(op_msg, F_LRMD_CALLBACK_TOKEN, token);
527  crm_xml_add(op_msg, F_LRMD_OPERATION, op);
529  crm_xml_add_int(op_msg, F_LRMD_CALLOPTS, options);
530 
531  if (data != NULL) {
533  }
534 
535  crm_trace("Created executor %s command with call options %.8lx (%d)",
536  op, (long)options, options);
537  return op_msg;
538 }
539 
540 static void
541 lrmd_ipc_connection_destroy(gpointer userdata)
542 {
543  lrmd_t *lrmd = userdata;
544  lrmd_private_t *native = lrmd->lrmd_private;
545 
546  crm_info("IPC connection destroyed");
547 
548  /* Prevent these from being cleaned up in lrmd_api_disconnect() */
549  native->ipc = NULL;
550  native->source = NULL;
551 
552  if (native->callback) {
553  lrmd_event_data_t event = { 0, };
554  event.type = lrmd_event_disconnect;
555  event.remote_nodename = native->remote_nodename;
556  native->callback(&event);
557  }
558 }
559 
560 #ifdef HAVE_GNUTLS_GNUTLS_H
561 static void
562 lrmd_tls_connection_destroy(gpointer userdata)
563 {
564  lrmd_t *lrmd = userdata;
565  lrmd_private_t *native = lrmd->lrmd_private;
566 
567  crm_info("TLS connection destroyed");
568 
569  if (native->remote->tls_session) {
570  gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
571  gnutls_deinit(*native->remote->tls_session);
572  gnutls_free(native->remote->tls_session);
573  }
574  if (native->psk_cred_c) {
575  gnutls_psk_free_client_credentials(native->psk_cred_c);
576  }
577  if (native->sock) {
578  close(native->sock);
579  }
580  if (native->process_notify) {
581  mainloop_destroy_trigger(native->process_notify);
582  native->process_notify = NULL;
583  }
584  if (native->pending_notify) {
585  g_list_free_full(native->pending_notify, lrmd_free_xml);
586  native->pending_notify = NULL;
587  }
588 
589  free(native->remote->buffer);
590  native->remote->buffer = NULL;
591  native->source = 0;
592  native->sock = 0;
593  native->psk_cred_c = NULL;
594  native->remote->tls_session = NULL;
595  native->sock = 0;
596 
597  if (native->callback) {
598  lrmd_event_data_t event = { 0, };
599  event.remote_nodename = native->remote_nodename;
600  event.type = lrmd_event_disconnect;
601  native->callback(&event);
602  }
603  return;
604 }
605 
606 // \return Standard Pacemaker return code
607 int
608 lrmd__remote_send_xml(pcmk__remote_t *session, xmlNode *msg, uint32_t id,
609  const char *msg_type)
610 {
612  crm_xml_add(msg, F_LRMD_REMOTE_MSG_TYPE, msg_type);
613  return pcmk__remote_send_xml(session, msg);
614 }
615 
616 // \return Standard Pacemaker return code
617 static int
618 read_remote_reply(lrmd_t *lrmd, int total_timeout, int expected_reply_id,
619  xmlNode **reply)
620 {
621  lrmd_private_t *native = lrmd->lrmd_private;
622  time_t start = time(NULL);
623  const char *msg_type = NULL;
624  int reply_id = 0;
625  int remaining_timeout = 0;
626  int rc = pcmk_rc_ok;
627 
628  /* A timeout of 0 here makes no sense. We have to wait a period of time
629  * for the response to come back. If -1 or 0, default to 10 seconds. */
630  if (total_timeout <= 0 || total_timeout > MAX_TLS_RECV_WAIT) {
631  total_timeout = MAX_TLS_RECV_WAIT;
632  }
633 
634  for (*reply = NULL; *reply == NULL; ) {
635 
636  *reply = pcmk__remote_message_xml(native->remote);
637  if (*reply == NULL) {
638  /* read some more off the tls buffer if we still have time left. */
639  if (remaining_timeout) {
640  remaining_timeout = total_timeout - ((time(NULL) - start) * 1000);
641  } else {
642  remaining_timeout = total_timeout;
643  }
644  if (remaining_timeout <= 0) {
645  return ETIME;
646  }
647 
648  rc = pcmk__read_remote_message(native->remote, remaining_timeout);
649  if (rc != pcmk_rc_ok) {
650  return rc;
651  }
652 
653  *reply = pcmk__remote_message_xml(native->remote);
654  if (*reply == NULL) {
655  return ENOMSG;
656  }
657  }
658 
659  crm_element_value_int(*reply, F_LRMD_REMOTE_MSG_ID, &reply_id);
660  msg_type = crm_element_value(*reply, F_LRMD_REMOTE_MSG_TYPE);
661 
662  if (!msg_type) {
663  crm_err("Empty msg type received while waiting for reply");
664  free_xml(*reply);
665  *reply = NULL;
666  } else if (pcmk__str_eq(msg_type, "notify", pcmk__str_casei)) {
667  /* got a notify while waiting for reply, trigger the notify to be processed later */
668  crm_info("queueing notify");
669  native->pending_notify = g_list_append(native->pending_notify, *reply);
670  if (native->process_notify) {
671  crm_info("notify trigger set.");
672  mainloop_set_trigger(native->process_notify);
673  }
674  *reply = NULL;
675  } else if (!pcmk__str_eq(msg_type, "reply", pcmk__str_casei)) {
676  /* msg isn't a reply, make some noise */
677  crm_err("Expected a reply, got %s", msg_type);
678  free_xml(*reply);
679  *reply = NULL;
680  } else if (reply_id != expected_reply_id) {
681  if (native->expected_late_replies > 0) {
682  native->expected_late_replies--;
683  } else {
684  crm_err("Got outdated reply, expected id %d got id %d", expected_reply_id, reply_id);
685  }
686  free_xml(*reply);
687  *reply = NULL;
688  }
689  }
690 
691  if (native->remote->buffer && native->process_notify) {
692  mainloop_set_trigger(native->process_notify);
693  }
694 
695  return rc;
696 }
697 
698 // \return Standard Pacemaker return code
699 static int
700 send_remote_message(lrmd_t *lrmd, xmlNode *msg)
701 {
702  int rc = pcmk_rc_ok;
703  lrmd_private_t *native = lrmd->lrmd_private;
704 
705  global_remote_msg_id++;
706  if (global_remote_msg_id <= 0) {
707  global_remote_msg_id = 1;
708  }
709 
710  rc = lrmd__remote_send_xml(native->remote, msg, global_remote_msg_id,
711  "request");
712  if (rc != pcmk_rc_ok) {
713  crm_err("Disconnecting because TLS message could not be sent to "
714  "Pacemaker Remote: %s", pcmk_rc_str(rc));
715  lrmd_tls_disconnect(lrmd);
716  }
717  return rc;
718 }
719 
720 static int
721 lrmd_tls_send_recv(lrmd_t * lrmd, xmlNode * msg, int timeout, xmlNode ** reply)
722 {
723  int rc = 0;
724  xmlNode *xml = NULL;
725 
726  if (!remote_executor_connected(lrmd)) {
727  return -ENOTCONN;
728  }
729 
730  rc = send_remote_message(lrmd, msg);
731  if (rc != pcmk_rc_ok) {
732  return pcmk_rc2legacy(rc);
733  }
734 
735  rc = read_remote_reply(lrmd, timeout, global_remote_msg_id, &xml);
736  if (rc != pcmk_rc_ok) {
737  crm_err("Disconnecting remote after request %d reply not received: %s "
738  CRM_XS " rc=%d timeout=%dms",
739  global_remote_msg_id, pcmk_rc_str(rc), rc, timeout);
740  lrmd_tls_disconnect(lrmd);
741  }
742 
743  if (reply) {
744  *reply = xml;
745  } else {
746  free_xml(xml);
747  }
748 
749  return pcmk_rc2legacy(rc);
750 }
751 #endif
752 
753 static int
754 lrmd_send_xml(lrmd_t * lrmd, xmlNode * msg, int timeout, xmlNode ** reply)
755 {
756  int rc = pcmk_ok;
757  lrmd_private_t *native = lrmd->lrmd_private;
758 
759  switch (native->type) {
760  case pcmk__client_ipc:
761  rc = crm_ipc_send(native->ipc, msg, crm_ipc_client_response, timeout, reply);
762  break;
763 #ifdef HAVE_GNUTLS_GNUTLS_H
764  case pcmk__client_tls:
765  rc = lrmd_tls_send_recv(lrmd, msg, timeout, reply);
766  break;
767 #endif
768  default:
769  crm_err("Unsupported executor connection type (bug?): %d",
770  native->type);
771  rc = -EPROTONOSUPPORT;
772  }
773 
774  return rc;
775 }
776 
777 static int
778 lrmd_send_xml_no_reply(lrmd_t * lrmd, xmlNode * msg)
779 {
780  int rc = pcmk_ok;
781  lrmd_private_t *native = lrmd->lrmd_private;
782 
783  switch (native->type) {
784  case pcmk__client_ipc:
785  rc = crm_ipc_send(native->ipc, msg, crm_ipc_flags_none, 0, NULL);
786  break;
787 #ifdef HAVE_GNUTLS_GNUTLS_H
788  case pcmk__client_tls:
789  rc = send_remote_message(lrmd, msg);
790  if (rc == pcmk_rc_ok) {
791  /* we don't want to wait around for the reply, but
792  * since the request/reply protocol needs to behave the same
793  * as libqb, a reply will eventually come later anyway. */
794  native->expected_late_replies++;
795  }
796  rc = pcmk_rc2legacy(rc);
797  break;
798 #endif
799  default:
800  crm_err("Unsupported executor connection type (bug?): %d",
801  native->type);
802  rc = -EPROTONOSUPPORT;
803  }
804 
805  return rc;
806 }
807 
808 static int
809 lrmd_api_is_connected(lrmd_t * lrmd)
810 {
811  lrmd_private_t *native = lrmd->lrmd_private;
812 
813  switch (native->type) {
814  case pcmk__client_ipc:
815  return crm_ipc_connected(native->ipc);
816 #ifdef HAVE_GNUTLS_GNUTLS_H
817  case pcmk__client_tls:
818  return remote_executor_connected(lrmd);
819 #endif
820  default:
821  crm_err("Unsupported executor connection type (bug?): %d",
822  native->type);
823  return 0;
824  }
825 }
826 
845 static int
846 lrmd_send_command(lrmd_t *lrmd, const char *op, xmlNode *data,
847  xmlNode **output_data, int timeout,
848  enum lrmd_call_options options, gboolean expect_reply)
849 {
850  int rc = pcmk_ok;
851  lrmd_private_t *native = lrmd->lrmd_private;
852  xmlNode *op_msg = NULL;
853  xmlNode *op_reply = NULL;
854 
855  if (!lrmd_api_is_connected(lrmd)) {
856  return -ENOTCONN;
857  }
858 
859  if (op == NULL) {
860  crm_err("No operation specified");
861  return -EINVAL;
862  }
863 
864  CRM_CHECK(native->token != NULL,;
865  );
866  crm_trace("Sending %s op to executor", op);
867 
868  op_msg = lrmd_create_op(native->token, op, data, timeout, options);
869 
870  if (op_msg == NULL) {
871  return -EINVAL;
872  }
873 
874  if (expect_reply) {
875  rc = lrmd_send_xml(lrmd, op_msg, timeout, &op_reply);
876  } else {
877  rc = lrmd_send_xml_no_reply(lrmd, op_msg);
878  goto done;
879  }
880 
881  if (rc < 0) {
882  crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%d): %d", op, timeout, rc);
883  goto done;
884 
885  } else if(op_reply == NULL) {
886  rc = -ENOMSG;
887  goto done;
888  }
889 
890  rc = pcmk_ok;
891  crm_trace("%s op reply received", op);
892  if (crm_element_value_int(op_reply, F_LRMD_RC, &rc) != 0) {
893  rc = -ENOMSG;
894  goto done;
895  }
896 
897  crm_log_xml_trace(op_reply, "Reply");
898 
899  if (output_data) {
900  *output_data = op_reply;
901  op_reply = NULL; /* Prevent subsequent free */
902  }
903 
904  done:
905  if (lrmd_api_is_connected(lrmd) == FALSE) {
906  crm_err("Executor disconnected");
907  }
908 
909  free_xml(op_msg);
910  free_xml(op_reply);
911  return rc;
912 }
913 
914 static int
915 lrmd_api_poke_connection(lrmd_t * lrmd)
916 {
917  int rc;
918  lrmd_private_t *native = lrmd->lrmd_private;
919  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
920 
921  crm_xml_add(data, F_LRMD_ORIGIN, __func__);
922  rc = lrmd_send_command(lrmd, LRMD_OP_POKE, data, NULL, 0, 0,
923  (native->type == pcmk__client_ipc));
924  free_xml(data);
925 
926  return rc < 0 ? rc : pcmk_ok;
927 }
928 
929 // \return Standard Pacemaker return code
930 int
931 lrmd__validate_remote_settings(lrmd_t *lrmd, GHashTable *hash)
932 {
933  int rc = pcmk_rc_ok;
934  const char *value;
935  lrmd_private_t *native = lrmd->lrmd_private;
936  xmlNode *data = create_xml_node(NULL, F_LRMD_OPERATION);
937 
938  crm_xml_add(data, F_LRMD_ORIGIN, __func__);
939 
940  value = g_hash_table_lookup(hash, "stonith-watchdog-timeout");
941  if ((value) &&
942  (stonith__watchdog_fencing_enabled_for_node(native->remote_nodename))) {
944  }
945 
946  rc = lrmd_send_command(lrmd, LRMD_OP_CHECK, data, NULL, 0, 0,
947  (native->type == pcmk__client_ipc));
948  free_xml(data);
949  return (rc < 0)? pcmk_legacy2rc(rc) : pcmk_rc_ok;
950 }
951 
952 static int
953 lrmd_handshake(lrmd_t * lrmd, const char *name)
954 {
955  int rc = pcmk_ok;
956  lrmd_private_t *native = lrmd->lrmd_private;
957  xmlNode *reply = NULL;
958  xmlNode *hello = create_xml_node(NULL, "lrmd_command");
959 
960  crm_xml_add(hello, F_TYPE, T_LRMD);
964 
965  /* advertise that we are a proxy provider */
966  if (native->proxy_callback) {
967  crm_xml_add(hello, F_LRMD_IS_IPC_PROVIDER, "true");
968  }
969 
970  rc = lrmd_send_xml(lrmd, hello, -1, &reply);
971 
972  if (rc < 0) {
973  crm_perror(LOG_DEBUG, "Couldn't complete registration with the executor API: %d", rc);
974  rc = -ECOMM;
975  } else if (reply == NULL) {
976  crm_err("Did not receive registration reply");
977  rc = -EPROTO;
978  } else {
979  const char *version = crm_element_value(reply, F_LRMD_PROTOCOL_VERSION);
980  const char *msg_type = crm_element_value(reply, F_LRMD_OPERATION);
981  const char *tmp_ticket = crm_element_value(reply, F_LRMD_CLIENTID);
982 
984 
985  if (rc == -EPROTO) {
986  crm_err("Executor protocol version mismatch between client (%s) and server (%s)",
988  crm_log_xml_err(reply, "Protocol Error");
989 
990  } else if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_casei)) {
991  crm_err("Invalid registration message: %s", msg_type);
992  crm_log_xml_err(reply, "Bad reply");
993  rc = -EPROTO;
994  } else if (tmp_ticket == NULL) {
995  crm_err("No registration token provided");
996  crm_log_xml_err(reply, "Bad reply");
997  rc = -EPROTO;
998  } else {
999  crm_trace("Obtained registration token: %s", tmp_ticket);
1000  native->token = strdup(tmp_ticket);
1001  native->peer_version = strdup(version?version:"1.0"); /* Included since 1.1 */
1002  rc = pcmk_ok;
1003  }
1004  }
1005 
1006  free_xml(reply);
1007  free_xml(hello);
1008 
1009  if (rc != pcmk_ok) {
1010  lrmd_api_disconnect(lrmd);
1011  }
1012  return rc;
1013 }
1014 
1015 static int
1016 lrmd_ipc_connect(lrmd_t * lrmd, int *fd)
1017 {
1018  int rc = pcmk_ok;
1019  lrmd_private_t *native = lrmd->lrmd_private;
1020 
1021  struct ipc_client_callbacks lrmd_callbacks = {
1022  .dispatch = lrmd_ipc_dispatch,
1023  .destroy = lrmd_ipc_connection_destroy
1024  };
1025 
1026  crm_info("Connecting to executor");
1027 
1028  if (fd) {
1029  /* No mainloop */
1030  native->ipc = crm_ipc_new(CRM_SYSTEM_LRMD, 0);
1031  if (native->ipc && crm_ipc_connect(native->ipc)) {
1032  *fd = crm_ipc_get_fd(native->ipc);
1033  } else if (native->ipc) {
1034  crm_perror(LOG_ERR, "Connection to executor failed");
1035  rc = -ENOTCONN;
1036  }
1037  } else {
1038  native->source = mainloop_add_ipc_client(CRM_SYSTEM_LRMD, G_PRIORITY_HIGH, 0, lrmd, &lrmd_callbacks);
1039  native->ipc = mainloop_get_ipc_client(native->source);
1040  }
1041 
1042  if (native->ipc == NULL) {
1043  crm_debug("Could not connect to the executor API");
1044  rc = -ENOTCONN;
1045  }
1046 
1047  return rc;
1048 }
1049 
1050 #ifdef HAVE_GNUTLS_GNUTLS_H
1051 static void
1052 copy_gnutls_datum(gnutls_datum_t *dest, gnutls_datum_t *source)
1053 {
1054  CRM_ASSERT((dest != NULL) && (source != NULL) && (source->data != NULL));
1055 
1056  dest->data = gnutls_malloc(source->size);
1057  CRM_ASSERT(dest->data);
1058 
1059  memcpy(dest->data, source->data, source->size);
1060  dest->size = source->size;
1061 }
1062 
1063 static void
1064 clear_gnutls_datum(gnutls_datum_t *datum)
1065 {
1066  gnutls_free(datum->data);
1067  datum->data = NULL;
1068  datum->size = 0;
1069 }
1070 
1071 #define KEY_READ_LEN 256 // Chunk size for reading key from file
1072 
1073 // \return Standard Pacemaker return code
1074 static int
1075 read_gnutls_key(const char *location, gnutls_datum_t *key)
1076 {
1077  FILE *stream = NULL;
1078  size_t buf_len = KEY_READ_LEN;
1079 
1080  if ((location == NULL) || (key == NULL)) {
1081  return EINVAL;
1082  }
1083 
1084  stream = fopen(location, "r");
1085  if (stream == NULL) {
1086  return errno;
1087  }
1088 
1089  key->data = gnutls_malloc(buf_len);
1090  key->size = 0;
1091  while (!feof(stream)) {
1092  int next = fgetc(stream);
1093 
1094  if (next == EOF) {
1095  if (!feof(stream)) {
1096  crm_warn("Pacemaker Remote key read was partially successful "
1097  "(copy in memory may be corrupted)");
1098  }
1099  break;
1100  }
1101  if (key->size == buf_len) {
1102  buf_len = key->size + KEY_READ_LEN;
1103  key->data = gnutls_realloc(key->data, buf_len);
1104  CRM_ASSERT(key->data);
1105  }
1106  key->data[key->size++] = (unsigned char) next;
1107  }
1108  fclose(stream);
1109 
1110  if (key->size == 0) {
1111  clear_gnutls_datum(key);
1112  return ENOKEY;
1113  }
1114  return pcmk_rc_ok;
1115 }
1116 
1117 // Cache the most recently used Pacemaker Remote authentication key
1118 
1119 struct key_cache_s {
1120  time_t updated; // When cached key was read (valid for 1 minute)
1121  const char *location; // Where cached key was read from
1122  gnutls_datum_t key; // Cached key
1123 };
1124 
1125 static bool
1126 key_is_cached(struct key_cache_s *key_cache)
1127 {
1128  return key_cache->updated != 0;
1129 }
1130 
1131 static bool
1132 key_cache_expired(struct key_cache_s *key_cache)
1133 {
1134  return (time(NULL) - key_cache->updated) >= 60;
1135 }
1136 
1137 static void
1138 clear_key_cache(struct key_cache_s *key_cache)
1139 {
1140  clear_gnutls_datum(&(key_cache->key));
1141  if ((key_cache->updated != 0) || (key_cache->location != NULL)) {
1142  key_cache->updated = 0;
1143  key_cache->location = NULL;
1144  crm_debug("Cleared Pacemaker Remote key cache");
1145  }
1146 }
1147 
1148 static void
1149 get_cached_key(struct key_cache_s *key_cache, gnutls_datum_t *key)
1150 {
1151  copy_gnutls_datum(key, &(key_cache->key));
1152  crm_debug("Using cached Pacemaker Remote key from %s",
1153  crm_str(key_cache->location));
1154 }
1155 
1156 static void
1157 cache_key(struct key_cache_s *key_cache, gnutls_datum_t *key,
1158  const char *location)
1159 {
1160  key_cache->updated = time(NULL);
1161  key_cache->location = location;
1162  copy_gnutls_datum(&(key_cache->key), key);
1163  crm_debug("Using (and cacheing) Pacemaker Remote key from %s",
1164  crm_str(location));
1165 }
1166 
1177 static int
1178 get_remote_key(const char *location, gnutls_datum_t *key)
1179 {
1180  static struct key_cache_s key_cache = { 0, };
1181  int rc = pcmk_rc_ok;
1182 
1183  if ((location == NULL) || (key == NULL)) {
1184  return EINVAL;
1185  }
1186 
1187  if (key_is_cached(&key_cache)) {
1188  if (key_cache_expired(&key_cache)) {
1189  clear_key_cache(&key_cache);
1190  } else {
1191  get_cached_key(&key_cache, key);
1192  return pcmk_rc_ok;
1193  }
1194  }
1195 
1196  rc = read_gnutls_key(location, key);
1197  if (rc != pcmk_rc_ok) {
1198  return rc;
1199  }
1200  cache_key(&key_cache, key, location);
1201  return pcmk_rc_ok;
1202 }
1203 
1217 int
1218 lrmd__init_remote_key(gnutls_datum_t *key)
1219 {
1220  static const char *env_location = NULL;
1221  static bool need_env = true;
1222 
1223  int env_rc = pcmk_rc_ok;
1224  int default_rc = pcmk_rc_ok;
1225  int alt_rc = pcmk_rc_ok;
1226 
1227  bool env_is_default = false;
1228  bool env_is_fallback = false;
1229 
1230  if (need_env) {
1231  env_location = getenv("PCMK_authkey_location");
1232  need_env = false;
1233  }
1234 
1235  // Try location in environment variable, if set
1236  if (env_location != NULL) {
1237  env_rc = get_remote_key(env_location, key);
1238  if (env_rc == pcmk_rc_ok) {
1239  return pcmk_rc_ok;
1240  }
1241 
1242  env_is_default = !strcmp(env_location, DEFAULT_REMOTE_KEY_LOCATION);
1243  env_is_fallback = !strcmp(env_location, ALT_REMOTE_KEY_LOCATION);
1244 
1245  /* @TODO It would be more secure to fail, rather than fall back to the
1246  * default, if an explicitly set key location is not readable, and it
1247  * would be better to never use the Corosync location as a fallback.
1248  * However, that would break any deployments currently working with the
1249  * fallbacks.
1250  */
1251  }
1252 
1253  // Try default location, if environment wasn't explicitly set to it
1254  if (env_is_default) {
1255  default_rc = env_rc;
1256  } else {
1257  default_rc = get_remote_key(DEFAULT_REMOTE_KEY_LOCATION, key);
1258  }
1259 
1260  // Try fallback location, if environment wasn't set to it and default failed
1261  if (env_is_fallback) {
1262  alt_rc = env_rc;
1263  } else if (default_rc != pcmk_rc_ok) {
1264  alt_rc = get_remote_key(ALT_REMOTE_KEY_LOCATION, key);
1265  }
1266 
1267  // We have all results, so log and return
1268 
1269  if ((env_rc != pcmk_rc_ok) && (default_rc != pcmk_rc_ok)
1270  && (alt_rc != pcmk_rc_ok)) { // Environment set, everything failed
1271 
1272  crm_warn("Could not read Pacemaker Remote key from %s (%s%s%s%s%s): %s",
1273  env_location,
1274  env_is_default? "" : "or default location ",
1275  env_is_default? "" : DEFAULT_REMOTE_KEY_LOCATION,
1276  !env_is_default && !env_is_fallback? " " : "",
1277  env_is_fallback? "" : "or fallback location ",
1278  env_is_fallback? "" : ALT_REMOTE_KEY_LOCATION,
1279  pcmk_rc_str(env_rc));
1280  return ENOKEY;
1281  }
1282 
1283  if (env_rc != pcmk_rc_ok) { // Environment set but failed, using a default
1284  crm_warn("Could not read Pacemaker Remote key from %s "
1285  "(using %s location %s instead): %s",
1286  env_location,
1287  (default_rc == pcmk_rc_ok)? "default" : "fallback",
1289  pcmk_rc_str(env_rc));
1290  return pcmk_rc_ok;
1291  }
1292 
1293  if ((default_rc != pcmk_rc_ok) && (alt_rc != pcmk_rc_ok)) {
1294  // Environment unset, defaults failed
1295  crm_warn("Could not read Pacemaker Remote key from default location %s"
1296  " (or fallback location %s): %s",
1298  pcmk_rc_str(default_rc));
1299  return ENOKEY;
1300  }
1301 
1302  return pcmk_rc_ok; // Environment variable unset, a default worked
1303 }
1304 
1305 static void
1306 lrmd_gnutls_global_init(void)
1307 {
1308  static int gnutls_init = 0;
1309 
1310  if (!gnutls_init) {
1311  crm_gnutls_global_init();
1312  }
1313  gnutls_init = 1;
1314 }
1315 #endif
1316 
1317 static void
1318 report_async_connection_result(lrmd_t * lrmd, int rc)
1319 {
1320  lrmd_private_t *native = lrmd->lrmd_private;
1321 
1322  if (native->callback) {
1323  lrmd_event_data_t event = { 0, };
1324  event.type = lrmd_event_connect;
1325  event.remote_nodename = native->remote_nodename;
1326  event.connection_rc = rc;
1327  native->callback(&event);
1328  }
1329 }
1330 
1331 #ifdef HAVE_GNUTLS_GNUTLS_H
1332 static inline int
1333 lrmd__tls_client_handshake(pcmk__remote_t *remote)
1334 {
1335  return pcmk__tls_client_handshake(remote, LRMD_CLIENT_HANDSHAKE_TIMEOUT);
1336 }
1337 
1347 static int
1348 add_tls_to_mainloop(lrmd_t *lrmd, bool do_handshake)
1349 {
1350  lrmd_private_t *native = lrmd->lrmd_private;
1351  int rc = pcmk_rc_ok;
1352 
1353  char *name = crm_strdup_printf("pacemaker-remote-%s:%d",
1354  native->server, native->port);
1355 
1356  struct mainloop_fd_callbacks tls_fd_callbacks = {
1357  .dispatch = lrmd_tls_dispatch,
1358  .destroy = lrmd_tls_connection_destroy,
1359  };
1360 
1361  native->process_notify = mainloop_add_trigger(G_PRIORITY_HIGH,
1362  lrmd_tls_dispatch, lrmd);
1363  native->source = mainloop_add_fd(name, G_PRIORITY_HIGH, native->sock, lrmd,
1364  &tls_fd_callbacks);
1365 
1366  /* Async connections lose the client name provided by the API caller, so we
1367  * have to use our generated name here to perform the executor handshake.
1368  *
1369  * @TODO Keep track of the caller-provided name. Perhaps we should be using
1370  * that name in this function instead of generating one anyway.
1371  */
1372  if (do_handshake) {
1373  rc = lrmd_handshake(lrmd, name);
1374  rc = pcmk_legacy2rc(rc);
1375  }
1376  free(name);
1377  return rc;
1378 }
1379 
1380 static void
1381 lrmd_tcp_connect_cb(void *userdata, int rc, int sock)
1382 {
1383  lrmd_t *lrmd = userdata;
1384  lrmd_private_t *native = lrmd->lrmd_private;
1385  gnutls_datum_t psk_key = { NULL, 0 };
1386 
1387  native->async_timer = 0;
1388 
1389  if (rc != pcmk_rc_ok) {
1390  lrmd_tls_connection_destroy(lrmd);
1391  crm_info("Could not connect to Pacemaker Remote at %s:%d: %s "
1392  CRM_XS " rc=%d",
1393  native->server, native->port, pcmk_rc_str(rc), rc);
1394  report_async_connection_result(lrmd, pcmk_rc2legacy(rc));
1395  return;
1396  }
1397 
1398  /* The TCP connection was successful, so establish the TLS connection.
1399  * @TODO make this async to avoid blocking code in client
1400  */
1401 
1402  native->sock = sock;
1403 
1404  rc = lrmd__init_remote_key(&psk_key);
1405  if (rc != pcmk_rc_ok) {
1406  crm_info("Could not connect to Pacemaker Remote at %s:%d: %s "
1407  CRM_XS " rc=%d",
1408  native->server, native->port, pcmk_rc_str(rc), rc);
1409  lrmd_tls_connection_destroy(lrmd);
1410  report_async_connection_result(lrmd, pcmk_rc2legacy(rc));
1411  return;
1412  }
1413 
1414  gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1415  gnutls_psk_set_client_credentials(native->psk_cred_c, DEFAULT_REMOTE_USERNAME, &psk_key, GNUTLS_PSK_KEY_RAW);
1416  gnutls_free(psk_key.data);
1417 
1418  native->remote->tls_session = pcmk__new_tls_session(sock, GNUTLS_CLIENT,
1419  GNUTLS_CRD_PSK,
1420  native->psk_cred_c);
1421  if (native->remote->tls_session == NULL) {
1422  lrmd_tls_connection_destroy(lrmd);
1423  report_async_connection_result(lrmd, -EPROTO);
1424  return;
1425  }
1426 
1427  if (lrmd__tls_client_handshake(native->remote) != pcmk_rc_ok) {
1428  crm_warn("Disconnecting after TLS handshake with Pacemaker Remote server %s:%d failed",
1429  native->server, native->port);
1430  gnutls_deinit(*native->remote->tls_session);
1431  gnutls_free(native->remote->tls_session);
1432  native->remote->tls_session = NULL;
1433  lrmd_tls_connection_destroy(lrmd);
1434  report_async_connection_result(lrmd, -EKEYREJECTED);
1435  return;
1436  }
1437 
1438  crm_info("TLS connection to Pacemaker Remote server %s:%d succeeded",
1439  native->server, native->port);
1440  rc = add_tls_to_mainloop(lrmd, true);
1441  report_async_connection_result(lrmd, pcmk_rc2legacy(rc));
1442 }
1443 
1444 static int
1445 lrmd_tls_connect_async(lrmd_t * lrmd, int timeout /*ms */ )
1446 {
1447  int rc;
1448  int timer_id = 0;
1449  lrmd_private_t *native = lrmd->lrmd_private;
1450 
1451  lrmd_gnutls_global_init();
1452  native->sock = -1;
1453  rc = pcmk__connect_remote(native->server, native->port, timeout, &timer_id,
1454  &(native->sock), lrmd, lrmd_tcp_connect_cb);
1455  if (rc != pcmk_rc_ok) {
1456  crm_warn("Pacemaker Remote connection to %s:%d failed: %s "
1457  CRM_XS " rc=%d",
1458  native->server, native->port, pcmk_rc_str(rc), rc);
1459  return pcmk_rc2legacy(rc);
1460  }
1461  native->async_timer = timer_id;
1462  return pcmk_ok;
1463 }
1464 
1465 static int
1466 lrmd_tls_connect(lrmd_t * lrmd, int *fd)
1467 {
1468  int rc;
1469 
1470  lrmd_private_t *native = lrmd->lrmd_private;
1471  gnutls_datum_t psk_key = { NULL, 0 };
1472 
1473  lrmd_gnutls_global_init();
1474 
1475  native->sock = -1;
1476  rc = pcmk__connect_remote(native->server, native->port, 0, NULL,
1477  &(native->sock), NULL, NULL);
1478  if (rc != pcmk_rc_ok) {
1479  crm_warn("Pacemaker Remote connection to %s:%d failed: %s "
1480  CRM_XS " rc=%d",
1481  native->server, native->port, pcmk_rc_str(rc), rc);
1482  lrmd_tls_connection_destroy(lrmd);
1483  return -ENOTCONN;
1484  }
1485 
1486  rc = lrmd__init_remote_key(&psk_key);
1487  if (rc != pcmk_rc_ok) {
1488  lrmd_tls_connection_destroy(lrmd);
1489  return pcmk_rc2legacy(rc);
1490  }
1491 
1492  gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1493  gnutls_psk_set_client_credentials(native->psk_cred_c, DEFAULT_REMOTE_USERNAME, &psk_key, GNUTLS_PSK_KEY_RAW);
1494  gnutls_free(psk_key.data);
1495 
1496  native->remote->tls_session = pcmk__new_tls_session(native->sock, GNUTLS_CLIENT,
1497  GNUTLS_CRD_PSK,
1498  native->psk_cred_c);
1499  if (native->remote->tls_session == NULL) {
1500  lrmd_tls_connection_destroy(lrmd);
1501  return -EPROTO;
1502  }
1503 
1504  if (lrmd__tls_client_handshake(native->remote) != pcmk_rc_ok) {
1505  crm_err("Session creation for %s:%d failed", native->server, native->port);
1506  gnutls_deinit(*native->remote->tls_session);
1507  gnutls_free(native->remote->tls_session);
1508  native->remote->tls_session = NULL;
1509  lrmd_tls_connection_destroy(lrmd);
1510  return -EKEYREJECTED;
1511  }
1512 
1513  crm_info("Client TLS connection established with Pacemaker Remote server %s:%d", native->server,
1514  native->port);
1515 
1516  if (fd) {
1517  *fd = native->sock;
1518  } else {
1519  add_tls_to_mainloop(lrmd, false);
1520  }
1521  return pcmk_ok;
1522 }
1523 #endif
1524 
1525 static int
1526 lrmd_api_connect(lrmd_t * lrmd, const char *name, int *fd)
1527 {
1528  int rc = -ENOTCONN;
1529  lrmd_private_t *native = lrmd->lrmd_private;
1530 
1531  switch (native->type) {
1532  case pcmk__client_ipc:
1533  rc = lrmd_ipc_connect(lrmd, fd);
1534  break;
1535 #ifdef HAVE_GNUTLS_GNUTLS_H
1536  case pcmk__client_tls:
1537  rc = lrmd_tls_connect(lrmd, fd);
1538  break;
1539 #endif
1540  default:
1541  crm_err("Unsupported executor connection type (bug?): %d",
1542  native->type);
1543  rc = -EPROTONOSUPPORT;
1544  }
1545 
1546  if (rc == pcmk_ok) {
1547  rc = lrmd_handshake(lrmd, name);
1548  }
1549 
1550  return rc;
1551 }
1552 
1553 static int
1554 lrmd_api_connect_async(lrmd_t * lrmd, const char *name, int timeout)
1555 {
1556  int rc = pcmk_ok;
1557  lrmd_private_t *native = lrmd->lrmd_private;
1558 
1559  CRM_CHECK(native && native->callback, return -EINVAL);
1560 
1561  switch (native->type) {
1562  case pcmk__client_ipc:
1563  /* fake async connection with ipc. it should be fast
1564  * enough that we gain very little from async */
1565  rc = lrmd_api_connect(lrmd, name, NULL);
1566  if (!rc) {
1567  report_async_connection_result(lrmd, rc);
1568  }
1569  break;
1570 #ifdef HAVE_GNUTLS_GNUTLS_H
1571  case pcmk__client_tls:
1572  rc = lrmd_tls_connect_async(lrmd, timeout);
1573  if (rc) {
1574  /* connection failed, report rc now */
1575  report_async_connection_result(lrmd, rc);
1576  }
1577  break;
1578 #endif
1579  default:
1580  crm_err("Unsupported executor connection type (bug?): %d",
1581  native->type);
1582  rc = -EPROTONOSUPPORT;
1583  }
1584 
1585  return rc;
1586 }
1587 
1588 static void
1589 lrmd_ipc_disconnect(lrmd_t * lrmd)
1590 {
1591  lrmd_private_t *native = lrmd->lrmd_private;
1592 
1593  if (native->source != NULL) {
1594  /* Attached to mainloop */
1595  mainloop_del_ipc_client(native->source);
1596  native->source = NULL;
1597  native->ipc = NULL;
1598 
1599  } else if (native->ipc) {
1600  /* Not attached to mainloop */
1601  crm_ipc_t *ipc = native->ipc;
1602 
1603  native->ipc = NULL;
1604  crm_ipc_close(ipc);
1605  crm_ipc_destroy(ipc);
1606  }
1607 }
1608 
1609 #ifdef HAVE_GNUTLS_GNUTLS_H
1610 static void
1611 lrmd_tls_disconnect(lrmd_t * lrmd)
1612 {
1613  lrmd_private_t *native = lrmd->lrmd_private;
1614 
1615  if (native->remote->tls_session) {
1616  gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
1617  gnutls_deinit(*native->remote->tls_session);
1618  gnutls_free(native->remote->tls_session);
1619  native->remote->tls_session = 0;
1620  }
1621 
1622  if (native->async_timer) {
1623  g_source_remove(native->async_timer);
1624  native->async_timer = 0;
1625  }
1626 
1627  if (native->source != NULL) {
1628  /* Attached to mainloop */
1629  mainloop_del_ipc_client(native->source);
1630  native->source = NULL;
1631 
1632  } else if (native->sock) {
1633  close(native->sock);
1634  native->sock = 0;
1635  }
1636 
1637  if (native->pending_notify) {
1638  g_list_free_full(native->pending_notify, lrmd_free_xml);
1639  native->pending_notify = NULL;
1640  }
1641 }
1642 #endif
1643 
1644 static int
1645 lrmd_api_disconnect(lrmd_t * lrmd)
1646 {
1647  lrmd_private_t *native = lrmd->lrmd_private;
1648  int rc = pcmk_ok;
1649 
1650  crm_info("Disconnecting %s %s executor connection",
1651  pcmk__client_type_str(native->type),
1652  (native->remote_nodename? native->remote_nodename : "local"));
1653  switch (native->type) {
1654  case pcmk__client_ipc:
1655  lrmd_ipc_disconnect(lrmd);
1656  break;
1657 #ifdef HAVE_GNUTLS_GNUTLS_H
1658  case pcmk__client_tls:
1659  lrmd_tls_disconnect(lrmd);
1660  break;
1661 #endif
1662  default:
1663  crm_err("Unsupported executor connection type (bug?): %d",
1664  native->type);
1665  rc = -EPROTONOSUPPORT;
1666  }
1667 
1668  free(native->token);
1669  native->token = NULL;
1670 
1671  free(native->peer_version);
1672  native->peer_version = NULL;
1673  return rc;
1674 }
1675 
1676 static int
1677 lrmd_api_register_rsc(lrmd_t * lrmd,
1678  const char *rsc_id,
1679  const char *class,
1680  const char *provider, const char *type, enum lrmd_call_options options)
1681 {
1682  int rc = pcmk_ok;
1683  xmlNode *data = NULL;
1684 
1685  if (!class || !type || !rsc_id) {
1686  return -EINVAL;
1687  }
1689  && (provider == NULL)) {
1690  return -EINVAL;
1691  }
1692 
1693  data = create_xml_node(NULL, F_LRMD_RSC);
1694 
1695  crm_xml_add(data, F_LRMD_ORIGIN, __func__);
1696  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1697  crm_xml_add(data, F_LRMD_CLASS, class);
1698  crm_xml_add(data, F_LRMD_PROVIDER, provider);
1700  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_REG, data, NULL, 0, options, TRUE);
1701  free_xml(data);
1702 
1703  return rc;
1704 }
1705 
1706 static int
1707 lrmd_api_unregister_rsc(lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options options)
1708 {
1709  int rc = pcmk_ok;
1710  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
1711 
1712  crm_xml_add(data, F_LRMD_ORIGIN, __func__);
1713  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1714  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_UNREG, data, NULL, 0, options, TRUE);
1715  free_xml(data);
1716 
1717  return rc;
1718 }
1719 
1721 lrmd_new_rsc_info(const char *rsc_id, const char *standard,
1722  const char *provider, const char *type)
1723 {
1724  lrmd_rsc_info_t *rsc_info = calloc(1, sizeof(lrmd_rsc_info_t));
1725 
1726  CRM_ASSERT(rsc_info);
1727  if (rsc_id) {
1728  rsc_info->id = strdup(rsc_id);
1729  CRM_ASSERT(rsc_info->id);
1730  }
1731  if (standard) {
1732  rsc_info->standard = strdup(standard);
1733  CRM_ASSERT(rsc_info->standard);
1734  }
1735  if (provider) {
1736  rsc_info->provider = strdup(provider);
1737  CRM_ASSERT(rsc_info->provider);
1738  }
1739  if (type) {
1740  rsc_info->type = strdup(type);
1741  CRM_ASSERT(rsc_info->type);
1742  }
1743  return rsc_info;
1744 }
1745 
1748 {
1749  return lrmd_new_rsc_info(rsc_info->id, rsc_info->standard,
1750  rsc_info->provider, rsc_info->type);
1751 }
1752 
1753 void
1755 {
1756  if (!rsc_info) {
1757  return;
1758  }
1759  free(rsc_info->id);
1760  free(rsc_info->type);
1761  free(rsc_info->standard);
1762  free(rsc_info->provider);
1763  free(rsc_info);
1764 }
1765 
1766 static lrmd_rsc_info_t *
1767 lrmd_api_get_rsc_info(lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options options)
1768 {
1769  lrmd_rsc_info_t *rsc_info = NULL;
1770  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
1771  xmlNode *output = NULL;
1772  const char *class = NULL;
1773  const char *provider = NULL;
1774  const char *type = NULL;
1775 
1776  crm_xml_add(data, F_LRMD_ORIGIN, __func__);
1777  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1778  lrmd_send_command(lrmd, LRMD_OP_RSC_INFO, data, &output, 0, options, TRUE);
1779  free_xml(data);
1780 
1781  if (!output) {
1782  return NULL;
1783  }
1784 
1785  class = crm_element_value(output, F_LRMD_CLASS);
1786  provider = crm_element_value(output, F_LRMD_PROVIDER);
1787  type = crm_element_value(output, F_LRMD_TYPE);
1788 
1789  if (!class || !type) {
1790  free_xml(output);
1791  return NULL;
1793  && !provider) {
1794  free_xml(output);
1795  return NULL;
1796  }
1797 
1798  rsc_info = lrmd_new_rsc_info(rsc_id, class, provider, type);
1799  free_xml(output);
1800  return rsc_info;
1801 }
1802 
1803 void
1805 {
1806  if (op_info) {
1807  free(op_info->rsc_id);
1808  free(op_info->action);
1809  free(op_info->interval_ms_s);
1810  free(op_info->timeout_ms_s);
1811  free(op_info);
1812  }
1813 }
1814 
1815 static int
1816 lrmd_api_get_recurring_ops(lrmd_t *lrmd, const char *rsc_id, int timeout_ms,
1817  enum lrmd_call_options options, GList **output)
1818 {
1819  xmlNode *data = NULL;
1820  xmlNode *output_xml = NULL;
1821  int rc = pcmk_ok;
1822 
1823  if (output == NULL) {
1824  return -EINVAL;
1825  }
1826  *output = NULL;
1827 
1828  // Send request
1829  if (rsc_id) {
1830  data = create_xml_node(NULL, F_LRMD_RSC);
1831  crm_xml_add(data, F_LRMD_ORIGIN, __func__);
1832  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1833  }
1834  rc = lrmd_send_command(lrmd, LRMD_OP_GET_RECURRING, data, &output_xml,
1835  timeout_ms, options, TRUE);
1836  if (data) {
1837  free_xml(data);
1838  }
1839 
1840  // Process reply
1841  if ((rc != pcmk_ok) || (output_xml == NULL)) {
1842  return rc;
1843  }
1844  for (xmlNode *rsc_xml = first_named_child(output_xml, F_LRMD_RSC);
1845  (rsc_xml != NULL) && (rc == pcmk_ok);
1846  rsc_xml = crm_next_same_xml(rsc_xml)) {
1847 
1848  rsc_id = crm_element_value(rsc_xml, F_LRMD_RSC_ID);
1849  if (rsc_id == NULL) {
1850  crm_err("Could not parse recurring operation information from executor");
1851  continue;
1852  }
1853  for (xmlNode *op_xml = first_named_child(rsc_xml, T_LRMD_RSC_OP);
1854  op_xml != NULL; op_xml = crm_next_same_xml(op_xml)) {
1855 
1856  lrmd_op_info_t *op_info = calloc(1, sizeof(lrmd_op_info_t));
1857 
1858  if (op_info == NULL) {
1859  rc = -ENOMEM;
1860  break;
1861  }
1862  op_info->rsc_id = strdup(rsc_id);
1863  op_info->action = crm_element_value_copy(op_xml, F_LRMD_RSC_ACTION);
1864  op_info->interval_ms_s = crm_element_value_copy(op_xml,
1866  op_info->timeout_ms_s = crm_element_value_copy(op_xml,
1867  F_LRMD_TIMEOUT);
1868  *output = g_list_prepend(*output, op_info);
1869  }
1870  }
1871  free_xml(output_xml);
1872  return rc;
1873 }
1874 
1875 
1876 static void
1877 lrmd_api_set_callback(lrmd_t * lrmd, lrmd_event_callback callback)
1878 {
1879  lrmd_private_t *native = lrmd->lrmd_private;
1880 
1881  native->callback = callback;
1882 }
1883 
1884 void
1885 lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
1886 {
1887  lrmd_private_t *native = lrmd->lrmd_private;
1888 
1889  native->proxy_callback = callback;
1890  native->proxy_callback_userdata = userdata;
1891 }
1892 
1893 void
1894 lrmd_internal_proxy_dispatch(lrmd_t *lrmd, xmlNode *msg)
1895 {
1896  lrmd_private_t *native = lrmd->lrmd_private;
1897 
1898  if (native->proxy_callback) {
1899  crm_log_xml_trace(msg, "PROXY_INBOUND");
1900  native->proxy_callback(lrmd, native->proxy_callback_userdata, msg);
1901  }
1902 }
1903 
1904 int
1905 lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg)
1906 {
1907  if (lrmd == NULL) {
1908  return -ENOTCONN;
1909  }
1911 
1912  crm_log_xml_trace(msg, "PROXY_OUTBOUND");
1913  return lrmd_send_xml_no_reply(lrmd, msg);
1914 }
1915 
1916 static int
1917 stonith_get_metadata(const char *provider, const char *type, char **output)
1918 {
1919  int rc = pcmk_ok;
1920  stonith_t *stonith_api = stonith_api_new();
1921 
1922  if (stonith_api == NULL) {
1923  crm_err("Could not get fence agent meta-data: API memory allocation failed");
1924  return -ENOMEM;
1925  }
1926 
1927  rc = stonith_api->cmds->metadata(stonith_api, st_opt_sync_call, type,
1928  provider, output, 0);
1929  if ((rc == pcmk_ok) && (*output == NULL)) {
1930  rc = -EIO;
1931  }
1932  stonith_api->cmds->free(stonith_api);
1933  return rc;
1934 }
1935 
1936 static int
1937 lrmd_api_get_metadata(lrmd_t *lrmd, const char *standard, const char *provider,
1938  const char *type, char **output,
1939  enum lrmd_call_options options)
1940 {
1941  return lrmd->cmds->get_metadata_params(lrmd, standard, provider, type,
1942  output, options, NULL);
1943 }
1944 
1945 static int
1946 lrmd_api_get_metadata_params(lrmd_t *lrmd, const char *standard,
1947  const char *provider, const char *type,
1948  char **output, enum lrmd_call_options options,
1949  lrmd_key_value_t *params)
1950 {
1951  svc_action_t *action = NULL;
1952  GHashTable *params_table = NULL;
1953 
1954  if (!standard || !type) {
1955  lrmd_key_value_freeall(params);
1956  return -EINVAL;
1957  }
1958 
1959  if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
1960  lrmd_key_value_freeall(params);
1961  return stonith_get_metadata(provider, type, output);
1962  }
1963 
1964  params_table = pcmk__strkey_table(free, free);
1965  for (const lrmd_key_value_t *param = params; param; param = param->next) {
1966  g_hash_table_insert(params_table, strdup(param->key), strdup(param->value));
1967  }
1968  action = services__create_resource_action(type, standard, provider, type,
1971  params_table, 0);
1972  lrmd_key_value_freeall(params);
1973 
1974  if (action == NULL) {
1975  return -ENOMEM;
1976  }
1977  if (action->rc != PCMK_OCF_UNKNOWN) {
1979  return -EINVAL;
1980  }
1981 
1982  if (!services_action_sync(action)) {
1983  crm_err("Failed to retrieve meta-data for %s:%s:%s",
1984  standard, provider, type);
1986  return -EIO;
1987  }
1988 
1989  if (!action->stdout_data) {
1990  crm_err("Failed to receive meta-data for %s:%s:%s",
1991  standard, provider, type);
1993  return -EIO;
1994  }
1995 
1996  *output = strdup(action->stdout_data);
1998 
1999  return pcmk_ok;
2000 }
2001 
2002 static int
2003 lrmd_api_exec(lrmd_t *lrmd, const char *rsc_id, const char *action,
2004  const char *userdata, guint interval_ms,
2005  int timeout, /* ms */
2006  int start_delay, /* ms */
2007  enum lrmd_call_options options, lrmd_key_value_t * params)
2008 {
2009  int rc = pcmk_ok;
2010  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
2011  xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
2012  lrmd_key_value_t *tmp = NULL;
2013 
2014  crm_xml_add(data, F_LRMD_ORIGIN, __func__);
2015  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
2018  crm_xml_add_ms(data, F_LRMD_RSC_INTERVAL, interval_ms);
2021 
2022  for (tmp = params; tmp; tmp = tmp->next) {
2023  hash2smartfield((gpointer) tmp->key, (gpointer) tmp->value, args);
2024  }
2025 
2026  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_EXEC, data, NULL, timeout, options, TRUE);
2027  free_xml(data);
2028 
2029  lrmd_key_value_freeall(params);
2030  return rc;
2031 }
2032 
2033 /* timeout is in ms */
2034 static int
2035 lrmd_api_exec_alert(lrmd_t *lrmd, const char *alert_id, const char *alert_path,
2036  int timeout, lrmd_key_value_t *params)
2037 {
2038  int rc = pcmk_ok;
2039  xmlNode *data = create_xml_node(NULL, F_LRMD_ALERT);
2040  xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
2041  lrmd_key_value_t *tmp = NULL;
2042 
2043  crm_xml_add(data, F_LRMD_ORIGIN, __func__);
2044  crm_xml_add(data, F_LRMD_ALERT_ID, alert_id);
2045  crm_xml_add(data, F_LRMD_ALERT_PATH, alert_path);
2047 
2048  for (tmp = params; tmp; tmp = tmp->next) {
2049  hash2smartfield((gpointer) tmp->key, (gpointer) tmp->value, args);
2050  }
2051 
2052  rc = lrmd_send_command(lrmd, LRMD_OP_ALERT_EXEC, data, NULL, timeout,
2054  free_xml(data);
2055 
2056  lrmd_key_value_freeall(params);
2057  return rc;
2058 }
2059 
2060 static int
2061 lrmd_api_cancel(lrmd_t *lrmd, const char *rsc_id, const char *action,
2062  guint interval_ms)
2063 {
2064  int rc = pcmk_ok;
2065  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
2066 
2067  crm_xml_add(data, F_LRMD_ORIGIN, __func__);
2069  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
2070  crm_xml_add_ms(data, F_LRMD_RSC_INTERVAL, interval_ms);
2071  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_CANCEL, data, NULL, 0, 0, TRUE);
2072  free_xml(data);
2073  return rc;
2074 }
2075 
2076 static int
2077 list_stonith_agents(lrmd_list_t ** resources)
2078 {
2079  int rc = 0;
2080  stonith_t *stonith_api = stonith_api_new();
2081  stonith_key_value_t *stonith_resources = NULL;
2082  stonith_key_value_t *dIter = NULL;
2083 
2084  if (stonith_api == NULL) {
2085  crm_err("Could not list fence agents: API memory allocation failed");
2086  return -ENOMEM;
2087  }
2088  stonith_api->cmds->list_agents(stonith_api, st_opt_sync_call, NULL,
2089  &stonith_resources, 0);
2090  stonith_api->cmds->free(stonith_api);
2091 
2092  for (dIter = stonith_resources; dIter; dIter = dIter->next) {
2093  rc++;
2094  if (resources) {
2095  *resources = lrmd_list_add(*resources, dIter->value);
2096  }
2097  }
2098 
2099  stonith_key_value_freeall(stonith_resources, 1, 0);
2100  return rc;
2101 }
2102 
2103 static int
2104 lrmd_api_list_agents(lrmd_t * lrmd, lrmd_list_t ** resources, const char *class,
2105  const char *provider)
2106 {
2107  int rc = 0;
2108  int stonith_count = 0; // Initially, whether to include stonith devices
2109 
2110  if (pcmk__str_eq(class, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
2111  stonith_count = 1;
2112 
2113  } else {
2114  GList *gIter = NULL;
2115  GList *agents = resources_list_agents(class, provider);
2116 
2117  for (gIter = agents; gIter != NULL; gIter = gIter->next) {
2118  *resources = lrmd_list_add(*resources, (const char *)gIter->data);
2119  rc++;
2120  }
2121  g_list_free_full(agents, free);
2122 
2123  if (!class) {
2124  stonith_count = 1;
2125  }
2126  }
2127 
2128  if (stonith_count) {
2129  // Now, if stonith devices are included, how many there are
2130  stonith_count = list_stonith_agents(resources);
2131  if (stonith_count > 0) {
2132  rc += stonith_count;
2133  }
2134  }
2135  if (rc == 0) {
2136  crm_notice("No agents found for class %s", class);
2137  rc = -EPROTONOSUPPORT;
2138  }
2139  return rc;
2140 }
2141 
2142 static bool
2143 does_provider_have_agent(const char *agent, const char *provider, const char *class)
2144 {
2145  bool found = false;
2146  GList *agents = NULL;
2147  GList *gIter2 = NULL;
2148 
2149  agents = resources_list_agents(class, provider);
2150  for (gIter2 = agents; gIter2 != NULL; gIter2 = gIter2->next) {
2151  if (pcmk__str_eq(agent, gIter2->data, pcmk__str_casei)) {
2152  found = true;
2153  }
2154  }
2155  g_list_free_full(agents, free);
2156  return found;
2157 }
2158 
2159 static int
2160 lrmd_api_list_ocf_providers(lrmd_t * lrmd, const char *agent, lrmd_list_t ** providers)
2161 {
2162  int rc = pcmk_ok;
2163  char *provider = NULL;
2164  GList *ocf_providers = NULL;
2165  GList *gIter = NULL;
2166 
2168 
2169  for (gIter = ocf_providers; gIter != NULL; gIter = gIter->next) {
2170  provider = gIter->data;
2171  if (!agent || does_provider_have_agent(agent, provider,
2173  *providers = lrmd_list_add(*providers, (const char *)gIter->data);
2174  rc++;
2175  }
2176  }
2177 
2178  g_list_free_full(ocf_providers, free);
2179  return rc;
2180 }
2181 
2182 static int
2183 lrmd_api_list_standards(lrmd_t * lrmd, lrmd_list_t ** supported)
2184 {
2185  int rc = 0;
2186  GList *standards = NULL;
2187  GList *gIter = NULL;
2188 
2189  standards = resources_list_standards();
2190 
2191  for (gIter = standards; gIter != NULL; gIter = gIter->next) {
2192  *supported = lrmd_list_add(*supported, (const char *)gIter->data);
2193  rc++;
2194  }
2195 
2196  if (list_stonith_agents(NULL) > 0) {
2197  *supported = lrmd_list_add(*supported, PCMK_RESOURCE_CLASS_STONITH);
2198  rc++;
2199  }
2200 
2201  g_list_free_full(standards, free);
2202  return rc;
2203 }
2204 
2224 int
2225 lrmd__new(lrmd_t **api, const char *nodename, const char *server, int port)
2226 {
2227  lrmd_private_t *pvt = NULL;
2228 
2229  if (api == NULL) {
2230  return EINVAL;
2231  }
2232  *api = NULL;
2233 
2234  // Allocate all memory needed
2235 
2236  *api = calloc(1, sizeof(lrmd_t));
2237  if (*api == NULL) {
2238  return ENOMEM;
2239  }
2240 
2241  pvt = calloc(1, sizeof(lrmd_private_t));
2242  if (pvt == NULL) {
2243  lrmd_api_delete(*api);
2244  *api = NULL;
2245  return ENOMEM;
2246  }
2247  (*api)->lrmd_private = pvt;
2248 
2249  // @TODO Do we need to do this for local connections?
2250  pvt->remote = calloc(1, sizeof(pcmk__remote_t));
2251 
2252  (*api)->cmds = calloc(1, sizeof(lrmd_api_operations_t));
2253 
2254  if ((pvt->remote == NULL) || ((*api)->cmds == NULL)) {
2255  lrmd_api_delete(*api);
2256  *api = NULL;
2257  return ENOMEM;
2258  }
2259 
2260  // Set methods
2261  (*api)->cmds->connect = lrmd_api_connect;
2262  (*api)->cmds->connect_async = lrmd_api_connect_async;
2263  (*api)->cmds->is_connected = lrmd_api_is_connected;
2264  (*api)->cmds->poke_connection = lrmd_api_poke_connection;
2265  (*api)->cmds->disconnect = lrmd_api_disconnect;
2266  (*api)->cmds->register_rsc = lrmd_api_register_rsc;
2267  (*api)->cmds->unregister_rsc = lrmd_api_unregister_rsc;
2268  (*api)->cmds->get_rsc_info = lrmd_api_get_rsc_info;
2269  (*api)->cmds->get_recurring_ops = lrmd_api_get_recurring_ops;
2270  (*api)->cmds->set_callback = lrmd_api_set_callback;
2271  (*api)->cmds->get_metadata = lrmd_api_get_metadata;
2272  (*api)->cmds->exec = lrmd_api_exec;
2273  (*api)->cmds->cancel = lrmd_api_cancel;
2274  (*api)->cmds->list_agents = lrmd_api_list_agents;
2275  (*api)->cmds->list_ocf_providers = lrmd_api_list_ocf_providers;
2276  (*api)->cmds->list_standards = lrmd_api_list_standards;
2277  (*api)->cmds->exec_alert = lrmd_api_exec_alert;
2278  (*api)->cmds->get_metadata_params = lrmd_api_get_metadata_params;
2279 
2280  if ((nodename == NULL) && (server == NULL)) {
2281  pvt->type = pcmk__client_ipc;
2282  } else {
2283 #ifdef HAVE_GNUTLS_GNUTLS_H
2284  if (nodename == NULL) {
2285  nodename = server;
2286  } else if (server == NULL) {
2287  server = nodename;
2288  }
2289  pvt->type = pcmk__client_tls;
2290  pvt->remote_nodename = strdup(nodename);
2291  pvt->server = strdup(server);
2292  if ((pvt->remote_nodename == NULL) || (pvt->server == NULL)) {
2293  lrmd_api_delete(*api);
2294  *api = NULL;
2295  return ENOMEM;
2296  }
2297  pvt->port = port;
2298  if (pvt->port == 0) {
2299  pvt->port = crm_default_remote_port();
2300  }
2301 #else
2302  crm_err("Cannot communicate with Pacemaker Remote "
2303  "because GnuTLS is not enabled for this build");
2304  lrmd_api_delete(*api);
2305  *api = NULL;
2306  return EOPNOTSUPP;
2307 #endif
2308  }
2309  return pcmk_rc_ok;
2310 }
2311 
2312 lrmd_t *
2314 {
2315  lrmd_t *api = NULL;
2316 
2317  CRM_ASSERT(lrmd__new(&api, NULL, NULL, 0) == pcmk_rc_ok);
2318  return api;
2319 }
2320 
2321 lrmd_t *
2322 lrmd_remote_api_new(const char *nodename, const char *server, int port)
2323 {
2324  lrmd_t *api = NULL;
2325 
2326  CRM_ASSERT(lrmd__new(&api, nodename, server, port) == pcmk_rc_ok);
2327  return api;
2328 }
2329 
2330 void
2332 {
2333  if (lrmd == NULL) {
2334  return;
2335  }
2336  if (lrmd->cmds != NULL) { // Never NULL, but make static analysis happy
2337  lrmd->cmds->disconnect(lrmd); // No-op if already disconnected
2338  free(lrmd->cmds);
2339  }
2340  if (lrmd->lrmd_private != NULL) {
2341  lrmd_private_t *native = lrmd->lrmd_private;
2342 
2343 #ifdef HAVE_GNUTLS_GNUTLS_H
2344  free(native->server);
2345 #endif
2346  free(native->remote_nodename);
2347  free(native->remote);
2348  free(native->token);
2349  free(native->peer_version);
2350  free(lrmd->lrmd_private);
2351  }
2352  free(lrmd);
2353 }
2354 
2364 void
2366  const char *exit_reason)
2367 {
2368  if (event == NULL) {
2369  return;
2370  }
2371 
2372  event->rc = rc;
2373  event->op_status = op_status;
2374 
2375  if (!pcmk__str_eq(event->exit_reason, exit_reason, pcmk__str_none)) {
2376  free((void *) event->exit_reason);
2377  event->exit_reason = (exit_reason == NULL)? NULL : strdup(exit_reason);
2378  }
2379 }
2380 
2387 void
2389 {
2390  if (event == NULL) {
2391  return;
2392  }
2393 
2394  free((void *) event->exit_reason);
2395  event->exit_reason = NULL;
2396 
2397  free((void *) event->output);
2398  event->output = NULL;
2399 }
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition: agents.c:31
@ pcmk_ra_cap_provider
Definition: agents.h:47
uint32_t version
Definition: remote.c:1
int pcmk__remote_ready(pcmk__remote_t *remote, int timeout_ms)
Definition: remote.c:633
int pcmk__remote_send_xml(pcmk__remote_t *remote, xmlNode *msg)
Definition: remote.c:488
int pcmk__connect_remote(const char *host, int port, int timeout_ms, int *timer_id, int *sock_fd, void *userdata, void(*callback)(void *userdata, int rc, int sock))
Definition: remote.c:1063
xmlNode * pcmk__remote_message_xml(pcmk__remote_t *remote)
Definition: remote.c:540
int pcmk__read_remote_message(pcmk__remote_t *remote, int timeout_ms)
Definition: remote.c:791
int crm_default_remote_port(void)
Get the default remote connection TCP port on this host.
Definition: remote.c:1249
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:114
enum crm_ais_msg_types type
Definition: cpg.c:3
char data[0]
Definition: cpg.c:10
A dumping ground.
#define CRMD_ACTION_METADATA
Definition: crm.h:191
#define CRM_OP_IPC_FWD
Definition: crm.h:147
#define CRM_OP_REGISTER
Definition: crm.h:146
#define CRM_SYSTEM_LRMD
Definition: crm.h:107
#define CRMD_METADATA_CALL_TIMEOUT
Definition: crm.h:192
gboolean stonith__watchdog_fencing_enabled_for_node(const char *node)
Definition: st_client.c:254
void crm_ipc_destroy(crm_ipc_t *client)
Definition: ipc_client.c:875
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
Definition: ipc_client.c:1150
const char * crm_ipc_buffer(crm_ipc_t *client)
Definition: ipc_client.c:1056
long crm_ipc_read(crm_ipc_t *client)
Definition: ipc_client.c:1011
int crm_ipc_get_fd(crm_ipc_t *client)
Definition: ipc_client.c:901
@ crm_ipc_flags_none
Definition: ipc.h:145
@ crm_ipc_client_response
Definition: ipc.h:150
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
Definition: ipc_client.c:947
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc_client.c:915
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition: ipc_client.c:792
void crm_ipc_close(crm_ipc_t *client)
Definition: ipc_client.c:862
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Create a new (legacy) object for using Pacemaker daemon IPC.
Definition: ipc_client.c:745
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:162
const char * pcmk__client_type_str(uint64_t client_type)
Definition: ipc_common.c:96
@ pcmk__client_ipc
Definition: ipc_internal.h:122
#define crm_str(x)
Definition: logging.h:383
#define crm_info(fmt, args...)
Definition: logging.h:360
#define crm_warn(fmt, args...)
Definition: logging.h:358
#define CRM_XS
Definition: logging.h:54
#define crm_log_xml_err(xml, text)
Definition: logging.h:366
#define crm_notice(fmt, args...)
Definition: logging.h:359
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:308
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:225
#define crm_debug(fmt, args...)
Definition: logging.h:362
#define crm_err(fmt, args...)
Definition: logging.h:357
#define crm_log_xml_trace(xml, text)
Definition: logging.h:371
#define crm_trace(fmt, args...)
Definition: logging.h:363
Resource agent executor.
#define F_LRMD_ALERT
Definition: lrmd.h:91
#define LRMD_OP_NEW_CLIENT
Definition: lrmd.h:100
#define DEFAULT_REMOTE_USERNAME
Definition: lrmd.h:51
#define T_LRMD_RSC_OP
Definition: lrmd.h:127
#define F_LRMD_CLASS
Definition: lrmd.h:69
#define LRMD_OP_RSC_REG
Definition: lrmd.h:93
#define F_LRMD_OP_STATUS
Definition: lrmd.h:66
#define F_LRMD_ALERT_PATH
Definition: lrmd.h:90
#define F_LRMD_TYPE
Definition: lrmd.h:71
#define LRMD_OP_RSC_EXEC
Definition: lrmd.h:94
#define LRMD_OP_GET_RECURRING
Definition: lrmd.h:103
#define DEFAULT_REMOTE_KEY_LOCATION
Definition: lrmd.h:48
lrmd_call_options
Definition: lrmd.h:173
@ lrmd_opt_notify_orig_only
Definition: lrmd.h:177
#define F_LRMD_RSC_ACTION
Definition: lrmd.h:80
#define F_LRMD_REMOTE_MSG_TYPE
Definition: lrmd.h:58
#define F_LRMD_RSC_RCCHANGE_TIME
Definition: lrmd.h:75
#define T_LRMD
Definition: lrmd.h:123
#define F_LRMD_EXEC_RC
Definition: lrmd.h:65
#define F_LRMD_TIMEOUT
Definition: lrmd.h:67
#define F_LRMD_IS_IPC_PROVIDER
Definition: lrmd.h:55
#define F_LRMD_CALLDATA
Definition: lrmd.h:63
#define F_LRMD_OPERATION
Definition: lrmd.h:53
#define F_LRMD_CALLBACK_TOKEN
Definition: lrmd.h:60
@ lrmd_event_new_client
Definition: lrmd.h:194
@ lrmd_event_connect
Definition: lrmd.h:192
@ lrmd_event_unregister
Definition: lrmd.h:189
@ lrmd_event_exec_complete
Definition: lrmd.h:190
@ lrmd_event_register
Definition: lrmd.h:188
@ lrmd_event_poke
Definition: lrmd.h:193
@ lrmd_event_disconnect
Definition: lrmd.h:191
#define F_LRMD_RSC_ID
Definition: lrmd.h:79
#define F_LRMD_CALLID
Definition: lrmd.h:61
#define LRMD_OP_POKE
Definition: lrmd.h:99
#define F_LRMD_RSC_INTERVAL
Definition: lrmd.h:85
#define ALT_REMOTE_KEY_LOCATION
Definition: lrmd.h:49
#define F_LRMD_CLIENTNAME
Definition: lrmd.h:54
#define F_LRMD_RSC_USERDATA_STR
Definition: lrmd.h:81
#define F_LRMD_RSC_OUTPUT
Definition: lrmd.h:82
#define LRMD_OP_RSC_INFO
Definition: lrmd.h:97
#define F_LRMD_RSC
Definition: lrmd.h:87
#define F_LRMD_RSC_EXEC_TIME
Definition: lrmd.h:76
#define F_LRMD_RSC_DELETED
Definition: lrmd.h:86
#define LRMD_OP_RSC_UNREG
Definition: lrmd.h:96
#define F_LRMD_PROVIDER
Definition: lrmd.h:70
#define LRMD_OP_CHECK
Definition: lrmd.h:101
#define F_LRMD_RSC_RUN_TIME
Definition: lrmd.h:74
#define F_LRMD_CLIENTID
Definition: lrmd.h:56
#define F_LRMD_PROTOCOL_VERSION
Definition: lrmd.h:57
#define F_LRMD_RSC_START_DELAY
Definition: lrmd.h:84
#define F_LRMD_WATCHDOG
Definition: lrmd.h:68
#define F_LRMD_RSC_EXIT_REASON
Definition: lrmd.h:83
#define F_LRMD_IPC_SESSION
Definition: lrmd.h:116
#define F_LRMD_ORIGIN
Definition: lrmd.h:72
#define F_LRMD_RSC_QUEUE_TIME
Definition: lrmd.h:77
#define F_LRMD_ALERT_ID
Definition: lrmd.h:89
#define LRMD_PROTOCOL_VERSION
Definition: lrmd.h:37
#define F_LRMD_RC
Definition: lrmd.h:64
#define F_LRMD_REMOTE_MSG_ID
Definition: lrmd.h:59
#define F_LRMD_CALLOPTS
Definition: lrmd.h:62
void(* lrmd_event_callback)(lrmd_event_data_t *event)
Definition: lrmd.h:277
#define LRMD_OP_RSC_CANCEL
Definition: lrmd.h:95
#define LRMD_OP_ALERT_EXEC
Definition: lrmd.h:102
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
Definition: lrmd_client.c:1905
lrmd_event_data_t * lrmd_copy_event(lrmd_event_data_t *event)
Definition: lrmd_client.c:214
struct lrmd_private_s lrmd_private_t
lrmd_key_value_t * lrmd_key_value_add(lrmd_key_value_t *head, const char *key, const char *value)
Definition: lrmd_client.c:147
#define MAX_TLS_RECV_WAIT
Definition: lrmd_client.c:51
lrmd_t * lrmd_remote_api_new(const char *nodename, const char *server, int port)
Create a new TLS connection to a remote executor.
Definition: lrmd_client.c:2322
lrmd_event_data_t * lrmd_new_event(const char *rsc_id, const char *task, guint interval_ms)
Definition: lrmd_client.c:196
void lrmd__reset_result(lrmd_event_data_t *event)
Definition: lrmd_client.c:2388
void lrmd_key_value_freeall(lrmd_key_value_t *head)
Definition: lrmd_client.c:170
bool lrmd_dispatch(lrmd_t *lrmd)
Use after lrmd_poll returns 1 to read and dispatch a message.
Definition: lrmd_client.c:480
void lrmd_free_op_info(lrmd_op_info_t *op_info)
Definition: lrmd_client.c:1804
void lrmd__set_result(lrmd_event_data_t *event, enum ocf_exitcode rc, int op_status, const char *exit_reason)
Definition: lrmd_client.c:2365
void lrmd_api_delete(lrmd_t *lrmd)
Destroy executor connection object.
Definition: lrmd_client.c:2331
void lrmd_list_freeall(lrmd_list_t *head)
Definition: lrmd_client.c:132
lrmd_t * lrmd_api_new(void)
Create a new connection to the local executor.
Definition: lrmd_client.c:2313
void lrmd_internal_set_proxy_callback(lrmd_t *lrmd, void *userdata, void(*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
Definition: lrmd_client.c:1885
CRM_TRACE_INIT_DATA(lrmd)
void lrmd_free_event(lrmd_event_data_t *event)
Free an executor event.
Definition: lrmd_client.c:242
void lrmd_free_rsc_info(lrmd_rsc_info_t *rsc_info)
Definition: lrmd_client.c:1754
int lrmd__validate_remote_settings(lrmd_t *lrmd, GHashTable *hash)
Definition: lrmd_client.c:931
int lrmd__new(lrmd_t **api, const char *nodename, const char *server, int port)
Definition: lrmd_client.c:2225
lrmd_rsc_info_t * lrmd_copy_rsc_info(lrmd_rsc_info_t *rsc_info)
Definition: lrmd_client.c:1747
lrmd_rsc_info_t * lrmd_new_rsc_info(const char *rsc_id, const char *standard, const char *provider, const char *type)
Definition: lrmd_client.c:1721
int lrmd_poll(lrmd_t *lrmd, int timeout)
Poll for a specified timeout period to determine if a message is ready for dispatch.
Definition: lrmd_client.c:446
int lrmd__remote_send_xml(pcmk__remote_t *session, xmlNode *msg, uint32_t id, const char *msg_type)
Wrappers for and extensions to glib mainloop.
mainloop_io_t * mainloop_add_ipc_client(const char *name, int priority, size_t max_size, void *userdata, struct ipc_client_callbacks *callbacks)
Definition: mainloop.c:935
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
Definition: mainloop.c:975
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:966
crm_trigger_t * mainloop_add_trigger(int priority, int(*dispatch)(gpointer user_data), gpointer userdata)
Create a trigger to be used as a mainloop source.
Definition: mainloop.c:186
void mainloop_set_trigger(crm_trigger_t *source)
Definition: mainloop.c:198
gboolean mainloop_destroy_trigger(crm_trigger_t *source)
Definition: mainloop.c:206
struct mainloop_io_s mainloop_io_t
Definition: mainloop.h:32
struct trigger_s crm_trigger_t
Definition: mainloop.h:31
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:960
#define F_XML_TAGNAME
Definition: msg_xml.h:71
#define XML_TAG_ATTRS
Definition: msg_xml.h:205
#define F_TYPE
Definition: msg_xml.h:63
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:565
GHashTable * xml2list(xmlNode *parent)
Retrieve XML attributes as a hash table.
Definition: nvpair.c:911
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: nvpair.c:726
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition: nvpair.c:622
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:431
void hash2smartfield(gpointer key, gpointer value, gpointer user_data)
Add hash table entry to XML as (possibly legacy) name/value.
Definition: nvpair.c:751
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:323
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:529
const char * crm_xml_add_ms(xmlNode *node, const char *name, guint ms)
Create an XML attribute with specified name and unsigned value.
Definition: nvpair.c:453
int crm_element_value_epoch(const xmlNode *xml, const char *name, time_t *dest)
Retrieve the seconds-since-epoch value of an XML attribute.
Definition: nvpair.c:650
unsigned int timeout
Definition: pcmk_fence.c:32
char * name
Definition: pcmk_fence.c:31
const char * action
Definition: pcmk_fence.c:30
int rc
Definition: pcmk_fence.c:35
#define ENOKEY
Definition: portability.h:139
#define ETIME
Definition: portability.h:147
#define ECOMM
Definition: portability.h:123
#define EKEYREJECTED
Definition: portability.h:159
#define CRM_ASSERT(expr)
Definition: results.h:42
ocf_exitcode
Exit status codes for resource agents.
Definition: results.h:161
@ PCMK_OCF_UNKNOWN
Action is pending.
Definition: results.h:188
@ pcmk_rc_ok
Definition: results.h:146
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:432
#define pcmk_ok
Definition: results.h:68
int pcmk_rc2legacy(int rc)
Definition: results.c:449
int pcmk_legacy2rc(int legacy_rc)
Definition: results.c:462
Services API.
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
Definition: services.c:1112
gboolean services_action_sync(svc_action_t *op)
Definition: services.c:1013
#define PCMK_RESOURCE_CLASS_STONITH
Definition: services.h:45
GList * resources_list_standards(void)
Definition: services.c:1054
void services_action_free(svc_action_t *op)
Definition: services.c:580
#define PCMK_RESOURCE_CLASS_OCF
Definition: services.h:39
GList * resources_list_providers(const char *standard)
Get a list of providers.
Definition: services.c:1102
op_status
svc_action_t * services__create_resource_action(const char *name, const char *standard, const char *provider, const char *agent, const char *action, guint interval_ms, int timeout, GHashTable *params, enum svc_action_flags flags)
Create a new resource action.
Definition: services.c:254
Fencing aka. STONITH.
@ st_opt_sync_call
Definition: stonith-ng.h:58
void stonith_key_value_freeall(stonith_key_value_t *kvp, int keys, int values)
Definition: st_client.c:2288
stonith_t * stonith_api_new(void)
Definition: st_client.c:2162
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:611
GHashTable * pcmk__str_table_dup(GHashTable *old_table)
Definition: strings.c:675
@ pcmk__str_none
@ pcmk__str_casei
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
Definition: mainloop.h:83
int(* get_metadata_params)(lrmd_t *lrmd, const char *standard, const char *provider, const char *agent, char **output, enum lrmd_call_options options, lrmd_key_value_t *params)
Get resource metadata for a resource agent, passing parameters.
Definition: lrmd.h:502
int(* disconnect)(lrmd_t *lrmd)
Disconnect from the executor.
Definition: lrmd.h:325
int(* connect)(lrmd_t *lrmd, const char *client_name, int *fd)
Connect to an executor.
Definition: lrmd.h:293
const char * op_type
Definition: lrmd.h:206
const char * remote_nodename
Definition: lrmd.h:246
const char * exit_reason
Definition: lrmd.h:249
const char * user_data
Definition: lrmd.h:208
const char * output
Definition: lrmd.h:226
enum lrmd_callback_event type
Definition: lrmd.h:201
void * params
Definition: lrmd.h:241
const char * rsc_id
Definition: lrmd.h:204
char * key
Definition: lrmd.h:29
struct lrmd_key_value_s * next
Definition: lrmd.h:31
char * value
Definition: lrmd.h:30
const char * val
Definition: lrmd.h:280
struct lrmd_list_s * next
Definition: lrmd.h:281
char * timeout_ms_s
Definition: lrmd.h:268
char * rsc_id
Definition: lrmd.h:265
char * interval_ms_s
Definition: lrmd.h:267
char * action
Definition: lrmd.h:266
char * id
Definition: lrmd.h:258
char * standard
Definition: lrmd.h:260
char * type
Definition: lrmd.h:259
char * provider
Definition: lrmd.h:261
Definition: lrmd.h:509
void * lrmd_private
Definition: lrmd.h:511
lrmd_api_operations_t * cmds
Definition: lrmd.h:510
int(* dispatch)(gpointer userdata)
Dispatch function for mainloop file descriptor with data ready.
Definition: mainloop.h:137
int(* free)(stonith_t *st)
Destroy the stonith api structure.
Definition: stonith-ng.h:154
int(* metadata)(stonith_t *st, int options, const char *device, const char *provider, char **output, int timeout)
Get the metadata documentation for a resource.
Definition: stonith-ng.h:215
int(* list_agents)(stonith_t *stonith, int call_options, const char *provider, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed stonith agents.
Definition: stonith-ng.h:227
struct stonith_key_value_s * next
Definition: stonith-ng.h:101
stonith_api_operations_t * cmds
Definition: stonith-ng.h:420
Object for executing external actions.
Definition: services.h:120
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2815
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: messages.c:162
void free_xml(xmlNode *child)
Definition: xml.c:824
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:696
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2789
xmlNode * string2xml(const char *input)
Definition: xml.c:869