|
|
ed0026 |
commit d0cd173e2b9d26a3af6e28746003453500f8f655
|
|
|
ed0026 |
Author: Andrew Beekhof <andrew@beekhof.net>
|
|
|
ed0026 |
Date: Thu Oct 31 08:18:11 2013 +1100
|
|
|
ed0026 |
|
|
|
ed0026 |
Fix: remote: Handle endian changes between client and server and improve forward compatibility
|
|
|
ed0026 |
|
|
|
ed0026 |
(cherry picked from commit 0c8cb451bb31335e242da328c8a537ab60095a0f)
|
|
|
ed0026 |
|
|
|
ed0026 |
diff --git a/configure.ac b/configure.ac
|
|
|
ed0026 |
index cfc1b1f..b94c26e 100644
|
|
|
ed0026 |
--- a/configure.ac
|
|
|
ed0026 |
+++ b/configure.ac
|
|
|
ed0026 |
@@ -727,6 +727,7 @@ AC_CHECK_HEADERS(glib.h)
|
|
|
ed0026 |
AC_CHECK_HEADERS(grp.h)
|
|
|
ed0026 |
AC_CHECK_HEADERS(limits.h)
|
|
|
ed0026 |
AC_CHECK_HEADERS(linux/errqueue.h)
|
|
|
ed0026 |
+AC_CHECK_HEADERS(linux/swab.h)
|
|
|
ed0026 |
AC_CHECK_HEADERS(malloc.h)
|
|
|
ed0026 |
AC_CHECK_HEADERS(netdb.h)
|
|
|
ed0026 |
AC_CHECK_HEADERS(netinet/in.h)
|
|
|
ed0026 |
diff --git a/lib/common/remote.c b/lib/common/remote.c
|
|
|
ed0026 |
index c991761..47f0205 100644
|
|
|
ed0026 |
--- a/lib/common/remote.c
|
|
|
ed0026 |
+++ b/lib/common/remote.c
|
|
|
ed0026 |
@@ -43,9 +43,7 @@
|
|
|
ed0026 |
#ifdef HAVE_GNUTLS_GNUTLS_H
|
|
|
ed0026 |
# undef KEYFILE
|
|
|
ed0026 |
# include <gnutls/gnutls.h>
|
|
|
ed0026 |
-#endif
|
|
|
ed0026 |
|
|
|
ed0026 |
-#ifdef HAVE_GNUTLS_GNUTLS_H
|
|
|
ed0026 |
const int psk_tls_kx_order[] = {
|
|
|
ed0026 |
GNUTLS_KX_DHE_PSK,
|
|
|
ed0026 |
GNUTLS_KX_PSK,
|
|
|
ed0026 |
@@ -58,17 +56,87 @@ const int anon_tls_kx_order[] = {
|
|
|
ed0026 |
GNUTLS_KX_RSA,
|
|
|
ed0026 |
0
|
|
|
ed0026 |
};
|
|
|
ed0026 |
+#endif
|
|
|
ed0026 |
+
|
|
|
ed0026 |
+/* Swab macros from linux/swab.h */
|
|
|
ed0026 |
+#ifdef HAVE_LINUX_SWAB_H
|
|
|
ed0026 |
+# include <linux/swab.h>
|
|
|
ed0026 |
+#else
|
|
|
ed0026 |
+/*
|
|
|
ed0026 |
+ * casts are necessary for constants, because we never know how for sure
|
|
|
ed0026 |
+ * how U/UL/ULL map to __u16, __u32, __u64. At least not in a portable way.
|
|
|
ed0026 |
+ */
|
|
|
ed0026 |
+#define ___swab16(x) ((__u16)( \
|
|
|
ed0026 |
+ (((__u16)(x) & (__u16)0x00ffU) << 8) | \
|
|
|
ed0026 |
+ (((__u16)(x) & (__u16)0xff00U) >> 8)))
|
|
|
ed0026 |
+
|
|
|
ed0026 |
+#define ___swab32(x) ((__u32)( \
|
|
|
ed0026 |
+ (((__u32)(x) & (__u32)0x000000ffUL) << 24) | \
|
|
|
ed0026 |
+ (((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \
|
|
|
ed0026 |
+ (((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \
|
|
|
ed0026 |
+ (((__u32)(x) & (__u32)0xff000000UL) >> 24)))
|
|
|
ed0026 |
+
|
|
|
ed0026 |
+#define ___swab64(x) ((__u64)( \
|
|
|
ed0026 |
+ (((__u64)(x) & (__u64)0x00000000000000ffULL) << 56) | \
|
|
|
ed0026 |
+ (((__u64)(x) & (__u64)0x000000000000ff00ULL) << 40) | \
|
|
|
ed0026 |
+ (((__u64)(x) & (__u64)0x0000000000ff0000ULL) << 24) | \
|
|
|
ed0026 |
+ (((__u64)(x) & (__u64)0x00000000ff000000ULL) << 8) | \
|
|
|
ed0026 |
+ (((__u64)(x) & (__u64)0x000000ff00000000ULL) >> 8) | \
|
|
|
ed0026 |
+ (((__u64)(x) & (__u64)0x0000ff0000000000ULL) >> 24) | \
|
|
|
ed0026 |
+ (((__u64)(x) & (__u64)0x00ff000000000000ULL) >> 40) | \
|
|
|
ed0026 |
+ (((__u64)(x) & (__u64)0xff00000000000000ULL) >> 56)))
|
|
|
ed0026 |
+#endif
|
|
|
ed0026 |
+
|
|
|
ed0026 |
+#define REMOTE_MSG_VERSION 1
|
|
|
ed0026 |
+#define ENDIAN_LOCAL 0xBADADBBD
|
|
|
ed0026 |
|
|
|
ed0026 |
struct crm_remote_header_v0
|
|
|
ed0026 |
{
|
|
|
ed0026 |
+ uint32_t endian; /* Detect messages from hosts with different endian-ness */
|
|
|
ed0026 |
+ uint32_t version;
|
|
|
ed0026 |
uint64_t id;
|
|
|
ed0026 |
uint64_t flags;
|
|
|
ed0026 |
- uint32_t error;
|
|
|
ed0026 |
- uint32_t version;
|
|
|
ed0026 |
uint32_t size_total;
|
|
|
ed0026 |
- uint32_t payload_uncompressed;
|
|
|
ed0026 |
+ uint32_t payload_offset;
|
|
|
ed0026 |
uint32_t payload_compressed;
|
|
|
ed0026 |
-};
|
|
|
ed0026 |
+ uint32_t payload_uncompressed;
|
|
|
ed0026 |
+
|
|
|
ed0026 |
+ /* New fields get added here */
|
|
|
ed0026 |
+
|
|
|
ed0026 |
+} __attribute__ ((packed));
|
|
|
ed0026 |
+
|
|
|
ed0026 |
+static struct crm_remote_header_v0 *
|
|
|
ed0026 |
+crm_remote_header(crm_remote_t * remote)
|
|
|
ed0026 |
+{
|
|
|
ed0026 |
+ struct crm_remote_header_v0 *header = (struct crm_remote_header_v0 *)remote->buffer;
|
|
|
ed0026 |
+ if(remote->buffer_offset < sizeof(struct crm_remote_header_v0)) {
|
|
|
ed0026 |
+ return NULL;
|
|
|
ed0026 |
+
|
|
|
ed0026 |
+ } else if(header->endian != ENDIAN_LOCAL) {
|
|
|
ed0026 |
+ uint32_t endian = __swab32(header->endian);
|
|
|
ed0026 |
+
|
|
|
ed0026 |
+ CRM_LOG_ASSERT(endian == ENDIAN_LOCAL);
|
|
|
ed0026 |
+ if(endian != ENDIAN_LOCAL) {
|
|
|
ed0026 |
+ crm_err("Invalid message detected, endian mismatch: %lx is neither %lx nor the swab'd %lx",
|
|
|
ed0026 |
+ ENDIAN_LOCAL, header->endian, endian);
|
|
|
ed0026 |
+ return NULL;
|
|
|
ed0026 |
+ }
|
|
|
ed0026 |
+
|
|
|
ed0026 |
+ header->id = __swab64(header->id);
|
|
|
ed0026 |
+ header->flags = __swab64(header->flags);
|
|
|
ed0026 |
+ header->endian = __swab32(header->endian);
|
|
|
ed0026 |
+
|
|
|
ed0026 |
+ header->version = __swab32(header->version);
|
|
|
ed0026 |
+ header->size_total = __swab32(header->size_total);
|
|
|
ed0026 |
+ header->payload_offset = __swab32(header->payload_offset);
|
|
|
ed0026 |
+ header->payload_compressed = __swab32(header->payload_compressed);
|
|
|
ed0026 |
+ header->payload_uncompressed = __swab32(header->payload_uncompressed);
|
|
|
ed0026 |
+ }
|
|
|
ed0026 |
+
|
|
|
ed0026 |
+ return header;
|
|
|
ed0026 |
+}
|
|
|
ed0026 |
+
|
|
|
ed0026 |
+#ifdef HAVE_GNUTLS_GNUTLS_H
|
|
|
ed0026 |
|
|
|
ed0026 |
int
|
|
|
ed0026 |
crm_initiate_client_tls_handshake(crm_remote_t * remote, int timeout_ms)
|
|
|
ed0026 |
@@ -253,13 +321,11 @@ crm_remote_sendv(crm_remote_t * remote, struct iovec * iov, int iovs)
|
|
|
ed0026 |
return rc;
|
|
|
ed0026 |
}
|
|
|
ed0026 |
|
|
|
ed0026 |
-#define PCMK_TLS_VERSION 1
|
|
|
ed0026 |
-
|
|
|
ed0026 |
int
|
|
|
ed0026 |
crm_remote_send(crm_remote_t * remote, xmlNode * msg)
|
|
|
ed0026 |
{
|
|
|
ed0026 |
- static uint64_t id = 0;
|
|
|
ed0026 |
int rc = -1;
|
|
|
ed0026 |
+ static uint64_t id = 0;
|
|
|
ed0026 |
char *xml_text = dump_xml_unformatted(msg);
|
|
|
ed0026 |
|
|
|
ed0026 |
struct iovec iov[2];
|
|
|
ed0026 |
@@ -278,19 +344,25 @@ crm_remote_send(crm_remote_t * remote, xmlNode * msg)
|
|
|
ed0026 |
|
|
|
ed0026 |
id++;
|
|
|
ed0026 |
header->id = id;
|
|
|
ed0026 |
- header->version = PCMK_TLS_VERSION;
|
|
|
ed0026 |
- header->size_total = iov[0].iov_len + iov[1].iov_len;
|
|
|
ed0026 |
+ header->endian = ENDIAN_LOCAL;
|
|
|
ed0026 |
+ header->version = REMOTE_MSG_VERSION;
|
|
|
ed0026 |
+ header->payload_offset = iov[0].iov_len;
|
|
|
ed0026 |
header->payload_uncompressed = iov[1].iov_len;
|
|
|
ed0026 |
+ header->size_total = iov[0].iov_len + iov[1].iov_len;
|
|
|
ed0026 |
|
|
|
ed0026 |
+ crm_trace("Sending len[0]=%d, start=%x\n",
|
|
|
ed0026 |
+ (int)iov[0].iov_len, *(int*)xml_text);
|
|
|
ed0026 |
rc = crm_remote_sendv(remote, iov, 2);
|
|
|
ed0026 |
if (rc < 0) {
|
|
|
ed0026 |
crm_err("Failed to send remote msg, rc = %d", rc);
|
|
|
ed0026 |
}
|
|
|
ed0026 |
|
|
|
ed0026 |
- free(xml_text);
|
|
|
ed0026 |
+ free(iov[0].iov_base);
|
|
|
ed0026 |
+ free(iov[1].iov_base);
|
|
|
ed0026 |
return rc;
|
|
|
ed0026 |
}
|
|
|
ed0026 |
|
|
|
ed0026 |
+
|
|
|
ed0026 |
/*!
|
|
|
ed0026 |
* \internal
|
|
|
ed0026 |
* \brief handles the recv buffer and parsing out msgs.
|
|
|
ed0026 |
@@ -300,34 +372,35 @@ xmlNode *
|
|
|
ed0026 |
crm_remote_parse_buffer(crm_remote_t * remote)
|
|
|
ed0026 |
{
|
|
|
ed0026 |
xmlNode *xml = NULL;
|
|
|
ed0026 |
- size_t offset = sizeof(struct crm_remote_header_v0);
|
|
|
ed0026 |
- struct crm_remote_header_v0 *header = NULL;
|
|
|
ed0026 |
+ struct crm_remote_header_v0 *header = crm_remote_header(remote);
|
|
|
ed0026 |
|
|
|
ed0026 |
- if (remote->buffer == NULL) {
|
|
|
ed0026 |
- return NULL;
|
|
|
ed0026 |
-
|
|
|
ed0026 |
- } else if(remote->buffer_offset < sizeof(struct crm_remote_header_v0)) {
|
|
|
ed0026 |
+ if (remote->buffer == NULL || header == NULL) {
|
|
|
ed0026 |
return NULL;
|
|
|
ed0026 |
}
|
|
|
ed0026 |
|
|
|
ed0026 |
/* take ownership of the buffer */
|
|
|
ed0026 |
remote->buffer_offset = 0;
|
|
|
ed0026 |
|
|
|
ed0026 |
- header = (struct crm_remote_header_v0 *)remote->buffer;
|
|
|
ed0026 |
/* Support compression on the receiving end now, in case we ever want to add it later */
|
|
|
ed0026 |
if (header->payload_compressed) {
|
|
|
ed0026 |
int rc = 0;
|
|
|
ed0026 |
unsigned int size_u = 1 + header->payload_uncompressed;
|
|
|
ed0026 |
- char *uncompressed = calloc(1, offset + size_u);
|
|
|
ed0026 |
+ char *uncompressed = calloc(1, header->payload_offset + size_u);
|
|
|
ed0026 |
|
|
|
ed0026 |
crm_trace("Decompressing message data %d bytes into %d bytes",
|
|
|
ed0026 |
header->payload_compressed, size_u);
|
|
|
ed0026 |
|
|
|
ed0026 |
- rc = BZ2_bzBuffToBuffDecompress(uncompressed + offset, &size_u,
|
|
|
ed0026 |
- remote->buffer + offset,
|
|
|
ed0026 |
+ rc = BZ2_bzBuffToBuffDecompress(uncompressed + header->payload_offset, &size_u,
|
|
|
ed0026 |
+ remote->buffer + header->payload_offset,
|
|
|
ed0026 |
header->payload_compressed, 1, 0);
|
|
|
ed0026 |
|
|
|
ed0026 |
- if (rc != BZ_OK) {
|
|
|
ed0026 |
+ if (rc != BZ_OK && header->version > REMOTE_MSG_VERSION) {
|
|
|
ed0026 |
+ crm_warn("Couldn't decompress v%d message, we only understand v%d",
|
|
|
ed0026 |
+ header->version, REMOTE_MSG_VERSION);
|
|
|
ed0026 |
+ free(uncompressed);
|
|
|
ed0026 |
+ return NULL;
|
|
|
ed0026 |
+
|
|
|
ed0026 |
+ } else if (rc != BZ_OK) {
|
|
|
ed0026 |
crm_err("Decompression failed: %s (%d)", bz2_strerror(rc), rc);
|
|
|
ed0026 |
free(uncompressed);
|
|
|
ed0026 |
return NULL;
|
|
|
ed0026 |
@@ -335,19 +408,23 @@ crm_remote_parse_buffer(crm_remote_t * remote)
|
|
|
ed0026 |
|
|
|
ed0026 |
CRM_ASSERT(size_u == header->payload_uncompressed);
|
|
|
ed0026 |
|
|
|
ed0026 |
- memcpy(uncompressed, remote->buffer, offset); /* Preserve the header */
|
|
|
ed0026 |
- header = (struct crm_remote_header_v0 *)uncompressed;
|
|
|
ed0026 |
+ memcpy(uncompressed, remote->buffer, header->payload_offset); /* Preserve the header */
|
|
|
ed0026 |
+ remote->buffer_size = header->payload_offset + size_u;
|
|
|
ed0026 |
|
|
|
ed0026 |
free(remote->buffer);
|
|
|
ed0026 |
- remote->buffer_size = offset + size_u;
|
|
|
ed0026 |
remote->buffer = uncompressed;
|
|
|
ed0026 |
+ header = crm_remote_header(remote);
|
|
|
ed0026 |
}
|
|
|
ed0026 |
|
|
|
ed0026 |
- CRM_ASSERT(remote->buffer[sizeof(struct crm_remote_header_v0) + header->payload_uncompressed - 1] == 0);
|
|
|
ed0026 |
+ CRM_LOG_ASSERT(remote->buffer[sizeof(struct crm_remote_header_v0) + header->payload_uncompressed - 1] == 0);
|
|
|
ed0026 |
+
|
|
|
ed0026 |
+ xml = string2xml(remote->buffer + header->payload_offset);
|
|
|
ed0026 |
+ if (xml == NULL && header->version > REMOTE_MSG_VERSION) {
|
|
|
ed0026 |
+ crm_warn("Couldn't parse v%d message, we only understand v%d",
|
|
|
ed0026 |
+ header->version, REMOTE_MSG_VERSION);
|
|
|
ed0026 |
|
|
|
ed0026 |
- xml = string2xml(remote->buffer + offset);
|
|
|
ed0026 |
- if (xml == NULL) {
|
|
|
ed0026 |
- crm_err("Couldn't parse: '%.120s'", remote->buffer + offset);
|
|
|
ed0026 |
+ } else if (xml == NULL) {
|
|
|
ed0026 |
+ crm_err("Couldn't parse: '%.120s'", remote->buffer + header->payload_offset);
|
|
|
ed0026 |
}
|
|
|
ed0026 |
|
|
|
ed0026 |
return xml;
|
|
|
ed0026 |
@@ -424,16 +501,16 @@ crm_remote_recv_once(crm_remote_t * remote)
|
|
|
ed0026 |
{
|
|
|
ed0026 |
int rc = 0;
|
|
|
ed0026 |
size_t read_len = sizeof(struct crm_remote_header_v0);
|
|
|
ed0026 |
+ struct crm_remote_header_v0 *header = crm_remote_header(remote);
|
|
|
ed0026 |
|
|
|
ed0026 |
- if(remote->buffer_offset >= sizeof(struct crm_remote_header_v0)) {
|
|
|
ed0026 |
- struct crm_remote_header_v0 *hdr = (struct crm_remote_header_v0 *)remote->buffer;
|
|
|
ed0026 |
-
|
|
|
ed0026 |
- read_len = hdr->size_total;
|
|
|
ed0026 |
+ if(header) {
|
|
|
ed0026 |
+ /* Stop at the end of the current message */
|
|
|
ed0026 |
+ read_len = header->size_total;
|
|
|
ed0026 |
}
|
|
|
ed0026 |
|
|
|
ed0026 |
/* automatically grow the buffer when needed */
|
|
|
ed0026 |
if(remote->buffer_size < read_len) {
|
|
|
ed0026 |
- remote->buffer_size = 2 * read_len;
|
|
|
ed0026 |
+ remote->buffer_size = 2 * read_len;
|
|
|
ed0026 |
crm_trace("Expanding buffer to %u bytes", remote->buffer_size);
|
|
|
ed0026 |
|
|
|
ed0026 |
remote->buffer = realloc(remote->buffer, remote->buffer_size + 1);
|
|
|
ed0026 |
@@ -488,23 +565,18 @@ crm_remote_recv_once(crm_remote_t * remote)
|
|
|
ed0026 |
return -ENOTCONN;
|
|
|
ed0026 |
}
|
|
|
ed0026 |
|
|
|
ed0026 |
- if(remote->buffer_offset < sizeof(struct crm_remote_header_v0)) {
|
|
|
ed0026 |
- crm_trace("Not enough data to fill header: %u < %u bytes",
|
|
|
ed0026 |
- remote->buffer_offset, sizeof(struct crm_remote_header_v0));
|
|
|
ed0026 |
- return -EAGAIN;
|
|
|
ed0026 |
-
|
|
|
ed0026 |
- } else {
|
|
|
ed0026 |
- struct crm_remote_header_v0 *hdr = (struct crm_remote_header_v0 *)remote->buffer;
|
|
|
ed0026 |
-
|
|
|
ed0026 |
- if(remote->buffer_offset < hdr->size_total) {
|
|
|
ed0026 |
+ header = crm_remote_header(remote);
|
|
|
ed0026 |
+ if(header) {
|
|
|
ed0026 |
+ if(remote->buffer_offset < header->size_total) {
|
|
|
ed0026 |
crm_trace("Read less than the advertised length: %u < %u bytes",
|
|
|
ed0026 |
- remote->buffer_offset, hdr->size_total);
|
|
|
ed0026 |
- return -EAGAIN;
|
|
|
ed0026 |
+ remote->buffer_offset, header->size_total);
|
|
|
ed0026 |
+ } else {
|
|
|
ed0026 |
+ crm_trace("Read full message of %u bytes", remote->buffer_offset);
|
|
|
ed0026 |
+ return remote->buffer_offset;
|
|
|
ed0026 |
}
|
|
|
ed0026 |
}
|
|
|
ed0026 |
|
|
|
ed0026 |
- crm_trace("Read full message of %u bytes", remote->buffer_offset);
|
|
|
ed0026 |
- return remote->buffer_offset;
|
|
|
ed0026 |
+ return -EAGAIN;
|
|
|
ed0026 |
}
|
|
|
ed0026 |
|
|
|
ed0026 |
/*!
|
|
|
ed0026 |
diff --git a/lib/lrmd/lrmd_client.c b/lib/lrmd/lrmd_client.c
|
|
|
ed0026 |
index d037022..d99d7c8 100644
|
|
|
ed0026 |
--- a/lib/lrmd/lrmd_client.c
|
|
|
ed0026 |
+++ b/lib/lrmd/lrmd_client.c
|
|
|
ed0026 |
@@ -414,9 +414,6 @@ lrmd_poll(lrmd_t * lrmd, int timeout)
|
|
|
ed0026 |
case CRM_CLIENT_TLS:
|
|
|
ed0026 |
if (native->pending_notify) {
|
|
|
ed0026 |
return 1;
|
|
|
ed0026 |
- } else if (native->remote->buffer
|
|
|
ed0026 |
- && strstr(native->remote->buffer, REMOTE_MSG_TERMINATOR)) {
|
|
|
ed0026 |
- return 1;
|
|
|
ed0026 |
}
|
|
|
ed0026 |
|
|
|
ed0026 |
return crm_remote_ready(native->remote, 0);
|