pacemaker  1.1.14-70404b0
Scalable High-Availability cluster resource manager
lrmd_client.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012 David Vossel <davidvossel@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  */
19 
20 #include <crm_internal.h>
21 
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <stdarg.h>
26 #include <string.h>
27 #include <ctype.h>
28 
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 
32 #include <glib.h>
33 #include <dirent.h>
34 
35 #include <crm/crm.h>
36 #include <crm/lrmd.h>
37 #include <crm/services.h>
38 #include <crm/common/mainloop.h>
39 #include <crm/common/ipcs.h>
40 #include <crm/msg_xml.h>
41 
42 #include <crm/stonith-ng.h>
43 
44 #ifdef HAVE_GNUTLS_GNUTLS_H
45 # undef KEYFILE
46 # include <gnutls/gnutls.h>
47 #endif
48 
49 #include <sys/socket.h>
50 #include <netinet/in.h>
51 #include <netinet/ip.h>
52 #include <arpa/inet.h>
53 #include <netdb.h>
54 
55 #define MAX_TLS_RECV_WAIT 10000
56 
58 
59 static int lrmd_api_disconnect(lrmd_t * lrmd);
60 static int lrmd_api_is_connected(lrmd_t * lrmd);
61 
62 /* IPC proxy functions */
63 int lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg);
64 static void lrmd_internal_proxy_dispatch(lrmd_t *lrmd, xmlNode *msg);
65 void lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg));
66 
67 #ifdef HAVE_GNUTLS_GNUTLS_H
68 # define LRMD_CLIENT_HANDSHAKE_TIMEOUT 5000 /* 5 seconds */
69 gnutls_psk_client_credentials_t psk_cred_s;
70 int lrmd_tls_set_key(gnutls_datum_t * key);
71 static void lrmd_tls_disconnect(lrmd_t * lrmd);
72 static int global_remote_msg_id = 0;
73 int lrmd_tls_send_msg(crm_remote_t * session, xmlNode * msg, uint32_t id, const char *msg_type);
74 static void lrmd_tls_connection_destroy(gpointer userdata);
75 #endif
76 
77 typedef struct lrmd_private_s {
78  enum client_type type;
79  char *token;
80  mainloop_io_t *source;
81 
82  /* IPC parameters */
83  crm_ipc_t *ipc;
84 
85  crm_remote_t *remote;
86 
87  /* Extra TLS parameters */
88  char *remote_nodename;
89 #ifdef HAVE_GNUTLS_GNUTLS_H
90  char *server;
91  int port;
92  gnutls_psk_client_credentials_t psk_cred_c;
93 
94  /* while the async connection is occuring, this is the id
95  * of the connection timeout timer. */
96  int async_timer;
97  int sock;
98  /* since tls requires a round trip across the network for a
99  * request/reply, there are times where we just want to be able
100  * to send a request from the client and not wait around (or even care
101  * about) what the reply is. */
102  int expected_late_replies;
103  GList *pending_notify;
104  crm_trigger_t *process_notify;
105 #endif
106 
107  lrmd_event_callback callback;
108 
109  /* Internal IPC proxy msg passing for remote guests */
110  void (*proxy_callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg);
111  void *proxy_callback_userdata;
113 
114 static lrmd_list_t *
115 lrmd_list_add(lrmd_list_t * head, const char *value)
116 {
117  lrmd_list_t *p, *end;
118 
119  p = calloc(1, sizeof(lrmd_list_t));
120  p->val = strdup(value);
121 
122  end = head;
123  while (end && end->next) {
124  end = end->next;
125  }
126 
127  if (end) {
128  end->next = p;
129  } else {
130  head = p;
131  }
132 
133  return head;
134 }
135 
136 void
138 {
139  lrmd_list_t *p;
140 
141  while (head) {
142  char *val = (char *)head->val;
143 
144  p = head->next;
145  free(val);
146  free(head);
147  head = p;
148  }
149 }
150 
152 lrmd_key_value_add(lrmd_key_value_t * head, const char *key, const char *value)
153 {
154  lrmd_key_value_t *p, *end;
155 
156  p = calloc(1, sizeof(lrmd_key_value_t));
157  p->key = strdup(key);
158  p->value = strdup(value);
159 
160  end = head;
161  while (end && end->next) {
162  end = end->next;
163  }
164 
165  if (end) {
166  end->next = p;
167  } else {
168  head = p;
169  }
170 
171  return head;
172 }
173 
174 void
176 {
177  lrmd_key_value_t *p;
178 
179  while (head) {
180  p = head->next;
181  free(head->key);
182  free(head->value);
183  free(head);
184  head = p;
185  }
186 }
187 
188 static void
189 dup_attr(gpointer key, gpointer value, gpointer user_data)
190 {
191  g_hash_table_replace(user_data, strdup(key), strdup(value));
192 }
193 
196 {
197  lrmd_event_data_t *copy = NULL;
198 
199  copy = calloc(1, sizeof(lrmd_event_data_t));
200 
201  /* This will get all the int values.
202  * we just have to be careful not to leave any
203  * dangling pointers to strings. */
204  memcpy(copy, event, sizeof(lrmd_event_data_t));
205 
206  copy->rsc_id = event->rsc_id ? strdup(event->rsc_id) : NULL;
207  copy->op_type = event->op_type ? strdup(event->op_type) : NULL;
208  copy->user_data = event->user_data ? strdup(event->user_data) : NULL;
209  copy->output = event->output ? strdup(event->output) : NULL;
210  copy->exit_reason = event->exit_reason ? strdup(event->exit_reason) : NULL;
211  copy->remote_nodename = event->remote_nodename ? strdup(event->remote_nodename) : NULL;
212 
213  if (event->params) {
214  copy->params = g_hash_table_new_full(crm_str_hash,
215  g_str_equal, g_hash_destroy_str, g_hash_destroy_str);
216 
217  if (copy->params != NULL) {
218  g_hash_table_foreach(event->params, dup_attr, copy->params);
219  }
220  }
221 
222  return copy;
223 }
224 
225 void
227 {
228  if (!event) {
229  return;
230  }
231 
232  /* free gives me grief if i try to cast */
233  free((char *)event->rsc_id);
234  free((char *)event->op_type);
235  free((char *)event->user_data);
236  free((char *)event->output);
237  free((char *)event->exit_reason);
238  free((char *)event->remote_nodename);
239  if (event->params) {
240  g_hash_table_destroy(event->params);
241  }
242  free(event);
243 }
244 
245 static int
246 lrmd_dispatch_internal(lrmd_t * lrmd, xmlNode * msg)
247 {
248  const char *type;
249  const char *proxy_session = crm_element_value(msg, F_LRMD_IPC_SESSION);
250  lrmd_private_t *native = lrmd->private;
251  lrmd_event_data_t event = { 0, };
252 
253  if (proxy_session != NULL) {
254  /* this is proxy business */
255  lrmd_internal_proxy_dispatch(lrmd, msg);
256  return 1;
257  } else if (!native->callback) {
258  /* no callback set */
259  crm_trace("notify event received but client has not set callback");
260  return 1;
261  }
262 
263  event.remote_nodename = native->remote_nodename;
264  type = crm_element_value(msg, F_LRMD_OPERATION);
265  crm_element_value_int(msg, F_LRMD_CALLID, &event.call_id);
266  event.rsc_id = crm_element_value(msg, F_LRMD_RSC_ID);
267 
268  if (crm_str_eq(type, LRMD_OP_RSC_REG, TRUE)) {
269  event.type = lrmd_event_register;
270  } else if (crm_str_eq(type, LRMD_OP_RSC_UNREG, TRUE)) {
271  event.type = lrmd_event_unregister;
272  } else if (crm_str_eq(type, LRMD_OP_RSC_EXEC, TRUE)) {
273  crm_element_value_int(msg, F_LRMD_TIMEOUT, &event.timeout);
274  crm_element_value_int(msg, F_LRMD_RSC_INTERVAL, &event.interval);
275  crm_element_value_int(msg, F_LRMD_RSC_START_DELAY, &event.start_delay);
276  crm_element_value_int(msg, F_LRMD_EXEC_RC, (int *)&event.rc);
277  crm_element_value_int(msg, F_LRMD_OP_STATUS, &event.op_status);
278  crm_element_value_int(msg, F_LRMD_RSC_DELETED, &event.rsc_deleted);
279 
280  crm_element_value_int(msg, F_LRMD_RSC_RUN_TIME, (int *)&event.t_run);
281  crm_element_value_int(msg, F_LRMD_RSC_RCCHANGE_TIME, (int *)&event.t_rcchange);
282  crm_element_value_int(msg, F_LRMD_RSC_EXEC_TIME, (int *)&event.exec_time);
283  crm_element_value_int(msg, F_LRMD_RSC_QUEUE_TIME, (int *)&event.queue_time);
284 
285  event.op_type = crm_element_value(msg, F_LRMD_RSC_ACTION);
286  event.user_data = crm_element_value(msg, F_LRMD_RSC_USERDATA_STR);
287  event.output = crm_element_value(msg, F_LRMD_RSC_OUTPUT);
288  event.exit_reason = crm_element_value(msg, F_LRMD_RSC_EXIT_REASON);
289  event.type = lrmd_event_exec_complete;
290 
291  event.params = xml2list(msg);
292  } else if (crm_str_eq(type, LRMD_OP_NEW_CLIENT, TRUE)) {
293  event.type = lrmd_event_new_client;
294  } else if (crm_str_eq(type, LRMD_OP_POKE, TRUE)) {
295  event.type = lrmd_event_poke;
296  } else {
297  return 1;
298  }
299 
300  crm_trace("op %s notify event received", type);
301  native->callback(&event);
302 
303  if (event.params) {
304  g_hash_table_destroy(event.params);
305  }
306  return 1;
307 }
308 
309 static int
310 lrmd_ipc_dispatch(const char *buffer, ssize_t length, gpointer userdata)
311 {
312  lrmd_t *lrmd = userdata;
313  lrmd_private_t *native = lrmd->private;
314  xmlNode *msg;
315  int rc;
316 
317  if (!native->callback) {
318  /* no callback set */
319  return 1;
320  }
321 
322  msg = string2xml(buffer);
323  rc = lrmd_dispatch_internal(lrmd, msg);
324  free_xml(msg);
325  return rc;
326 }
327 
328 #ifdef HAVE_GNUTLS_GNUTLS_H
329 static void
330 lrmd_free_xml(gpointer userdata)
331 {
332  free_xml((xmlNode *) userdata);
333 }
334 
335 static int
336 lrmd_tls_connected(lrmd_t * lrmd)
337 {
338  lrmd_private_t *native = lrmd->private;
339 
340  if (native->remote->tls_session) {
341  return TRUE;
342  }
343 
344  return FALSE;
345 }
346 
347 static int
348 lrmd_tls_dispatch(gpointer userdata)
349 {
350  lrmd_t *lrmd = userdata;
351  lrmd_private_t *native = lrmd->private;
352  xmlNode *xml = NULL;
353  int rc = 0;
354  int disconnected = 0;
355 
356  if (lrmd_tls_connected(lrmd) == FALSE) {
357  crm_trace("tls dispatch triggered after disconnect");
358  return 0;
359  }
360 
361  crm_trace("tls_dispatch triggered");
362 
363  /* First check if there are any pending notifies to process that came
364  * while we were waiting for replies earlier. */
365  if (native->pending_notify) {
366  GList *iter = NULL;
367 
368  crm_trace("Processing pending notifies");
369  for (iter = native->pending_notify; iter; iter = iter->next) {
370  lrmd_dispatch_internal(lrmd, iter->data);
371  }
372  g_list_free_full(native->pending_notify, lrmd_free_xml);
373  native->pending_notify = NULL;
374  }
375 
376  /* Next read the current buffer and see if there are any messages to handle. */
377  rc = crm_remote_ready(native->remote, 0);
378  if (rc == 0) {
379  /* nothing to read, see if any full messages are already in buffer. */
380  xml = crm_remote_parse_buffer(native->remote);
381  } else if (rc < 0) {
382  disconnected = 1;
383  } else {
384  crm_remote_recv(native->remote, -1, &disconnected);
385  xml = crm_remote_parse_buffer(native->remote);
386  }
387  while (xml) {
388  const char *msg_type = crm_element_value(xml, F_LRMD_REMOTE_MSG_TYPE);
389  if (safe_str_eq(msg_type, "notify")) {
390  lrmd_dispatch_internal(lrmd, xml);
391  } else if (safe_str_eq(msg_type, "reply")) {
392  if (native->expected_late_replies > 0) {
393  native->expected_late_replies--;
394  } else {
395  int reply_id = 0;
396  crm_element_value_int(xml, F_LRMD_CALLID, &reply_id);
397  /* if this happens, we want to know about it */
398  crm_err("Got outdated reply %d", reply_id);
399  }
400  }
401  free_xml(xml);
402  xml = crm_remote_parse_buffer(native->remote);
403  }
404 
405  if (disconnected) {
406  crm_info("Server disconnected while reading remote server msg.");
407  lrmd_tls_disconnect(lrmd);
408  return 0;
409  }
410  return 1;
411 }
412 #endif
413 
414 /* Not used with mainloop */
415 int
416 lrmd_poll(lrmd_t * lrmd, int timeout)
417 {
418  lrmd_private_t *native = lrmd->private;
419 
420  switch (native->type) {
421  case CRM_CLIENT_IPC:
422  return crm_ipc_ready(native->ipc);
423 
424 #ifdef HAVE_GNUTLS_GNUTLS_H
425  case CRM_CLIENT_TLS:
426  if (native->pending_notify) {
427  return 1;
428  }
429 
430  return crm_remote_ready(native->remote, 0);
431 #endif
432  default:
433  crm_err("Unsupported connection type: %d", native->type);
434  }
435 
436  return 0;
437 }
438 
439 /* Not used with mainloop */
440 bool
442 {
443  lrmd_private_t *private = NULL;
444 
445  CRM_ASSERT(lrmd != NULL);
446 
447  private = lrmd->private;
448  switch (private->type) {
449  case CRM_CLIENT_IPC:
450  while (crm_ipc_ready(private->ipc)) {
451  if (crm_ipc_read(private->ipc) > 0) {
452  const char *msg = crm_ipc_buffer(private->ipc);
453 
454  lrmd_ipc_dispatch(msg, strlen(msg), lrmd);
455  }
456  }
457  break;
458 #ifdef HAVE_GNUTLS_GNUTLS_H
459  case CRM_CLIENT_TLS:
460  lrmd_tls_dispatch(lrmd);
461  break;
462 #endif
463  default:
464  crm_err("Unsupported connection type: %d", private->type);
465  }
466 
467  if (lrmd_api_is_connected(lrmd) == FALSE) {
468  crm_err("Connection closed");
469  return FALSE;
470  }
471 
472  return TRUE;
473 }
474 
475 static xmlNode *
476 lrmd_create_op(const char *token, const char *op, xmlNode * data, enum lrmd_call_options options)
477 {
478  xmlNode *op_msg = create_xml_node(NULL, "lrmd_command");
479 
480  CRM_CHECK(op_msg != NULL, return NULL);
481  CRM_CHECK(token != NULL, return NULL);
482 
483  crm_xml_add(op_msg, F_XML_TAGNAME, "lrmd_command");
484 
485  crm_xml_add(op_msg, F_TYPE, T_LRMD);
486  crm_xml_add(op_msg, F_LRMD_CALLBACK_TOKEN, token);
487  crm_xml_add(op_msg, F_LRMD_OPERATION, op);
488  crm_trace("Sending call options: %.8lx, %d", (long)options, options);
489  crm_xml_add_int(op_msg, F_LRMD_CALLOPTS, options);
490 
491  if (data != NULL) {
492  add_message_xml(op_msg, F_LRMD_CALLDATA, data);
493  }
494 
495  return op_msg;
496 }
497 
498 static void
499 lrmd_ipc_connection_destroy(gpointer userdata)
500 {
501  lrmd_t *lrmd = userdata;
502  lrmd_private_t *native = lrmd->private;
503 
504  crm_info("IPC connection destroyed");
505 
506  /* Prevent these from being cleaned up in lrmd_api_disconnect() */
507  native->ipc = NULL;
508  native->source = NULL;
509 
510  if (native->callback) {
511  lrmd_event_data_t event = { 0, };
512  event.type = lrmd_event_disconnect;
513  event.remote_nodename = native->remote_nodename;
514  native->callback(&event);
515  }
516 }
517 
518 #ifdef HAVE_GNUTLS_GNUTLS_H
519 static void
520 lrmd_tls_connection_destroy(gpointer userdata)
521 {
522  lrmd_t *lrmd = userdata;
523  lrmd_private_t *native = lrmd->private;
524 
525  crm_info("TLS connection destroyed");
526 
527  if (native->remote->tls_session) {
528  gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
529  gnutls_deinit(*native->remote->tls_session);
530  gnutls_free(native->remote->tls_session);
531  }
532  if (native->psk_cred_c) {
533  gnutls_psk_free_client_credentials(native->psk_cred_c);
534  }
535  if (native->sock) {
536  close(native->sock);
537  }
538  if (native->process_notify) {
539  mainloop_destroy_trigger(native->process_notify);
540  native->process_notify = NULL;
541  }
542  if (native->pending_notify) {
543  g_list_free_full(native->pending_notify, lrmd_free_xml);
544  native->pending_notify = NULL;
545  }
546 
547  free(native->remote->buffer);
548  native->remote->buffer = NULL;
549  native->source = 0;
550  native->sock = 0;
551  native->psk_cred_c = NULL;
552  native->remote->tls_session = NULL;
553  native->sock = 0;
554 
555  if (native->callback) {
556  lrmd_event_data_t event = { 0, };
557  event.remote_nodename = native->remote_nodename;
558  event.type = lrmd_event_disconnect;
559  native->callback(&event);
560  }
561  return;
562 }
563 
564 int
565 lrmd_tls_send_msg(crm_remote_t * session, xmlNode * msg, uint32_t id, const char *msg_type)
566 {
567  int rc = -1;
568 
570  crm_xml_add(msg, F_LRMD_REMOTE_MSG_TYPE, msg_type);
571 
572  rc = crm_remote_send(session, msg);
573 
574  if (rc < 0) {
575  crm_err("Failed to send remote lrmd tls msg, rc = %d", rc);
576  return rc;
577  }
578 
579  return rc;
580 }
581 
582 static xmlNode *
583 lrmd_tls_recv_reply(lrmd_t * lrmd, int total_timeout, int expected_reply_id, int *disconnected)
584 {
585  lrmd_private_t *native = lrmd->private;
586  xmlNode *xml = NULL;
587  time_t start = time(NULL);
588  const char *msg_type = NULL;
589  int reply_id = 0;
590  int remaining_timeout = 0;
591 
592  /* A timeout of 0 here makes no sense. We have to wait a period of time
593  * for the response to come back. If -1 or 0, default to 10 seconds. */
594  if (total_timeout <= 0 || total_timeout > MAX_TLS_RECV_WAIT) {
595  total_timeout = MAX_TLS_RECV_WAIT;
596  }
597 
598  while (!xml) {
599 
600  xml = crm_remote_parse_buffer(native->remote);
601  if (!xml) {
602  /* read some more off the tls buffer if we still have time left. */
603  if (remaining_timeout) {
604  remaining_timeout = remaining_timeout - ((time(NULL) - start) * 1000);
605  } else {
606  remaining_timeout = total_timeout;
607  }
608  if (remaining_timeout <= 0) {
609  crm_err("Never received the expected reply during the timeout period, disconnecting.");
610  *disconnected = TRUE;
611  return NULL;
612  }
613 
614  crm_remote_recv(native->remote, remaining_timeout, disconnected);
615  xml = crm_remote_parse_buffer(native->remote);
616  if (!xml) {
617  crm_err("Unable to receive expected reply, disconnecting.");
618  *disconnected = TRUE;
619  return NULL;
620  } else if (*disconnected) {
621  return NULL;
622  }
623  }
624 
625  CRM_ASSERT(xml != NULL);
626 
628  msg_type = crm_element_value(xml, F_LRMD_REMOTE_MSG_TYPE);
629 
630  if (!msg_type) {
631  crm_err("Empty msg type received while waiting for reply");
632  free_xml(xml);
633  xml = NULL;
634  } else if (safe_str_eq(msg_type, "notify")) {
635  /* got a notify while waiting for reply, trigger the notify to be processed later */
636  crm_info("queueing notify");
637  native->pending_notify = g_list_append(native->pending_notify, xml);
638  if (native->process_notify) {
639  crm_info("notify trigger set.");
640  mainloop_set_trigger(native->process_notify);
641  }
642  xml = NULL;
643  } else if (safe_str_neq(msg_type, "reply")) {
644  /* msg isn't a reply, make some noise */
645  crm_err("Expected a reply, got %s", msg_type);
646  free_xml(xml);
647  xml = NULL;
648  } else if (reply_id != expected_reply_id) {
649  if (native->expected_late_replies > 0) {
650  native->expected_late_replies--;
651  } else {
652  crm_err("Got outdated reply, expected id %d got id %d", expected_reply_id, reply_id);
653  }
654  free_xml(xml);
655  xml = NULL;
656  }
657  }
658 
659  if (native->remote->buffer && native->process_notify) {
660  mainloop_set_trigger(native->process_notify);
661  }
662 
663  return xml;
664 }
665 
666 static int
667 lrmd_tls_send(lrmd_t * lrmd, xmlNode * msg)
668 {
669  int rc = 0;
670  lrmd_private_t *native = lrmd->private;
671 
672  global_remote_msg_id++;
673  if (global_remote_msg_id <= 0) {
674  global_remote_msg_id = 1;
675  }
676 
677  rc = lrmd_tls_send_msg(native->remote, msg, global_remote_msg_id, "request");
678  if (rc <= 0) {
679  crm_err("Remote lrmd send failed, disconnecting");
680  lrmd_tls_disconnect(lrmd);
681  return -ENOTCONN;
682  }
683  return pcmk_ok;
684 }
685 
686 static int
687 lrmd_tls_send_recv(lrmd_t * lrmd, xmlNode * msg, int timeout, xmlNode ** reply)
688 {
689  int rc = 0;
690  int disconnected = 0;
691  xmlNode *xml = NULL;
692 
693  if (lrmd_tls_connected(lrmd) == FALSE) {
694  return -1;
695  }
696 
697  rc = lrmd_tls_send(lrmd, msg);
698  if (rc < 0) {
699  return rc;
700  }
701 
702  xml = lrmd_tls_recv_reply(lrmd, timeout, global_remote_msg_id, &disconnected);
703 
704  if (disconnected) {
705  crm_err("Remote lrmd server disconnected while waiting for reply with id %d. ",
706  global_remote_msg_id);
707  lrmd_tls_disconnect(lrmd);
708  rc = -ENOTCONN;
709  } else if (!xml) {
710  crm_err("Remote lrmd never received reply for request id %d. timeout: %dms ",
711  global_remote_msg_id, timeout);
712  rc = -ECOMM;
713  }
714 
715  if (reply) {
716  *reply = xml;
717  } else {
718  free_xml(xml);
719  }
720 
721  return rc;
722 }
723 #endif
724 
725 static int
726 lrmd_send_xml(lrmd_t * lrmd, xmlNode * msg, int timeout, xmlNode ** reply)
727 {
728  int rc = -1;
729  lrmd_private_t *native = lrmd->private;
730 
731  switch (native->type) {
732  case CRM_CLIENT_IPC:
733  rc = crm_ipc_send(native->ipc, msg, crm_ipc_client_response, timeout, reply);
734  break;
735 #ifdef HAVE_GNUTLS_GNUTLS_H
736  case CRM_CLIENT_TLS:
737  rc = lrmd_tls_send_recv(lrmd, msg, timeout, reply);
738  break;
739 #endif
740  default:
741  crm_err("Unsupported connection type: %d", native->type);
742  }
743 
744  return rc;
745 }
746 
747 static int
748 lrmd_send_xml_no_reply(lrmd_t * lrmd, xmlNode * msg)
749 {
750  int rc = -1;
751  lrmd_private_t *native = lrmd->private;
752 
753  switch (native->type) {
754  case CRM_CLIENT_IPC:
755  rc = crm_ipc_send(native->ipc, msg, crm_ipc_flags_none, 0, NULL);
756  break;
757 #ifdef HAVE_GNUTLS_GNUTLS_H
758  case CRM_CLIENT_TLS:
759  rc = lrmd_tls_send(lrmd, msg);
760  if (rc == pcmk_ok) {
761  /* we don't want to wait around for the reply, but
762  * since the request/reply protocol needs to behave the same
763  * as libqb, a reply will eventually come later anyway. */
764  native->expected_late_replies++;
765  }
766  break;
767 #endif
768  default:
769  crm_err("Unsupported connection type: %d", native->type);
770  }
771 
772  return rc;
773 }
774 
775 static int
776 lrmd_api_is_connected(lrmd_t * lrmd)
777 {
778  lrmd_private_t *native = lrmd->private;
779 
780  switch (native->type) {
781  case CRM_CLIENT_IPC:
782  return crm_ipc_connected(native->ipc);
783  break;
784 #ifdef HAVE_GNUTLS_GNUTLS_H
785  case CRM_CLIENT_TLS:
786  return lrmd_tls_connected(lrmd);
787  break;
788 #endif
789  default:
790  crm_err("Unsupported connection type: %d", native->type);
791  }
792 
793  return 0;
794 }
795 
796 static int
797 lrmd_send_command(lrmd_t * lrmd, const char *op, xmlNode * data, xmlNode ** output_data, int timeout, /* ms. defaults to 1000 if set to 0 */
798  enum lrmd_call_options options, gboolean expect_reply)
799 { /* TODO we need to reduce usage of this boolean */
800  int rc = pcmk_ok;
801  int reply_id = -1;
802  lrmd_private_t *native = lrmd->private;
803  xmlNode *op_msg = NULL;
804  xmlNode *op_reply = NULL;
805 
806  if (!lrmd_api_is_connected(lrmd)) {
807  return -ENOTCONN;
808  }
809 
810  if (op == NULL) {
811  crm_err("No operation specified");
812  return -EINVAL;
813  }
814 
815  CRM_CHECK(native->token != NULL,;
816  );
817  crm_trace("sending %s op to lrmd", op);
818 
819  op_msg = lrmd_create_op(native->token, op, data, options);
820 
821  if (op_msg == NULL) {
822  return -EINVAL;
823  }
824 
825  crm_xml_add_int(op_msg, F_LRMD_TIMEOUT, timeout);
826 
827  if (expect_reply) {
828  rc = lrmd_send_xml(lrmd, op_msg, timeout, &op_reply);
829  } else {
830  rc = lrmd_send_xml_no_reply(lrmd, op_msg);
831  goto done;
832  }
833 
834  if (rc < 0) {
835  crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%d): %d", op, timeout, rc);
836  rc = -ECOMM;
837  goto done;
838 
839  } else if(op_reply == NULL) {
840  rc = -ENOMSG;
841  goto done;
842  }
843 
844  rc = pcmk_ok;
845  crm_element_value_int(op_reply, F_LRMD_CALLID, &reply_id);
846  crm_trace("%s op reply received", op);
847  if (crm_element_value_int(op_reply, F_LRMD_RC, &rc) != 0) {
848  rc = -ENOMSG;
849  goto done;
850  }
851 
852  crm_log_xml_trace(op_reply, "Reply");
853 
854  if (output_data) {
855  *output_data = op_reply;
856  op_reply = NULL; /* Prevent subsequent free */
857  }
858 
859  done:
860  if (lrmd_api_is_connected(lrmd) == FALSE) {
861  crm_err("LRMD disconnected");
862  }
863 
864  free_xml(op_msg);
865  free_xml(op_reply);
866  return rc;
867 }
868 
869 static int
870 lrmd_api_poke_connection(lrmd_t * lrmd)
871 {
872  int rc;
873  lrmd_private_t *native = lrmd->private;
874  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
875 
876  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
877  rc = lrmd_send_command(lrmd, LRMD_OP_POKE, data, NULL, 0, 0, native->type == CRM_CLIENT_IPC ? TRUE : FALSE);
878  free_xml(data);
879 
880  return rc < 0 ? rc : pcmk_ok;
881 }
882 
883 static int
884 lrmd_handshake(lrmd_t * lrmd, const char *name)
885 {
886  int rc = pcmk_ok;
887  lrmd_private_t *native = lrmd->private;
888  xmlNode *reply = NULL;
889  xmlNode *hello = create_xml_node(NULL, "lrmd_command");
890 
891  crm_xml_add(hello, F_TYPE, T_LRMD);
893  crm_xml_add(hello, F_LRMD_CLIENTNAME, name);
895 
896  /* advertise that we are a proxy provider */
897  if (native->proxy_callback) {
898  crm_xml_add(hello, F_LRMD_IS_IPC_PROVIDER, "true");
899  }
900 
901  rc = lrmd_send_xml(lrmd, hello, -1, &reply);
902 
903  if (rc < 0) {
904  crm_perror(LOG_DEBUG, "Couldn't complete registration with the lrmd API: %d", rc);
905  rc = -ECOMM;
906  } else if (reply == NULL) {
907  crm_err("Did not receive registration reply");
908  rc = -EPROTO;
909  } else {
910  const char *msg_type = crm_element_value(reply, F_LRMD_OPERATION);
911  const char *tmp_ticket = crm_element_value(reply, F_LRMD_CLIENTID);
912 
913  crm_element_value_int(reply, F_LRMD_RC, &rc);
914 
915  if (rc == -EPROTO) {
916  crm_err("LRMD protocol mismatch client version %s, server version %s",
918  crm_log_xml_err(reply, "Protocol Error");
919 
920  } else if (safe_str_neq(msg_type, CRM_OP_REGISTER)) {
921  crm_err("Invalid registration message: %s", msg_type);
922  crm_log_xml_err(reply, "Bad reply");
923  rc = -EPROTO;
924  } else if (tmp_ticket == NULL) {
925  crm_err("No registration token provided");
926  crm_log_xml_err(reply, "Bad reply");
927  rc = -EPROTO;
928  } else {
929  crm_trace("Obtained registration token: %s", tmp_ticket);
930  native->token = strdup(tmp_ticket);
931  rc = pcmk_ok;
932  }
933  }
934 
935  free_xml(reply);
936  free_xml(hello);
937 
938  if (rc != pcmk_ok) {
939  lrmd_api_disconnect(lrmd);
940  }
941  return rc;
942 }
943 
944 static int
945 lrmd_ipc_connect(lrmd_t * lrmd, int *fd)
946 {
947  int rc = pcmk_ok;
948  lrmd_private_t *native = lrmd->private;
949 
950  static struct ipc_client_callbacks lrmd_callbacks = {
951  .dispatch = lrmd_ipc_dispatch,
952  .destroy = lrmd_ipc_connection_destroy
953  };
954 
955  crm_info("Connecting to lrmd");
956 
957  if (fd) {
958  /* No mainloop */
959  native->ipc = crm_ipc_new(CRM_SYSTEM_LRMD, 0);
960  if (native->ipc && crm_ipc_connect(native->ipc)) {
961  *fd = crm_ipc_get_fd(native->ipc);
962  } else if (native->ipc) {
963  crm_perror(LOG_ERR, "Connection to local resource manager failed");
964  rc = -ENOTCONN;
965  }
966  } else {
967  native->source = mainloop_add_ipc_client(CRM_SYSTEM_LRMD, G_PRIORITY_HIGH, 0, lrmd, &lrmd_callbacks);
968  native->ipc = mainloop_get_ipc_client(native->source);
969  }
970 
971  if (native->ipc == NULL) {
972  crm_debug("Could not connect to the LRMD API");
973  rc = -ENOTCONN;
974  }
975 
976  return rc;
977 }
978 
979 #ifdef HAVE_GNUTLS_GNUTLS_H
980 static int
981 set_key(gnutls_datum_t * key, const char *location)
982 {
983  FILE *stream;
984  int read_len = 256;
985  int cur_len = 0;
986  int buf_len = read_len;
987  static char *key_cache = NULL;
988  static size_t key_cache_len = 0;
989  static time_t key_cache_updated;
990 
991  if (location == NULL) {
992  return -1;
993  }
994 
995  if (key_cache) {
996  time_t now = time(NULL);
997 
998  if ((now - key_cache_updated) < 60) {
999  key->data = gnutls_malloc(key_cache_len + 1);
1000  key->size = key_cache_len;
1001  memcpy(key->data, key_cache, key_cache_len);
1002 
1003  crm_debug("using cached LRMD key");
1004  return 0;
1005  } else {
1006  key_cache_len = 0;
1007  key_cache_updated = 0;
1008  free(key_cache);
1009  key_cache = NULL;
1010  crm_debug("clearing lrmd key cache");
1011  }
1012  }
1013 
1014  stream = fopen(location, "r");
1015  if (!stream) {
1016  return -1;
1017  }
1018 
1019  key->data = gnutls_malloc(read_len);
1020  while (!feof(stream)) {
1021  int next;
1022 
1023  if (cur_len == buf_len) {
1024  buf_len = cur_len + read_len;
1025  key->data = gnutls_realloc(key->data, buf_len);
1026  }
1027  next = fgetc(stream);
1028  if (next == EOF && feof(stream)) {
1029  break;
1030  }
1031 
1032  key->data[cur_len] = next;
1033  cur_len++;
1034  }
1035  fclose(stream);
1036 
1037  key->size = cur_len;
1038  if (!cur_len) {
1039  gnutls_free(key->data);
1040  key->data = 0;
1041  return -1;
1042  }
1043 
1044  if (!key_cache) {
1045  key_cache = calloc(1, key->size + 1);
1046  memcpy(key_cache, key->data, key->size);
1047 
1048  key_cache_len = key->size;
1049  key_cache_updated = time(NULL);
1050  }
1051 
1052  return 0;
1053 }
1054 
1055 int
1056 lrmd_tls_set_key(gnutls_datum_t * key)
1057 {
1058  int rc = 0;
1059  const char *specific_location = getenv("PCMK_authkey_location");
1060 
1061  if (set_key(key, specific_location) == 0) {
1062  crm_debug("Using custom authkey location %s", specific_location);
1063  return 0;
1064 
1065  } else if (specific_location) {
1066  crm_err("No valid lrmd remote key found at %s, trying default location", specific_location);
1067  }
1068 
1069  if (set_key(key, DEFAULT_REMOTE_KEY_LOCATION) != 0) {
1070  rc = set_key(key, ALT_REMOTE_KEY_LOCATION);
1071  }
1072 
1073  if (rc) {
1074  crm_err("No valid lrmd remote key found at %s", DEFAULT_REMOTE_KEY_LOCATION);
1075  return -1;
1076  }
1077 
1078  return rc;
1079 }
1080 
1081 static void
1082 lrmd_gnutls_global_init(void)
1083 {
1084  static int gnutls_init = 0;
1085 
1086  if (!gnutls_init) {
1087  crm_gnutls_global_init();
1088  }
1089  gnutls_init = 1;
1090 }
1091 #endif
1092 
1093 static void
1094 report_async_connection_result(lrmd_t * lrmd, int rc)
1095 {
1096  lrmd_private_t *native = lrmd->private;
1097 
1098  if (native->callback) {
1099  lrmd_event_data_t event = { 0, };
1100  event.type = lrmd_event_connect;
1101  event.remote_nodename = native->remote_nodename;
1102  event.connection_rc = rc;
1103  native->callback(&event);
1104  }
1105 }
1106 
1107 #ifdef HAVE_GNUTLS_GNUTLS_H
1108 static void
1109 lrmd_tcp_connect_cb(void *userdata, int sock)
1110 {
1111  lrmd_t *lrmd = userdata;
1112  lrmd_private_t *native = lrmd->private;
1113  char name[256] = { 0, };
1114  static struct mainloop_fd_callbacks lrmd_tls_callbacks = {
1115  .dispatch = lrmd_tls_dispatch,
1116  .destroy = lrmd_tls_connection_destroy,
1117  };
1118  int rc = sock;
1119  gnutls_datum_t psk_key = { NULL, 0 };
1120 
1121  native->async_timer = 0;
1122 
1123  if (rc < 0) {
1124  lrmd_tls_connection_destroy(lrmd);
1125  crm_info("remote lrmd connect to %s at port %d failed", native->server, native->port);
1126  report_async_connection_result(lrmd, rc);
1127  return;
1128  }
1129 
1130  /* TODO continue with tls stuff now that tcp connect passed. make this async as well soon
1131  * to avoid all blocking code in the client. */
1132  native->sock = sock;
1133 
1134  if (lrmd_tls_set_key(&psk_key) != 0) {
1135  lrmd_tls_connection_destroy(lrmd);
1136  return;
1137  }
1138 
1139  gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1140  gnutls_psk_set_client_credentials(native->psk_cred_c, DEFAULT_REMOTE_USERNAME, &psk_key, GNUTLS_PSK_KEY_RAW);
1141  gnutls_free(psk_key.data);
1142 
1143  native->remote->tls_session = create_psk_tls_session(sock, GNUTLS_CLIENT, native->psk_cred_c);
1144 
1145  if (crm_initiate_client_tls_handshake(native->remote, LRMD_CLIENT_HANDSHAKE_TIMEOUT) != 0) {
1146  crm_warn("Client tls handshake failed for server %s:%d. Disconnecting", native->server,
1147  native->port);
1148  gnutls_deinit(*native->remote->tls_session);
1149  gnutls_free(native->remote->tls_session);
1150  native->remote->tls_session = NULL;
1151  lrmd_tls_connection_destroy(lrmd);
1152  report_async_connection_result(lrmd, -1);
1153  return;
1154  }
1155 
1156  crm_info("Remote lrmd client TLS connection established with server %s:%d", native->server,
1157  native->port);
1158 
1159  snprintf(name, 128, "remote-lrmd-%s:%d", native->server, native->port);
1160 
1161  native->process_notify = mainloop_add_trigger(G_PRIORITY_HIGH, lrmd_tls_dispatch, lrmd);
1162  native->source =
1163  mainloop_add_fd(name, G_PRIORITY_HIGH, native->sock, lrmd, &lrmd_tls_callbacks);
1164 
1165  rc = lrmd_handshake(lrmd, name);
1166  report_async_connection_result(lrmd, rc);
1167 
1168  return;
1169 }
1170 
1171 static int
1172 lrmd_tls_connect_async(lrmd_t * lrmd, int timeout /*ms */ )
1173 {
1174  int rc = -1;
1175  int sock = 0;
1176  int timer_id = 0;
1177 
1178  lrmd_private_t *native = lrmd->private;
1179 
1180  lrmd_gnutls_global_init();
1181 
1182  sock = crm_remote_tcp_connect_async(native->server, native->port, timeout, &timer_id, lrmd,
1183  lrmd_tcp_connect_cb);
1184 
1185  if (sock != -1) {
1186  native->sock = sock;
1187  rc = 0;
1188  native->async_timer = timer_id;
1189  }
1190 
1191  return rc;
1192 }
1193 
1194 static int
1195 lrmd_tls_connect(lrmd_t * lrmd, int *fd)
1196 {
1197  static struct mainloop_fd_callbacks lrmd_tls_callbacks = {
1198  .dispatch = lrmd_tls_dispatch,
1199  .destroy = lrmd_tls_connection_destroy,
1200  };
1201 
1202  lrmd_private_t *native = lrmd->private;
1203  int sock;
1204  gnutls_datum_t psk_key = { NULL, 0 };
1205 
1206  lrmd_gnutls_global_init();
1207 
1208  sock = crm_remote_tcp_connect(native->server, native->port);
1209  if (sock < 0) {
1210  crm_warn("Could not establish remote lrmd connection to %s", native->server);
1211  lrmd_tls_connection_destroy(lrmd);
1212  return -ENOTCONN;
1213  }
1214 
1215  native->sock = sock;
1216 
1217  if (lrmd_tls_set_key(&psk_key) != 0) {
1218  lrmd_tls_connection_destroy(lrmd);
1219  return -1;
1220  }
1221 
1222  gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1223  gnutls_psk_set_client_credentials(native->psk_cred_c, DEFAULT_REMOTE_USERNAME, &psk_key, GNUTLS_PSK_KEY_RAW);
1224  gnutls_free(psk_key.data);
1225 
1226  native->remote->tls_session = create_psk_tls_session(sock, GNUTLS_CLIENT, native->psk_cred_c);
1227 
1228  if (crm_initiate_client_tls_handshake(native->remote, LRMD_CLIENT_HANDSHAKE_TIMEOUT) != 0) {
1229  crm_err("Session creation for %s:%d failed", native->server, native->port);
1230  gnutls_deinit(*native->remote->tls_session);
1231  gnutls_free(native->remote->tls_session);
1232  native->remote->tls_session = NULL;
1233  lrmd_tls_connection_destroy(lrmd);
1234  return -1;
1235  }
1236 
1237  crm_info("Remote lrmd client TLS connection established with server %s:%d", native->server,
1238  native->port);
1239 
1240  if (fd) {
1241  *fd = sock;
1242  } else {
1243  char name[256] = { 0, };
1244  snprintf(name, 128, "remote-lrmd-%s:%d", native->server, native->port);
1245 
1246  native->process_notify = mainloop_add_trigger(G_PRIORITY_HIGH, lrmd_tls_dispatch, lrmd);
1247  native->source =
1248  mainloop_add_fd(name, G_PRIORITY_HIGH, native->sock, lrmd, &lrmd_tls_callbacks);
1249  }
1250  return pcmk_ok;
1251 }
1252 #endif
1253 
1254 static int
1255 lrmd_api_connect(lrmd_t * lrmd, const char *name, int *fd)
1256 {
1257  int rc = -ENOTCONN;
1258  lrmd_private_t *native = lrmd->private;
1259 
1260  switch (native->type) {
1261  case CRM_CLIENT_IPC:
1262  rc = lrmd_ipc_connect(lrmd, fd);
1263  break;
1264 #ifdef HAVE_GNUTLS_GNUTLS_H
1265  case CRM_CLIENT_TLS:
1266  rc = lrmd_tls_connect(lrmd, fd);
1267  break;
1268 #endif
1269  default:
1270  crm_err("Unsupported connection type: %d", native->type);
1271  }
1272 
1273  if (rc == pcmk_ok) {
1274  rc = lrmd_handshake(lrmd, name);
1275  }
1276 
1277  return rc;
1278 }
1279 
1280 static int
1281 lrmd_api_connect_async(lrmd_t * lrmd, const char *name, int timeout)
1282 {
1283  int rc = 0;
1284  lrmd_private_t *native = lrmd->private;
1285 
1286  if (!native->callback) {
1287  crm_err("Async connect not possible, no lrmd client callback set.");
1288  return -1;
1289  }
1290 
1291  switch (native->type) {
1292  case CRM_CLIENT_IPC:
1293  /* fake async connection with ipc. it should be fast
1294  * enough that we gain very little from async */
1295  rc = lrmd_api_connect(lrmd, name, NULL);
1296  if (!rc) {
1297  report_async_connection_result(lrmd, rc);
1298  }
1299  break;
1300 #ifdef HAVE_GNUTLS_GNUTLS_H
1301  case CRM_CLIENT_TLS:
1302  rc = lrmd_tls_connect_async(lrmd, timeout);
1303  if (rc) {
1304  /* connection failed, report rc now */
1305  report_async_connection_result(lrmd, rc);
1306  }
1307  break;
1308 #endif
1309  default:
1310  crm_err("Unsupported connection type: %d", native->type);
1311  }
1312 
1313  return rc;
1314 }
1315 
1316 static void
1317 lrmd_ipc_disconnect(lrmd_t * lrmd)
1318 {
1319  lrmd_private_t *native = lrmd->private;
1320 
1321  if (native->source != NULL) {
1322  /* Attached to mainloop */
1323  mainloop_del_ipc_client(native->source);
1324  native->source = NULL;
1325  native->ipc = NULL;
1326 
1327  } else if (native->ipc) {
1328  /* Not attached to mainloop */
1329  crm_ipc_t *ipc = native->ipc;
1330 
1331  native->ipc = NULL;
1332  crm_ipc_close(ipc);
1333  crm_ipc_destroy(ipc);
1334  }
1335 }
1336 
1337 #ifdef HAVE_GNUTLS_GNUTLS_H
1338 static void
1339 lrmd_tls_disconnect(lrmd_t * lrmd)
1340 {
1341  lrmd_private_t *native = lrmd->private;
1342 
1343  if (native->remote->tls_session) {
1344  gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
1345  gnutls_deinit(*native->remote->tls_session);
1346  gnutls_free(native->remote->tls_session);
1347  native->remote->tls_session = 0;
1348  }
1349 
1350  if (native->async_timer) {
1351  g_source_remove(native->async_timer);
1352  native->async_timer = 0;
1353  }
1354 
1355  if (native->source != NULL) {
1356  /* Attached to mainloop */
1357  mainloop_del_ipc_client(native->source);
1358  native->source = NULL;
1359 
1360  } else if (native->sock) {
1361  close(native->sock);
1362  }
1363 
1364  if (native->pending_notify) {
1365  g_list_free_full(native->pending_notify, lrmd_free_xml);
1366  native->pending_notify = NULL;
1367  }
1368 }
1369 #endif
1370 
1371 static int
1372 lrmd_api_disconnect(lrmd_t * lrmd)
1373 {
1374  lrmd_private_t *native = lrmd->private;
1375 
1376  crm_info("Disconnecting from %d lrmd service", native->type);
1377  switch (native->type) {
1378  case CRM_CLIENT_IPC:
1379  lrmd_ipc_disconnect(lrmd);
1380  break;
1381 #ifdef HAVE_GNUTLS_GNUTLS_H
1382  case CRM_CLIENT_TLS:
1383  lrmd_tls_disconnect(lrmd);
1384  break;
1385 #endif
1386  default:
1387  crm_err("Unsupported connection type: %d", native->type);
1388  }
1389 
1390  free(native->token);
1391  native->token = NULL;
1392  return 0;
1393 }
1394 
1395 static int
1396 lrmd_api_register_rsc(lrmd_t * lrmd,
1397  const char *rsc_id,
1398  const char *class,
1399  const char *provider, const char *type, enum lrmd_call_options options)
1400 {
1401  int rc = pcmk_ok;
1402  xmlNode *data = NULL;
1403 
1404  if (!class || !type || !rsc_id) {
1405  return -EINVAL;
1406  }
1407  if (safe_str_eq(class, "ocf") && !provider) {
1408  return -EINVAL;
1409  }
1410 
1411  data = create_xml_node(NULL, F_LRMD_RSC);
1412 
1413  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
1414  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1415  crm_xml_add(data, F_LRMD_CLASS, class);
1416  crm_xml_add(data, F_LRMD_PROVIDER, provider);
1417  crm_xml_add(data, F_LRMD_TYPE, type);
1418  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_REG, data, NULL, 0, options, TRUE);
1419  free_xml(data);
1420 
1421  return rc;
1422 }
1423 
1424 static int
1425 lrmd_api_unregister_rsc(lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options options)
1426 {
1427  int rc = pcmk_ok;
1428  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
1429 
1430  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
1431  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1432  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_UNREG, data, NULL, 0, options, TRUE);
1433  free_xml(data);
1434 
1435  return rc;
1436 }
1437 
1440 {
1441  lrmd_rsc_info_t *copy = NULL;
1442 
1443  copy = calloc(1, sizeof(lrmd_rsc_info_t));
1444 
1445  copy->id = strdup(rsc_info->id);
1446  copy->type = strdup(rsc_info->type);
1447  copy->class = strdup(rsc_info->class);
1448  if (rsc_info->provider) {
1449  copy->provider = strdup(rsc_info->provider);
1450  }
1451 
1452  return copy;
1453 }
1454 
1455 void
1457 {
1458  if (!rsc_info) {
1459  return;
1460  }
1461  free(rsc_info->id);
1462  free(rsc_info->type);
1463  free(rsc_info->class);
1464  free(rsc_info->provider);
1465  free(rsc_info);
1466 }
1467 
1468 static lrmd_rsc_info_t *
1469 lrmd_api_get_rsc_info(lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options options)
1470 {
1471  lrmd_rsc_info_t *rsc_info = NULL;
1472  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
1473  xmlNode *output = NULL;
1474  const char *class = NULL;
1475  const char *provider = NULL;
1476  const char *type = NULL;
1477 
1478  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
1479  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1480  lrmd_send_command(lrmd, LRMD_OP_RSC_INFO, data, &output, 0, options, TRUE);
1481  free_xml(data);
1482 
1483  if (!output) {
1484  return NULL;
1485  }
1486 
1487  class = crm_element_value(output, F_LRMD_CLASS);
1488  provider = crm_element_value(output, F_LRMD_PROVIDER);
1489  type = crm_element_value(output, F_LRMD_TYPE);
1490 
1491  if (!class || !type) {
1492  free_xml(output);
1493  return NULL;
1494  } else if (safe_str_eq(class, "ocf") && !provider) {
1495  free_xml(output);
1496  return NULL;
1497  }
1498 
1499  rsc_info = calloc(1, sizeof(lrmd_rsc_info_t));
1500  rsc_info->id = strdup(rsc_id);
1501  rsc_info->class = strdup(class);
1502  if (provider) {
1503  rsc_info->provider = strdup(provider);
1504  }
1505  rsc_info->type = strdup(type);
1506 
1507  free_xml(output);
1508  return rsc_info;
1509 }
1510 
1511 static void
1512 lrmd_api_set_callback(lrmd_t * lrmd, lrmd_event_callback callback)
1513 {
1514  lrmd_private_t *native = lrmd->private;
1515 
1516  native->callback = callback;
1517 }
1518 
1519 void
1520 lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
1521 {
1522  lrmd_private_t *native = lrmd->private;
1523 
1524  native->proxy_callback = callback;
1525  native->proxy_callback_userdata = userdata;
1526 }
1527 
1528 void
1529 lrmd_internal_proxy_dispatch(lrmd_t *lrmd, xmlNode *msg)
1530 {
1531  lrmd_private_t *native = lrmd->private;
1532 
1533  if (native->proxy_callback) {
1534  crm_log_xml_trace(msg, "PROXY_INBOUND");
1535  native->proxy_callback(lrmd, native->proxy_callback_userdata, msg);
1536  }
1537 }
1538 
1539 int
1540 lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg)
1541 {
1542  if (lrmd == NULL) {
1543  return -ENOTCONN;
1544  }
1546 
1547  crm_log_xml_trace(msg, "PROXY_OUTBOUND");
1548  return lrmd_send_xml_no_reply(lrmd, msg);
1549 }
1550 
1551 static int
1552 stonith_get_metadata(const char *provider, const char *type, char **output)
1553 {
1554  int rc = pcmk_ok;
1555  stonith_t *stonith_api = stonith_api_new();
1556 
1557  if(stonith_api) {
1558  stonith_api->cmds->metadata(stonith_api, st_opt_sync_call, type, provider, output, 0);
1559  stonith_api->cmds->free(stonith_api);
1560  }
1561  if (*output == NULL) {
1562  rc = -EIO;
1563  }
1564  return rc;
1565 }
1566 
1567 #define lsb_metadata_template \
1568  "<?xml version='1.0'?>\n" \
1569  "<!DOCTYPE resource-agent SYSTEM 'ra-api-1.dtd'>\n" \
1570  "<resource-agent name='%s' version='0.1'>\n" \
1571  " <version>1.0</version>\n" \
1572  " <longdesc lang='en'>\n" \
1573  " %s\n" \
1574  " </longdesc>\n" \
1575  " <shortdesc lang='en'>%s</shortdesc>\n" \
1576  " <parameters>\n" \
1577  " </parameters>\n" \
1578  " <actions>\n" \
1579  " <action name='meta-data' timeout='5' />\n" \
1580  " <action name='start' timeout='15' />\n" \
1581  " <action name='stop' timeout='15' />\n" \
1582  " <action name='status' timeout='15' />\n" \
1583  " <action name='restart' timeout='15' />\n" \
1584  " <action name='force-reload' timeout='15' />\n" \
1585  " <action name='monitor' timeout='15' interval='15' />\n" \
1586  " </actions>\n" \
1587  " <special tag='LSB'>\n" \
1588  " <Provides>%s</Provides>\n" \
1589  " <Required-Start>%s</Required-Start>\n" \
1590  " <Required-Stop>%s</Required-Stop>\n" \
1591  " <Should-Start>%s</Should-Start>\n" \
1592  " <Should-Stop>%s</Should-Stop>\n" \
1593  " <Default-Start>%s</Default-Start>\n" \
1594  " <Default-Stop>%s</Default-Stop>\n" \
1595  " </special>\n" \
1596  "</resource-agent>\n"
1597 
1598 #define LSB_INITSCRIPT_INFOBEGIN_TAG "### BEGIN INIT INFO"
1599 #define LSB_INITSCRIPT_INFOEND_TAG "### END INIT INFO"
1600 #define PROVIDES "# Provides:"
1601 #define REQ_START "# Required-Start:"
1602 #define REQ_STOP "# Required-Stop:"
1603 #define SHLD_START "# Should-Start:"
1604 #define SHLD_STOP "# Should-Stop:"
1605 #define DFLT_START "# Default-Start:"
1606 #define DFLT_STOP "# Default-Stop:"
1607 #define SHORT_DSCR "# Short-Description:"
1608 #define DESCRIPTION "# Description:"
1609 
1610 #define lsb_meta_helper_free_value(m) \
1611  do { \
1612  if ((m) != NULL) { \
1613  xmlFree(m); \
1614  (m) = NULL; \
1615  } \
1616  } while(0)
1617 
1618 /*
1619  * \internal
1620  * \brief Grab an LSB header value
1621  *
1622  * \param[in] line Line read from LSB init script
1623  * \param[in/out] value If not set, will be set to XML-safe copy of value
1624  * \param[in] prefix Set value if line starts with this pattern
1625  *
1626  * \return TRUE if value was set, FALSE otherwise
1627  */
1628 static inline gboolean
1629 lsb_meta_helper_get_value(const char *line, char **value, const char *prefix)
1630 {
1631  if (!*value && !strncasecmp(line, prefix, strlen(prefix))) {
1632  *value = (char *)xmlEncodeEntitiesReentrant(NULL, BAD_CAST line+strlen(prefix));
1633  return TRUE;
1634  }
1635  return FALSE;
1636 }
1637 
1638 static int
1639 lsb_get_metadata(const char *type, char **output)
1640 {
1641  char ra_pathname[PATH_MAX] = { 0, };
1642  FILE *fp;
1643  char buffer[1024];
1644  char *provides = NULL;
1645  char *req_start = NULL;
1646  char *req_stop = NULL;
1647  char *shld_start = NULL;
1648  char *shld_stop = NULL;
1649  char *dflt_start = NULL;
1650  char *dflt_stop = NULL;
1651  char *s_dscrpt = NULL;
1652  char *xml_l_dscrpt = NULL;
1653  int offset = 0;
1654  int max = 2048;
1655  char description[max];
1656 
1657  if(type[0] == '/') {
1658  snprintf(ra_pathname, sizeof(ra_pathname), "%s", type);
1659  } else {
1660  snprintf(ra_pathname, sizeof(ra_pathname), "%s/%s", LSB_ROOT_DIR, type);
1661  }
1662 
1663  crm_trace("Looking into %s", ra_pathname);
1664  if (!(fp = fopen(ra_pathname, "r"))) {
1665  return -errno;
1666  }
1667 
1668  /* Enter into the lsb-compliant comment block */
1669  while (fgets(buffer, sizeof(buffer), fp)) {
1670 
1671  /* Now suppose each of the following eight arguments contain only one line */
1672  if (lsb_meta_helper_get_value(buffer, &provides, PROVIDES)) {
1673  continue;
1674  }
1675  if (lsb_meta_helper_get_value(buffer, &req_start, REQ_START)) {
1676  continue;
1677  }
1678  if (lsb_meta_helper_get_value(buffer, &req_stop, REQ_STOP)) {
1679  continue;
1680  }
1681  if (lsb_meta_helper_get_value(buffer, &shld_start, SHLD_START)) {
1682  continue;
1683  }
1684  if (lsb_meta_helper_get_value(buffer, &shld_stop, SHLD_STOP)) {
1685  continue;
1686  }
1687  if (lsb_meta_helper_get_value(buffer, &dflt_start, DFLT_START)) {
1688  continue;
1689  }
1690  if (lsb_meta_helper_get_value(buffer, &dflt_stop, DFLT_STOP)) {
1691  continue;
1692  }
1693  if (lsb_meta_helper_get_value(buffer, &s_dscrpt, SHORT_DSCR)) {
1694  continue;
1695  }
1696 
1697  /* Long description may cross multiple lines */
1698  if (offset == 0 && (0 == strncasecmp(buffer, DESCRIPTION, strlen(DESCRIPTION)))) {
1699  /* Between # and keyword, more than one space, or a tab
1700  * character, indicates the continuation line.
1701  *
1702  * Extracted from LSB init script standard
1703  */
1704  while (fgets(buffer, sizeof(buffer), fp)) {
1705  if (!strncmp(buffer, "# ", 3) || !strncmp(buffer, "#\t", 2)) {
1706  buffer[0] = ' ';
1707  offset += snprintf(description+offset, max-offset, "%s", buffer);
1708 
1709  } else {
1710  fputs(buffer, fp);
1711  break; /* Long description ends */
1712  }
1713  }
1714  continue;
1715  }
1716 
1717  if (xml_l_dscrpt == NULL && offset > 0) {
1718  xml_l_dscrpt = (char *)xmlEncodeEntitiesReentrant(NULL, BAD_CAST(description));
1719  }
1720 
1721  if (!strncasecmp(buffer, LSB_INITSCRIPT_INFOEND_TAG, strlen(LSB_INITSCRIPT_INFOEND_TAG))) {
1722  /* Get to the out border of LSB comment block */
1723  break;
1724  }
1725  if (buffer[0] != '#') {
1726  break; /* Out of comment block in the beginning */
1727  }
1728  }
1729  fclose(fp);
1730 
1731  *output = crm_strdup_printf(lsb_metadata_template, type,
1732  (xml_l_dscrpt == NULL) ? type : xml_l_dscrpt,
1733  (s_dscrpt == NULL) ? type : s_dscrpt, (provides == NULL) ? "" : provides,
1734  (req_start == NULL) ? "" : req_start, (req_stop == NULL) ? "" : req_stop,
1735  (shld_start == NULL) ? "" : shld_start, (shld_stop == NULL) ? "" : shld_stop,
1736  (dflt_start == NULL) ? "" : dflt_start, (dflt_stop == NULL) ? "" : dflt_stop);
1737 
1738  lsb_meta_helper_free_value(xml_l_dscrpt);
1739  lsb_meta_helper_free_value(s_dscrpt);
1740  lsb_meta_helper_free_value(provides);
1741  lsb_meta_helper_free_value(req_start);
1742  lsb_meta_helper_free_value(req_stop);
1743  lsb_meta_helper_free_value(shld_start);
1744  lsb_meta_helper_free_value(shld_stop);
1745  lsb_meta_helper_free_value(dflt_start);
1746  lsb_meta_helper_free_value(dflt_stop);
1747 
1748  crm_trace("Created fake metadata: %d", strlen(*output));
1749  return pcmk_ok;
1750 }
1751 
1752 #if SUPPORT_NAGIOS
1753 static int
1754 nagios_get_metadata(const char *type, char **output)
1755 {
1756  int rc = pcmk_ok;
1757  FILE *file_strm = NULL;
1758  int start = 0, length = 0, read_len = 0;
1759  char *metadata_file = NULL;
1760  int len = 36;
1761 
1762  len += strlen(NAGIOS_METADATA_DIR);
1763  len += strlen(type);
1764  metadata_file = calloc(1, len);
1765  CRM_CHECK(metadata_file != NULL, return -ENOMEM);
1766 
1767  sprintf(metadata_file, "%s/%s.xml", NAGIOS_METADATA_DIR, type);
1768  file_strm = fopen(metadata_file, "r");
1769  if (file_strm == NULL) {
1770  crm_err("Metadata file %s does not exist", metadata_file);
1771  free(metadata_file);
1772  return -EIO;
1773  }
1774 
1775  /* see how big the file is */
1776  start = ftell(file_strm);
1777  fseek(file_strm, 0L, SEEK_END);
1778  length = ftell(file_strm);
1779  fseek(file_strm, 0L, start);
1780 
1781  CRM_ASSERT(length >= 0);
1782  CRM_ASSERT(start == ftell(file_strm));
1783 
1784  if (length <= 0) {
1785  crm_info("%s was not valid", metadata_file);
1786  free(*output);
1787  *output = NULL;
1788  rc = -EIO;
1789 
1790  } else {
1791  crm_trace("Reading %d bytes from file", length);
1792  *output = calloc(1, (length + 1));
1793  read_len = fread(*output, 1, length, file_strm);
1794  if (read_len != length) {
1795  crm_err("Calculated and read bytes differ: %d vs. %d", length, read_len);
1796  free(*output);
1797  *output = NULL;
1798  rc = -EIO;
1799  }
1800  }
1801 
1802  fclose(file_strm);
1803  free(metadata_file);
1804  return rc;
1805 }
1806 #endif
1807 
1808 #if SUPPORT_HEARTBEAT
1809 /* strictly speaking, support for class=heartbeat style scripts
1810  * does not require "heartbeat support" to be enabled.
1811  * But since those scripts are part of the "heartbeat" package usually,
1812  * and are very unlikely to be present in any other deployment,
1813  * I leave it inside this ifdef.
1814  *
1815  * Yes, I know, these are legacy and should die,
1816  * or at least be rewritten to be a proper OCF style agent.
1817  * But they exist, and custom scripts following these rules do, too.
1818  *
1819  * Taken from the old "glue" lrmd, see
1820  * http://hg.linux-ha.org/glue/file/0a7add1d9996/lib/plugins/lrm/raexechb.c#l49
1821  * http://hg.linux-ha.org/glue/file/0a7add1d9996/lib/plugins/lrm/raexechb.c#l393
1822  */
1823 
1824 static const char hb_metadata_template[] =
1825 "<?xml version='1.0'?>\n"
1826 "<!DOCTYPE resource-agent SYSTEM 'ra-api-1.dtd'>\n"
1827 "<resource-agent name='%s' version='0.1'>\n"
1828 "<version>1.0</version>\n"
1829 "<longdesc lang='en'>\n"
1830 "%s"
1831 "</longdesc>\n"
1832 "<shortdesc lang='en'>%s</shortdesc>\n"
1833 "<parameters>\n"
1834 "<parameter name='1' unique='1' required='0'>\n"
1835 "<longdesc lang='en'>\n"
1836 "This argument will be passed as the first argument to the "
1837 "heartbeat resource agent (assuming it supports one)\n"
1838 "</longdesc>\n"
1839 "<shortdesc lang='en'>argv[1]</shortdesc>\n"
1840 "<content type='string' default=' ' />\n"
1841 "</parameter>\n"
1842 "<parameter name='2' unique='1' required='0'>\n"
1843 "<longdesc lang='en'>\n"
1844 "This argument will be passed as the second argument to the "
1845 "heartbeat resource agent (assuming it supports one)\n"
1846 "</longdesc>\n"
1847 "<shortdesc lang='en'>argv[2]</shortdesc>\n"
1848 "<content type='string' default=' ' />\n"
1849 "</parameter>\n"
1850 "<parameter name='3' unique='1' required='0'>\n"
1851 "<longdesc lang='en'>\n"
1852 "This argument will be passed as the third argument to the "
1853 "heartbeat resource agent (assuming it supports one)\n"
1854 "</longdesc>\n"
1855 "<shortdesc lang='en'>argv[3]</shortdesc>\n"
1856 "<content type='string' default=' ' />\n"
1857 "</parameter>\n"
1858 "<parameter name='4' unique='1' required='0'>\n"
1859 "<longdesc lang='en'>\n"
1860 "This argument will be passed as the fourth argument to the "
1861 "heartbeat resource agent (assuming it supports one)\n"
1862 "</longdesc>\n"
1863 "<shortdesc lang='en'>argv[4]</shortdesc>\n"
1864 "<content type='string' default=' ' />\n"
1865 "</parameter>\n"
1866 "<parameter name='5' unique='1' required='0'>\n"
1867 "<longdesc lang='en'>\n"
1868 "This argument will be passed as the fifth argument to the "
1869 "heartbeat resource agent (assuming it supports one)\n"
1870 "</longdesc>\n"
1871 "<shortdesc lang='en'>argv[5]</shortdesc>\n"
1872 "<content type='string' default=' ' />\n"
1873 "</parameter>\n"
1874 "</parameters>\n"
1875 "<actions>\n"
1876 "<action name='start' timeout='15' />\n"
1877 "<action name='stop' timeout='15' />\n"
1878 "<action name='status' timeout='15' />\n"
1879 "<action name='monitor' timeout='15' interval='15' start-delay='15' />\n"
1880 "<action name='meta-data' timeout='5' />\n"
1881 "</actions>\n"
1882 "<special tag='heartbeat'>\n"
1883 "</special>\n"
1884 "</resource-agent>\n";
1885 
1886 static int
1887 heartbeat_get_metadata(const char *type, char **output)
1888 {
1889  *output = crm_strdup_printf(hb_metadata_template, type, type, type);
1890  crm_trace("Created fake metadata: %d", strlen(*output));
1891  return pcmk_ok;
1892 }
1893 #endif
1894 
1895 static int
1896 generic_get_metadata(const char *standard, const char *provider, const char *type, char **output)
1897 {
1898  svc_action_t *action = resources_action_create(type,
1899  standard,
1900  provider,
1901  type,
1902  "meta-data",
1903  0,
1904  30000,
1905  NULL,
1906  0);
1907 
1908  if (!(services_action_sync(action))) {
1909  crm_err("Failed to retrieve meta-data for %s:%s:%s", standard, provider, type);
1910  services_action_free(action);
1911  return -EIO;
1912  }
1913 
1914  if (!action->stdout_data) {
1915  crm_err("Failed to retrieve meta-data for %s:%s:%s", standard, provider, type);
1916  services_action_free(action);
1917  return -EIO;
1918  }
1919 
1920  *output = strdup(action->stdout_data);
1921  services_action_free(action);
1922 
1923  return pcmk_ok;
1924 }
1925 
1926 static int
1927 lrmd_api_get_metadata(lrmd_t * lrmd,
1928  const char *class,
1929  const char *provider,
1930  const char *type, char **output, enum lrmd_call_options options)
1931 {
1932  if (!class || !type) {
1933  return -EINVAL;
1934  }
1935 
1936  if (safe_str_eq(class, "service")) {
1937  class = resources_find_service_class(type);
1938  }
1939 
1940  if (safe_str_eq(class, "stonith")) {
1941  return stonith_get_metadata(provider, type, output);
1942  } else if (safe_str_eq(class, "lsb")) {
1943  return lsb_get_metadata(type, output);
1944 #if SUPPORT_NAGIOS
1945  } else if (safe_str_eq(class, "nagios")) {
1946  return nagios_get_metadata(type, output);
1947 #endif
1948 #if SUPPORT_HEARTBEAT
1949  } else if (safe_str_eq(class, "heartbeat")) {
1950  return heartbeat_get_metadata(type, output);
1951 #endif
1952  }
1953  return generic_get_metadata(class, provider, type, output);
1954 }
1955 
1956 static int
1957 lrmd_api_exec(lrmd_t * lrmd, const char *rsc_id, const char *action, const char *userdata, int interval, /* ms */
1958  int timeout, /* ms */
1959  int start_delay, /* ms */
1960  enum lrmd_call_options options, lrmd_key_value_t * params)
1961 {
1962  int rc = pcmk_ok;
1963  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
1964  xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
1965  lrmd_key_value_t *tmp = NULL;
1966 
1967  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
1968  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1969  crm_xml_add(data, F_LRMD_RSC_ACTION, action);
1970  crm_xml_add(data, F_LRMD_RSC_USERDATA_STR, userdata);
1971  crm_xml_add_int(data, F_LRMD_RSC_INTERVAL, interval);
1972  crm_xml_add_int(data, F_LRMD_TIMEOUT, timeout);
1973  crm_xml_add_int(data, F_LRMD_RSC_START_DELAY, start_delay);
1974 
1975  for (tmp = params; tmp; tmp = tmp->next) {
1976  hash2smartfield((gpointer) tmp->key, (gpointer) tmp->value, args);
1977  }
1978 
1979  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_EXEC, data, NULL, timeout, options, TRUE);
1980  free_xml(data);
1981 
1982  lrmd_key_value_freeall(params);
1983  return rc;
1984 }
1985 
1986 static int
1987 lrmd_api_cancel(lrmd_t * lrmd, const char *rsc_id, const char *action, int interval)
1988 {
1989  int rc = pcmk_ok;
1990  xmlNode *data = create_xml_node(NULL, F_LRMD_RSC);
1991 
1992  crm_xml_add(data, F_LRMD_ORIGIN, __FUNCTION__);
1993  crm_xml_add(data, F_LRMD_RSC_ACTION, action);
1994  crm_xml_add(data, F_LRMD_RSC_ID, rsc_id);
1995  crm_xml_add_int(data, F_LRMD_RSC_INTERVAL, interval);
1996  rc = lrmd_send_command(lrmd, LRMD_OP_RSC_CANCEL, data, NULL, 0, 0, TRUE);
1997  free_xml(data);
1998  return rc;
1999 }
2000 
2001 static int
2002 list_stonith_agents(lrmd_list_t ** resources)
2003 {
2004  int rc = 0;
2005  stonith_t *stonith_api = stonith_api_new();
2006  stonith_key_value_t *stonith_resources = NULL;
2007  stonith_key_value_t *dIter = NULL;
2008 
2009  if(stonith_api) {
2010  stonith_api->cmds->list_agents(stonith_api, st_opt_sync_call, NULL, &stonith_resources, 0);
2011  stonith_api->cmds->free(stonith_api);
2012  }
2013 
2014  for (dIter = stonith_resources; dIter; dIter = dIter->next) {
2015  rc++;
2016  if (resources) {
2017  *resources = lrmd_list_add(*resources, dIter->value);
2018  }
2019  }
2020 
2021  stonith_key_value_freeall(stonith_resources, 1, 0);
2022  return rc;
2023 }
2024 
2025 static int
2026 lrmd_api_list_agents(lrmd_t * lrmd, lrmd_list_t ** resources, const char *class,
2027  const char *provider)
2028 {
2029  int rc = 0;
2030 
2031  if (safe_str_eq(class, "stonith")) {
2032  rc += list_stonith_agents(resources);
2033 
2034  } else {
2035  GListPtr gIter = NULL;
2036  GList *agents = resources_list_agents(class, provider);
2037 
2038  for (gIter = agents; gIter != NULL; gIter = gIter->next) {
2039  *resources = lrmd_list_add(*resources, (const char *)gIter->data);
2040  rc++;
2041  }
2042  g_list_free_full(agents, free);
2043 
2044  if (!class) {
2045  rc += list_stonith_agents(resources);
2046  }
2047  }
2048 
2049  if (rc == 0) {
2050  crm_notice("No agents found for class %s", class);
2051  rc = -EPROTONOSUPPORT;
2052  }
2053  return rc;
2054 }
2055 
2056 static int
2057 does_provider_have_agent(const char *agent, const char *provider, const char *class)
2058 {
2059  int found = 0;
2060  GList *agents = NULL;
2061  GListPtr gIter2 = NULL;
2062 
2063  agents = resources_list_agents(class, provider);
2064  for (gIter2 = agents; gIter2 != NULL; gIter2 = gIter2->next) {
2065  if (safe_str_eq(agent, gIter2->data)) {
2066  found = 1;
2067  }
2068  }
2069  g_list_free_full(agents, free);
2070 
2071  return found;
2072 }
2073 
2074 static int
2075 lrmd_api_list_ocf_providers(lrmd_t * lrmd, const char *agent, lrmd_list_t ** providers)
2076 {
2077  int rc = pcmk_ok;
2078  char *provider = NULL;
2079  GList *ocf_providers = NULL;
2080  GListPtr gIter = NULL;
2081 
2082  ocf_providers = resources_list_providers("ocf");
2083 
2084  for (gIter = ocf_providers; gIter != NULL; gIter = gIter->next) {
2085  provider = gIter->data;
2086  if (!agent || does_provider_have_agent(agent, provider, "ocf")) {
2087  *providers = lrmd_list_add(*providers, (const char *)gIter->data);
2088  rc++;
2089  }
2090  }
2091 
2092  g_list_free_full(ocf_providers, free);
2093  return rc;
2094 }
2095 
2096 static int
2097 lrmd_api_list_standards(lrmd_t * lrmd, lrmd_list_t ** supported)
2098 {
2099  int rc = 0;
2100  GList *standards = NULL;
2101  GListPtr gIter = NULL;
2102 
2103  standards = resources_list_standards();
2104 
2105  for (gIter = standards; gIter != NULL; gIter = gIter->next) {
2106  *supported = lrmd_list_add(*supported, (const char *)gIter->data);
2107  rc++;
2108  }
2109 
2110  if (list_stonith_agents(NULL) > 0) {
2111  *supported = lrmd_list_add(*supported, "stonith");
2112  rc++;
2113  }
2114 
2115  g_list_free_full(standards, free);
2116  return rc;
2117 }
2118 
2119 lrmd_t *
2121 {
2122  lrmd_t *new_lrmd = NULL;
2123  lrmd_private_t *pvt = NULL;
2124 
2125  new_lrmd = calloc(1, sizeof(lrmd_t));
2126  pvt = calloc(1, sizeof(lrmd_private_t));
2127  pvt->remote = calloc(1, sizeof(crm_remote_t));
2128  new_lrmd->cmds = calloc(1, sizeof(lrmd_api_operations_t));
2129 
2130  pvt->type = CRM_CLIENT_IPC;
2131  new_lrmd->private = pvt;
2132 
2133  new_lrmd->cmds->connect = lrmd_api_connect;
2134  new_lrmd->cmds->connect_async = lrmd_api_connect_async;
2135  new_lrmd->cmds->is_connected = lrmd_api_is_connected;
2136  new_lrmd->cmds->poke_connection = lrmd_api_poke_connection;
2137  new_lrmd->cmds->disconnect = lrmd_api_disconnect;
2138  new_lrmd->cmds->register_rsc = lrmd_api_register_rsc;
2139  new_lrmd->cmds->unregister_rsc = lrmd_api_unregister_rsc;
2140  new_lrmd->cmds->get_rsc_info = lrmd_api_get_rsc_info;
2141  new_lrmd->cmds->set_callback = lrmd_api_set_callback;
2142  new_lrmd->cmds->get_metadata = lrmd_api_get_metadata;
2143  new_lrmd->cmds->exec = lrmd_api_exec;
2144  new_lrmd->cmds->cancel = lrmd_api_cancel;
2145  new_lrmd->cmds->list_agents = lrmd_api_list_agents;
2146  new_lrmd->cmds->list_ocf_providers = lrmd_api_list_ocf_providers;
2147  new_lrmd->cmds->list_standards = lrmd_api_list_standards;
2148 
2149  return new_lrmd;
2150 }
2151 
2152 lrmd_t *
2153 lrmd_remote_api_new(const char *nodename, const char *server, int port)
2154 {
2155 #ifdef HAVE_GNUTLS_GNUTLS_H
2156  lrmd_t *new_lrmd = lrmd_api_new();
2157  lrmd_private_t *native = new_lrmd->private;
2158 
2159  if (!nodename && !server) {
2160  lrmd_api_delete(new_lrmd);
2161  return NULL;
2162  }
2163 
2164  native->type = CRM_CLIENT_TLS;
2165  native->remote_nodename = nodename ? strdup(nodename) : strdup(server);
2166  native->server = server ? strdup(server) : strdup(nodename);
2167  native->port = port;
2168  if (native->port == 0) {
2169  const char *remote_port_str = getenv("PCMK_remote_port");
2170  native->port = remote_port_str ? atoi(remote_port_str) : DEFAULT_REMOTE_PORT;
2171  }
2172 
2173  return new_lrmd;
2174 #else
2175  crm_err("GNUTLS is not enabled for this build, remote LRMD client can not be created");
2176  return NULL;
2177 #endif
2178 
2179 }
2180 
2181 void
2183 {
2184  if (!lrmd) {
2185  return;
2186  }
2187  lrmd->cmds->disconnect(lrmd); /* no-op if already disconnected */
2188  free(lrmd->cmds);
2189  if (lrmd->private) {
2190  lrmd_private_t *native = lrmd->private;
2191 
2192 #ifdef HAVE_GNUTLS_GNUTLS_H
2193  free(native->server);
2194 #endif
2195  free(native->remote_nodename);
2196  free(native->remote);
2197  }
2198 
2199  free(lrmd->private);
2200  free(lrmd);
2201 }
Services API.
#define F_LRMD_RSC
Definition: lrmd.h:81
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:164
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition: ipc.c:808
A dumping ground.
client_type
Definition: ipcs.h:33
#define F_TYPE
Definition: msg_xml.h:34
#define crm_notice(fmt, args...)
Definition: logging.h:250
GHashTable * xml2list(xmlNode *parent)
Definition: xml.c:5042
lrmd_event_data_t * lrmd_copy_event(lrmd_event_data_t *event)
Definition: lrmd_client.c:195
gboolean safe_str_neq(const char *a, const char *b)
Definition: utils.c:659
void services_action_free(svc_action_t *op)
Definition: services.c:432
lrmd_call_options
Definition: lrmd.h:151
int crm_remote_ready(crm_remote_t *remote, int total_timeout)
Definition: remote.c:447
gboolean crm_remote_recv(crm_remote_t *remote, int total_timeout, int *disconnected)
Definition: remote.c:599
const char * user_data
Definition: lrmd.h:186
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
Definition: mainloop.c:806
#define F_LRMD_IS_IPC_PROVIDER
Definition: lrmd.h:48
const char * rsc_id
Definition: lrmd.h:182
char * class
Definition: lrmd.h:238
#define F_LRMD_IPC_SESSION
Definition: lrmd.h:95
#define F_LRMD_RSC_EXEC_TIME
Definition: lrmd.h:69
int(* list_agents)(stonith_t *stonith, int call_options, const char *namespace, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed stonith agents.
Definition: stonith-ng.h:210
#define F_LRMD_RSC_ACTION
Definition: lrmd.h:73
#define LRMD_OP_RSC_CANCEL
Definition: lrmd.h:86
int crm_ipc_get_fd(crm_ipc_t *client)
Definition: ipc.c:914
#define F_LRMD_ORIGIN
Definition: lrmd.h:65
#define F_LRMD_RSC_OUTPUT
Definition: lrmd.h:75
int(* connect_async)(lrmd_t *lrmd, const char *client_name, int timeout)
Establish an connection to lrmd, don&#39;t block while connecting.
Definition: lrmd.h:274
#define SHLD_START
Definition: lrmd_client.c:1603
void(* lrmd_event_callback)(lrmd_event_data_t *event)
Definition: lrmd.h:245
#define pcmk_ok
Definition: error.h:42
svc_action_t * resources_action_create(const char *name, const char *standard, const char *provider, const char *agent, const char *action, int interval, int timeout, GHashTable *params, enum svc_action_flags flags)
Create a new resource action.
Definition: services.c:118
struct stonith_key_value_s * next
Definition: stonith-ng.h:76
void lrmd_key_value_freeall(lrmd_key_value_t *head)
Definition: lrmd_client.c:175
char * id
Definition: lrmd.h:236
#define XML_TAG_ATTRS
Definition: msg_xml.h:175
struct mainloop_io_s mainloop_io_t
Definition: mainloop.h:35
void mainloop_set_trigger(crm_trigger_t *source)
Definition: mainloop.c:223
#define DEFAULT_REMOTE_USERNAME
Definition: lrmd.h:44
Local Resource Manager.
#define MAX_TLS_RECV_WAIT
Definition: lrmd_client.c:55
#define F_LRMD_EXEC_RC
Definition: lrmd.h:59
const char * output
Definition: lrmd.h:204
void g_hash_destroy_str(gpointer data)
Definition: utils.c:578
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
Definition: lrmd_client.c:1540
#define SHLD_STOP
Definition: lrmd_client.c:1604
#define LRMD_OP_POKE
Definition: lrmd.h:90
lrmd_rsc_info_t * lrmd_copy_rsc_info(lrmd_rsc_info_t *rsc_info)
Definition: lrmd_client.c:1439
long crm_ipc_read(crm_ipc_t *client)
Definition: ipc.c:1012
#define REQ_STOP
Definition: lrmd_client.c:1602
gboolean mainloop_destroy_trigger(crm_trigger_t *source)
Definition: mainloop.c:231
#define REQ_START
Definition: lrmd_client.c:1601
int(* exec)(lrmd_t *lrmd, const char *rsc_id, const char *action, const char *userdata, int interval, int timeout, int start_delay, enum lrmd_call_options options, lrmd_key_value_t *params)
Issue a command on a resource.
Definition: lrmd.h:359
int(* cancel)(lrmd_t *lrmd, const char *rsc_id, const char *action, int interval)
Cancel a recurring command.
Definition: lrmd.h:388
#define F_LRMD_RSC_ID
Definition: lrmd.h:72
int crm_remote_tcp_connect(const char *host, int port)
Definition: remote.c:919
Wrappers for and extensions to glib mainloop.
#define F_LRMD_PROTOCOL_VERSION
Definition: lrmd.h:50
#define F_LRMD_RC
Definition: lrmd.h:58
lrmd_t * lrmd_remote_api_new(const char *nodename, const char *server, int port)
Create a new remote lrmd connection using tls backend.
Definition: lrmd_client.c:2153
stonith_t * stonith_api_new(void)
Definition: st_client.c:2462
#define CRM_OP_REGISTER
Definition: crm.h:122
xmlNode * string2xml(const char *input)
Definition: xml.c:2957
const char * crm_ipc_buffer(crm_ipc_t *client)
Definition: ipc.c:1058
const char * val
Definition: lrmd.h:248
#define LRMD_OP_RSC_UNREG
Definition: lrmd.h:87
#define F_LRMD_CLIENTID
Definition: lrmd.h:49
#define DEFAULT_REMOTE_PORT
Definition: lrmd.h:43
#define DEFAULT_REMOTE_KEY_LOCATION
Definition: lrmd.h:41
struct trigger_s crm_trigger_t
Definition: mainloop.h:34
void hash2smartfield(gpointer key, gpointer value, gpointer user_data)
Definition: xml.c:4985
struct lrmd_private_s lrmd_private_t
#define PROVIDES
Definition: lrmd_client.c:1600
int(* free)(stonith_t *st)
Destroy the stonith api structure.
Definition: stonith-ng.h:125
int(* dispatch)(gpointer userdata)
Definition: mainloop.h:90
#define DESCRIPTION
Definition: lrmd_client.c:1608
void * params
Definition: lrmd.h:219
#define crm_warn(fmt, args...)
Definition: logging.h:249
int(* poke_connection)(lrmd_t *lrmd)
Poke lrmd connection to verify it is still capable of serving requests.
Definition: lrmd.h:291
const char * exit_reason
Definition: lrmd.h:228
#define crm_debug(fmt, args...)
Definition: logging.h:253
int crm_initiate_client_tls_handshake(crm_remote_t *remote, int timeout_ms)
#define DFLT_START
Definition: lrmd_client.c:1605
#define lsb_metadata_template
Definition: lrmd_client.c:1567
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:61
#define F_LRMD_RSC_EXIT_REASON
Definition: lrmd.h:76
#define ALT_REMOTE_KEY_LOCATION
Definition: lrmd.h:42
bool lrmd_dispatch(lrmd_t *lrmd)
Use after lrmd_poll returns 1 to read and dispatch a message.
Definition: lrmd_client.c:441
char * key
Definition: lrmd.h:33
struct lrmd_list_s * next
Definition: lrmd.h:249
gboolean services_action_sync(svc_action_t *op)
Definition: services.c:778
char * stdout_data
Definition: services.h:174
#define LRMD_PROTOCOL_VERSION
Definition: lrmd.h:38
xmlNode * crm_remote_parse_buffer(crm_remote_t *remote)
Definition: remote.c:377
int(* get_metadata)(lrmd_t *lrmd, const char *class, const char *provider, const char *agent, char **output, enum lrmd_call_options options)
Get the metadata documentation for a resource.
Definition: lrmd.h:398
#define F_LRMD_TIMEOUT
Definition: lrmd.h:61
lrmd_rsc_info_t *(* get_rsc_info)(lrmd_t *lrmd, const char *rsc_id, enum lrmd_call_options options)
Retrieve registration info for a rsc.
Definition: lrmd.h:320
void lrmd_list_freeall(lrmd_list_t *head)
Definition: lrmd_client.c:137
int(* connect)(lrmd_t *lrmd, const char *client_name, int *fd)
Connect from the lrmd.
Definition: lrmd.h:262
#define F_LRMD_CALLDATA
Definition: lrmd.h:57
#define crm_trace(fmt, args...)
Definition: logging.h:254
#define F_LRMD_TYPE
Definition: lrmd.h:64
#define F_LRMD_CLASS
Definition: lrmd.h:62
crm_trigger_t * mainloop_add_trigger(int priority, int(*dispatch)(gpointer user_data), gpointer userdata)
Definition: mainloop.c:211
#define LRMD_OP_NEW_CLIENT
Definition: lrmd.h:91
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:2793
int crm_element_value_int(xmlNode *data, const char *name, int *dest)
Definition: xml.c:4006
const char * crm_element_value(xmlNode *data, const char *name)
Definition: xml.c:5839
void stonith_key_value_freeall(stonith_key_value_t *kvp, int keys, int values)
Definition: st_client.c:2541
#define ECOMM
Definition: portability.h:231
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:791
void crm_ipc_destroy(crm_ipc_t *client)
Definition: ipc.c:891
GList * resources_list_providers(const char *standard)
Get a list of providers.
Definition: services.c:875
lrmd_t * lrmd_api_new(void)
Create a new local lrmd connection.
Definition: lrmd_client.c:2120
#define LSB_INITSCRIPT_INFOEND_TAG
Definition: lrmd_client.c:1599
struct lrmd_key_value_s * next
Definition: lrmd.h:35
#define F_LRMD_RSC_USERDATA_STR
Definition: lrmd.h:74
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: xml.c:3332
void free_xml(xmlNode *child)
Definition: xml.c:2848
#define F_LRMD_RSC_INTERVAL
Definition: lrmd.h:78
void lrmd_free_rsc_info(lrmd_rsc_info_t *rsc_info)
Definition: lrmd_client.c:1456
int crm_remote_tcp_connect_async(const char *host, int port, int timeout, int *timer_id, void *userdata, void(*callback)(void *userdata, int sock))
Definition: remote.c:830
#define LSB_ROOT_DIR
Definition: services.h:42
CRM_TRACE_INIT_DATA(lrmd)
#define LRMD_OP_RSC_EXEC
Definition: lrmd.h:85
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: utils.c:1428
#define F_LRMD_OP_STATUS
Definition: lrmd.h:60
int(* unregister_rsc)(lrmd_t *lrmd, const char *rsc_id, enum lrmd_call_options options)
Unregister a resource from the lrmd.
Definition: lrmd.h:337
#define F_LRMD_RSC_START_DELAY
Definition: lrmd.h:77
int(* disconnect)(lrmd_t *lrmd)
Disconnect from the lrmd.
Definition: lrmd.h:299
const char * op_type
Definition: lrmd.h:184
#define LRMD_OP_RSC_REG
Definition: lrmd.h:84
#define SHORT_DSCR
Definition: lrmd_client.c:1607
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc.c:928
void * private
Definition: lrmd.h:441
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:416
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
int crm_ipc_ready(crm_ipc_t *client)
Definition: ipc.c:953
#define F_LRMD_RSC_RCCHANGE_TIME
Definition: lrmd.h:68
int(* list_agents)(lrmd_t *lrmd, lrmd_list_t **agents, const char *class, const char *provider)
Retrieve a list of installed resource agents.
Definition: lrmd.h:412
#define lsb_meta_helper_free_value(m)
Definition: lrmd_client.c:1610
char * type
Definition: lrmd.h:237
#define crm_log_xml_err(xml, text)
Definition: logging.h:257
#define F_LRMD_PROVIDER
Definition: lrmd.h:63
void lrmd_api_delete(lrmd_t *lrmd)
Destroy lrmd object.
Definition: lrmd_client.c:2182
#define F_LRMD_REMOTE_MSG_ID
Definition: lrmd.h:52
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:226
const char * remote_nodename
Definition: lrmd.h:225
lrmd_api_operations_t * cmds
Definition: lrmd.h:440
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:797
GList * resources_list_standards(void)
Definition: services.c:830
#define crm_err(fmt, args...)
Definition: logging.h:248
#define T_LRMD
Definition: lrmd.h:103
enum lrmd_callback_event type
Definition: lrmd.h:179
lrmd_key_value_t * lrmd_key_value_add(lrmd_key_value_t *head, const char *key, const char *value)
Definition: lrmd_client.c:152
stonith_api_operations_t * cmds
Definition: stonith-ng.h:369
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
Fencing aka. STONITH.
#define F_LRMD_CALLID
Definition: lrmd.h:54
int(* list_standards)(lrmd_t *lrmd, lrmd_list_t **standards)
Retrieve a list of standards supported by this machine/installation.
Definition: lrmd.h:435
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Definition: ipc.c:778
#define F_LRMD_CALLOPTS
Definition: lrmd.h:56
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
Definition: services.c:885
#define CRM_SYSTEM_LRMD
Definition: crm.h:85
#define uint32_t
Definition: stdint.in.h:158
#define CRM_ASSERT(expr)
Definition: error.h:35
char data[0]
Definition: internal.h:58
void * create_psk_tls_session(int csock, int type, void *credentials)
#define F_LRMD_RSC_RUN_TIME
Definition: lrmd.h:67
char * provider
Definition: lrmd.h:239
Definition: lrmd.h:439
int(* register_rsc)(lrmd_t *lrmd, const char *rsc_id, const char *class, const char *provider, const char *agent, enum lrmd_call_options options)
Register a resource with the lrmd.
Definition: lrmd.h:309
int(* list_ocf_providers)(lrmd_t *lrmd, const char *agent, lrmd_list_t **providers)
Retrieve a list of resource agent providers.
Definition: lrmd.h:425
void lrmd_internal_set_proxy_callback(lrmd_t *lrmd, void *userdata, void(*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
Definition: lrmd_client.c:1520
#define crm_log_xml_trace(xml, text)
Definition: logging.h:262
#define F_LRMD_CLIENTNAME
Definition: lrmd.h:47
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:763
#define F_LRMD_RSC_QUEUE_TIME
Definition: lrmd.h:70
#define F_LRMD_RSC_DELETED
Definition: lrmd.h:80
#define F_LRMD_OPERATION
Definition: lrmd.h:46
#define CRM_OP_IPC_FWD
Definition: crm.h:123
#define safe_str_eq(a, b)
Definition: util.h:74
#define F_LRMD_CALLBACK_TOKEN
Definition: lrmd.h:53
int(* metadata)(stonith_t *st, int options, const char *device, const char *namespace, char **output, int timeout)
Get the metadata documentation for a resource.
Definition: stonith-ng.h:197
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
#define crm_str_hash
Definition: crm.h:196
#define F_XML_TAGNAME
Definition: msg_xml.h:42
void lrmd_free_event(lrmd_event_data_t *event)
Definition: lrmd_client.c:226
#define F_LRMD_REMOTE_MSG_TYPE
Definition: lrmd.h:51
void crm_ipc_close(crm_ipc_t *client)
Definition: ipc.c:876
GList * GListPtr
Definition: crm.h:190
char * value
Definition: lrmd.h:34
#define DFLT_STOP
Definition: lrmd_client.c:1606
int crm_remote_send(crm_remote_t *remote, xmlNode *msg)
Definition: remote.c:329
#define crm_info(fmt, args...)
Definition: logging.h:251
#define NAGIOS_METADATA_DIR
Definition: config.h:499
int(* is_connected)(lrmd_t *lrmd)
Is connected to lrmd daemon?
Definition: lrmd.h:282
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Definition: mainloop.h:73
void(* set_callback)(lrmd_t *lrmd, lrmd_event_callback callback)
Sets the callback to receive lrmd events on.
Definition: lrmd.h:342
#define LRMD_OP_RSC_INFO
Definition: lrmd.h:88
enum crm_ais_msg_types type
Definition: internal.h:51