diff -up pidgin-2.10.7/libpurple/protocols/irc/msgs.c.CVE-2014-0020 pidgin-2.10.7/libpurple/protocols/irc/msgs.c --- pidgin-2.10.7/libpurple/protocols/irc/msgs.c.CVE-2014-0020 2013-02-11 04:16:52.000000000 -0500 +++ pidgin-2.10.7/libpurple/protocols/irc/msgs.c 2014-01-29 23:28:32.833335259 -0500 @@ -20,6 +20,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ +/* + * Note: If you change any of these functions to use additional args you + * MUST ensure the arg count is correct in parse.c. Otherwise it may be + * possible for a malicious server or man-in-the-middle to trigger a crash. + */ + #include "internal.h" #include "conversation.h" @@ -203,9 +209,6 @@ void irc_msg_features(struct irc_conn *i gchar **features; int i; - if (!args || !args[0] || !args[1]) - return; - features = g_strsplit(args[1], " ", -1); for (i = 0; features[i]; i++) { char *val; @@ -220,9 +223,6 @@ void irc_msg_features(struct irc_conn *i void irc_msg_luser(struct irc_conn *irc, const char *name, const char *from, char **args) { - if (!args || !args[0]) - return; - if (!strcmp(name, "251")) { /* 251 is required, so we pluck our nick from here and * finalize connection */ @@ -238,9 +238,6 @@ void irc_msg_away(struct irc_conn *irc, PurpleConnection *gc; char *msg; - if (!args || !args[1]) - return; - if (irc->whois.nick && !purple_utf8_strcasecmp(irc->whois.nick, args[1])) { /* We're doing a whois, show this in the whois dialog */ irc_msg_whois(irc, name, from, args); @@ -259,8 +256,7 @@ void irc_msg_badmode(struct irc_conn *ir { PurpleConnection *gc = purple_account_get_connection(irc->account); - if (!args || !args[1] || !gc) - return; + g_return_if_fail(gc); purple_notify_error(gc, NULL, _("Bad mode"), args[1]); } @@ -269,17 +265,13 @@ void irc_msg_ban(struct irc_conn *irc, c { PurpleConversation *convo; - if (!args || !args[0] || !args[1]) - return; - convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account); if (!strcmp(name, "367")) { char *msg = NULL; /* Ban list entry */ - if (!args[2]) - return; + g_return_if_fail(args[2]); if (args[3] && args[4]) { /* This is an extended syntax, not in RFC 1459 */ int t1 = atoi(args[4]); @@ -315,8 +307,7 @@ void irc_msg_banned(struct irc_conn *irc PurpleConnection *gc = purple_account_get_connection(irc->account); char *buf; - if (!args || !args[1] || !gc) - return; + g_return_if_fail(gc); buf = g_strdup_printf(_("You are banned from %s."), args[1]); purple_notify_error(gc, _("Banned"), _("Banned"), buf); @@ -328,9 +319,6 @@ void irc_msg_banfull(struct irc_conn *ir PurpleConversation *convo; char *buf, *nick; - if (!args || !args[0] || !args[1] || !args[2]) - return; - convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account); if (!convo) return; @@ -349,9 +337,6 @@ void irc_msg_chanmode(struct irc_conn *i PurpleConversation *convo; char *buf, *escaped; - if (!args || !args[1] || !args[2]) - return; - convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account); if (!convo) /* XXX punt on channels we are not in for now */ return; @@ -489,13 +474,6 @@ void irc_msg_who(struct irc_conn *irc, c PurpleConvChatBuddyFlags flags; GList *keys = NULL, *values = NULL; - if (!args || !args[0] || !args[1] || !args[2] || !args[3] - || !args[4] || !args[5] || !args[6] || !args[7]) { - purple_debug(PURPLE_DEBUG_ERROR, "irc", - "Got a WHO response with not enough arguments\n"); - return; - } - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account); if (!conv) { purple_debug(PURPLE_DEBUG_ERROR, "irc","Got a WHO response for %s, which doesn't exist\n", args[1]); @@ -571,9 +549,6 @@ void irc_msg_list(struct irc_conn *irc, PurpleRoomlistRoom *room; char *topic; - if (!args[0] || !args[1] || !args[2] || !args[3]) - return; - if (!purple_roomlist_get_in_progress(irc->roomlist)) { purple_debug_warning("irc", "Buggy server didn't send RPL_LISTSTART.\n"); purple_roomlist_set_in_progress(irc->roomlist, TRUE); @@ -595,13 +570,13 @@ void irc_msg_topic(struct irc_conn *irc, PurpleConversation *convo; if (!strcmp(name, "topic")) { - if (!args[0] || !args[1]) - return; + g_return_if_fail(args[0]); + g_return_if_fail(args[1]); chan = args[0]; topic = irc_mirc2txt (args[1]); } else { - if (!args[0] || !args[1] || !args[2]) - return; + g_return_if_fail(args[1]); + g_return_if_fail(args[2]); chan = args[1]; topic = irc_mirc2txt (args[2]); } @@ -652,9 +627,6 @@ void irc_msg_topicinfo(struct irc_conn * struct tm *tm; time_t t; char *msg, *timestamp, *datestamp; - - if (!args || !args[1] || !args[2] || !args[3]) - return; convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account); if (!convo) { @@ -683,8 +655,7 @@ void irc_msg_unknown(struct irc_conn *ir PurpleConnection *gc = purple_account_get_connection(irc->account); char *buf; - if (!args || !args[1] || !gc) - return; + g_return_if_fail(gc); buf = g_strdup_printf(_("Unknown message '%s'"), args[1]); purple_notify_error(gc, _("Unknown message"), buf, _("The IRC server received a message it did not understand.")); @@ -776,9 +747,6 @@ void irc_msg_motd(struct irc_conn *irc, { char *escaped; - if (!args || !args[0]) - return; - if (!strcmp(name, "375")) { if (irc->motd) g_string_free(irc->motd, TRUE); @@ -815,11 +783,9 @@ void irc_msg_motd(struct irc_conn *irc, void irc_msg_time(struct irc_conn *irc, const char *name, const char *from, char **args) { - PurpleConnection *gc; + PurpleConnection *gc = purple_account_get_connection(irc->account); - gc = purple_account_get_connection(irc->account); - if (gc == NULL || args == NULL || args[2] == NULL) - return; + g_return_if_fail(gc); purple_notify_message(gc, PURPLE_NOTIFY_MSG_INFO, _("Time Response"), _("The IRC server's local time is:"), @@ -830,8 +796,7 @@ void irc_msg_nochan(struct irc_conn *irc { PurpleConnection *gc = purple_account_get_connection(irc->account); - if (gc == NULL || args == NULL || args[1] == NULL) - return; + g_return_if_fail(gc); purple_notify_error(gc, NULL, _("No such channel"), args[1]); } @@ -892,9 +857,6 @@ void irc_msg_notop(struct irc_conn *irc, { PurpleConversation *convo; - if (!args || !args[1] || !args[2]) - return; - convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account); if (!convo) return; @@ -908,8 +870,7 @@ void irc_msg_invite(struct irc_conn *irc GHashTable *components; gchar *nick; - if (!args || !args[1] || !gc) - return; + g_return_if_fail(gc); components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); nick = irc_mask_nick(from); @@ -925,8 +886,7 @@ void irc_msg_inviteonly(struct irc_conn PurpleConnection *gc = purple_account_get_connection(irc->account); char *buf; - if (!args || !args[1] || !gc) - return; + g_return_if_fail(gc); buf = g_strdup_printf(_("Joining %s requires an invitation."), args[1]); purple_notify_error(gc, _("Invitation only"), _("Invitation only"), buf); @@ -939,9 +899,6 @@ void irc_msg_ison(struct irc_conn *irc, struct irc_buddy *ib; int i; - if (!args || !args[1]) - return; - nicks = g_strsplit(args[1], " ", -1); for (i = 0; nicks[i]; i++) { if ((ib = g_hash_table_lookup(irc->buddies, (gconstpointer)nicks[i])) == NULL) { @@ -982,14 +939,13 @@ void irc_msg_join(struct irc_conn *irc, PurpleConvChat *chat; PurpleConvChatBuddy *cb; - char *nick = irc_mask_nick(from), *userhost, *buf; + char *nick, *userhost, *buf; struct irc_buddy *ib; static int id = 1; - if (!gc) { - g_free(nick); - return; - } + g_return_if_fail(gc); + + nick = irc_mask_nick(from); if (!purple_utf8_strcasecmp(nick, purple_connection_get_display_name(gc))) { /* We are joining a channel for the first time */ @@ -1049,12 +1005,11 @@ void irc_msg_kick(struct irc_conn *irc, { PurpleConnection *gc = purple_account_get_connection(irc->account); PurpleConversation *convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[0], irc->account); - char *nick = irc_mask_nick(from), *buf; + char *nick, *buf; - if (!gc) { - g_free(nick); - return; - } + g_return_if_fail(gc); + + nick = irc_mask_nick(from); if (!convo) { purple_debug(PURPLE_DEBUG_ERROR, "irc", "Received a KICK for unknown channel %s\n", args[0]); @@ -1197,9 +1152,6 @@ void irc_msg_nickused(struct irc_conn *i char *newnick, *buf, *end; PurpleConnection *gc = purple_account_get_connection(irc->account); - if (!args || !args[1]) - return; - if (gc && purple_connection_get_state(gc) == PURPLE_CONNECTED) { /* We only want to do the following dance if the connection has not been successfully completed. If it has, just @@ -1238,9 +1190,6 @@ void irc_msg_nickused(struct irc_conn *i void irc_msg_notice(struct irc_conn *irc, const char *name, const char *from, char **args) { - if (!args || !args[0] || !args[1]) - return; - irc_msg_handle_privmsg(irc, name, from, args[0], args[1], TRUE); } @@ -1248,8 +1197,7 @@ void irc_msg_nochangenick(struct irc_con { PurpleConnection *gc = purple_account_get_connection(irc->account); - if (!args || !args[2] || !gc) - return; + g_return_if_fail(gc); purple_notify_error(gc, _("Cannot change nick"), _("Could not change nick"), args[2]); } @@ -1260,8 +1208,7 @@ void irc_msg_part(struct irc_conn *irc, PurpleConversation *convo; char *nick, *msg, *channel; - if (!args || !args[0] || !gc) - return; + g_return_if_fail(gc); /* Undernet likes to :-quote the channel name, for no good reason * that I can see. This catches that. */ @@ -1294,8 +1241,6 @@ void irc_msg_part(struct irc_conn *irc, void irc_msg_ping(struct irc_conn *irc, const char *name, const char *from, char **args) { char *buf; - if (!args || !args[0]) - return; buf = irc_format(irc, "v:", "PONG", args[0]); irc_send(irc, buf); @@ -1309,9 +1254,6 @@ void irc_msg_pong(struct irc_conn *irc, char **parts, *msg; time_t oldstamp; - if (!args || !args[1]) - return; - parts = g_strsplit(args[1], " ", 2); if (!parts[0] || !parts[1]) { @@ -1345,9 +1287,6 @@ void irc_msg_pong(struct irc_conn *irc, void irc_msg_privmsg(struct irc_conn *irc, const char *name, const char *from, char **args) { - if (!args || !args[0] || !args[1]) - return; - irc_msg_handle_privmsg(irc, name, from, args[0], args[1], FALSE); } @@ -1401,8 +1340,7 @@ void irc_msg_regonly(struct irc_conn *ir PurpleConversation *convo; char *msg; - if (!args || !args[1] || !args[2] || !gc) - return; + g_return_if_fail(gc); convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account); if (convo) { @@ -1424,8 +1362,7 @@ void irc_msg_quit(struct irc_conn *irc, struct irc_buddy *ib; char *data[2]; - if (!args || !args[0] || !gc) - return; + g_return_if_fail(gc); data[0] = irc_mask_nick(from); data[1] = args[0]; @@ -1445,9 +1382,6 @@ void irc_msg_unavailable(struct irc_conn { PurpleConnection *gc = purple_account_get_connection(irc->account); - if (!args || !args[1]) - return; - purple_notify_error(gc, NULL, _("Nick or channel is temporarily unavailable."), args[1]); } @@ -1456,8 +1390,7 @@ void irc_msg_wallops(struct irc_conn *ir PurpleConnection *gc = purple_account_get_connection(irc->account); char *nick, *msg; - if (!args || !args[0] || !gc) - return; + g_return_if_fail(gc); nick = irc_mask_nick(from); msg = g_strdup_printf (_("Wallops from %s"), nick); @@ -1633,7 +1566,7 @@ irc_msg_cap(struct irc_conn *irc, const PurpleConnection *gc = purple_account_get_connection(irc->account); const char *mech_list = NULL; - if (!args[1] || !args[2] || strncmp(args[2], "sasl ", 6)) + if (strncmp(args[2], "sasl ", 6)) return; if (strncmp(args[1], "ACK", 4)) { const char *tmp = _("SASL authentication failed: Server does not support SASL authentication."); diff -up pidgin-2.10.7/libpurple/protocols/irc/parse.c.CVE-2014-0020 pidgin-2.10.7/libpurple/protocols/irc/parse.c --- pidgin-2.10.7/libpurple/protocols/irc/parse.c.CVE-2014-0020 2013-02-11 04:16:52.000000000 -0500 +++ pidgin-2.10.7/libpurple/protocols/irc/parse.c 2014-01-29 23:28:32.834335227 -0500 @@ -50,80 +50,85 @@ extern PurplePlugin *_irc_plugin; static struct _irc_msg { char *name; char *format; + + /** The required parameter count, based on values we use, not protocol + * specification. */ + int req_cnt; + void (*cb)(struct irc_conn *irc, const char *name, const char *from, char **args); } _irc_msgs[] = { - { "005", "n*", irc_msg_features }, /* Feature list */ - { "251", "n:", irc_msg_luser }, /* Client & Server count */ - { "255", "n:", irc_msg_luser }, /* Client & Server count Mk. II */ - { "301", "nn:", irc_msg_away }, /* User is away */ - { "303", "n:", irc_msg_ison }, /* ISON reply */ - { "311", "nnvvv:", irc_msg_whois }, /* Whois user */ - { "312", "nnv:", irc_msg_whois }, /* Whois server */ - { "313", "nn:", irc_msg_whois }, /* Whois ircop */ - { "317", "nnvv", irc_msg_whois }, /* Whois idle */ - { "318", "nt:", irc_msg_endwhois }, /* End of WHOIS */ - { "319", "nn:", irc_msg_whois }, /* Whois channels */ - { "320", "nn:", irc_msg_whois }, /* Whois (fn ident) */ - { "314", "nnnvv:", irc_msg_whois }, /* Whowas user */ - { "315", "nt:", irc_msg_who }, /* end of WHO channel */ - { "369", "nt:", irc_msg_endwhois }, /* End of WHOWAS */ - { "321", "*", irc_msg_list }, /* Start of list */ - { "322", "ncv:", irc_msg_list }, /* List. */ - { "323", ":", irc_msg_list }, /* End of list. */ - { "324", "ncv:", irc_msg_chanmode }, /* Channel modes */ - { "331", "nc:", irc_msg_topic }, /* No channel topic */ - { "332", "nc:", irc_msg_topic }, /* Channel topic */ - { "333", "ncvv", irc_msg_topicinfo }, /* Topic setter stuff */ - { "352", "ncvvvnv:", irc_msg_who }, /* Channel WHO */ - { "353", "nvc:", irc_msg_names }, /* Names list */ - { "366", "nc:", irc_msg_names }, /* End of names */ - { "367", "ncnnv", irc_msg_ban }, /* Ban list */ - { "368", "nc:", irc_msg_ban }, /* End of ban list */ - { "372", "n:", irc_msg_motd }, /* MOTD */ - { "375", "n:", irc_msg_motd }, /* Start MOTD */ - { "376", "n:", irc_msg_motd }, /* End of MOTD */ - { "391", "nv:", irc_msg_time }, /* Time reply */ - { "401", "nt:", irc_msg_nonick }, /* No such nick/chan */ - { "406", "nt:", irc_msg_nonick }, /* No such nick for WHOWAS */ - { "403", "nc:", irc_msg_nochan }, /* No such channel */ - { "404", "nt:", irc_msg_nosend }, /* Cannot send to chan */ - { "421", "nv:", irc_msg_unknown }, /* Unknown command */ - { "422", "n:", irc_msg_motd }, /* MOTD file missing */ - { "432", "vn:", irc_msg_badnick }, /* Erroneous nickname */ - { "433", "vn:", irc_msg_nickused }, /* Nickname already in use */ - { "437", "nc:", irc_msg_unavailable }, /* Nick/channel is unavailable */ - { "438", "nn:", irc_msg_nochangenick }, /* Nick may not change */ - { "442", "nc:", irc_msg_notinchan }, /* Not in channel */ - { "473", "nc:", irc_msg_inviteonly }, /* Tried to join invite-only */ - { "474", "nc:", irc_msg_banned }, /* Banned from channel */ - { "477", "nc:", irc_msg_regonly }, /* Registration Required */ - { "478", "nct:", irc_msg_banfull }, /* Banlist is full */ - { "482", "nc:", irc_msg_notop }, /* Need to be op to do that */ - { "501", "n:", irc_msg_badmode }, /* Unknown mode flag */ - { "506", "nc:", irc_msg_nosend }, /* Must identify to send */ - { "515", "nc:", irc_msg_regonly }, /* Registration required */ + { "005", "n*", 2, irc_msg_features }, /* Feature list */ + { "251", "n:", 1, irc_msg_luser }, /* Client & Server count */ + { "255", "n:", 1, irc_msg_luser }, /* Client & Server count Mk. II */ + { "301", "nn:", 3, irc_msg_away }, /* User is away */ + { "303", "n:", 2, irc_msg_ison }, /* ISON reply */ + { "311", "nnvvv:", 6, irc_msg_whois }, /* Whois user */ + { "312", "nnv:", 4, irc_msg_whois }, /* Whois server */ + { "313", "nn:", 2, irc_msg_whois }, /* Whois ircop */ + { "317", "nnvv", 4, irc_msg_whois }, /* Whois idle */ + { "318", "nt:", 2, irc_msg_endwhois }, /* End of WHOIS */ + { "319", "nn:", 3, irc_msg_whois }, /* Whois channels */ + { "320", "nn:", 2, irc_msg_whois }, /* Whois (fn ident) */ + { "314", "nnnvv:", 6, irc_msg_whois }, /* Whowas user */ + { "315", "nt:", 0, irc_msg_who }, /* end of WHO channel */ + { "369", "nt:", 2, irc_msg_endwhois }, /* End of WHOWAS */ + { "321", "*", 0, irc_msg_list }, /* Start of list */ + { "322", "ncv:", 4, irc_msg_list }, /* List. */ + { "323", ":", 0, irc_msg_list }, /* End of list. */ + { "324", "ncv:", 3, irc_msg_chanmode }, /* Channel modes */ + { "331", "nc:", 3, irc_msg_topic }, /* No channel topic */ + { "332", "nc:", 3, irc_msg_topic }, /* Channel topic */ + { "333", "ncvv", 4, irc_msg_topicinfo }, /* Topic setter stuff */ + { "352", "ncvvvnv:", 8, irc_msg_who }, /* Channel WHO */ + { "353", "nvc:", 4, irc_msg_names }, /* Names list */ + { "366", "nc:", 2, irc_msg_names }, /* End of names */ + { "367", "ncnnv", 3, irc_msg_ban }, /* Ban list */ + { "368", "nc:", 2, irc_msg_ban }, /* End of ban list */ + { "372", "n:", 1, irc_msg_motd }, /* MOTD */ + { "375", "n:", 1, irc_msg_motd }, /* Start MOTD */ + { "376", "n:", 1, irc_msg_motd }, /* End of MOTD */ + { "391", "nv:", 3, irc_msg_time }, /* Time reply */ + { "401", "nt:", 2, irc_msg_nonick }, /* No such nick/chan */ + { "406", "nt:", 2, irc_msg_nonick }, /* No such nick for WHOWAS */ + { "403", "nc:", 2, irc_msg_nochan }, /* No such channel */ + { "404", "nt:", 3, irc_msg_nosend }, /* Cannot send to chan */ + { "421", "nv:", 2, irc_msg_unknown }, /* Unknown command */ + { "422", "n:", 1, irc_msg_motd }, /* MOTD file missing */ + { "432", "vn:", 0, irc_msg_badnick }, /* Erroneous nickname */ + { "433", "vn:", 2, irc_msg_nickused }, /* Nickname already in use */ + { "437", "nc:", 2, irc_msg_unavailable }, /* Nick/channel is unavailable */ + { "438", "nn:", 3, irc_msg_nochangenick }, /* Nick may not change */ + { "442", "nc:", 3, irc_msg_notinchan }, /* Not in channel */ + { "473", "nc:", 2, irc_msg_inviteonly }, /* Tried to join invite-only */ + { "474", "nc:", 2, irc_msg_banned }, /* Banned from channel */ + { "477", "nc:", 3, irc_msg_regonly }, /* Registration Required */ + { "478", "nct:", 3, irc_msg_banfull }, /* Banlist is full */ + { "482", "nc:", 3, irc_msg_notop }, /* Need to be op to do that */ + { "501", "n:", 2, irc_msg_badmode }, /* Unknown mode flag */ + { "506", "nc:", 3, irc_msg_nosend }, /* Must identify to send */ + { "515", "nc:", 3, irc_msg_regonly }, /* Registration required */ #ifdef HAVE_CYRUS_SASL - { "903", "*", irc_msg_authok}, /* SASL auth successful */ - { "904", "*", irc_msg_authtryagain }, /* SASL auth failed, can recover */ - { "905", "*", irc_msg_authfail }, /* SASL auth failed */ - { "906", "*", irc_msg_authfail }, /* SASL auth failed */ - { "907", "*", irc_msg_authfail }, /* SASL auth failed */ - { "cap", "vv:", irc_msg_cap }, /* SASL capable */ + { "903", "*", 0, irc_msg_authok}, /* SASL auth successful */ + { "904", "*", 0, irc_msg_authtryagain }, /* SASL auth failed, can recover*/ + { "905", "*", 0, irc_msg_authfail }, /* SASL auth failed */ + { "906", "*", 0, irc_msg_authfail }, /* SASL auth failed */ + { "907", "*", 0, irc_msg_authfail }, /* SASL auth failed */ + { "cap", "vv:", 3, irc_msg_cap }, /* SASL capable */ #endif - { "invite", "n:", irc_msg_invite }, /* Invited */ - { "join", ":", irc_msg_join }, /* Joined a channel */ - { "kick", "cn:", irc_msg_kick }, /* KICK */ - { "mode", "tv:", irc_msg_mode }, /* MODE for channel */ - { "nick", ":", irc_msg_nick }, /* Nick change */ - { "notice", "t:", irc_msg_notice }, /* NOTICE recv */ - { "part", "c:", irc_msg_part }, /* Parted a channel */ - { "ping", ":", irc_msg_ping }, /* Received PING from server */ - { "pong", "v:", irc_msg_pong }, /* Received PONG from server */ - { "privmsg", "t:", irc_msg_privmsg }, /* Received private message */ - { "topic", "c:", irc_msg_topic }, /* TOPIC command */ - { "quit", ":", irc_msg_quit }, /* QUIT notice */ - { "wallops", ":", irc_msg_wallops }, /* WALLOPS command */ - { NULL, NULL, NULL } + { "invite", "n:", 2, irc_msg_invite }, /* Invited */ + { "join", ":", 1, irc_msg_join }, /* Joined a channel */ + { "kick", "cn:", 3, irc_msg_kick }, /* KICK */ + { "mode", "tv:", 2, irc_msg_mode }, /* MODE for channel */ + { "nick", ":", 1, irc_msg_nick }, /* Nick change */ + { "notice", "t:", 2, irc_msg_notice }, /* NOTICE recv */ + { "part", "c:", 1, irc_msg_part }, /* Parted a channel */ + { "ping", ":", 1, irc_msg_ping }, /* Received PING from server */ + { "pong", "v:", 2, irc_msg_pong }, /* Received PONG from server */ + { "privmsg", "t:", 2, irc_msg_privmsg }, /* Received private message */ + { "topic", "c:", 2, irc_msg_topic }, /* TOPIC command */ + { "quit", ":", 1, irc_msg_quit }, /* QUIT notice */ + { "wallops", ":", 1, irc_msg_wallops }, /* WALLOPS command */ + { NULL, NULL, 0, NULL } }; static struct _irc_user_cmd { @@ -660,6 +665,8 @@ void irc_parse_msg(struct irc_conn *irc, char *cur, *end, *tmp, *from, *msgname, *fmt, **args, *msg; guint i; PurpleConnection *gc = purple_account_get_connection(irc->account); + gboolean fmt_valid; + int args_cnt; irc->recv_time = time(NULL); @@ -716,7 +723,9 @@ void irc_parse_msg(struct irc_conn *irc, } g_free(msgname); + fmt_valid = TRUE; args = g_new0(char *, strlen(msgent->format)); + args_cnt = 0; for (cur = end, fmt = msgent->format, i = 0; fmt[i] && *cur++; i++) { switch (fmt[i]) { case 'v': @@ -753,12 +762,23 @@ void irc_parse_msg(struct irc_conn *irc, break; default: purple_debug(PURPLE_DEBUG_ERROR, "irc", "invalid message format character '%c'\n", fmt[i]); + fmt_valid = FALSE; break; } + if (fmt_valid) + args_cnt = i + 1; + } + if (G_UNLIKELY(!fmt_valid)) { + purple_debug_error("irc", "message format was invalid"); + } else if (G_LIKELY(args_cnt >= msgent->req_cnt)) { + tmp = irc_recv_convert(irc, from); + (msgent->cb)(irc, msgent->name, tmp, args); + g_free(tmp); + } else { + purple_debug_error("irc", "args count (%d) doesn't reach " + "expected value of %d for the '%s' command", + args_cnt, msgent->req_cnt, msgent->name); } - tmp = irc_recv_convert(irc, from); - (msgent->cb)(irc, msgent->name, tmp, args); - g_free(tmp); for (i = 0; i < strlen(msgent->format); i++) { g_free(args[i]); }