# HG changeset patch # User Paul Aurich # Date 1229454970 0 # Node ID 151b4054ce409c30ebd63ff2ca94361642a2344d # Parent 3918ed48d7a8160f0e147aadd29f1292561dac80 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 diff -r 3918ed48d7a8 -r 151b4054ce40 libpurple/protocols/jabber/ibb.c --- 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 -#include - #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 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; } - - diff -r 3918ed48d7a8 -r 151b4054ce40 libpurple/protocols/jabber/ibb.h --- 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_ */ diff -r 3918ed48d7a8 -r 151b4054ce40 libpurple/protocols/jabber/si.c --- 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); } }