changeset 32384:3ed4800c5e17

propagate from branch 'im.pidgin.pidgin.2.x.y' (head 051fd526bf8c89add8c1960afd9d0c7ee77b091a) to branch 'im.pidgin.pidgin' (head 11e7ee045ef2505f4215dd05ca8d6c8735e81ab6)
author Mark Doliner <mark@kingant.net>
date Fri, 09 Dec 2011 18:35:12 +0000
parents 7967bb7db191 (diff) d413405ab2fb (current diff)
children 969fb5413ea5
files ChangeLog ChangeLog.API configure.ac gaim-uninstalled.pc.in gaim.pc.in libpurple/gaim-compat.h libpurple/protocols/oscar/family_feedbag.c libpurple/protocols/silc/ops.c libpurple/protocols/silc10/Makefile.am libpurple/protocols/silc10/Makefile.mingw libpurple/protocols/silc10/README libpurple/protocols/silc10/TODO libpurple/protocols/silc10/buddy.c libpurple/protocols/silc10/chat.c libpurple/protocols/silc10/ft.c libpurple/protocols/silc10/ops.c libpurple/protocols/silc10/pk.c libpurple/protocols/silc10/silc.c libpurple/protocols/silc10/silcpurple.h libpurple/protocols/silc10/util.c libpurple/protocols/silc10/wb.c libpurple/protocols/silc10/wb.h libpurple/purple-2-uninstalled.pc.in libpurple/purple-2.pc.in libpurple/purple-uninstalled.pc.in libpurple/purple.pc.in pidgin/gtkdocklet-gtk.c pidgin/gtkgaim-compat.h pidgin/pidgin-2-uninstalled.pc.in pidgin/pidgin-2.pc.in pidgin/pidgin-uninstalled.pc.in pidgin/pidgin.pc.in
diffstat 8 files changed, 203 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun Dec 04 22:11:15 2011 +0000
+++ b/ChangeLog	Fri Dec 09 18:35:12 2011 +0000
@@ -37,10 +37,15 @@
 	  (#14529)
 	* Support file transfers up to ~9 EiB.
 
-version 2.10.1 (10/11/2011):
+version 2.10.1 (12/06/2011):
 	Finch:
 	* Fix compilation on OpenBSD.
 
+	AIM and ICQ:
+	* Fix remotely-triggerable crashes by validating strings in a few
+	  messages related to buddy list management.  Thanks to Evgeny Boger
+	  for reporting this!  (#14682)
+
 	Bonjour:
 	* IPv6 fixes (Linus Lüssing)
 
@@ -48,9 +53,13 @@
 	* Fix problems linking against GnuTLS. (#14544)
 
 	IRC:
-	* Fix a leak when admitting UTF-8 text with a non-UTF-8 primary
+	* Fix a memory leak when admitting UTF-8 text with a non-UTF-8 primary
 	  encoding.  (#14700)
 
+	Jabber:
+	* Fix crashes and memory leaks when receiving malformed voice
+	  and video requests.  Thanks to Thijs Alkemade for reporting this!
+
 	Sametime:
 	* Separate "username" and "server" when adding new Sametime accounts.
 	  (#14608)
--- a/ChangeLog.API	Sun Dec 04 22:11:15 2011 +0000
+++ b/ChangeLog.API	Fri Dec 09 18:35:12 2011 +0000
@@ -240,6 +240,9 @@
 		* xmlnode_set_attrib_with_namespace
 		* xmlnode_set_attrib_with_prefix
 
+version 2.10.1:
+	* No changes
+
 version 2.10.0:
 	libpurple:
 		Added:
--- a/libpurple/protocols/jabber/jingle/jingle.c	Sun Dec 04 22:11:15 2011 +0000
+++ b/libpurple/protocols/jabber/jingle/jingle.c	Fri Dec 09 18:35:12 2011 +0000
@@ -126,7 +126,7 @@
 		if (local_content != NULL) {
 			const gchar *senders = xmlnode_get_attrib(content, "senders");
 			gchar *local_senders = jingle_content_get_senders(local_content);
-			if (strcmp(senders, local_senders))
+			if (!purple_strequal(senders, local_senders))
 				jingle_content_modify(local_content, senders);
 			g_free(local_senders);
 		} else {
--- a/libpurple/protocols/jabber/jingle/rtp.c	Sun Dec 04 22:11:15 2011 +0000
+++ b/libpurple/protocols/jabber/jingle/rtp.c	Fri Dec 09 18:35:12 2011 +0000
@@ -577,11 +577,12 @@
 	guint num_params;
 
 	/* maybe this create ought to just be in initiate and handle initiate */
-	if (media == NULL)
+	if (media == NULL) {
 		media = jingle_rtp_create_media(content);
 
-	if (media == NULL)
-		return FALSE;
+		if (media == NULL)
+			return FALSE;
+	}
 
 	name = jingle_content_get_name(content);
 	media_type = jingle_rtp_get_media_type(content);
@@ -589,6 +590,16 @@
 	senders = jingle_content_get_senders(content);
 	transport = jingle_content_get_transport(content);
 
+	if (media_type == NULL) {
+		g_free(name);
+		g_free(remote_jid);
+		g_free(senders);
+		g_free(params);
+		g_object_unref(transport);
+		g_object_unref(session);
+		return FALSE;
+	}
+
 	if (JINGLE_IS_RAWUDP(transport))
 		transmitter = "rawudp";
 	else if (JINGLE_IS_ICEUDP(transport))
@@ -597,17 +608,17 @@
 		transmitter = "notransmitter";
 	g_object_unref(transport);
 
-	is_audio = !strcmp(media_type, "audio");
+	is_audio = g_str_equal(media_type, "audio");
 
-	if (!strcmp(senders, "both"))
-		type = is_audio == TRUE ? PURPLE_MEDIA_AUDIO
+	if (purple_strequal(senders, "both"))
+		type = is_audio ? PURPLE_MEDIA_AUDIO
 				: PURPLE_MEDIA_VIDEO;
-	else if ((strcmp(senders, "initiator") == 0) ==
+	else if (purple_strequal(senders, "initiator") ==
 			jingle_session_is_initiator(session))
-		type = is_audio == TRUE ? PURPLE_MEDIA_SEND_AUDIO
+		type = is_audio ? PURPLE_MEDIA_SEND_AUDIO
 				: PURPLE_MEDIA_SEND_VIDEO;
 	else
-		type = is_audio == TRUE ? PURPLE_MEDIA_RECV_AUDIO
+		type = is_audio ? PURPLE_MEDIA_RECV_AUDIO
 				: PURPLE_MEDIA_RECV_VIDEO;
 
 	params =
@@ -615,7 +626,17 @@
 			NULL, NULL, &num_params);
 
 	creator = jingle_content_get_creator(content);
-	if (!strcmp(creator, "initiator"))
+	if (creator == NULL) {
+		g_free(name);
+		g_free(media_type);
+		g_free(remote_jid);
+		g_free(senders);
+		g_free(params);
+		g_object_unref(session);
+		return FALSE;
+	}
+
+	if (g_str_equal(creator, "initiator"))
 		is_creator = jingle_session_is_initiator(session);
 	else
 		is_creator = !jingle_session_is_initiator(session);
@@ -624,6 +645,8 @@
 	if(!purple_media_add_stream(media, name, remote_jid,
 			type, is_creator, transmitter, num_params, params)) {
 		purple_media_end(media, NULL, NULL);
+		/* TODO: How much clean-up is necessary here? (does calling
+		         purple_media_end lead to cleaning up Jingle structs?) */
 		return FALSE;
 	}
 
@@ -645,9 +668,22 @@
 	const char *encoding_name,*id, *clock_rate;
 	PurpleMediaCodec *codec;
 	const gchar *media = xmlnode_get_attrib(description, "media");
-	PurpleMediaSessionType type =
-			!strcmp(media, "video") ? PURPLE_MEDIA_VIDEO :
-			!strcmp(media, "audio") ? PURPLE_MEDIA_AUDIO : 0;
+	PurpleMediaSessionType type;
+
+	if (media == NULL) {
+		purple_debug_warning("jingle-rtp", "missing media type\n");
+		return NULL;
+	}
+
+	if (g_str_equal(media, "video")) {
+		type = PURPLE_MEDIA_VIDEO;
+	} else if (g_str_equal(media, "audio")) {
+		type = PURPLE_MEDIA_AUDIO;
+	} else {
+		purple_debug_warning("jingle-rtp", "unknown media type: %s\n",
+				media);
+		return NULL;
+	}
 
 	for (codec_element = xmlnode_get_child(description, "payload-type") ;
 		 codec_element ;
@@ -768,19 +804,19 @@
 	switch (action) {
 		case JINGLE_SESSION_ACCEPT:
 		case JINGLE_SESSION_INITIATE: {
-			JingleSession *session = jingle_content_get_session(content);
-			JingleTransport *transport = jingle_transport_parse(
-					xmlnode_get_child(xmlcontent, "transport"));
-			xmlnode *description = xmlnode_get_child(xmlcontent, "description");
-			GList *candidates = jingle_rtp_transport_to_candidates(transport);
-			GList *codecs = jingle_rtp_parse_codecs(description);
-			gchar *name = jingle_content_get_name(content);
-			gchar *remote_jid =
-					jingle_session_get_remote_jid(session);
+			JingleSession *session;
+			JingleTransport *transport;
+			xmlnode *description;
+			GList *candidates;
+			GList *codecs;
+			gchar *name;
+			gchar *remote_jid;
 			PurpleMedia *media;
 
+			session = jingle_content_get_session(content);
+
 			if (action == JINGLE_SESSION_INITIATE &&
-					jingle_rtp_init_media(content) == FALSE) {
+					!jingle_rtp_init_media(content)) {
 				/* XXX: send error */
 				jabber_iq_send(jingle_session_terminate_packet(
 						session, "general-error"));
@@ -788,6 +824,14 @@
 				break;
 			}
 
+			transport = jingle_transport_parse(
+					xmlnode_get_child(xmlcontent, "transport"));
+			description = xmlnode_get_child(xmlcontent, "description");
+			candidates = jingle_rtp_transport_to_candidates(transport);
+			codecs = jingle_rtp_parse_codecs(description);
+			name = jingle_content_get_name(content);
+			remote_jid = jingle_session_get_remote_jid(session);
+
 			media = jingle_rtp_get_media(session);
 			purple_media_set_remote_codecs(media,
 					name, remote_jid, codecs);
--- a/libpurple/protocols/jabber/jingle/session.c	Sun Dec 04 22:11:15 2011 +0000
+++ b/libpurple/protocols/jabber/jingle/session.c	Fri Dec 09 18:35:12 2011 +0000
@@ -288,7 +288,7 @@
 	if (!js->sessions) {
 		purple_debug_info("jingle",
 				"Creating hash table for sessions\n");
-		js->sessions = g_hash_table_new(g_str_hash, g_str_equal);
+		js->sessions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
 	}
 	purple_debug_info("jingle",
 			"inserting session with key: %s into table\n", sid);
@@ -411,26 +411,24 @@
 			xmlnode_new("jingle");
 	gchar *local_jid = jingle_session_get_local_jid(session);
 	gchar *remote_jid = jingle_session_get_remote_jid(session);
+	gchar *sid = jingle_session_get_sid(session);
 
 	xmlnode_set_namespace(jingle, JINGLE);
 	xmlnode_set_attrib(jingle, "action", jingle_get_action_name(action));
 
 	if (jingle_session_is_initiator(session)) {
-		xmlnode_set_attrib(jingle, "initiator",
-				jingle_session_get_local_jid(session));
-		xmlnode_set_attrib(jingle, "responder",
-				jingle_session_get_remote_jid(session));
+		xmlnode_set_attrib(jingle, "initiator", local_jid);
+		xmlnode_set_attrib(jingle, "responder", remote_jid);
 	} else {
-		xmlnode_set_attrib(jingle, "initiator",
-				jingle_session_get_remote_jid(session));
-		xmlnode_set_attrib(jingle, "responder",
-				jingle_session_get_local_jid(session));
+		xmlnode_set_attrib(jingle, "initiator", remote_jid);
+		xmlnode_set_attrib(jingle, "responder", local_jid);
 	}
 
+	xmlnode_set_attrib(jingle, "sid", sid);
+
 	g_free(local_jid);
 	g_free(remote_jid);
-
-	xmlnode_set_attrib(jingle, "sid", jingle_session_get_sid(session));
+	g_free(sid);
 
 	return jingle;
 }
@@ -508,11 +506,16 @@
 JingleContent *
 jingle_session_find_content(JingleSession *session, const gchar *name, const gchar *creator)
 {
-	GList *iter = session->priv->contents;
+	GList *iter;
+
+	if (name == NULL)
+		return NULL;
+
+	iter = session->priv->contents;
 	for (; iter; iter = g_list_next(iter)) {
 		JingleContent *content = iter->data;
 		gchar *cname = jingle_content_get_name(content);
-		gboolean result = !strcmp(name, cname);
+		gboolean result = g_str_equal(name, cname);
 		g_free(cname);
 
 		if (creator != NULL) {
@@ -530,11 +533,16 @@
 JingleContent *
 jingle_session_find_pending_content(JingleSession *session, const gchar *name, const gchar *creator)
 {
-	GList *iter = session->priv->pending_contents;
+	GList *iter;
+
+	if (name == NULL)
+		return NULL;
+
+	iter = session->priv->pending_contents;
 	for (; iter; iter = g_list_next(iter)) {
 		JingleContent *content = iter->data;
 		gchar *cname = jingle_content_get_name(content);
-		gboolean result = !strcmp(name, cname);
+		gboolean result = g_str_equal(name, cname);
 		g_free(cname);
 
 		if (creator != NULL) {
--- a/libpurple/protocols/oscar/family_feedbag.c	Sun Dec 04 22:11:15 2011 +0000
+++ b/libpurple/protocols/oscar/family_feedbag.c	Fri Dec 09 18:35:12 2011 +0000
@@ -1674,18 +1674,35 @@
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	guint16 tmp;
-	char *bn, *msg;
+	char *bn, *msg, *tmpstr;
 
 	/* Read buddy name */
-	if ((tmp = byte_stream_get8(bs)))
-		bn = byte_stream_getstr(bs, tmp);
-	else
-		bn = NULL;
+	tmp = byte_stream_get8(bs);
+	if (!tmp) {
+		purple_debug_warning("oscar", "Dropping auth grant SNAC "
+				"because username was empty\n");
+		return 0;
+	}
+	bn = byte_stream_getstr(bs, tmp);
+	if (!g_utf8_validate(bn, -1, NULL)) {
+		purple_debug_warning("oscar", "Dropping auth grant SNAC "
+				"because the username was not valid UTF-8\n");
+		g_free(bn);
+	}
 
-	/* Read message (null terminated) */
-	if ((tmp = byte_stream_get16(bs)))
+	/* Read message */
+	tmp = byte_stream_get16(bs);
+	if (tmp) {
 		msg = byte_stream_getstr(bs, tmp);
-	else
+		if (!g_utf8_validate(msg, -1, NULL)) {
+			/* Ugh, msg isn't UTF8.  Let's salvage. */
+			purple_debug_warning("oscar", "Got non-UTF8 message in auth "
+					"grant from %s\n", bn);
+			tmpstr = purple_utf8_salvage(msg);
+			g_free(msg);
+			msg = tmpstr;
+		}
+	} else
 		msg = NULL;
 
 	/* Unknown */
@@ -1748,18 +1765,35 @@
 	int ret = 0;
 	aim_rxcallback_t userfunc;
 	guint16 tmp;
-	char *bn, *msg;
+	char *bn, *msg, *tmpstr;
 
 	/* Read buddy name */
-	if ((tmp = byte_stream_get8(bs)))
-		bn = byte_stream_getstr(bs, tmp);
-	else
-		bn = NULL;
+	tmp = byte_stream_get8(bs);
+	if (!tmp) {
+		purple_debug_warning("oscar", "Dropping auth request SNAC "
+				"because username was empty\n");
+		return 0;
+	}
+	bn = byte_stream_getstr(bs, tmp);
+	if (!g_utf8_validate(bn, -1, NULL)) {
+		purple_debug_warning("oscar", "Dropping auth request SNAC "
+				"because the username was not valid UTF-8\n");
+		g_free(bn);
+	}
 
-	/* Read message (null terminated) */
-	if ((tmp = byte_stream_get16(bs)))
+	/* Read message */
+	tmp = byte_stream_get16(bs);
+	if (tmp) {
 		msg = byte_stream_getstr(bs, tmp);
-	else
+		if (!g_utf8_validate(msg, -1, NULL)) {
+			/* Ugh, msg isn't UTF8.  Let's salvage. */
+			purple_debug_warning("oscar", "Got non-UTF8 message in auth "
+					"request from %s\n", bn);
+			tmpstr = purple_utf8_salvage(msg);
+			g_free(msg);
+			msg = tmpstr;
+		}
+	} else
 		msg = NULL;
 
 	/* Unknown */
@@ -1832,21 +1866,38 @@
 	aim_rxcallback_t userfunc;
 	guint16 tmp;
 	guint8 reply;
-	char *bn, *msg;
+	char *bn, *msg, *tmpstr;
 
 	/* Read buddy name */
-	if ((tmp = byte_stream_get8(bs)))
-		bn = byte_stream_getstr(bs, tmp);
-	else
-		bn = NULL;
+	tmp = byte_stream_get8(bs);
+	if (!tmp) {
+		purple_debug_warning("oscar", "Dropping auth reply SNAC "
+				"because username was empty\n");
+		return 0;
+	}
+	bn = byte_stream_getstr(bs, tmp);
+	if (!g_utf8_validate(bn, -1, NULL)) {
+		purple_debug_warning("oscar", "Dropping auth reply SNAC "
+				"because the username was not valid UTF-8\n");
+		g_free(bn);
+	}
 
 	/* Read reply */
 	reply = byte_stream_get8(bs);
 
-	/* Read message (null terminated) */
-	if ((tmp = byte_stream_get16(bs)))
+	/* Read message */
+	tmp = byte_stream_get16(bs);
+	if (tmp) {
 		msg = byte_stream_getstr(bs, tmp);
-	else
+		if (!g_utf8_validate(msg, -1, NULL)) {
+			/* Ugh, msg isn't UTF8.  Let's salvage. */
+			purple_debug_warning("oscar", "Got non-UTF8 message in auth "
+					"reply from %s\n", bn);
+			tmpstr = purple_utf8_salvage(msg);
+			g_free(msg);
+			msg = tmpstr;
+		}
+	} else
 		msg = NULL;
 
 	/* Unknown */
@@ -1872,10 +1923,18 @@
 	char *bn;
 
 	/* Read buddy name */
-	if ((tmp = byte_stream_get8(bs)))
-		bn = byte_stream_getstr(bs, tmp);
-	else
-		bn = NULL;
+	tmp = byte_stream_get8(bs);
+	if (!tmp) {
+		purple_debug_warning("oscar", "Dropping 'you were added' SNAC "
+				"because username was empty\n");
+		return 0;
+	}
+	bn = byte_stream_getstr(bs, tmp);
+	if (!g_utf8_validate(bn, -1, NULL)) {
+		purple_debug_warning("oscar", "Dropping 'you were added' SNAC "
+				"because the username was not valid UTF-8\n");
+		g_free(bn);
+	}
 
 	if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
 		ret = userfunc(od, conn, frame, bn);
--- a/libpurple/protocols/silc/ops.c	Sun Dec 04 22:11:15 2011 +0000
+++ b/libpurple/protocols/silc/ops.c	Fri Dec 09 18:35:12 2011 +0000
@@ -332,10 +332,17 @@
 	}
 
 	if (flags & SILC_MESSAGE_FLAG_UTF8) {
-		tmp = g_markup_escape_text((const char *)message, -1);
+		const char *msg = (const char *)message;
+		char *salvaged = NULL;
+		if (!g_utf8_validate((const char *)message, -1, NULL)) {
+			salvaged = purple_utf8_salvage((const char *)message);
+			msg = salvaged;
+		}
+		tmp = g_markup_escape_text(msg, -1);
 		/* Send to Purple */
 		serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)),
 				 sender->nickname, 0, tmp, time(NULL));
+		g_free(salvaged);
 		g_free(tmp);
 	}
 }
--- a/po/ChangeLog	Sun Dec 04 22:11:15 2011 +0000
+++ b/po/ChangeLog	Fri Dec 09 18:35:12 2011 +0000
@@ -1,5 +1,8 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+version 2.10.1
+	* No changes
+
 version 2.10.0
 	* Afrikaans translation updated (Friedel Wolff)
 	* Albanian translation updated (Besnik Bleta)