[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:26:31 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