12 #if defined(US_AUTH_PEERCRED_UCRED) || defined(US_AUTH_PEERCRED_SOCKPEERCRED)    13 #  ifdef US_AUTH_PEERCRED_UCRED    18 #  include <sys/socket.h>    19 #elif defined(US_AUTH_GETPEERUCRED)    24 #include <sys/types.h>    58     (*api)->server = server;
    73             (*api)->ipc_size_max = 512 * 1024; 
    92             (*api)->ipc_size_max = 5 * 1024 * 1024; 
    95     if ((*api)->cmds == NULL) {
   102                               (*api)->ipc_size_max);
   103     if ((*api)->ipc == NULL) {
   110     if ((*api)->cmds->new_data != NULL) {
   111         if ((*api)->cmds->new_data(*api) != 
pcmk_rc_ok) {
   124     if ((api != NULL) && (api->
cmds != NULL)) {
   147     if ((api != NULL) && (api->
cb != NULL)) {
   148         api->
cb(api, event_type, status, event_data, api->
user_data);
   161 ipc_post_disconnect(gpointer user_data)
   188         free_daemon_specific_data(api);
   189         crm_trace(
"Freeing IPC API object after disconnect");
   202     bool free_on_disconnect = 
false;
   209     if (api->
ipc != NULL) {
   224     if (!free_on_disconnect) {
   225         free_daemon_specific_data(api);
   244         return for_log? 
"Pacemaker" : NULL;
   248             return for_log? 
"attribute manager" : NULL ;
   251             return for_log? 
"CIB manager" : NULL ;
   257             return for_log? 
"executor" : NULL ;
   260             return for_log? 
"fencer" : NULL ;
   266             return for_log? 
"scheduler" : NULL ;
   269             return for_log? 
"Pacemaker" : NULL;
   318 dispatch_ipc_data(
const char *buffer, ssize_t length, gpointer user_data)
   325     if (buffer == NULL) {
   326         crm_warn(
"Empty message received from %s IPC",
   333         crm_warn(
"Malformed message received from %s IPC",
   337     call_api_dispatch(api, msg);
   364     struct pollfd pollfd = { 0, };
   370     pollfd.events = POLLIN;
   371     rc = poll(&pollfd, 1, timeout_ms);
   374     } 
else if (
rc == 0) {
   411         .destroy = ipc_post_disconnect,
   419     crm_debug(
"Connected to %s IPC (attached to main loop)",
   438     crm_debug(
"Connected to %s IPC (without main loop)",
   457         crm_err(
"Cannot connect to uninitialized API object");
   461     if (api->
ipc == NULL) {
   464         if (api->
ipc == NULL) {
   465             crm_err(
"Failed to re-create IPC API");
   476     switch (dispatch_type) {
   478             rc = connect_with_main_loop(api);
   483             rc = connect_without_main_loop(api);
   513     if ((api == NULL) || (api->
ipc == NULL)) {
   542                 ipc_post_disconnect(api);
   587     xmlNode *reply = NULL;
   590     if ((api == NULL) || (api->
ipc == NULL) || (request == NULL)) {
   597         && (api->
cmds != NULL)
   608     } 
else if (
rc == 0) {
   614         call_api_dispatch(api, reply);
   643 create_purge_node_request(
pcmk_ipc_api_t *api, 
const char *node_name,
   646     xmlNode *request = NULL;
   695     xmlNode *request = NULL;
   700     if ((node_name == NULL) && (nodeid == 0)) {
   704     request = create_purge_node_request(api, node_name, nodeid);
   705     if (request == NULL) {
   711     crm_debug(
"%s peer cache purge of node %s[%lu]: rc=%d",
   722     unsigned int max_buf_size; 
   723     unsigned int buf_size;     
   728     qb_ipcc_connection_t *ipc;
   750     if (client == NULL) {
   755     client->server_name = strdup(
name);
   756     if (client->server_name == NULL) {
   757         crm_err(
"Could not create %s IPC connection: %s",
   763     client->buffer = malloc(client->buf_size);
   764     if (client->buffer == NULL) {
   765         crm_err(
"Could not create %s IPC connection: %s",
   767         free(client->server_name);
   773     client->max_buf_size = client->buf_size;
   776     client->pfd.events = POLLIN;
   777     client->pfd.revents = 0;
   796     pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
   799     client->need_reply = FALSE;
   800     client->ipc = qb_ipcc_connect(client->server_name, client->buf_size);
   802     if (client->ipc == NULL) {
   803         crm_debug(
"Could not establish %s IPC connection: %s (%d)",
   809     if (client->pfd.fd < 0) {
   826                                                   &found_pid, &found_uid,
   828         crm_err(
"%s IPC provider authentication failed: process %lld has "   829                 "uid %lld (expected %lld) and gid %lld (expected %lld)",
   832                 (
long long) found_uid, (
long long) cl_uid,
   833                 (
long long) found_gid, (
long long) cl_gid);
   835         errno = ECONNABORTED;
   839         crm_perror(LOG_ERR, 
"Could not verify authenticity of %s IPC provider",
   840                    client->server_name);
   850     qb_ipcc_context_set(client->ipc, client);
   852     client->max_buf_size = qb_ipcc_get_buffer_size(client->ipc);
   853     if (client->max_buf_size > client->buf_size) {
   854         free(client->buffer);
   855         client->buffer = calloc(1, client->max_buf_size);
   856         client->buf_size = client->max_buf_size;
   866             qb_ipcc_connection_t *ipc = client->ipc;
   869             qb_ipcc_disconnect(ipc);
   878         if (client->ipc && qb_ipcc_is_connected(client->ipc)) {
   879             crm_notice(
"Destroying active %s IPC connection",
   880                        client->server_name);
   891             crm_trace(
"Destroying inactive %s IPC connection",
   892                       client->server_name);
   894         free(client->buffer);
   895         free(client->server_name);
   905     if (client && client->ipc && (qb_ipcc_fd_get(client->ipc, &fd) == 0)) {
   909     crm_perror(LOG_ERR, 
"Could not obtain file descriptor for %s IPC",
   910                (client? client->server_name : 
"unspecified"));
   919     if (client == NULL) {
   923     } 
else if (client->ipc == NULL) {
   927     } 
else if (client->pfd.fd < 0) {
   932     rc = qb_ipcc_is_connected(client->ipc);
   934         client->pfd.fd = -EINVAL;
   957     client->pfd.revents = 0;
   958     rc = poll(&(client->pfd), 1, 0);
   959     return (
rc < 0)? -errno : 
rc;
   972         unsigned int new_buf_size = QB_MAX((
sizeof(
pcmk__ipc_header_t) + size_u), client->max_buf_size);
   973         char *uncompressed = calloc(1, new_buf_size);
   975         crm_trace(
"Decompressing message data %u bytes into %u bytes",
  1001         free(client->buffer);
  1002         client->buf_size = new_buf_size;
  1003         client->buffer = uncompressed;
  1019     client->buffer[0] = 0;
  1020     client->msg_size = qb_ipcc_event_recv(client->ipc, client->buffer,
  1021                                           client->buf_size, 0);
  1022     if (client->msg_size >= 0) {
  1023         int rc = crm_ipc_decompress(client);
  1034         crm_trace(
"Received %s IPC event %d size=%u rc=%d text='%.100s'",
  1035                   client->server_name, header->
qb.id, header->
qb.size,
  1040         crm_trace(
"No message received from %s IPC: %s",
  1045         crm_err(
"Connection to %s IPC failed", client->server_name);
  1068     if (client->buffer == NULL) {
  1073     return header->
flags;
  1080     return client->server_name;
  1085 internal_ipc_get_reply(
crm_ipc_t *client, 
int request_id, 
int ms_timeout,
  1088     time_t 
timeout = time(NULL) + 1 + (ms_timeout / 1000);
  1092     crm_trace(
"Waiting on reply to %s IPC message %d",
  1093               client->server_name, request_id);
  1096         *bytes = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, 1000);
  1100             rc = crm_ipc_decompress(client);
  1106             if (hdr->
qb.id == request_id) {
  1109             } 
else if (hdr->
qb.id < request_id) {
  1112                 crm_err(
"Discarding old reply %d (need %d)", hdr->
qb.id, request_id);
  1118                 crm_err(
"Discarding newer reply %d (need %d)", hdr->
qb.id, request_id);
  1123             crm_err(
"%s IPC provider disconnected while waiting for message %d",
  1124                     client->server_name, request_id);
  1128     } 
while (time(NULL) < 
timeout);
  1157     static uint32_t 
id = 0;
  1158     static int factor = 8;
  1161     if (client == NULL) {
  1162         crm_notice(
"Can't send IPC request without connection (bug?): %.100s",
  1168         crm_notice(
"Can't send %s IPC requests: Connection closed",
  1169                    client->server_name);
  1173     if (ms_timeout == 0) {
  1177     if (client->need_reply) {
  1178         qb_rc = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, ms_timeout);
  1180             crm_warn(
"Sending %s IPC disabled until pending reply received",
  1181                      client->server_name);
  1185             crm_notice(
"Sending %s IPC re-enabled after pending reply received",
  1186                        client->server_name);
  1187             client->need_reply = FALSE;
  1200     header = iov[0].iov_base;
  1209         if(factor < 10 && (client->max_buf_size / 10) < (bytes / factor)) {
  1210             crm_notice(
"Compressed message exceeds %d0%% of configured IPC "  1211                        "limit (%u bytes); consider setting PCMK_ipc_buffer to "  1213                        factor, client->max_buf_size, 2 * client->max_buf_size);
  1218     crm_trace(
"Sending %s IPC request %d of %u bytes using %dms timeout",
  1219               client->server_name, header->
qb.id, header->
qb.size, ms_timeout);
  1223         time_t 
timeout = time(NULL) + 1 + (ms_timeout / 1000);
  1233             qb_rc = qb_ipcc_sendv(client->ipc, iov, 2);
  1234         } 
while ((qb_rc == -EAGAIN) && (time(NULL) < 
timeout));
  1241             crm_trace(
"Not waiting for reply to %s IPC request %d",
  1242                       client->server_name, header->
qb.id);
  1246         rc = internal_ipc_get_reply(client, header->
qb.id, ms_timeout, &bytes);
  1254             client->need_reply = TRUE;
  1261             qb_rc = qb_ipcc_sendv_recv(client->ipc, iov, 2, client->buffer,
  1262                                        client->buf_size, -1);
  1270         crm_trace(
"Received %d-byte reply %d to %s IPC %d: %.100s",
  1271                   rc, hdr->
qb.id, client->server_name, header->
qb.id,
  1279         crm_trace(
"No reply to %s IPC %d: rc=%d",
  1280                   client->server_name, header->
qb.id, 
rc);
  1285         crm_notice(
"Couldn't send %s IPC request %d: Connection closed "  1286                    CRM_XS " rc=%d", client->server_name, header->
qb.id, 
rc);
  1288     } 
else if (
rc == -ETIMEDOUT) {
  1289         crm_warn(
"%s IPC request %d failed: %s after %dms " CRM_XS " rc=%d",
  1294     } 
else if (
rc <= 0) {
  1296                  client->server_name, header->
qb.id,
  1306                                    pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
  1309     pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
  1310 #if defined(US_AUTH_PEERCRED_UCRED)  1312     socklen_t ucred_len = 
sizeof(ucred);
  1315 #ifdef HAVE_QB_IPCC_AUTH_GET  1316     if (qb_ipc && !qb_ipcc_auth_get(qb_ipc, &found_pid, &found_uid, &found_gid)) {
  1321 #if defined(US_AUTH_PEERCRED_UCRED)  1322     if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
  1324                 && ucred_len == 
sizeof(ucred)) {
  1325         found_pid = ucred.pid; found_uid = ucred.uid; found_gid = ucred.gid;
  1327 #elif defined(US_AUTH_PEERCRED_SOCKPEERCRED)  1328     struct sockpeercred sockpeercred;
  1329     socklen_t sockpeercred_len = 
sizeof(sockpeercred);
  1331     if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
  1332                     &sockpeercred, &sockpeercred_len)
  1333                 && sockpeercred_len == 
sizeof(sockpeercred_len)) {
  1334         found_pid = sockpeercred.pid;
  1335         found_uid = sockpeercred.uid; found_gid = sockpeercred.gid;
  1337 #elif defined(US_AUTH_GETPEEREID)  1338     if (!getpeereid(sock, &found_uid, &found_gid)) {
  1341 #elif defined(US_AUTH_GETPEERUCRED)  1343     if (!getpeerucred(sock, &ucred)) {
  1345         found_pid = ucred_getpid(ucred);
  1346         found_uid = ucred_geteuid(ucred); found_gid = ucred_getegid(ucred);
  1354 #  error "No way to authenticate a Unix socket peer"  1358 #ifdef HAVE_QB_IPCC_AUTH_GET  1361         if (gotpid != NULL) {
  1362             *gotpid = found_pid;
  1364         if (gotuid != NULL) {
  1365             *gotuid = found_uid;
  1367         if (gotgid != NULL) {
  1368             *gotgid = found_gid;
  1370         if (found_uid == 0 || found_uid == refuid || found_gid == refgid) {
  1383                              pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
  1386                                                   gotpid, gotuid, gotgid);
  1400                                       gid_t refgid, pid_t *gotpid)
  1402     static char last_asked_name[PATH_MAX / 2] = 
"";  
  1407     pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
  1408     qb_ipcc_connection_t *c;
  1410     c = qb_ipcc_connect(
name, 0);
  1417     qb_rc = qb_ipcc_fd_get(c, &fd);
  1420         crm_err(
"Could not get fd from %s IPC: %s " CRM_XS " rc=%d",
  1426                                                  &found_uid, &found_gid);
  1428         crm_err(
"Daemon (IPC %s) effectively blocked with unauthorized"  1429                 " process %lld (uid: %lld, gid: %lld)",
  1431                 (
long long) found_uid, (
long long) found_gid);
  1438         crm_err(
"Could not get peer credentials from %s IPC: %s "  1443     if (gotpid != NULL) {
  1444         *gotpid = found_pid;
  1448     if ((found_uid != refuid || found_gid != refgid)
  1449             && strncmp(last_asked_name, 
name, 
sizeof(last_asked_name))) {
  1450         if ((found_uid == 0) && (refuid != 0)) {
  1451             crm_warn(
"Daemon (IPC %s) runs as root, whereas the expected"  1452                      " credentials are %lld:%lld, hazard of violating"  1453                      " the least privilege principle",
  1454                      name, (
long long) refuid, (
long long) refgid);
  1456             crm_notice(
"Daemon (IPC %s) runs as %lld:%lld, whereas the"  1457                        " expected credentials are %lld:%lld, which may"  1458                        " mean a different set of privileges than expected",
  1459                        name, (
long long) found_uid, (
long long) found_gid,
  1460                        (
long long) refuid, (
long long) refgid);
  1462         memccpy(last_asked_name, 
name, 
'\0', 
sizeof(last_asked_name));
  1467         qb_ipcc_disconnect(c);
 
#define CRM_CHECK(expr, failure_action)
 
int pcmk__ipc_prepare_iov(uint32_t request, xmlNode *message, uint32_t max_send_size, struct iovec **result, ssize_t *bytes)
 
void crm_write_blackbox(int nsig, struct qb_log_callsite *callsite)
 
#define crm_notice(fmt, args...)
 
const char * pcmk_strerror(int rc)
 
const char * bz2_strerror(int rc)
 
void(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
 
enum pcmk_ipc_dispatch dispatch_type
 
#define PCMK__ATTRD_CMD_PEER_REMOVE
 
int pcmk_rc2legacy(int rc)
 
int pcmk_poll_ipc(pcmk_ipc_api_t *api, int timeout_ms)
Check whether an IPC connection has data available (without main loop) 
 
long crm_ipc_read(crm_ipc_t *client)
 
void pcmk_free_ipc_api(pcmk_ipc_api_t *api)
Free the contents of an IPC API object. 
 
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__pacemakerd_api_methods(void)
 
const char * crm_ipc_buffer(crm_ipc_t *client)
 
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value. 
 
int pcmk_ipc_purge_node(pcmk_ipc_api_t *api, const char *node_name, uint32_t nodeid)
Ask a Pacemaker daemon to purge a node from its peer cache. 
 
struct mainloop_io_s mainloop_io_t
 
#define PCMK__SPECIAL_PID_AS_0(p)
 
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value. 
 
#define PCMK__XA_ATTR_NODE_ID
 
int pcmk_new_ipc_api(pcmk_ipc_api_t **api, enum pcmk_ipc_server server)
Create a new object for using Pacemaker daemon IPC. 
 
#define PCMK__SPECIAL_PID
 
enum crm_exit_e crm_exit_t
 
void crm_ipc_destroy(crm_ipc_t *client)
 
#define CRM_LOG_ASSERT(expr)
 
int pcmk__send_ipc_request(pcmk_ipc_api_t *api, xmlNode *request)
 
int pcmk_daemon_user(uid_t *uid, gid_t *gid)
Get user and group IDs of pacemaker daemon user. 
 
struct pcmk__ipc_header_s pcmk__ipc_header_t
 
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code. 
 
char * strerror(int errnum)
 
int crm_ipc_get_fd(crm_ipc_t *client)
 
xmlNode * string2xml(const char *input)
 
int pcmk__ipc_is_authentic_process_active(const char *name, uid_t refuid, gid_t refgid, pid_t *gotpid)
 
Caller will poll and dispatch IPC. 
 
#define crm_warn(fmt, args...)
 
pcmk_ipc_server
Available IPC interfaces. 
 
#define crm_debug(fmt, args...)
 
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component. 
 
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Create a new (legacy) object for using Pacemaker daemon IPC. 
 
struct crm_ipc_s crm_ipc_t
 
void pcmk_register_ipc_callback(pcmk_ipc_api_t *api, pcmk_ipc_callback_t cb, void *user_data)
Register a callback for IPC API events. 
 
const char * pcmk_ipc_name(pcmk_ipc_api_t *api, bool for_log)
Get the IPC name used with an IPC API connection. 
 
#define crm_trace(fmt, args...)
 
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag. 
 
void crm_xml_set_id(xmlNode *xml, const char *format,...) G_GNUC_PRINTF(2
 
void pcmk__call_ipc_callback(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data)
 
uint32_t crm_ipc_buffer_flags(crm_ipc_t *client)
 
#define pcmk__clear_ipc_flags(ipc_flags, ipc_name, flags_to_clear)
 
void pcmk_disconnect_ipc(pcmk_ipc_api_t *api)
Disconnect an IPC API instance. 
 
G_GNUC_INTERNAL bool pcmk__valid_ipc_header(const pcmk__ipc_header_t *header)
 
xmlNode * create_xml_node(xmlNode *parent, const char *name)
 
void crm_ipc_close(crm_ipc_t *client)
 
void mainloop_del_ipc_client(mainloop_io_t *client)
 
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 pcmk_legacy2rc(int legacy_rc)
 
void free_xml(xmlNode *child)
 
void pcmk_free_ipc_event(struct iovec *event)
Free an I/O vector created by pcmk__ipc_prepare_iov() 
 
void(* pcmk_ipc_callback_t)(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data, void *user_data)
Callback function type for Pacemaker daemon IPC APIs. 
 
int pcmk__crm_ipc_is_authentic_process(qb_ipcc_connection_t *qb_ipc, int sock, uid_t refuid, gid_t refgid, pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
Check the authenticity of the IPC socket peer process. 
 
int(* post_connect)(pcmk_ipc_api_t *api)
 
G_GNUC_INTERNAL unsigned int pcmk__ipc_buffer_size(unsigned int max)
 
#define CRM_OP_RM_NODE_CACHE
 
pcmk_ipc_dispatch
How IPC replies should be dispatched. 
 
pcmk_ipc_event
Possible event types that an IPC event callback can be called for. 
 
bool crm_ipc_connected(crm_ipc_t *client)
 
#define PCMK__XA_ATTR_NODE_NAME
 
Attach IPC to GMainLoop for dispatch. 
 
Termination of IPC connection. 
 
mainloop_io_t * mainloop_io
 
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr. 
 
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
 
#define crm_err(fmt, args...)
 
Sending a command will wait for any reply. 
 
void pcmk_dispatch_ipc(pcmk_ipc_api_t *api)
Dispatch available messages on an IPC connection (without main loop) 
 
#define crm_log_xml_notice(xml, text)
 
Lost connection to something. 
 
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read. 
 
void(* free_data)(void *api_data)
 
bool(* reply_expected)(pcmk_ipc_api_t *api, xmlNode *request)
 
bool pcmk_ipc_is_connected(pcmk_ipc_api_t *api)
Check whether an IPC API connection is active. 
 
IPC interface to Pacemaker daemons. 
 
int pcmk_connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type)
Connect to a Pacemaker daemon via IPC. 
 
#define crm_log_xml_trace(xml, text)
 
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__controld_api_methods(void)
 
pcmk__ipc_methods_t * cmds
 
void(* post_disconnect)(pcmk_ipc_api_t *api)
 
int pcmk__add_mainloop_ipc(crm_ipc_t *ipc, int priority, void *userdata, struct ipc_client_callbacks *callbacks, mainloop_io_t **source)
Connect to IPC and add it as a main loop source. 
 
enum pcmk_ipc_server server
 
#define create_request(task, xml_data, host_to, sys_to, sys_from, uuid_from)
 
#define crm_info(fmt, args...)
 
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source. 
 
int crm_ipc_is_authentic_process(int sock, uid_t refuid, gid_t refgid, pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
Check the authenticity of the IPC socket peer process (legacy) 
 
const char * crm_ipc_name(crm_ipc_t *client)