[Pkg-privacy-commits] [irssi-plugin-otr] 189/267: Support split OTR message on receive

Ximin Luo infinity0 at moszumanska.debian.org
Sat Aug 22 12:41:41 UTC 2015


This is an automated email from the git hooks/post-receive script.

infinity0 pushed a commit to branch debian
in repository irssi-plugin-otr.

commit d1d044ae5ebec934a3434a865a451d8c7e754351
Author: David Goulet <dgoulet at ev0ke.net>
Date:   Thu Jan 24 10:54:21 2013 -0500

    Support split OTR message on receive
    
    This has been observed in bitlbee where a full OTR message is split in
    different PRIVMSG so now this patch adds a support to check for
    fragmented OTR message and reconstruct it before passing the message to
    libotr.
    
    Reported-by: Micah Anderson <micah at riseup.net>
    Reported-by: Jacob Appelbaum <jacob at appelbaum.net>
    Signed-off-by: David Goulet <dgoulet at ev0ke.net>
---
 src/module.c |   9 ++--
 src/otr.c    | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 src/otr.h    |  24 ++++++++++
 3 files changed, 171 insertions(+), 13 deletions(-)

diff --git a/src/module.c b/src/module.c
index 2fde1d8..06c8b46 100644
--- a/src/module.c
+++ b/src/module.c
@@ -281,11 +281,10 @@ error_alloc:
 void irssi_send_message(SERVER_REC *irssi, const char *recipient,
 		const char *msg)
 {
-	/* XXX: Maybe an assert here. Code flow error? */
-	if (irssi) {
-		irssi->send_message(irssi, recipient, msg,
-				GPOINTER_TO_INT(SEND_TARGET_NICK));
-	}
+	assert(irssi);
+
+	irssi->send_message(irssi, recipient, msg,
+			GPOINTER_TO_INT(SEND_TARGET_NICK));
 }
 
 /*
diff --git a/src/otr.c b/src/otr.c
index 3b9e026..ad81237 100644
--- a/src/otr.c
+++ b/src/otr.c
@@ -692,6 +692,112 @@ end:
 }
 
 /*
+ * For the given message we received through irssi, check if we need to queue
+ * it for the case where that message is part of a bigger OTR full message.
+ * This can happen with bitlbee for instance where OTR message are split in
+ * different PRIVMSG.
+ *
+ * This uses a "queue" in the peer context so it's it very important to have
+ * the peer context associated with the message (nickname + irssi object).
+ *
+ * Return an otr_msg_status code indicating the caller what to do with the msg.
+ * OTR_MSG_ERROR indicates an error probably memory related. OTR_MSG_WAIT_MORE
+ * tells the caller to NOT send out the message since we are waiting for more
+ * to complete the OTR original message. OTR_MSG_ORIGINAL tell the caller to
+ * simply use the original message. OTR_MSG_USE_QUEUE indicates that full_msg
+ * can be used containing the reconstructed message. The caller SHOULD free(3)
+ * this pointer after use.
+ */
+static enum otr_msg_status enqueue_otr_fragment(const char *msg,
+		struct otr_peer_context *opc, char **full_msg)
+{
+	enum otr_msg_status ret;
+	size_t msg_len;
+
+	assert(msg);
+	assert(opc);
+
+	/* We are going to use it quite a bit so ease our life a bit. */
+	msg_len = strlen(msg);
+
+	if (opc->full_msg) {
+		if (msg_len > (opc->msg_size - opc->msg_len)) {
+			char *tmp_ptr;
+
+			/* Realloc memory if there is not enough space. */
+			tmp_ptr = realloc(opc->full_msg, opc->msg_size + msg_len + 1);
+			if (!tmp_ptr) {
+				free(opc->full_msg);
+				opc->full_msg = NULL;
+				ret = OTR_MSG_ERROR;
+				goto end;
+			}
+			opc->full_msg = tmp_ptr;
+			opc->msg_size += msg_len + 1;
+		}
+
+		/* Copy msg to full message since we already have a part pending. */
+		strncpy(opc->full_msg + opc->msg_len, msg, msg_len);
+		opc->msg_len += msg_len;
+		opc->full_msg[opc->msg_len] = '\0';
+
+		IRSSI_DEBUG("Partial OTR message added to queue: %s", msg);
+
+		/*
+		 * Are we waiting for more? If the message ends with a ".", the
+		 * transmission has ended else we have to wait for more.
+		 */
+		if (msg[msg_len - 1] != OTR_MSG_END_TAG) {
+			ret = OTR_MSG_WAIT_MORE;
+			goto end;
+		}
+
+		/*
+		 * Dup the string with enough space for the NULL byte since we are
+		 * about to free it before passing it to the caller.
+		 */
+		*full_msg = strndup(opc->full_msg, opc->msg_len + 1);
+		/* Reset everything. */
+		free(opc->full_msg);
+		opc->full_msg = NULL;
+		opc->msg_size = opc->msg_len = 0;
+		ret = OTR_MSG_USE_QUEUE;
+		goto end;
+	} else {
+		char *pos;
+
+		/*
+		 * Try to find the OTR message tag at the _beginning_of the packet and
+		 * check if this packet is not the end with the end tag of OTR "."
+		 */
+		pos = strstr(msg, OTR_MSG_BEGIN_TAG);
+		if (pos && (pos == msg) && msg[msg_len - 1] != OTR_MSG_END_TAG) {
+			/* Allocate full message buffer with an extra for NULL byte. */
+			opc->full_msg = zmalloc((msg_len * 2) + 1);
+			if (!opc->full_msg) {
+				ret = OTR_MSG_ERROR;
+				goto end;
+			}
+			/* Copy full message with NULL terminated byte. */
+			strncpy(opc->full_msg, msg, msg_len);
+			opc->msg_len += msg_len;
+			opc->msg_size += ((msg_len * 2) + 1);
+			opc->full_msg[opc->msg_len] = '\0';
+			ret = OTR_MSG_WAIT_MORE;
+			IRSSI_DEBUG("Partial OTR message begins the queue: %s", msg);
+			goto end;
+		}
+
+		/* Use original message. */
+		ret = OTR_MSG_ORIGINAL;
+		goto end;
+	}
+
+end:
+	return ret;
+}
+
+/*
  * Hand the given message to OTR.
  *
  * Returns 0 if its an OTR protocol message or else negative value.
@@ -700,9 +806,11 @@ int otr_receive(SERVER_REC *irssi, const char *msg, const char *from,
 		char **new_msg)
 {
 	int ret = -1;
-	char *accname = NULL;
+	char *accname = NULL, *full_msg = NULL;
+	const char *recv_msg = NULL;
 	OtrlTLV *tlvs;
 	ConnContext *ctx;
+	struct otr_peer_context *opc;
 
 	assert(irssi);
 
@@ -713,9 +821,38 @@ int otr_receive(SERVER_REC *irssi, const char *msg, const char *from,
 
 	IRSSI_DEBUG("Receiving message...");
 
+	ctx = otr_find_context(irssi, from, 1);
+	if (!ctx) {
+		goto error;
+	}
+
+	/* Add peer context to OTR context if none exists */
+	if (!ctx->app_data) {
+		add_peer_context_cb(irssi, ctx);
+	}
+
+	opc = ctx->app_data;
+	assert(opc);
+
+	ret = enqueue_otr_fragment(msg, opc, &full_msg);
+	switch (ret) {
+	case OTR_MSG_ORIGINAL:
+		recv_msg = msg;
+		break;
+	case OTR_MSG_WAIT_MORE:
+		ret = 1;
+		goto error;
+	case OTR_MSG_USE_QUEUE:
+		recv_msg = full_msg;
+		break;
+	case OTR_MSG_ERROR:
+		ret = -1;
+		goto error;
+	}
+
 	ret = otrl_message_receiving(user_state_global->otr_state,
-		&otr_ops, irssi, accname, OTR_PROTOCOL_ID, from, msg, new_msg, &tlvs,
-		&ctx, add_peer_context_cb, irssi);
+		&otr_ops, irssi, accname, OTR_PROTOCOL_ID, from, recv_msg, new_msg,
+		&tlvs, &ctx, add_peer_context_cb, irssi);
 	if (ret) {
 		IRSSI_DEBUG("Ignoring message of length %d from %s to %s.\n"
 				"%s", strlen(msg), from, accname, msg);
@@ -725,11 +862,6 @@ int otr_receive(SERVER_REC *irssi, const char *msg, const char *from,
 		}
 	}
 
-	/* Add peer context to OTR context if non exists */
-	if (ctx && !ctx->app_data) {
-		add_peer_context_cb(irssi, ctx);
-	}
-
 	/* Check for disconnected message */
 	OtrlTLV *tlv = otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED);
 	if (tlv) {
@@ -745,6 +877,9 @@ int otr_receive(SERVER_REC *irssi, const char *msg, const char *from,
 	IRSSI_DEBUG("Message received.");
 
 error:
+	if (full_msg) {
+		free(full_msg);
+	}
 	free(accname);
 	return ret;
 }
diff --git a/src/otr.h b/src/otr.h
index 06df708..69952c3 100644
--- a/src/otr.h
+++ b/src/otr.h
@@ -48,6 +48,13 @@
 #define OTR_INSTAG_FILE               OTR_DIR "/otr.instag"
 
 /*
+ * Specified in OTR protocol version 3. See:
+ * http://www.cypherpunks.ca/otr/Protocol-v3-4.0.0.html
+ */
+#define OTR_MSG_BEGIN_TAG             "?OTR:"
+#define OTR_MSG_END_TAG               '.'
+
+/*
  * Memory allocation zeroed. Really useful!
  */
 #define zmalloc(x) calloc(1, x)
@@ -71,6 +78,16 @@ struct otr_peer_context {
 	 * automatically.
 	 */
 	Fingerprint *active_fingerprint;
+	/*
+	 * If needed, used to reconstruct the full message from fragmentation.
+	 * Bitlbee for instance does that where we receive a *long* OTR message
+	 * split in multiple PRIVMSG so we need to reconstruct it.
+	 */
+	char *full_msg;
+	/* Size of full_msg. Note this is the allocated memory size. */
+	size_t msg_size;
+	/* Len of the actual string in full_msg NOT counting the NULL byte. */
+	size_t msg_len;
 };
 
 /* given to otr_status_change */
@@ -92,6 +109,13 @@ enum otr_status_event {
 	OTR_STATUS_CTX_UPDATE
 };
 
+enum otr_msg_status {
+	OTR_MSG_ORIGINAL		= 1,
+	OTR_MSG_WAIT_MORE		= 2,
+	OTR_MSG_USE_QUEUE		= 3,
+	OTR_MSG_ERROR			= 4,
+};
+
 /* there can be only one */
 extern struct otr_user_state *user_state_global;
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/irssi-plugin-otr.git



More information about the Pkg-privacy-commits mailing list