21 #include <sys/types.h>    40 #ifdef HAVE_GNUTLS_GNUTLS_H    41 #  include <gnutls/gnutls.h>    44 #include <sys/socket.h>    45 #include <netinet/in.h>    46 #include <netinet/ip.h>    47 #include <arpa/inet.h>    50 #define MAX_TLS_RECV_WAIT 10000    54 static int lrmd_api_disconnect(
lrmd_t * lrmd);
    55 static int lrmd_api_is_connected(
lrmd_t * lrmd);
    59 static void lrmd_internal_proxy_dispatch(
lrmd_t *lrmd, xmlNode *msg);
    62 #ifdef HAVE_GNUTLS_GNUTLS_H    63 #  define LRMD_CLIENT_HANDSHAKE_TIMEOUT 5000        64 gnutls_psk_client_credentials_t psk_cred_s;
    65 static void lrmd_tls_disconnect(
lrmd_t * lrmd);
    66 static int global_remote_msg_id = 0;
    67 static void lrmd_tls_connection_destroy(gpointer userdata);
    70 typedef struct lrmd_private_s {
    81     char *remote_nodename;
    82 #ifdef HAVE_GNUTLS_GNUTLS_H    85     gnutls_psk_client_credentials_t psk_cred_c;
    95     int expected_late_replies;
    96     GList *pending_notify;
   103     void (*proxy_callback)(
lrmd_t *lrmd, 
void *userdata, xmlNode *msg);
   104     void *proxy_callback_userdata;
   109 lrmd_list_add(
lrmd_list_t * head, 
const char *value)
   114     p->
val = strdup(value);
   117     while (end && end->
next) {
   136         char *val = (
char *)head->
val;
   151     p->
key = strdup(key);
   152     p->
value = strdup(value);
   155     while (end && end->
next) {
   202     event->interval_ms = interval_ms;
   213     copy->
type = 
event->type;
   217     copy->
call_id = 
event->call_id;
   218     copy->
timeout = 
event->timeout;
   222     copy->
rc = 
event->rc;
   225     copy->
t_run = 
event->t_run;
   249     free((
void *) event->
rsc_id);
   254     if (event->
params != NULL) {
   255         g_hash_table_destroy(event->
params);
   261 lrmd_dispatch_internal(
lrmd_t * lrmd, xmlNode * msg)
   268     if (proxy_session != NULL) {
   270         lrmd_internal_proxy_dispatch(lrmd, msg);
   272     } 
else if (!native->callback) {
   274         crm_trace(
"notify event received but client has not set callback");
   278     event.remote_nodename = native->remote_nodename;
   298         event.t_run = (
unsigned int) epoch;
   301         event.t_rcchange = (
unsigned int) epoch;
   325     native->callback(&event);
   328         g_hash_table_destroy(event.params);
   335 lrmd_ipc_dispatch(
const char *buffer, ssize_t length, gpointer userdata)
   340     if (native->callback != NULL) {
   343         lrmd_dispatch_internal(lrmd, msg);
   349 #ifdef HAVE_GNUTLS_GNUTLS_H   351 lrmd_free_xml(gpointer userdata)
   357 remote_executor_connected(
lrmd_t * lrmd)
   361     return (native->remote->tls_session != NULL);
   376 lrmd_tls_dispatch(gpointer userdata)
   383     if (!remote_executor_connected(lrmd)) {
   384         crm_trace(
"TLS dispatch triggered after disconnect");
   392     if (native->pending_notify) {
   395         crm_trace(
"Processing pending notifies");
   396         for (iter = native->pending_notify; iter; iter = iter->next) {
   397             lrmd_dispatch_internal(lrmd, iter->data);
   399         g_list_free_full(native->pending_notify, lrmd_free_xml);
   400         native->pending_notify = NULL;
   420             lrmd_dispatch_internal(lrmd, xml);
   422             if (native->expected_late_replies > 0) {
   423                 native->expected_late_replies--;
   428                 crm_err(
"Got outdated Pacemaker Remote reply %d", reply_id);
   435     if (rc == ENOTCONN) {
   436         crm_info(
"Lost %s executor connection while reading data",
   437                  (native->remote_nodename? native->remote_nodename : 
"local"));
   438         lrmd_tls_disconnect(lrmd);
   451     switch (native->type) {
   455 #ifdef HAVE_GNUTLS_GNUTLS_H   456         case pcmk__client_tls:
   457             if (native->pending_notify) {
   473             crm_err(
"Unsupported executor connection type (bug?): %d",
   475             return -EPROTONOSUPPORT;
   488     switch (private->type) {
   494                     lrmd_ipc_dispatch(msg, strlen(msg), lrmd);
   498 #ifdef HAVE_GNUTLS_GNUTLS_H   499         case pcmk__client_tls:
   500             lrmd_tls_dispatch(lrmd);
   504             crm_err(
"Unsupported executor connection type (bug?): %d",
   508     if (lrmd_api_is_connected(lrmd) == FALSE) {
   517 lrmd_create_op(
const char *token, 
const char *op, xmlNode *
data, 
int timeout,
   536     crm_trace(
"Created executor %s command with call options %.8lx (%d)",
   537               op, (
long)options, options);
   542 lrmd_ipc_connection_destroy(gpointer userdata)
   547     crm_info(
"IPC connection destroyed");
   551     native->source = NULL;
   553     if (native->callback) {
   556         event.remote_nodename = native->remote_nodename;
   557         native->callback(&event);
   561 #ifdef HAVE_GNUTLS_GNUTLS_H   563 lrmd_tls_connection_destroy(gpointer userdata)
   568     crm_info(
"TLS connection destroyed");
   570     if (native->remote->tls_session) {
   571         gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
   572         gnutls_deinit(*native->remote->tls_session);
   573         gnutls_free(native->remote->tls_session);
   575     if (native->psk_cred_c) {
   576         gnutls_psk_free_client_credentials(native->psk_cred_c);
   581     if (native->process_notify) {
   583         native->process_notify = NULL;
   585     if (native->pending_notify) {
   586         g_list_free_full(native->pending_notify, lrmd_free_xml);
   587         native->pending_notify = NULL;
   590     free(native->remote->buffer);
   591     native->remote->buffer = NULL;
   594     native->psk_cred_c = NULL;
   595     native->remote->tls_session = NULL;
   598     if (native->callback) {
   602         native->callback(&event);
   610                       const char *msg_type)
   619 read_remote_reply(
lrmd_t *lrmd, 
int total_timeout, 
int expected_reply_id,
   623     time_t start = time(NULL);
   624     const char *msg_type = NULL;
   626     int remaining_timeout = 0;
   635     for (*reply = NULL; *reply == NULL; ) {
   638         if (*reply == NULL) {
   640             if (remaining_timeout) {
   641                 remaining_timeout = total_timeout - ((time(NULL) - start) * 1000);
   643                 remaining_timeout = total_timeout;
   645             if (remaining_timeout <= 0) {
   655             if (*reply == NULL) {
   664             crm_err(
"Empty msg type received while waiting for reply");
   670             native->pending_notify = g_list_append(native->pending_notify, *reply);
   671             if (native->process_notify) {
   678             crm_err(
"Expected a reply, got %s", msg_type);
   681         } 
else if (reply_id != expected_reply_id) {
   682             if (native->expected_late_replies > 0) {
   683                 native->expected_late_replies--;
   685                 crm_err(
"Got outdated reply, expected id %d got id %d", expected_reply_id, reply_id);
   692     if (native->remote->buffer && native->process_notify) {
   701 send_remote_message(
lrmd_t *lrmd, xmlNode *msg)
   706     global_remote_msg_id++;
   707     if (global_remote_msg_id <= 0) {
   708         global_remote_msg_id = 1;
   714         crm_err(
"Disconnecting because TLS message could not be sent to "   716         lrmd_tls_disconnect(lrmd);
   722 lrmd_tls_send_recv(
lrmd_t * lrmd, xmlNode * msg, 
int timeout, xmlNode ** reply)
   727     if (!remote_executor_connected(lrmd)) {
   731     rc = send_remote_message(lrmd, msg);
   736     rc = read_remote_reply(lrmd, 
timeout, global_remote_msg_id, &xml);
   738         crm_err(
"Disconnecting remote after request %d reply not received: %s "   739                 CRM_XS " rc=%d timeout=%dms",
   741         lrmd_tls_disconnect(lrmd);
   755 lrmd_send_xml(
lrmd_t * lrmd, xmlNode * msg, 
int timeout, xmlNode ** reply)
   760     switch (native->type) {
   764 #ifdef HAVE_GNUTLS_GNUTLS_H   765         case pcmk__client_tls:
   766             rc = lrmd_tls_send_recv(lrmd, msg, 
timeout, reply);
   770             crm_err(
"Unsupported executor connection type (bug?): %d",
   772             rc = -EPROTONOSUPPORT;
   779 lrmd_send_xml_no_reply(
lrmd_t * lrmd, xmlNode * msg)
   784     switch (native->type) {
   788 #ifdef HAVE_GNUTLS_GNUTLS_H   789         case pcmk__client_tls:
   790             rc = send_remote_message(lrmd, msg);
   795                 native->expected_late_replies++;
   801             crm_err(
"Unsupported executor connection type (bug?): %d",
   803             rc = -EPROTONOSUPPORT;
   810 lrmd_api_is_connected(
lrmd_t * lrmd)
   814     switch (native->type) {
   817 #ifdef HAVE_GNUTLS_GNUTLS_H   818         case pcmk__client_tls:
   819             return remote_executor_connected(lrmd);
   822             crm_err(
"Unsupported executor connection type (bug?): %d",
   847 lrmd_send_command(
lrmd_t *lrmd, 
const char *op, xmlNode *
data,
   848                   xmlNode **output_data, 
int timeout,
   853     xmlNode *op_msg = NULL;
   854     xmlNode *op_reply = NULL;
   856     if (!lrmd_api_is_connected(lrmd)) {
   861         crm_err(
"No operation specified");
   867     crm_trace(
"Sending %s op to executor", op);
   869     op_msg = lrmd_create_op(native->token, op, 
data, 
timeout, options);
   871     if (op_msg == NULL) {
   876         rc = lrmd_send_xml(lrmd, op_msg, 
timeout, &op_reply);
   878         rc = lrmd_send_xml_no_reply(lrmd, op_msg);
   883         crm_perror(LOG_ERR, 
"Couldn't perform %s operation (timeout=%d): %d", op, 
timeout, rc);
   886     } 
else if(op_reply == NULL) {
   901         *output_data = op_reply;
   906     if (lrmd_api_is_connected(lrmd) == FALSE) {
   907         crm_err(
"Executor disconnected");
   916 lrmd_api_poke_connection(
lrmd_t * lrmd)
   941     value = g_hash_table_lookup(hash, 
"stonith-watchdog-timeout");
   954 lrmd_handshake(
lrmd_t * lrmd, 
const char *
name)
   958     xmlNode *reply = NULL;
   967     if (native->proxy_callback) {
   971     rc = lrmd_send_xml(lrmd, hello, -1, &reply);
   974         crm_perror(LOG_DEBUG, 
"Couldn't complete registration with the executor API: %d", rc);
   976     } 
else if (reply == NULL) {
   977         crm_err(
"Did not receive registration reply");
   987             crm_err(
"Executor protocol version mismatch between client (%s) and server (%s)",
   992             crm_err(
"Invalid registration message: %s", msg_type);
   995         } 
else if (tmp_ticket == NULL) {
   996             crm_err(
"No registration token provided");
  1000             crm_trace(
"Obtained registration token: %s", tmp_ticket);
  1001             native->token = strdup(tmp_ticket);
  1011         lrmd_api_disconnect(lrmd);
  1017 lrmd_ipc_connect(
lrmd_t * lrmd, 
int *fd)
  1024         .destroy = lrmd_ipc_connection_destroy
  1027     crm_info(
"Connecting to executor");
  1034         } 
else if (native->ipc) {
  1035             crm_perror(LOG_ERR, 
"Connection to executor failed");
  1043     if (native->ipc == NULL) {
  1044         crm_debug(
"Could not connect to the executor API");
  1051 #ifdef HAVE_GNUTLS_GNUTLS_H  1053 copy_gnutls_datum(gnutls_datum_t *dest, gnutls_datum_t *source)
  1055     CRM_ASSERT((dest != NULL) && (source != NULL) && (source->data != NULL));
  1057     dest->data = gnutls_malloc(source->size);
  1060     memcpy(dest->data, source->data, source->size);
  1061     dest->size = source->size;
  1065 clear_gnutls_datum(gnutls_datum_t *datum)
  1067     gnutls_free(datum->data);
  1072 #define KEY_READ_LEN 256    // Chunk size for reading key from file  1076 read_gnutls_key(
const char *location, gnutls_datum_t *key)
  1078     FILE *stream = NULL;
  1079     size_t buf_len = KEY_READ_LEN;
  1081     if ((location == NULL) || (key == NULL)) {
  1085     stream = fopen(location, 
"r");
  1086     if (stream == NULL) {
  1090     key->data = gnutls_malloc(buf_len);
  1092     while (!feof(stream)) {
  1093         int next = fgetc(stream);
  1096             if (!feof(stream)) {
  1097                 crm_warn(
"Pacemaker Remote key read was partially successful "  1098                          "(copy in memory may be corrupted)");
  1102         if (key->size == buf_len) {
  1103             buf_len = key->size + KEY_READ_LEN;
  1104             key->data = gnutls_realloc(key->data, buf_len);
  1107         key->data[key->size++] = (
unsigned char) next;
  1111     if (key->size == 0) {
  1112         clear_gnutls_datum(key);
  1120 struct key_cache_s {
  1122     const char *location;   
  1127 key_is_cached(
struct key_cache_s *key_cache)
  1129     return key_cache->updated != 0;
  1133 key_cache_expired(
struct key_cache_s *key_cache)
  1135     return (time(NULL) - key_cache->updated) >= 60;
  1139 clear_key_cache(
struct key_cache_s *key_cache)
  1141     clear_gnutls_datum(&(key_cache->key));
  1142     if ((key_cache->updated != 0) || (key_cache->location != NULL)) {
  1143         key_cache->updated = 0;
  1144         key_cache->location = NULL;
  1145         crm_debug(
"Cleared Pacemaker Remote key cache");
  1150 get_cached_key(
struct key_cache_s *key_cache, gnutls_datum_t *key)
  1152     copy_gnutls_datum(key, &(key_cache->key));
  1153     crm_debug(
"Using cached Pacemaker Remote key from %s",
  1154               pcmk__s(key_cache->location, 
"unknown location"));
  1158 cache_key(
struct key_cache_s *key_cache, gnutls_datum_t *key,
  1159           const char *location)
  1161     key_cache->updated = time(NULL);
  1162     key_cache->location = location;
  1163     copy_gnutls_datum(&(key_cache->key), key);
  1164     crm_debug(
"Using (and cacheing) Pacemaker Remote key from %s",
  1165               pcmk__s(location, 
"unknown location"));
  1179 get_remote_key(
const char *location, gnutls_datum_t *key)
  1181     static struct key_cache_s key_cache = { 0, };
  1184     if ((location == NULL) || (key == NULL)) {
  1188     if (key_is_cached(&key_cache)) {
  1189         if (key_cache_expired(&key_cache)) {
  1190             clear_key_cache(&key_cache);
  1192             get_cached_key(&key_cache, key);
  1197     rc = read_gnutls_key(location, key);
  1201     cache_key(&key_cache, key, location);
  1219 lrmd__init_remote_key(gnutls_datum_t *key)
  1221     static const char *env_location = NULL;
  1222     static bool need_env = 
true;
  1228     bool env_is_default = 
false;
  1229     bool env_is_fallback = 
false;
  1232         env_location = getenv(
"PCMK_authkey_location");
  1237     if (env_location != NULL) {
  1238         env_rc = get_remote_key(env_location, key);
  1255     if (env_is_default) {
  1256         default_rc = env_rc;
  1262     if (env_is_fallback) {
  1273         crm_warn(
"Could not read Pacemaker Remote key from %s (%s%s%s%s%s): %s",
  1275                  env_is_default? 
"" : 
"or default location ",
  1277                  !env_is_default && !env_is_fallback? 
" " : 
"",
  1278                  env_is_fallback? 
"" : 
"or fallback location ",
  1285         crm_warn(
"Could not read Pacemaker Remote key from %s "  1286                  "(using %s location %s instead): %s",
  1288                  (default_rc == 
pcmk_rc_ok)? 
"default" : 
"fallback",
  1296         crm_warn(
"Could not read Pacemaker Remote key from default location %s"  1297                  " (or fallback location %s): %s",
  1307 lrmd_gnutls_global_init(
void)
  1309     static int gnutls_init = 0;
  1312         crm_gnutls_global_init();
  1319 report_async_connection_result(
lrmd_t * lrmd, 
int rc)
  1323     if (native->callback) {
  1326         event.remote_nodename = native->remote_nodename;
  1327         event.connection_rc = rc;
  1328         native->callback(&event);
  1332 #ifdef HAVE_GNUTLS_GNUTLS_H  1336     return pcmk__tls_client_handshake(remote, LRMD_CLIENT_HANDSHAKE_TIMEOUT);
  1349 add_tls_to_mainloop(
lrmd_t *lrmd, 
bool do_handshake)
  1355                                    native->server, native->port);
  1359         .destroy = lrmd_tls_connection_destroy,
  1363                                                   lrmd_tls_dispatch, lrmd);
  1374         rc = lrmd_handshake(lrmd, 
name);
  1382 lrmd_tcp_connect_cb(
void *userdata, 
int rc, 
int sock)
  1386     gnutls_datum_t psk_key = { NULL, 0 };
  1388     native->async_timer = 0;
  1391         lrmd_tls_connection_destroy(lrmd);
  1392         crm_info(
"Could not connect to Pacemaker Remote at %s:%d: %s "  1394                  native->server, native->port, 
pcmk_rc_str(rc), rc);
  1403     native->sock = sock;
  1405     rc = lrmd__init_remote_key(&psk_key);
  1407         crm_info(
"Could not connect to Pacemaker Remote at %s:%d: %s "  1409                  native->server, native->port, 
pcmk_rc_str(rc), rc);
  1410         lrmd_tls_connection_destroy(lrmd);
  1415     gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
  1417     gnutls_free(psk_key.data);
  1419     native->remote->tls_session = pcmk__new_tls_session(sock, GNUTLS_CLIENT,
  1421                                                         native->psk_cred_c);
  1422     if (native->remote->tls_session == NULL) {
  1423         lrmd_tls_connection_destroy(lrmd);
  1424         report_async_connection_result(lrmd, -EPROTO);
  1428     if (lrmd__tls_client_handshake(native->remote) != 
pcmk_rc_ok) {
  1429         crm_warn(
"Disconnecting after TLS handshake with Pacemaker Remote server %s:%d failed",
  1430                  native->server, native->port);
  1431         gnutls_deinit(*native->remote->tls_session);
  1432         gnutls_free(native->remote->tls_session);
  1433         native->remote->tls_session = NULL;
  1434         lrmd_tls_connection_destroy(lrmd);
  1439     crm_info(
"TLS connection to Pacemaker Remote server %s:%d succeeded",
  1440              native->server, native->port);
  1441     rc = add_tls_to_mainloop(lrmd, 
true);
  1452     lrmd_gnutls_global_init();
  1455                               &(native->sock), lrmd, lrmd_tcp_connect_cb);
  1457         crm_warn(
"Pacemaker Remote connection to %s:%d failed: %s "  1459                  native->server, native->port, 
pcmk_rc_str(rc), rc);
  1462     native->async_timer = timer_id;
  1467 lrmd_tls_connect(
lrmd_t * lrmd, 
int *fd)
  1472     gnutls_datum_t psk_key = { NULL, 0 };
  1474     lrmd_gnutls_global_init();
  1478                               &(native->sock), NULL, NULL);
  1480         crm_warn(
"Pacemaker Remote connection to %s:%d failed: %s "  1482                  native->server, native->port, 
pcmk_rc_str(rc), rc);
  1483         lrmd_tls_connection_destroy(lrmd);
  1487     rc = lrmd__init_remote_key(&psk_key);
  1489         lrmd_tls_connection_destroy(lrmd);
  1493     gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
  1495     gnutls_free(psk_key.data);
  1497     native->remote->tls_session = pcmk__new_tls_session(native->sock, GNUTLS_CLIENT,
  1499                                                         native->psk_cred_c);
  1500     if (native->remote->tls_session == NULL) {
  1501         lrmd_tls_connection_destroy(lrmd);
  1505     if (lrmd__tls_client_handshake(native->remote) != 
pcmk_rc_ok) {
  1506         crm_err(
"Session creation for %s:%d failed", native->server, native->port);
  1507         gnutls_deinit(*native->remote->tls_session);
  1508         gnutls_free(native->remote->tls_session);
  1509         native->remote->tls_session = NULL;
  1510         lrmd_tls_connection_destroy(lrmd);
  1514     crm_info(
"Client TLS connection established with Pacemaker Remote server %s:%d", native->server,
  1520         add_tls_to_mainloop(lrmd, 
false);
  1527 lrmd_api_connect(
lrmd_t * lrmd, 
const char *
name, 
int *fd)
  1532     switch (native->type) {
  1534             rc = lrmd_ipc_connect(lrmd, fd);
  1536 #ifdef HAVE_GNUTLS_GNUTLS_H  1537         case pcmk__client_tls:
  1538             rc = lrmd_tls_connect(lrmd, fd);
  1542             crm_err(
"Unsupported executor connection type (bug?): %d",
  1544             rc = -EPROTONOSUPPORT;
  1548         rc = lrmd_handshake(lrmd, 
name);
  1560     CRM_CHECK(native && native->callback, 
return -EINVAL);
  1562     switch (native->type) {
  1566             rc = lrmd_api_connect(lrmd, 
name, NULL);
  1568                 report_async_connection_result(lrmd, rc);
  1571 #ifdef HAVE_GNUTLS_GNUTLS_H  1572         case pcmk__client_tls:
  1573             rc = lrmd_tls_connect_async(lrmd, 
timeout);
  1576                 report_async_connection_result(lrmd, rc);
  1581             crm_err(
"Unsupported executor connection type (bug?): %d",
  1583             rc = -EPROTONOSUPPORT;
  1590 lrmd_ipc_disconnect(
lrmd_t * lrmd)
  1594     if (native->source != NULL) {
  1597         native->source = NULL;
  1600     } 
else if (native->ipc) {
  1610 #ifdef HAVE_GNUTLS_GNUTLS_H  1612 lrmd_tls_disconnect(
lrmd_t * lrmd)
  1616     if (native->remote->tls_session) {
  1617         gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
  1618         gnutls_deinit(*native->remote->tls_session);
  1619         gnutls_free(native->remote->tls_session);
  1620         native->remote->tls_session = 0;
  1623     if (native->async_timer) {
  1624         g_source_remove(native->async_timer);
  1625         native->async_timer = 0;
  1628     if (native->source != NULL) {
  1631         native->source = NULL;
  1633     } 
else if (native->sock) {
  1634         close(native->sock);
  1638     if (native->pending_notify) {
  1639         g_list_free_full(native->pending_notify, lrmd_free_xml);
  1640         native->pending_notify = NULL;
  1646 lrmd_api_disconnect(
lrmd_t * lrmd)
  1651     crm_info(
"Disconnecting %s %s executor connection",
  1653              (native->remote_nodename? native->remote_nodename : 
"local"));
  1654     switch (native->type) {
  1656             lrmd_ipc_disconnect(lrmd);
  1658 #ifdef HAVE_GNUTLS_GNUTLS_H  1659         case pcmk__client_tls:
  1660             lrmd_tls_disconnect(lrmd);
  1664             crm_err(
"Unsupported executor connection type (bug?): %d",
  1666             rc = -EPROTONOSUPPORT;
  1669     free(native->token);
  1670     native->token = NULL;
  1672     free(native->peer_version);
  1673     native->peer_version = NULL;
  1678 lrmd_api_register_rsc(
lrmd_t * lrmd,
  1684     xmlNode *
data = NULL;
  1686     if (!
class || !
type || !rsc_id) {
  1690         && (provider == NULL)) {
  1723                   const char *provider, 
const char *
type)
  1749     free(rsc_info->
type);
  1760     xmlNode *output = NULL;
  1761     const char *
class = NULL;
  1762     const char *provider = NULL;
  1763     const char *
type = NULL;
  1778     if (!
class || !
type) {
  1805 lrmd_api_get_recurring_ops(
lrmd_t *lrmd, 
const char *rsc_id, 
int timeout_ms,
  1808     xmlNode *
data = NULL;
  1809     xmlNode *output_xml = NULL;
  1812     if (output == NULL) {
  1824                            timeout_ms, options, TRUE);
  1830     if ((rc != 
pcmk_ok) || (output_xml == NULL)) {
  1834          (rsc_xml != NULL) && (rc == 
pcmk_ok);
  1838         if (rsc_id == NULL) {
  1839             crm_err(
"Could not parse recurring operation information from executor");
  1847             if (op_info == NULL) {
  1851             op_info->
rsc_id = strdup(rsc_id);
  1857             *output = g_list_prepend(*output, op_info);
  1870     native->callback = callback;
  1878     native->proxy_callback = callback;
  1879     native->proxy_callback_userdata = userdata;
  1883 lrmd_internal_proxy_dispatch(
lrmd_t *lrmd, xmlNode *msg)
  1887     if (native->proxy_callback) {
  1889         native->proxy_callback(lrmd, native->proxy_callback_userdata, msg);
  1902     return lrmd_send_xml_no_reply(lrmd, msg);
  1906 stonith_get_metadata(
const char *provider, 
const char *
type, 
char **output)
  1911     if (stonith_api == NULL) {
  1912         crm_err(
"Could not get fence agent meta-data: API memory allocation failed");
  1917                                      provider, output, 0);
  1918     if ((rc == 
pcmk_ok) && (*output == NULL)) {
  1921     stonith_api->
cmds->
free(stonith_api);
  1926 lrmd_api_get_metadata(
lrmd_t *lrmd, 
const char *standard, 
const char *provider,
  1927                       const char *
type, 
char **output,
  1931                                            output, options, NULL);
  1935 lrmd_api_get_metadata_params(
lrmd_t *lrmd, 
const char *standard,
  1936                              const char *provider, 
const char *
type,
  1941     GHashTable *params_table = NULL;
  1943     if (!standard || !
type) {
  1950         return stonith_get_metadata(provider, 
type, output);
  1955         g_hash_table_insert(params_table, strdup(param->key), strdup(param->value));
  1972         crm_err(
"Failed to retrieve meta-data for %s:%s:%s",
  1973                 standard, provider, 
type);
  1978     if (!
action->stdout_data) {
  1979         crm_err(
"Failed to receive meta-data for %s:%s:%s",
  1980                 standard, provider, 
type);
  1985     *output = strdup(
action->stdout_data);
  1992 lrmd_api_exec(
lrmd_t *lrmd, 
const char *rsc_id, 
const char *
action,
  1993               const char *userdata, guint interval_ms,
  2011     for (tmp = params; tmp; tmp = tmp->
next) {
  2024 lrmd_api_exec_alert(
lrmd_t *lrmd, 
const char *alert_id, 
const char *alert_path,
  2037     for (tmp = params; tmp; tmp = tmp->
next) {
  2050 lrmd_api_cancel(
lrmd_t *lrmd, 
const char *rsc_id, 
const char *
action,
  2073     if (stonith_api == NULL) {
  2074         crm_err(
"Could not list fence agents: API memory allocation failed");
  2078                                    &stonith_resources, 0);
  2079     stonith_api->
cmds->
free(stonith_api);
  2081     for (dIter = stonith_resources; dIter; dIter = dIter->
next) {
  2084             *resources = lrmd_list_add(*resources, dIter->
value);
  2093 lrmd_api_list_agents(
lrmd_t * lrmd, 
lrmd_list_t ** resources, 
const char *
class,
  2094                      const char *provider)
  2097     int stonith_count = 0; 
  2103         GList *gIter = NULL;
  2106         for (gIter = agents; gIter != NULL; gIter = gIter->next) {
  2107             *resources = lrmd_list_add(*resources, (
const char *)gIter->data);
  2110         g_list_free_full(agents, free);
  2117     if (stonith_count) {
  2119         stonith_count = list_stonith_agents(resources);
  2120         if (stonith_count > 0) {
  2121             rc += stonith_count;
  2125         crm_notice(
"No agents found for class %s", 
class);
  2126         rc = -EPROTONOSUPPORT;
  2132 does_provider_have_agent(
const char *agent, 
const char *provider, 
const char *
class)
  2135     GList *agents = NULL;
  2136     GList *gIter2 = NULL;
  2139     for (gIter2 = agents; gIter2 != NULL; gIter2 = gIter2->next) {
  2144     g_list_free_full(agents, free);
  2149 lrmd_api_list_ocf_providers(
lrmd_t * lrmd, 
const char *agent, 
lrmd_list_t ** providers)
  2152     char *provider = NULL;
  2153     GList *ocf_providers = NULL;
  2154     GList *gIter = NULL;
  2158     for (gIter = ocf_providers; gIter != NULL; gIter = gIter->next) {
  2159         provider = gIter->data;
  2160         if (!agent || does_provider_have_agent(agent, provider,
  2162             *providers = lrmd_list_add(*providers, (
const char *)gIter->data);
  2167     g_list_free_full(ocf_providers, free);
  2175     GList *standards = NULL;
  2176     GList *gIter = NULL;
  2180     for (gIter = standards; gIter != NULL; gIter = gIter->next) {
  2181         *supported = lrmd_list_add(*supported, (
const char *)gIter->data);
  2185     if (list_stonith_agents(NULL) > 0) {
  2190     g_list_free_full(standards, free);
  2225     *api = calloc(1, 
sizeof(
lrmd_t));
  2243     if ((pvt->remote == NULL) || ((*api)->cmds == NULL)) {
  2251     (*api)->cmds->connect_async = lrmd_api_connect_async;
  2252     (*api)->cmds->is_connected = lrmd_api_is_connected;
  2253     (*api)->cmds->poke_connection = lrmd_api_poke_connection;
  2254     (*api)->cmds->disconnect = lrmd_api_disconnect;
  2255     (*api)->cmds->register_rsc = lrmd_api_register_rsc;
  2256     (*api)->cmds->unregister_rsc = lrmd_api_unregister_rsc;
  2257     (*api)->cmds->get_rsc_info = lrmd_api_get_rsc_info;
  2258     (*api)->cmds->get_recurring_ops = lrmd_api_get_recurring_ops;
  2259     (*api)->cmds->set_callback = lrmd_api_set_callback;
  2260     (*api)->cmds->get_metadata = lrmd_api_get_metadata;
  2261     (*api)->cmds->exec = lrmd_api_exec;
  2262     (*api)->cmds->cancel = lrmd_api_cancel;
  2263     (*api)->cmds->list_agents = lrmd_api_list_agents;
  2264     (*api)->cmds->list_ocf_providers = lrmd_api_list_ocf_providers;
  2265     (*api)->cmds->list_standards = lrmd_api_list_standards;
  2266     (*api)->cmds->exec_alert = lrmd_api_exec_alert;
  2267     (*api)->cmds->get_metadata_params = lrmd_api_get_metadata_params;
  2269     if ((nodename == NULL) && (server == NULL)) {
  2272 #ifdef HAVE_GNUTLS_GNUTLS_H  2273         if (nodename == NULL) {
  2275         } 
else if (server == NULL) {
  2278         pvt->type = pcmk__client_tls;
  2279         pvt->remote_nodename = strdup(nodename);
  2280         pvt->server = strdup(server);
  2281         if ((pvt->remote_nodename == NULL) || (pvt->server == NULL)) {
  2287         if (pvt->port == 0) {
  2291         crm_err(
"Cannot communicate with Pacemaker Remote "  2292                 "because GnuTLS is not enabled for this build");
  2325     if (lrmd->
cmds != NULL) { 
  2334 #ifdef HAVE_GNUTLS_GNUTLS_H  2335         free(native->server);
  2337         free(native->remote_nodename);
  2338         free(native->remote);
  2339         free(native->token);
  2340         free(native->peer_version);
  2346 struct metadata_cb {
  2361     struct metadata_cb *metadata_cb = (
struct metadata_cb *) 
action->cb_data;
  2368     metadata_cb->callback(0, &
result, metadata_cb->user_data);
  2393                      void (*callback)(
int pid,
  2399     struct metadata_cb *metadata_cb = NULL;
  2402     CRM_CHECK(callback != NULL, 
return EINVAL);
  2404     if ((rsc == NULL) || (rsc->
standard == NULL) || (rsc->
type == NULL)) {
  2407                          "Invalid resource specification");
  2408         callback(0, &
result, user_data);
  2416                                        callback, user_data);
  2427         callback(0, &
result, user_data);
  2434         callback(0, &
result, user_data);
  2440     action->cb_data = calloc(1, 
sizeof(
struct metadata_cb));
  2441     if (
action->cb_data == NULL) {
  2445         callback(0, &
result, user_data);
  2450     metadata_cb = (
struct metadata_cb *) 
action->cb_data;
  2451     metadata_cb->callback = callback;
  2452     metadata_cb->user_data = user_data;
  2473                  const char *exit_reason)
  2475     if (event == NULL) {
  2493     if (event == NULL) {
  2498     event->exit_reason = NULL;
  2500     free((
void *) event->
output);
  2501     event->output = NULL;
 
#define CRM_CHECK(expr, failure_action)
 
#define LRMD_OP_ALERT_EXEC
 
int pcmk__remote_send_xml(pcmk__remote_t *remote, xmlNode *msg)
 
#define CRMD_METADATA_CALL_TIMEOUT
 
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component. 
 
ocf_exitcode
Exit status codes for resource agents. 
 
#define crm_notice(fmt, args...)
 
lrmd_event_data_t * lrmd_copy_event(lrmd_event_data_t *event)
 
void services_action_free(svc_action_t *op)
 
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
 
#define F_LRMD_IS_IPC_PROVIDER
 
int pcmk_rc2legacy(int rc)
 
const char * crm_xml_add_ms(xmlNode *node, const char *name, guint ms)
Create an XML attribute with specified name and unsigned value. 
 
#define F_LRMD_IPC_SESSION
 
#define F_LRMD_RSC_EXEC_TIME
 
int(* list_agents)(stonith_t *stonith, int call_options, const char *namespace, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed fence agents. 
 
#define F_LRMD_RSC_ACTION
 
#define LRMD_OP_RSC_CANCEL
 
int crm_ipc_get_fd(crm_ipc_t *client)
 
const char * services__exit_reason(svc_action_t *action)
 
#define F_LRMD_RSC_OUTPUT
 
xmlNode * first_named_child(const xmlNode *parent, const char *name)
 
void(* lrmd_event_callback)(lrmd_event_data_t *event)
 
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value. 
 
void void pcmk__set_result_output(pcmk__action_result_t *result, char *out, char *err)
 
struct stonith_key_value_s * next
 
void lrmd_key_value_freeall(lrmd_key_value_t *head)
 
struct mainloop_io_s mainloop_io_t
 
lrmd_event_data_t * lrmd_new_event(const char *rsc_id, const char *task, guint interval_ms)
 
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value. 
 
void mainloop_set_trigger(crm_trigger_t *source)
 
#define DEFAULT_REMOTE_USERNAME
 
#define LRMD_OP_GET_RECURRING
 
#define MAX_TLS_RECV_WAIT
 
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
 
#define PCMK_RESOURCE_CLASS_OCF
 
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
 
lrmd_rsc_info_t * lrmd_copy_rsc_info(lrmd_rsc_info_t *rsc_info)
 
#define F_LRMD_ALERT_PATH
 
long crm_ipc_read(crm_ipc_t *client)
 
enum crm_ais_msg_types type
 
gboolean mainloop_destroy_trigger(crm_trigger_t *source)
 
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code. 
 
void lrmd__set_result(lrmd_event_data_t *event, enum ocf_exitcode rc, int op_status, const char *exit_reason)
 
int lrmd__metadata_async(lrmd_rsc_info_t *rsc, void(*callback)(int pid, const pcmk__action_result_t *result, void *user_data), void *user_data)
 
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute. 
 
void hash2smartfield(gpointer key, gpointer value, gpointer user_data)
Add hash table entry to XML as (possibly legacy) name/value. 
 
Wrappers for and extensions to glib mainloop. 
 
#define F_LRMD_PROTOCOL_VERSION
 
lrmd_t * lrmd_remote_api_new(const char *nodename, const char *server, int port)
Create a new TLS connection to a remote executor. 
 
stonith_t * stonith_api_new(void)
 
xmlNode * string2xml(const char *input)
 
const char * crm_ipc_buffer(crm_ipc_t *client)
 
#define LRMD_OP_RSC_UNREG
 
#define DEFAULT_REMOTE_KEY_LOCATION
 
struct trigger_s crm_trigger_t
 
struct lrmd_private_s lrmd_private_t
 
int(* free)(stonith_t *st)
Destroy a fencer connection. 
 
int(* dispatch)(gpointer userdata)
Dispatch function for mainloop file descriptor with data ready. 
 
#define PCMK__UNKNOWN_RESULT
 
#define crm_warn(fmt, args...)
 
GHashTable * xml2list(const xmlNode *parent)
Retrieve XML attributes as a hash table. 
 
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute. 
 
#define crm_debug(fmt, args...)
 
struct crm_ipc_s crm_ipc_t
 
#define F_LRMD_RSC_EXIT_REASON
 
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute. 
 
#define ALT_REMOTE_KEY_LOCATION
 
int pcmk__remote_ready(const pcmk__remote_t *remote, int timeout_ms)
 
bool lrmd_dispatch(lrmd_t *lrmd)
Use after lrmd_poll returns 1 to read and dispatch a message. 
 
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute. 
 
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. 
 
struct lrmd_list_s * next
 
gboolean services_action_sync(svc_action_t *op)
 
#define LRMD_PROTOCOL_VERSION
 
Parameter invalid (inherently) 
 
void lrmd_free_op_info(lrmd_op_info_t *op_info)
 
void lrmd_list_freeall(lrmd_list_t *head)
 
int(* connect)(lrmd_t *lrmd, const char *client_name, int *fd)
Connect to an executor. 
 
#define crm_trace(fmt, args...)
 
#define PCMK_RESOURCE_CLASS_STONITH
 
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
 
Object for executing external actions. 
 
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag. 
 
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))
 
void pcmk__str_update(char **str, const char *value)
 
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. 
 
#define LRMD_OP_NEW_CLIENT
 
xmlNode * create_xml_node(xmlNode *parent, const char *name)
 
int crm_element_value_epoch(const xmlNode *xml, const char *name, time_t *dest)
Retrieve the seconds-since-epoch value of an XML attribute. 
 
void stonith_key_value_freeall(stonith_key_value_t *kvp, int keys, int values)
 
lrmd_rsc_info_t * lrmd_new_rsc_info(const char *rsc_id, const char *standard, const char *provider, const char *type)
 
void mainloop_del_ipc_client(mainloop_io_t *client)
 
void crm_ipc_destroy(crm_ipc_t *client)
 
int pcmk_legacy2rc(int legacy_rc)
 
GList * resources_list_providers(const char *standard)
Get a list of providers. 
 
lrmd_t * lrmd_api_new(void)
Create a new connection to the local executor. 
 
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)
Retrieve resource agent metadata synchronously with parameters. 
 
Notify only the client that made the request (rather than all clients) 
 
Execution failed, do not retry anywhere. 
 
struct lrmd_key_value_s * next
 
#define F_LRMD_RSC_USERDATA_STR
 
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
 
void free_xml(xmlNode *child)
 
#define F_LRMD_RSC_INTERVAL
 
void lrmd_free_rsc_info(lrmd_rsc_info_t *rsc_info)
 
CRM_TRACE_INIT_DATA(lrmd)
 
#define F_LRMD_RSC_START_DELAY
 
int(* disconnect)(lrmd_t *lrmd)
Disconnect from the executor. 
 
int lrmd__new(lrmd_t **api, const char *nodename, const char *server, int port)
 
bool crm_ipc_connected(crm_ipc_t *client)
 
int lrmd_poll(lrmd_t *lrmd, int timeout)
Check whether a message is available on an executor connection. 
 
void lrmd__reset_result(lrmd_event_data_t *event)
 
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read. 
 
#define F_LRMD_RSC_RCCHANGE_TIME
 
#define crm_log_xml_err(xml, text)
 
void lrmd_api_delete(lrmd_t *lrmd)
Destroy executor connection object. 
 
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
 
pcmk__action_result_t result
 
#define F_LRMD_REMOTE_MSG_ID
 
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr. 
 
const char * remote_nodename
 
lrmd_api_operations_t * cmds
 
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
 
GList * resources_list_standards(void)
 
gboolean stonith__watchdog_fencing_enabled_for_node(const char *node)
 
#define crm_err(fmt, args...)
 
GHashTable * pcmk__str_table_dup(GHashTable *old_table)
 
enum lrmd_callback_event type
 
lrmd_key_value_t * lrmd_key_value_add(lrmd_key_value_t *head, const char *key, const char *value)
 
stonith_api_operations_t * cmds
 
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. 
 
int(* metadata)(stonith_t *stonith, int call_options, const char *agent, const char *namespace, char **output, int timeout_sec)
Retrieve a fence agent's metadata. 
 
#define CRMD_ACTION_METADATA
 
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Create a new (legacy) object for using Pacemaker daemon IPC. 
 
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents. 
 
int lrmd__remote_send_xml(pcmk__remote_t *session, xmlNode *msg, uint32_t id, const char *msg_type)
 
#define F_LRMD_RSC_RUN_TIME
 
const char * pcmk__client_type_str(uint64_t client_type)
 
void lrmd_internal_set_proxy_callback(lrmd_t *lrmd, void *userdata, void(*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
 
void pcmk__set_result(pcmk__action_result_t *result, int exit_status, enum pcmk_exec_status exec_status, const char *exit_reason)
 
#define crm_log_xml_trace(xml, text)
 
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard. 
 
#define F_LRMD_CLIENTNAME
 
int lrmd__validate_remote_settings(lrmd_t *lrmd, GHashTable *hash)
 
mainloop_io_t * mainloop_add_ipc_client(const char *name, int priority, size_t max_size, void *userdata, struct ipc_client_callbacks *callbacks)
 
#define F_LRMD_RSC_QUEUE_TIME
 
int pcmk__read_remote_message(pcmk__remote_t *remote, int timeout_ms)
 
#define F_LRMD_RSC_DELETED
 
#define F_LRMD_CALLBACK_TOKEN
 
gboolean services_action_async(svc_action_t *op, void(*action_callback)(svc_action_t *))
Request asynchronous execution of an action. 
 
void lrmd_free_event(lrmd_event_data_t *event)
Free an executor event. 
 
void pcmk__reset_result(pcmk__action_result_t *result)
 
#define F_LRMD_REMOTE_MSG_TYPE
 
void crm_ipc_close(crm_ipc_t *client)
 
Execution failed, may be retried. 
 
#define crm_info(fmt, args...)
 
xmlNode * pcmk__remote_message_xml(pcmk__remote_t *remote)
 
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source. 
 
int crm_default_remote_port(void)
Get the default remote connection TCP port on this host. 
 
int stonith__metadata_async(const char *agent, int timeout_sec, void(*callback)(int pid, const pcmk__action_result_t *result, void *user_data), void *user_data)
 
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.