changeset 25247:151b4054ce40

Trigger error callbacks when receiving a malformed-ish packet. Clean up a few pieces of code. Use G_GSIZE_FORMAT like KingAnt showed me. Don't crash if an iq packet doesn't contain the seq attribute. Error check g_fopen() Don't unref the PurpleXfer until after we've called some functions with it. Not sure that could ever actually crash it (I didn't bother to run through the ref-counts in my head to see if it would fail). committer: Marcus Lundblad <ml@update.uu.se>
author Paul Aurich <paul@darkrain42.org>
date Tue, 16 Dec 2008 19:16:10 +0000
parents 3918ed48d7a8
children 4b51394fd834
files libpurple/protocols/jabber/ibb.c libpurple/protocols/jabber/ibb.h libpurple/protocols/jabber/si.c
diffstat 3 files changed, 75 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/jabber/ibb.c	Mon Dec 15 23:13:49 2008 +0000
+++ b/libpurple/protocols/jabber/ibb.c	Tue Dec 16 19:16:10 2008 +0000
@@ -14,9 +14,6 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
  */
  
-#include <glib.h>
-#include <string.h>
-
 #include "internal.h"
 #include "ibb.h"
 #include "debug.h"
@@ -32,17 +29,11 @@
 	gpointer user_data)
 {
 	JabberIBBSession *sess = g_new0(JabberIBBSession, 1);
-	
-	if (!sess) {
-		purple_debug_error("jabber", "Could not allocate IBB session object\n");
-		return NULL;
-	}
-	
 	sess->js = js;
 	if (sid) {
 		sess->sid = g_strdup(sid);
 	} else {
-		sess->sid = g_strdup(jabber_get_next_id(js));
+		sess->sid = jabber_get_next_id(js);
 	}
 	sess->who = g_strdup(who);
 	sess->block_size = JABBER_IBB_SESSION_DEFAULT_BLOCK_SIZE;
@@ -63,38 +54,25 @@
 		XEP_0047_NAMESPACE);
 	const gchar *sid = xmlnode_get_attrib(open, "sid");
 	const gchar *block_size = xmlnode_get_attrib(open, "block-size");
-	gsize block_size_int;
 	
 	if (!open) {
 		return NULL;
 	}
-	
-	sess = g_new0(JabberIBBSession, 1);
-	
-	if (!sess) {
-		purple_debug_error("jabber", "Could not allocate IBB session object\n");
-		return NULL;
-	}
-	
+
 	if (!sid || !block_size) {
 		purple_debug_error("jabber", 
 			"IBB session open tag requires sid and block-size attributes\n");
 		g_free(sess);
 		return NULL;
 	}
-	
-	block_size_int = atoi(block_size);
-	sess->js = js;
-	sess->sid = g_strdup(sid);
+
+	sess = jabber_ibb_session_create(js, sid,
+			xmlnode_get_attrib(packet, "from"), user_data);
 	sess->id = g_strdup(xmlnode_get_attrib(packet, "id"));
-	sess->who = g_strdup(xmlnode_get_attrib(packet, "from"));
-	sess->block_size = block_size_int;
+	sess->block_size = atoi(block_size);
 	/* if we create a session from an incoming <open/> request, it means the
 	  session is immediatly open... */
 	sess->state = JABBER_IBB_SESSION_OPENED;
-	sess->user_data = user_data;
-	
-	g_hash_table_insert(jabber_ibb_sessions, sess->sid, sess);
 	
 	return sess;
 }
@@ -119,6 +97,7 @@
 	}
 	
 	g_hash_table_remove(jabber_ibb_sessions, sess->sid);
+	g_free(sess->id);
 	g_free(sess->sid);
 	g_free(sess->who);
 	g_free(sess);
@@ -248,7 +227,7 @@
 		xmlnode_set_attrib(set->node, "to", jabber_ibb_session_get_who(sess));
 		xmlnode_set_namespace(open, XEP_0047_NAMESPACE);
 		xmlnode_set_attrib(open, "sid", jabber_ibb_session_get_sid(sess));
-		g_snprintf(block_size, sizeof(block_size), "%ld", 
+		g_snprintf(block_size, sizeof(block_size), "%" G_GSIZE_FORMAT, 
 			jabber_ibb_session_get_block_size(sess));
 		xmlnode_set_attrib(open, "block-size", block_size);
 		xmlnode_insert_child(set->node, open);
@@ -327,11 +306,12 @@
 }
 
 void
-jabber_ibb_session_send_data(JabberIBBSession *sess, gpointer data, gsize size)
+jabber_ibb_session_send_data(JabberIBBSession *sess, gconstpointer data,
+                             gsize size)
 {
 	JabberIBBSessionState state = jabber_ibb_session_get_state(sess);
 	
-	purple_debug_info("jabber", "sending data block of %ld bytes on IBB stream\n",
+	purple_debug_info("jabber", "sending data block of %" G_GSIZE_FORMAT " bytes on IBB stream\n",
 		size);
 	
 	if (state != JABBER_IBB_SESSION_OPENED) {
@@ -346,13 +326,13 @@
 		xmlnode *data_element = xmlnode_new("data");
 		char *base64 = purple_base64_encode(data, size);
 		char seq[10];
-		g_snprintf(seq, sizeof(seq), "%d", jabber_ibb_session_get_send_seq(sess));
+		g_snprintf(seq, sizeof(seq), "%u", jabber_ibb_session_get_send_seq(sess));
 		
 		xmlnode_set_attrib(set->node, "to", jabber_ibb_session_get_who(sess));
 		xmlnode_set_namespace(data_element, XEP_0047_NAMESPACE);
 		xmlnode_set_attrib(data_element, "sid", jabber_ibb_session_get_sid(sess));
 		xmlnode_set_attrib(data_element, "seq", seq);
-		xmlnode_insert_data(data_element, base64, strlen(base64));
+		xmlnode_insert_data(data_element, base64, -1);
 		
 		xmlnode_insert_child(set->node, data_element);
 	
@@ -361,8 +341,8 @@
 			sess->sid);
 		jabber_iq_set_callback(set, jabber_ibb_session_send_acknowledge_cb, sess);
 		sess->last_iq_id = g_strdup(xmlnode_get_attrib(set->node, "id"));
-		purple_debug_info("jabber", "IBB: set sess->last_iq_id: %s %s\n",
-			sess->last_iq_id, xmlnode_get_attrib(set->node, "id"));
+		purple_debug_info("jabber", "IBB: set sess->last_iq_id: %s\n",
+			sess->last_iq_id);
 		jabber_iq_send(set);
 		
 		g_free(base64);
@@ -414,11 +394,13 @@
 			purple_debug_error("jabber", 
 				"Got IBB iq from wrong JID, ignoring\n");
 		} else if (data) {
-			guint16 seq = atoi(xmlnode_get_attrib(data, "seq"));
-			
+			const gchar *seq_attr = xmlnode_get_attrib(data, "seq");
+			guint16 seq = 0;
+
 			/* reject the data, and set the session in error if we get an
 			  out-of-order packet */
-			if (seq == jabber_ibb_session_get_recv_seq(sess)) {
+			if (seq_attr && (seq = atoi(seq_attr)) &&
+					seq == jabber_ibb_session_get_recv_seq(sess)) {
 				/* sequence # is the expected... */
 				JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT);
 				
@@ -435,10 +417,15 @@
 					
 					if (rawdata) {
 						purple_debug_info("jabber", 
-							"got %ld bytes of data on IBB stream\n", size);
+							"got %" G_GSIZE_FORMAT " bytes of data on IBB stream\n",
+							size);
 						if (size > jabber_ibb_session_get_block_size(sess)) {
 							purple_debug_error("jabber",
 								"IBB: received a too large packet\n");
+							if (sess->error_cb)
+								sess->error_cb(sess);
+							g_free(rawdata);
+							return;
 						} else {
 							purple_debug_info("jabber", 
 								"calling IBB callback for received data\n");
@@ -448,6 +435,10 @@
 					} else {
 						purple_debug_error("jabber", 
 							"IBB: invalid BASE64 data received\n");
+						if (sess->error_cb)
+							sess->error_cb(sess);
+						return;
+
 					}
 				}
 				
@@ -456,7 +447,7 @@
 				
 			} else {
 				purple_debug_error("jabber", 
-					"Received an out-of-order IBB packet\n");
+					"Received an out-of-order/invalid IBB packet\n");
 				sess->state = JABBER_IBB_SESSION_ERROR;
 				
 				if (sess->error_cb) {
@@ -483,7 +474,7 @@
 		/* run all open handlers registered until one returns true */
 		for (iterator = open_handlers ; iterator ; 
 			 iterator = g_list_next(iterator)) {
-			JabberIBBOpenHandler *handler = (JabberIBBOpenHandler *) iterator->data;
+			JabberIBBOpenHandler *handler = iterator->data;
 
 			if (handler(js, packet)) {
 				result = jabber_iq_new(js, JABBER_IQ_RESULT);
@@ -529,5 +520,3 @@
 	open_handlers = NULL;
 }
 
-
-		
--- a/libpurple/protocols/jabber/ibb.h	Mon Dec 15 23:13:49 2008 +0000
+++ b/libpurple/protocols/jabber/ibb.h	Tue Dec 16 19:16:10 2008 +0000
@@ -14,12 +14,12 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
  */
  
+#ifndef _PURPLE_JABBER_IBB_H_
+#define _PURPLE_JABBER_IBB_H_
+
 #include "jabber.h"
 #include "iq.h"
 
-#ifndef JABBER_IBB_SESSION
-#define JABBER_IBB_SESSION
-
 #define XEP_0047_NAMESPACE "http://jabber.org/protocol/ibb"
 
 typedef struct _JabberIBBSession JabberIBBSession;
@@ -89,7 +89,7 @@
 void jabber_ibb_session_open(JabberIBBSession *sess);
 void jabber_ibb_session_close(JabberIBBSession *sess);
 void jabber_ibb_session_accept(JabberIBBSession *sess);
-void jabber_ibb_session_send_data(JabberIBBSession *sess, gpointer data,
+void jabber_ibb_session_send_data(JabberIBBSession *sess, gconstpointer data,
 	gsize size);
 
 const gchar *jabber_ibb_session_get_sid(const JabberIBBSession *sess);
@@ -116,4 +116,4 @@
 void jabber_ibb_init(void);
 void jabber_ibb_uninit(void);
 
-#endif /* JABBER_IBB_SESSION */
+#endif /* _PURPLE_JABBER_IBB_H_ */
--- a/libpurple/protocols/jabber/si.c	Mon Dec 15 23:13:49 2008 +0000
+++ b/libpurple/protocols/jabber/si.c	Tue Dec 16 19:16:10 2008 +0000
@@ -32,9 +32,9 @@
 #include "buddy.h"
 #include "disco.h"
 #include "jabber.h"
+#include "ibb.h"
 #include "iq.h"
 #include "si.h"
-#include "ibb.h"
 
 #define STREAMHOST_CONNECT_TIMEOUT 15
 
@@ -999,7 +999,7 @@
 	JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
 	
 	if (size <= purple_xfer_get_bytes_remaining(xfer)) {
-		purple_debug_info("jabber", "about to write %lu bytes from IBB stream\n",
+		purple_debug_info("jabber", "about to write %" G_GSIZE_FORMAT " bytes from IBB stream\n",
 			size);
 		if(!fwrite(data, size, 1, jsx->fp)) {
 			purple_debug_error("jabber", "error writing to file\n");
@@ -1018,7 +1018,7 @@
 		/* trying to write past size of file transfers negotiated size,
 		  reject transfer to protect against malicious behaviour */
 		purple_debug_error("jabber", 
-			"IBB file transfer, trying to write past end of file\n");
+			"IBB file transfer send more data than expected\n");
 		jabber_si_xfer_cancel_recv(xfer);
 		purple_xfer_end(xfer);
 	}
@@ -1036,8 +1036,19 @@
 		JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
 		JabberIBBSession *sess = 
 			jabber_ibb_session_create_from_xmlnode(js, packet, xfer);
-		
+		const char *filename;
+
 		if (sess) {
+			/* open the file to write to */
+			filename = purple_xfer_get_local_filename(xfer);
+			jsx->fp = g_fopen(filename, "wb");
+			if (jsx->fp == NULL) {
+				purple_debug_error("jabber", "failed to open file %s for writing: %s\n",
+					filename, g_strerror(errno));
+				purple_xfer_cancel_remote(xfer);
+				return FALSE;
+			}
+
 			/* setup callbacks here...*/
 			jabber_ibb_session_set_data_received_callback(sess,
 				jabber_si_xfer_ibb_recv_data_cb);
@@ -1046,9 +1057,6 @@
 			jabber_ibb_session_set_error_callback(sess,
 				jabber_si_xfer_ibb_error_cb);
 			
-			/* open the file to write to */
-			jsx->fp = g_fopen(purple_xfer_get_local_filename(xfer), "wb");
-			
 			jsx->ibb_session = sess;
 			
 			/* start the transfer */
@@ -1082,7 +1090,7 @@
 	gpointer data = g_malloc(packet_size);
 	int res;
 	
-	purple_debug_info("jabber", "IBB: about to read %lu bytes from file %p\n",
+	purple_debug_info("jabber", "IBB: about to read %" G_GSIZE_FORMAT " bytes from file %p\n",
 		packet_size, jsx->fp);
 	res = fread(data, packet_size, 1, jsx->fp);
 	
@@ -1121,18 +1129,30 @@
 {
 	PurpleXfer *xfer = (PurpleXfer *) jabber_ibb_session_get_user_data(sess);
 	JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
-	
+	JabberStream *js = jabber_ibb_session_get_js(sess);
+	PurpleConnection *gc = js->gc;
+	PurpleAccount *account = purple_connection_get_account(gc);
+
 	if (jabber_ibb_session_get_state(sess) == JABBER_IBB_SESSION_OPENED) {
-		purple_xfer_start(xfer, 0, NULL, 0);
-		purple_xfer_set_bytes_sent(xfer, 0);
-		purple_xfer_update_progress(xfer);
-		jsx->fp = g_fopen(purple_xfer_get_local_filename(xfer), "rb");
-		jabber_si_xfer_ibb_send_data(sess);
+		const char *filename = purple_xfer_get_local_filename(xfer);
+		jsx->fp = g_fopen(filename, "rb");
+		if (jsx->fp == NULL) {
+			purple_debug_error("jabber", "Failed to open file %s for reading: %s\n",
+				filename, g_strerror(errno));
+			jabber_si_xfer_free(xfer);
+			purple_xfer_error(purple_xfer_get_type(xfer), account,
+				jabber_ibb_session_get_who(sess),
+				_("Failed to open the file"));
+			purple_xfer_end(xfer);
+		} else {
+			/* XXX: Shouldn't this specify a valid file descriptor? */
+			purple_xfer_start(xfer, 0, NULL, 0);
+			purple_xfer_set_bytes_sent(xfer, 0);
+			purple_xfer_update_progress(xfer);
+			jabber_si_xfer_ibb_send_data(sess);
+		}
 	} else {
 		/* error */
-		JabberStream *js = jabber_ibb_session_get_js(sess);
-		PurpleConnection *gc = js->gc;
-		PurpleAccount *account = purple_connection_get_account(gc);
 		jabber_si_xfer_free(xfer);
 		purple_xfer_error(purple_xfer_get_type(xfer), account,
 			jabber_ibb_session_get_who(sess), 
@@ -1167,10 +1187,10 @@
 		
 	} else {
 		/* failed to create IBB session */
-		purple_xfer_unref(xfer);
 		purple_debug_error("jabber", 
 			"failed to initiate IBB session for file transfer\n");
 		jabber_si_xfer_cancel_send(xfer);
+		purple_xfer_unref(xfer);
 	}
 }