From 56fe6857e8ff4a2786537a518460ba86c60cd7e9 Mon Sep 17 00:00:00 2001 From: CentOS Buildsys Date: Feb 03 2014 14:58:48 +0000 Subject: import pidgin-2.10.7-22.el7.src.rpm --- diff --git a/SOURCES/pidgin-2.10.7-CVE-2012-6152.patch b/SOURCES/pidgin-2.10.7-CVE-2012-6152.patch new file mode 100644 index 0000000..d29d797 --- /dev/null +++ b/SOURCES/pidgin-2.10.7-CVE-2012-6152.patch @@ -0,0 +1,1165 @@ +diff -up pidgin-2.10.7/libpurple/protocols/yahoo/libymsg.c.CVE-2012-6152 pidgin-2.10.7/libpurple/protocols/yahoo/libymsg.c +--- pidgin-2.10.7/libpurple/protocols/yahoo/libymsg.c.CVE-2012-6152 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/yahoo/libymsg.c 2014-01-27 10:20:14.473648650 -0500 +@@ -21,6 +21,12 @@ + * + */ + ++/* ++ * Note: When handling the list of struct yahoo_pair's from an incoming ++ * packet the value might not be UTF-8. You should either validate that ++ * it is UTF-8 using g_utf8_validate() or use yahoo_string_decode(). ++ */ ++ + #include "internal.h" + + #include "account.h" +@@ -592,14 +598,24 @@ static void yahoo_process_list_15(Purple + yd->current_list15_grp = yahoo_string_decode(gc, pair->value, FALSE); + break; + case 7: /* buddy's s/n */ +- g_free(temp); +- temp = g_strdup(purple_normalize(account, pair->value)); ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ g_free(temp); ++ temp = g_strdup(purple_normalize(account, pair->value)); ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_list_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 241: /* user on federated network */ + fed = strtol(pair->value, NULL, 10); + break; + case 59: /* somebody told cookies come here too, but im not sure */ +- yahoo_process_cookie(yd, pair->value); ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ yahoo_process_cookie(yd, pair->value); ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_list_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 317: /* Stealth Setting */ + stealth = strtol(pair->value, NULL, 10); +@@ -662,22 +678,42 @@ static void yahoo_process_list(PurpleCon + g_string_append(yd->tmp_serv_blist, pair->value); + break; + case 88: +- if (!yd->tmp_serv_ilist) +- yd->tmp_serv_ilist = g_string_new(pair->value); +- else +- g_string_append(yd->tmp_serv_ilist, pair->value); ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ if (!yd->tmp_serv_ilist) ++ yd->tmp_serv_ilist = g_string_new(pair->value); ++ else ++ g_string_append(yd->tmp_serv_ilist, pair->value); ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_list " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 89: +- yd->profiles = g_strsplit(pair->value, ",", -1); ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ yd->profiles = g_strsplit(pair->value, ",", -1); ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_list " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 59: /* cookies, yum */ +- yahoo_process_cookie(yd, pair->value); ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ yahoo_process_cookie(yd, pair->value); ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_list " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case YAHOO_SERVICE_PRESENCE_PERM: +- if (!yd->tmp_serv_plist) +- yd->tmp_serv_plist = g_string_new(pair->value); +- else +- g_string_append(yd->tmp_serv_plist, pair->value); ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ if (!yd->tmp_serv_plist) ++ yd->tmp_serv_plist = g_string_new(pair->value); ++ else ++ g_string_append(yd->tmp_serv_plist, pair->value); ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_list " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + } + } +@@ -700,6 +736,12 @@ static void yahoo_process_list(PurpleCon + grp = yahoo_string_decode(gc, split[0], FALSE); + buddies = g_strsplit(split[1], ",", -1); + for (bud = buddies; bud && *bud; bud++) { ++ if (!g_utf8_validate(*bud, -1, NULL)) { ++ purple_debug_warning("yahoo", "yahoo_process_list " ++ "got non-UTF-8 string for bud\n"); ++ continue; ++ } ++ + norm_bud = g_strdup(purple_normalize(account, *bud)); + f = yahoo_friend_find_or_new(gc, norm_bud); + +@@ -794,14 +836,26 @@ static void yahoo_process_notify(PurpleC + + while (l) { + struct yahoo_pair *pair = l->data; +- if (pair->key == 4 || pair->key == 1) +- from = pair->value; ++ if (pair->key == 4 || pair->key == 1) { ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ from = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_notify " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } ++ } + if (pair->key == 49) + msg = pair->value; + if (pair->key == 13) + stat = pair->value; +- if (pair->key == 14) +- game = pair->value; ++ if (pair->key == 14) { ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ game = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_notify " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } ++ } + if (pair->key == 11) + val_11 = strtol(pair->value, NULL, 10); + if (pair->key == 241) +@@ -905,10 +959,15 @@ static void yahoo_process_sms_message(Pu + while (l != NULL) { + struct yahoo_pair *pair = l->data; + if (pair->key == 4) { +- sms = g_new0(struct _yahoo_im, 1); +- sms->from = g_strdup_printf("+%s", pair->value); +- sms->time = time(NULL); +- sms->utf8 = TRUE; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ sms = g_new0(struct _yahoo_im, 1); ++ sms->from = g_strdup_printf("+%s", pair->value); ++ sms->time = time(NULL); ++ sms->utf8 = TRUE; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_sms_message " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + } + if (pair->key == 14) { + if (sms) +@@ -917,8 +976,14 @@ static void yahoo_process_sms_message(Pu + if (pair->key == 68) + if(sms) + g_hash_table_insert(yd->sms_carrier, g_strdup(sms->from), g_strdup(pair->value)); +- if (pair->key == 16) +- server_msg = pair->value; ++ if (pair->key == 16) { ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ server_msg = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_sms_message " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } ++ } + l = l->next; + } + +@@ -972,13 +1037,18 @@ static void yahoo_process_message(Purple + while (l != NULL) { + struct yahoo_pair *pair = l->data; + if (pair->key == 4 || pair->key == 1) { +- im = g_new0(struct _yahoo_im, 1); +- list = g_slist_append(list, im); +- im->from = pair->value; +- im->time = time(NULL); +- im->utf8 = TRUE; +- im->fed = YAHOO_FEDERATION_NONE; +- im->fed_from = g_strdup(im->from); ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ im = g_new0(struct _yahoo_im, 1); ++ list = g_slist_append(list, im); ++ im->from = pair->value; ++ im->time = time(NULL); ++ im->utf8 = TRUE; ++ im->fed = YAHOO_FEDERATION_NONE; ++ im->fed_from = g_strdup(im->from); ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_message " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + } + if (im && pair->key == 5) + im->active_id = pair->value; +@@ -1034,7 +1104,7 @@ static void yahoo_process_message(Purple + } + } + /* IMV key */ +- if (im && pair->key == 63) ++ if (im && pair->key == 63 && g_utf8_validate(pair->value, -1, NULL)) + { + /* Check for the Doodle IMV, no IMvironment for federated buddies */ + if (im->from != NULL && im->fed == YAHOO_FEDERATION_NONE) +@@ -1173,10 +1243,22 @@ static void yahoo_process_sysmessage(Pur + while (l) { + struct yahoo_pair *pair = l->data; + +- if (pair->key == 5) +- me = pair->value; +- if (pair->key == 14) +- msg = pair->value; ++ if (pair->key == 5) { ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ me = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_sysmessage " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } ++ } ++ if (pair->key == 14) { ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ msg = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_sysmessage " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } ++ } + + l = l->next; + } +@@ -1334,7 +1416,12 @@ static void yahoo_buddy_auth_req_15(Purp + + switch (pair->key) { + case 4: +- temp = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ temp = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 13: + response = strtol(pair->value, NULL, 10); +@@ -1389,22 +1476,42 @@ static void yahoo_buddy_auth_req_15(Purp + + switch (pair->key) { + case 4: +- temp = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ temp = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 5: +- add_req->id = g_strdup(pair->value); ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ add_req->id = g_strdup(pair->value); ++ } else { ++ purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 14: + msg = pair->value; + break; + case 216: +- firstname = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ firstname = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 241: + add_req->fed = strtol(pair->value, NULL, 10); + break; + case 254: +- lastname = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ lastname = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + + } +@@ -1485,10 +1592,20 @@ static void yahoo_buddy_added_us(PurpleC + + switch (pair->key) { + case 1: +- add_req->id = g_strdup(pair->value); ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ add_req->id = g_strdup(pair->value); ++ } else { ++ purple_debug_warning("yahoo", "yahoo_buddy_added_us " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 3: +- add_req->who = g_strdup(pair->value); ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ add_req->who = g_strdup(pair->value); ++ } else { ++ purple_debug_warning("yahoo", "yahoo_buddy_added_us " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 15: /* time, for when they add us and we're offline */ + break; +@@ -1540,10 +1657,20 @@ static void yahoo_buddy_denied_our_add_o + + switch (pair->key) { + case 3: +- who = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_buddy_denied_our_add_old " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 14: +- msg = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ msg = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_buddy_denied_our_add_old " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + } + l = l->next; +@@ -1640,12 +1767,28 @@ static void yahoo_process_mail(PurpleCon + struct yahoo_pair *pair = l->data; + if (pair->key == 9) + count = strtol(pair->value, NULL, 10); +- else if (pair->key == 43) +- who = pair->value; +- else if (pair->key == 42) +- email = pair->value; +- else if (pair->key == 18) +- subj = pair->value; ++ else if (pair->key == 43) { ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_mail " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } ++ } else if (pair->key == 42) { ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ email = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_mail " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } ++ } else if (pair->key == 18) { ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ subj = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_mail " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } ++ } + l = l->next; + } + +@@ -2075,10 +2218,22 @@ static void yahoo_process_auth(PurpleCon + + while (l) { + struct yahoo_pair *pair = l->data; +- if (pair->key == 94) +- seed = pair->value; +- if (pair->key == 1) +- sn = pair->value; ++ if (pair->key == 94) { ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ seed = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_auth " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } ++ } ++ if (pair->key == 1) { ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ sn = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_auth " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } ++ } + if (pair->key == 13) + m = atoi(pair->value); + l = l->next; +@@ -2150,10 +2305,20 @@ static void yahoo_process_ignore(PurpleC + struct yahoo_pair *pair = l->data; + switch (pair->key) { + case 0: +- who = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_ignore " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 1: +- me = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ me = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_ignore " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 13: + /* 1 == ignore, 2 == unignore */ +@@ -2222,8 +2387,14 @@ static void yahoo_process_authresp(Purpl + + if (pair->key == 66) + err = strtol(pair->value, NULL, 10); +- else if (pair->key == 20) +- url = pair->value; ++ else if (pair->key == 20) { ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ url = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_authresp " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } ++ } + + l = l->next; + } +@@ -2311,7 +2482,12 @@ static void yahoo_process_addbuddy(Purpl + err = strtol(pair->value, NULL, 10); + break; + case 7: +- temp = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ temp = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_addbuddy " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 65: + group = pair->value; +@@ -2468,11 +2644,16 @@ static void yahoo_p2p_process_p2pfilexfe + + switch (pair->key) { + case 4: +- who = pair->value; +- if(strncmp(who, p2p_data->host_username, strlen(p2p_data->host_username)) != 0) { +- /* from whom are we receiving the packets ?? */ +- purple_debug_warning("yahoo","p2p: received data from wrong user\n"); +- return; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ if(strncmp(who, p2p_data->host_username, strlen(p2p_data->host_username)) != 0) { ++ /* from whom are we receiving the packets ?? */ ++ purple_debug_warning("yahoo","p2p: received data from wrong user\n"); ++ return; ++ } ++ } else { ++ purple_debug_warning("yahoo", "yahoo_p2p_process_p2pfilexfer " ++ "got non-UTF-8 string for key %d\n", pair->key); + } + break; + case 13: +@@ -2841,15 +3022,25 @@ static void yahoo_process_p2p(PurpleConn + /* our identity */ + break; + case 4: +- who = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_p2p " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 1: + /* who again, the master identity this time? */ + break; + case 12: +- base64 = pair->value; +- /* so, this is an ip address. in base64. decoded it's in ascii. +- after strtol, it's in reversed byte order. Who thought this up?*/ ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ base64 = pair->value; ++ /* so, this is an ip address. in base64. decoded it's in ascii. ++ after strtol, it's in reversed byte order. Who thought this up?*/ ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_p2p " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 13: + val_13 = strtol(pair->value, NULL, 10); +@@ -2938,7 +3129,12 @@ static void yahoo_process_audible(Purple + + switch (pair->key) { + case 4: +- who = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_audible " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 5: + /* us */ +@@ -2946,11 +3142,21 @@ static void yahoo_process_audible(Purple + case 230: + /* the audible, in foo.locale.bar.baz format + eg: base.tw.smiley.smiley43 */ +- id = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ id = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_audible " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 231: + /* the text of the audible */ +- msg = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ msg = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_audible " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 232: + /* SHA-1 hash of audible SWF file (eg: 4e8691499d9c0fb8374478ff9720f4a9ea4a4915) */ +diff -up pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_aliases.c.CVE-2012-6152 pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_aliases.c +--- pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_aliases.c.CVE-2012-6152 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_aliases.c 2014-01-27 10:20:14.473648650 -0500 +@@ -696,8 +696,14 @@ void yahoo_process_contact_details(Purpl + struct yahoo_pair *pair = l->data; + switch (pair->key) { + case 4: +- who = pair->value; /* This is the person who sent us the details. +- But not necessarily about himself. */ ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ /* This is the person who sent us the details. ++ But not necessarily about himself. */ ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_contact_details " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 5: + break; +@@ -709,8 +715,13 @@ void yahoo_process_contact_details(Purpl + and look into the xml instead to see who the information is about. */ + break; + case 280: +- xml = pair->value; +- parse_contact_details(yd, who, xml); ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ xml = pair->value; ++ parse_contact_details(yd, who, xml); ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_contact_details " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + } + } +diff -up pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_filexfer.c.CVE-2012-6152 pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_filexfer.c +--- pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_filexfer.c.CVE-2012-6152 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_filexfer.c 2014-01-27 10:20:14.474648740 -0500 +@@ -749,25 +749,60 @@ void yahoo_process_p2pfilexfer(PurpleCon + + switch(pair->key) { + case 5: /* Get who the packet is for */ +- me = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ me = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 4: /* Get who the packet is from */ +- from = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ from = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 49: /* Get the type of service */ +- service = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ service = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 14: /* Get the 'message' of the packet */ +- message = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ message = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 13: /* Get the command associated with this packet */ +- command = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ command = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 63: /* IMVironment name and version */ +- imv = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ imv = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 64: /* Not sure, but it does vary with initialization of Doodle */ +- unknown = pair->value; /* So, I'll keep it (for a little while atleast) */ ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ unknown = pair->value; /* So, I'll keep it (for a little while atleast) */ ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + } + +@@ -813,16 +848,36 @@ void yahoo_process_filetransfer(PurpleCo + + switch (pair->key) { + case 4: +- from = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ from = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetransfer " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 5: +- to = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ to = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetransfer " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 14: +- msg = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ msg = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetransfer " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 20: +- url = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ url = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetransfer " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 38: + expires = strtol(pair->value, NULL, 10); +@@ -834,10 +889,20 @@ void yahoo_process_filetransfer(PurpleCo + filesize = atol(pair->value); + break; + case 49: +- service = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ service = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetransfer " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 63: +- imv = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ imv = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetransfer " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + } + } +@@ -1616,20 +1681,40 @@ void yahoo_process_filetrans_15(PurpleCo + + switch (pair->key) { + case 4: +- from = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ from = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetrans_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 5: +- to = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ to = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetrans_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 265: +- xfer_peer_idstring = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ xfer_peer_idstring = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetrans_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 27: + filename_list = g_slist_prepend(filename_list, g_strdup(pair->value)); + nooffiles++; + break; + case 28: +- size_list = g_slist_prepend(size_list, g_strdup(pair->value)); ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ size_list = g_slist_prepend(size_list, g_strdup(pair->value)); ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetrans_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 222: + val_222 = atol(pair->value); +@@ -1638,10 +1723,20 @@ void yahoo_process_filetrans_15(PurpleCo + + /* check for p2p and imviron .... not sure it comes by this service packet. Since it was bundled with filexfer in old ymsg version, still keeping it. */ + case 49: +- service = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ service = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetrans_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 63: +- imv = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ imv = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetrans_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + /* end check */ + +@@ -1803,7 +1898,12 @@ void yahoo_process_filetrans_info_15(Pur + to = pair->value; + break; + case 265: +- xfer_peer_idstring = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ xfer_peer_idstring = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetrans_info_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 27: + filename = pair->value; +@@ -1816,10 +1916,20 @@ void yahoo_process_filetrans_info_15(Pur + /* 249 has value 1 or 2 when doing p2p transfer and value 3 when relaying through yahoo server */ + break; + case 250: +- url = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ url = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetrans_info_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 251: +- xfer_idstring_for_relay = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ xfer_idstring_for_relay = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetrans_info_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + } + } +@@ -1902,10 +2012,20 @@ void yahoo_process_filetrans_acc_15(Purp + + switch (pair->key) { + case 251: +- xfer_idstring_for_relay = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ xfer_idstring_for_relay = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetrans_acc_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 265: +- xfer_peer_idstring = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ xfer_peer_idstring = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetrans_acc_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 66: + val_66 = atol(pair->value); +@@ -1914,7 +2034,13 @@ void yahoo_process_filetrans_acc_15(Purp + val_249 = atol(pair->value); + break; + case 250: +- url = pair->value; /* we get a p2p url here when sending file, connected as client */ ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ /* we get a p2p url here when sending file, connected as client */ ++ url = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_filetrans_acc_15 " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + } + } +diff -up pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_friend.c.CVE-2012-6152 pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_friend.c +--- pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_friend.c.CVE-2012-6152 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_friend.c 2014-01-27 10:20:14.474648740 -0500 +@@ -158,7 +158,12 @@ void yahoo_process_presence(PurpleConnec + + switch (pair->key) { + case 7: +- temp = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ temp = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_presence " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 31: + value = strtol(pair->value, NULL, 10); +diff -up pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_picture.c.CVE-2012-6152 pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_picture.c +--- pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_picture.c.CVE-2012-6152 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/yahoo/yahoo_picture.c 2014-01-27 10:20:14.475648826 -0500 +@@ -84,10 +84,20 @@ void yahoo_process_picture(PurpleConnect + switch (pair->key) { + case 1: + case 4: +- who = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_picture " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 5: +- us = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ us = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_picture " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 13: { + int tmp; +@@ -100,7 +110,12 @@ void yahoo_process_picture(PurpleConnect + break; + } + case 20: +- url = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ url = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_picture " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 192: + checksum = strtol(pair->value, NULL, 10); +@@ -154,7 +169,12 @@ void yahoo_process_picture_checksum(Purp + + switch (pair->key) { + case 4: +- who = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_picture_checksum " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 5: + /* us */ +@@ -197,7 +217,12 @@ void yahoo_process_picture_upload(Purple + /* filename on our computer. */ + break; + case 20: /* url at yahoo */ +- url = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ url = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_picture_upload " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + case 38: /* timestamp */ + break; + } +@@ -225,7 +250,12 @@ void yahoo_process_avatar_update(PurpleC + + switch (pair->key) { + case 4: +- who = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_avatar_upload " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 5: + /* us */ +diff -up pidgin-2.10.7/libpurple/protocols/yahoo/yahoochat.c.CVE-2012-6152 pidgin-2.10.7/libpurple/protocols/yahoo/yahoochat.c +--- pidgin-2.10.7/libpurple/protocols/yahoo/yahoochat.c.CVE-2012-6152 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/yahoo/yahoochat.c 2014-01-27 10:20:14.475648826 -0500 +@@ -156,15 +156,25 @@ void yahoo_process_conference_invite(Pur + room = yahoo_string_decode(gc, pair->value, FALSE); + break; + case 50: /* inviter */ +- who = pair->value; +- g_string_append_printf(members, "%s\n", who); ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ g_string_append_printf(members, "%s\n", who); ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_conference_invite " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 51: /* This user is being invited to the conference. Comes with status = 11, so we wont reach here */ + break; + case 52: /* Invited users. Assuming us invited, since we got this packet */ + break; /* break needed, or else we add the users to the conference before they accept the invitation */ + case 53: /* members who have already joined the conference */ +- g_string_append_printf(members, "%s\n", pair->value); ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ g_string_append_printf(members, "%s\n", pair->value); ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_conference_invite " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 58: + g_free(msg); +@@ -220,7 +230,12 @@ void yahoo_process_conference_decline(Pu + room = yahoo_string_decode(gc, pair->value, FALSE); + break; + case 54: +- who = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_conference_decline " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 14: + g_free(msg); +@@ -277,7 +292,12 @@ void yahoo_process_conference_logon(Purp + room = yahoo_string_decode(gc, pair->value, FALSE); + break; + case 53: +- who = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_conference_logon " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + } + } +@@ -309,7 +329,12 @@ void yahoo_process_conference_logoff(Pur + room = yahoo_string_decode(gc, pair->value, FALSE); + break; + case 56: +- who = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_conference_logoff " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + } + } +@@ -340,7 +365,12 @@ void yahoo_process_conference_message(Pu + room = yahoo_string_decode(gc, pair->value, FALSE); + break; + case 3: +- who = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_conference_message " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 14: + msg = pair->value; +@@ -506,18 +536,38 @@ void yahoo_process_chat_join(PurpleConne + topic = yahoo_string_decode(gc, pair->value, TRUE); + break; + case 128: +- someid = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ someid = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_chat_join " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 108: /* number of joiners */ + break; + case 129: +- someotherid = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ someotherid = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_chat_join " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 130: +- somebase64orhashosomething = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ somebase64orhashosomething = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_chat_join " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 126: +- somenegativenumber = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ somenegativenumber = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_chat_join " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 13: /* this is 1. maybe its the type of room? (normal, user created, private, etc?) */ + break; +@@ -528,7 +578,12 @@ void yahoo_process_chat_join(PurpleConne + info about individual room members, (including us) */ + + case 109: /* the yahoo id */ +- members = g_list_append(members, pair->value); ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ members = g_list_append(members, pair->value); ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_chat_join " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 110: /* age */ + break; +@@ -625,8 +680,14 @@ void yahoo_process_chat_exit(PurpleConne + g_free(room); + room = yahoo_string_decode(gc, pair->value, TRUE); + } +- if (pair->key == 109) +- who = pair->value; ++ if (pair->key == 109) { ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_chat_exit " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } ++ } + } + + if (who && room) { +@@ -658,10 +719,20 @@ void yahoo_process_chat_message(PurpleCo + room = yahoo_string_decode(gc, pair->value, TRUE); + break; + case 109: +- who = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_chat_message " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 117: +- msg = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ msg = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_chat_message " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 124: + msgtype = strtol(pair->value, NULL, 10); +@@ -724,7 +795,12 @@ void yahoo_process_chat_addinvite(Purple + msg = yahoo_string_decode(gc, pair->value, FALSE); + break; + case 119: +- who = pair->value; ++ if (g_utf8_validate(pair->value, -1, NULL)) { ++ who = pair->value; ++ } else { ++ purple_debug_warning("yahoo", "yahoo_process_chat_addinvite " ++ "got non-UTF-8 string for key %d\n", pair->key); ++ } + break; + case 118: /* us */ + break; diff --git a/SOURCES/pidgin-2.10.7-CVE-2013-6477.patch b/SOURCES/pidgin-2.10.7-CVE-2013-6477.patch new file mode 100644 index 0000000..6ee4bcc --- /dev/null +++ b/SOURCES/pidgin-2.10.7-CVE-2013-6477.patch @@ -0,0 +1,78 @@ +diff -up pidgin-2.10.7/libpurple/conversation.c.CVE-2013-6477 pidgin-2.10.7/libpurple/conversation.c +--- pidgin-2.10.7/libpurple/conversation.c.CVE-2013-6477 2013-02-11 04:16:51.000000000 -0500 ++++ pidgin-2.10.7/libpurple/conversation.c 2014-01-29 20:17:16.584055979 -0500 +@@ -1551,6 +1551,14 @@ purple_conv_chat_write(PurpleConvChat *c + if (purple_conv_chat_is_user_ignored(chat, who)) + return; + ++ if (mtime < 0) { ++ purple_debug_error("conversation", ++ "purple_conv_chat_write ignoring negative timestamp\n"); ++ /* TODO: Would be more appropriate to use a value that indicates ++ that the timestamp is unknown, and surface that in the UI. */ ++ mtime = time(NULL); ++ } ++ + if (!(flags & PURPLE_MESSAGE_WHISPER)) { + const char *str; + +diff -up pidgin-2.10.7/libpurple/log.c.CVE-2013-6477 pidgin-2.10.7/libpurple/log.c +--- pidgin-2.10.7/libpurple/log.c.CVE-2013-6477 2013-02-11 04:16:51.000000000 -0500 ++++ pidgin-2.10.7/libpurple/log.c 2014-01-29 20:17:16.584055979 -0500 +@@ -753,7 +753,7 @@ static char *log_get_timestamp(PurpleLog + { + gboolean show_date; + char *date; +- struct tm tm; ++ struct tm *tm; + + show_date = (log->type == PURPLE_LOG_SYSTEM) || (time(NULL) > when + 20*60); + +@@ -763,11 +763,11 @@ static char *log_get_timestamp(PurpleLog + if (date != NULL) + return date; + +- tm = *(localtime(&when)); ++ tm = localtime(&when); + if (show_date) +- return g_strdup(purple_date_format_long(&tm)); ++ return g_strdup(purple_date_format_long(tm)); + else +- return g_strdup(purple_time_format(&tm)); ++ return g_strdup(purple_time_format(tm)); + } + + /* NOTE: This can return msg (which you may or may not want to g_free()) +diff -up pidgin-2.10.7/libpurple/server.c.CVE-2013-6477 pidgin-2.10.7/libpurple/server.c +--- pidgin-2.10.7/libpurple/server.c.CVE-2013-6477 2013-02-11 04:16:53.000000000 -0500 ++++ pidgin-2.10.7/libpurple/server.c 2014-01-29 20:17:16.585055993 -0500 +@@ -567,6 +567,14 @@ void serv_got_im(PurpleConnection *gc, c + + account = purple_connection_get_account(gc); + ++ if (mtime < 0) { ++ purple_debug_error("server", ++ "serv_got_im ignoring negative timestamp\n"); ++ /* TODO: Would be more appropriate to use a value that indicates ++ that the timestamp is unknown, and surface that in the UI. */ ++ mtime = time(NULL); ++ } ++ + /* + * XXX: Should we be setting this here, or relying on prpls to set it? + */ +@@ -905,6 +913,14 @@ void serv_got_chat_in(PurpleConnection * + g_return_if_fail(who != NULL); + g_return_if_fail(message != NULL); + ++ if (mtime < 0) { ++ purple_debug_error("server", ++ "serv_got_chat_in ignoring negative timestamp\n"); ++ /* TODO: Would be more appropriate to use a value that indicates ++ that the timestamp is unknown, and surface that in the UI. */ ++ mtime = time(NULL); ++ } ++ + for (bcs = g->buddy_chats; bcs != NULL; bcs = bcs->next) { + conv = (PurpleConversation *)bcs->data; + diff --git a/SOURCES/pidgin-2.10.7-CVE-2013-6478.patch b/SOURCES/pidgin-2.10.7-CVE-2013-6478.patch new file mode 100644 index 0000000..2cfbd22 --- /dev/null +++ b/SOURCES/pidgin-2.10.7-CVE-2013-6478.patch @@ -0,0 +1,35 @@ +diff -up pidgin-2.10.7/pidgin/gtkimhtml.c.CVE-2013-6477 pidgin-2.10.7/pidgin/gtkimhtml.c +--- pidgin-2.10.7/pidgin/gtkimhtml.c.CVE-2013-6477 2013-02-11 04:16:53.000000000 -0500 ++++ pidgin-2.10.7/pidgin/gtkimhtml.c 2014-01-27 12:20:54.660113325 -0500 +@@ -514,7 +514,13 @@ gtk_imhtml_tip_paint (GtkIMHtml *imhtml) + + g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); + +- layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); ++ /* We set the text in a separate function call so we can specify a ++ max length. This is important so the tooltip isn't too wide for ++ the screen, and also because some X library function exits the ++ process when it can't allocate enough memory for a super wide ++ tooltip. */ ++ layout = gtk_widget_create_pango_layout(imhtml->tip_window, NULL); ++ pango_layout_set_text(layout, imhtml->tip, 200); + + gtk_paint_flat_box (imhtml->tip_window->style, imhtml->tip_window->window, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, imhtml->tip_window, +@@ -561,7 +567,15 @@ gtk_imhtml_tip (gpointer data) + G_CALLBACK (gtk_imhtml_tip_paint), imhtml); + + gtk_widget_ensure_style (imhtml->tip_window); +- layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); ++ ++ /* We set the text in a separate function call so we can specify a ++ max length. This is important so the tooltip isn't too wide for ++ the screen, and also because some X library function exits the ++ process when it can't allocate enough memory for a super wide ++ tooltip. */ ++ layout = gtk_widget_create_pango_layout(imhtml->tip_window, NULL); ++ pango_layout_set_text(layout, imhtml->tip, 200); ++ + font = pango_context_load_font(pango_layout_get_context(layout), + imhtml->tip_window->style->font_desc); + diff --git a/SOURCES/pidgin-2.10.7-CVE-2013-6479.patch b/SOURCES/pidgin-2.10.7-CVE-2013-6479.patch new file mode 100644 index 0000000..e1c4cf6 --- /dev/null +++ b/SOURCES/pidgin-2.10.7-CVE-2013-6479.patch @@ -0,0 +1,207 @@ +diff -up pidgin-2.10.7/libpurple/util.c.CVE-2013-6479 pidgin-2.10.7/libpurple/util.c +--- pidgin-2.10.7/libpurple/util.c.CVE-2013-6479 2013-02-11 04:16:53.000000000 -0500 ++++ pidgin-2.10.7/libpurple/util.c 2014-01-28 19:09:20.896950189 -0500 +@@ -33,6 +33,10 @@ + #include "prefs.h" + #include "util.h" + ++/* 512KiB Default value for maximum HTTP download size (when the client hasn't ++ specified a length) */ ++#define DEFAULT_MAX_HTTP_DOWNLOAD (512 * 1024) ++ + struct _PurpleUtilFetchUrlData + { + PurpleUtilFetchUrlCallback callback; +@@ -68,7 +72,7 @@ struct _PurpleUtilFetchUrlData + char *webdata; + gsize len; + unsigned long data_len; +- gssize max_len; ++ gsize max_len; + gboolean chunked; + PurpleAccount *account; + }; +@@ -3239,24 +3243,26 @@ purple_strcasereplace(const char *string + return ret; + } + +-const char * +-purple_strcasestr(const char *haystack, const char *needle) ++/** TODO: Expose this when we can add API */ ++static const char * ++purple_strcasestr_len(const char *haystack, gssize hlen, const char *needle, gssize nlen) + { +- size_t hlen, nlen; + const char *tmp, *ret; + + g_return_val_if_fail(haystack != NULL, NULL); + g_return_val_if_fail(needle != NULL, NULL); + +- hlen = strlen(haystack); +- nlen = strlen(needle); ++ if (hlen == -1) ++ hlen = strlen(haystack); ++ if (nlen == -1) ++ nlen = strlen(needle); + tmp = haystack, + ret = NULL; + + g_return_val_if_fail(hlen > 0, NULL); + g_return_val_if_fail(nlen > 0, NULL); + +- while (*tmp && !ret) { ++ while (*tmp && !ret && (hlen - (tmp - haystack)) >= nlen) { + if (!g_ascii_strncasecmp(needle, tmp, nlen)) + ret = tmp; + else +@@ -3266,6 +3272,12 @@ purple_strcasestr(const char *haystack, + return ret; + } + ++const char * ++purple_strcasestr(const char *haystack, const char *needle) ++{ ++ return purple_strcasestr_len(haystack, -1, needle, -1); ++} ++ + char * + purple_str_size_to_units(size_t size) + { +@@ -3575,7 +3587,7 @@ static void ssl_url_fetch_connect_cb(gpo + static void ssl_url_fetch_error_cb(PurpleSslConnection *ssl_connection, PurpleSslErrorType error, gpointer data); + + static gboolean +-parse_redirect(const char *data, size_t data_len, ++parse_redirect(const char *data, gsize data_len, + PurpleUtilFetchUrlData *gfud) + { + gchar *s; +@@ -3680,20 +3692,21 @@ parse_redirect(const char *data, size_t + return TRUE; + } + ++/* find the starting point of the content for the specified header and make ++ * sure that the content is safe to pass to sscanf */ + static const char * +-find_header_content(const char *data, size_t data_len, const char *header, size_t header_len) ++find_header_content(const char *data, gsize data_len, const char *header) + { + const char *p = NULL; + +- if (header_len <= 0) +- header_len = strlen(header); ++ gsize header_len = strlen(header); + +- /* Note: data is _not_ nul-terminated. */ + if (data_len > header_len) { ++ /* Check if the first header matches (data won't start with a \n") */ + if (header[0] == '\n') + p = (g_ascii_strncasecmp(data, header + 1, header_len - 1) == 0) ? data : NULL; + if (!p) +- p = purple_strcasestr(data, header); ++ p = purple_strcasestr_len(data, data_len, header, header_len); + if (p) + p += header_len; + } +@@ -3709,13 +3722,13 @@ find_header_content(const char *data, si + return NULL; + } + +-static size_t +-parse_content_len(const char *data, size_t data_len) ++static gsize ++parse_content_len(const char *data, gsize data_len) + { +- size_t content_len = 0; ++ gsize content_len = 0; + const char *p = NULL; + +- p = find_header_content(data, data_len, "\nContent-Length: ", sizeof("\nContent-Length: ") - 1); ++ p = find_header_content(data, data_len, "\nContent-Length: "); + if (p) { + sscanf(p, "%" G_GSIZE_FORMAT, &content_len); + purple_debug_misc("util", "parsed %" G_GSIZE_FORMAT "\n", content_len); +@@ -3725,9 +3738,9 @@ parse_content_len(const char *data, size + } + + static gboolean +-content_is_chunked(const char *data, size_t data_len) ++content_is_chunked(const char *data, gsize data_len) + { +- const char *p = find_header_content(data, data_len, "\nTransfer-Encoding: ", sizeof("\nTransfer-Encoding: ") - 1); ++ const char *p = find_header_content(data, data_len, "\nTransfer-Encoding: "); + if (p && g_ascii_strncasecmp(p, "chunked", 7) == 0) + return TRUE; + +@@ -3810,7 +3823,7 @@ url_fetch_recv_cb(gpointer url_data, gin + while ((gfud->is_ssl && ((len = purple_ssl_read(gfud->ssl_connection, buf, sizeof(buf))) > 0)) || + (!gfud->is_ssl && (len = read(source, buf, sizeof(buf))) > 0)) + { +- if(gfud->max_len != -1 && (gfud->len + len) > gfud->max_len) { ++ if((gfud->len + len) > gfud->max_len) { + purple_util_fetch_url_error(gfud, _("Error reading from %s: response too long (%d bytes limit)"), + gfud->website.address, gfud->max_len); + return; +@@ -3838,9 +3851,8 @@ url_fetch_recv_cb(gpointer url_data, gin + /* See if we've reached the end of the headers yet */ + end_of_headers = strstr(gfud->webdata, "\r\n\r\n"); + if (end_of_headers) { +- char *new_data; + guint header_len = (end_of_headers + 4 - gfud->webdata); +- size_t content_len; ++ gsize content_len; + + purple_debug_misc("util", "Response headers: '%.*s'\n", + header_len, gfud->webdata); +@@ -3860,15 +3872,36 @@ url_fetch_recv_cb(gpointer url_data, gin + content_len = 8192; + } else { + gfud->has_explicit_data_len = TRUE; ++ if (content_len > gfud->max_len) { ++ purple_debug_error("util", ++ "Overriding explicit Content-Length of %" G_GSIZE_FORMAT " with max of %" G_GSSIZE_FORMAT "\n", ++ content_len, gfud->max_len); ++ content_len = gfud->max_len; ++ } + } + + + /* If we're returning the headers too, we don't need to clean them out */ + if (gfud->include_headers) { ++ char *new_data; + gfud->data_len = content_len + header_len; +- gfud->webdata = g_realloc(gfud->webdata, gfud->data_len); ++ new_data = g_try_realloc(gfud->webdata, gfud->data_len); ++ if (new_data == NULL) { ++ purple_debug_error("util", ++ "Failed to allocate %" G_GSIZE_FORMAT " bytes: %s\n", ++ content_len, g_strerror(errno)); ++ purple_util_fetch_url_error(gfud, ++ _("Unable to allocate enough memory to hold " ++ "the contents from %s. The web server may " ++ "be trying something malicious."), ++ gfud->website.address); ++ ++ return; ++ } ++ gfud->webdata = new_data; + } else { +- size_t body_len = gfud->len - header_len; ++ char *new_data; ++ gsize body_len = gfud->len - header_len; + + content_len = MAX(content_len, body_len); + +@@ -4154,7 +4187,11 @@ purple_util_fetch_url_request_len_with_a + gfud->request = g_strdup(request); + gfud->include_headers = include_headers; + gfud->fd = -1; +- gfud->max_len = max_len; ++ if (max_len <= 0) { ++ max_len = DEFAULT_MAX_HTTP_DOWNLOAD; ++ purple_debug_error("util", "Defaulting max download from %s to %" G_GSSIZE_FORMAT "\n", url, max_len); ++ } ++ gfud->max_len = (gsize) max_len; + gfud->account = account; + + purple_url_parse(url, &gfud->website.address, &gfud->website.port, diff --git a/SOURCES/pidgin-2.10.7-CVE-2013-6481.patch b/SOURCES/pidgin-2.10.7-CVE-2013-6481.patch new file mode 100644 index 0000000..2100c66 --- /dev/null +++ b/SOURCES/pidgin-2.10.7-CVE-2013-6481.patch @@ -0,0 +1,67 @@ +diff -up pidgin-2.10.7/libpurple/protocols/yahoo/libymsg.c.CVE-2013-6481 pidgin-2.10.7/libpurple/protocols/yahoo/libymsg.c +--- pidgin-2.10.7/libpurple/protocols/yahoo/libymsg.c.CVE-2013-6481 2014-01-27 10:20:14.473648650 -0500 ++++ pidgin-2.10.7/libpurple/protocols/yahoo/libymsg.c 2014-01-28 20:57:13.990365865 -0500 +@@ -2720,7 +2720,7 @@ static void yahoo_p2p_read_pkt_cb(gpoint + int pos = 0; + int pktlen; + struct yahoo_packet *pkt; +- guchar *start = NULL; ++ guchar *start; + struct yahoo_p2p_data *p2p_data; + YahooData *yd; + +@@ -2742,19 +2742,29 @@ static void yahoo_p2p_read_pkt_cb(gpoint + return; + } + ++ /* TODO: It looks like there's a bug here (and above) where an incorrect ++ * assumtion is being made that the buffer will be added to when this ++ * is next called, but that's not really the case! */ + if(len < YAHOO_PACKET_HDRLEN) + return; + +- if(strncmp((char *)buf, "YMSG", MIN(4, len)) != 0) { ++ if(strncmp((char *)buf, "YMSG", 4) != 0) { + /* Not a YMSG packet */ +- purple_debug_warning("yahoo","p2p: Got something other than YMSG packet\n"); ++ purple_debug_warning("yahoo", "p2p: Got something other than YMSG packet\n"); + +- start = memchr(buf + 1, 'Y', len - 1); +- if (start == NULL) ++ start = (guchar *) g_strstr_len((char *) buf + 1, len - 1 ,"YMSG"); ++ if (start == NULL) { ++ /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */ ++ if (g_hash_table_lookup(yd->peers, p2p_data->host_username)) ++ g_hash_table_remove(yd->peers, p2p_data->host_username); ++ else ++ yahoo_p2p_disconnect_destroy_data(data); + return; ++ } ++ purple_debug_warning("yahoo","p2p: Got something other than YMSG packet\n"); + +- g_memmove(buf, start, len - (start - buf)); +- len -= start - buf; ++ len -= (start - buf); ++ g_memmove(buf, start, len); + } + + pos += 4; /* YMSG */ +@@ -2762,7 +2772,17 @@ static void yahoo_p2p_read_pkt_cb(gpoint + pos += 2; + + pktlen = yahoo_get16(buf + pos); pos += 2; +- purple_debug_misc("yahoo", "p2p: %d bytes to read\n", len); ++ if (len < (YAHOO_PACKET_HDRLEN + pktlen)) { ++ purple_debug_error("yahoo", "p2p: packet length(%d) > buffer length(%d)\n", ++ pktlen, (len - pos)); ++ /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */ ++ if (g_hash_table_lookup(yd->peers, p2p_data->host_username)) ++ g_hash_table_remove(yd->peers, p2p_data->host_username); ++ else ++ yahoo_p2p_disconnect_destroy_data(data); ++ return; ++ } else ++ purple_debug_misc("yahoo", "p2p: %d bytes to read\n", pktlen); + + pkt = yahoo_packet_new(0, 0, 0); + pkt->service = yahoo_get16(buf + pos); pos += 2; diff --git a/SOURCES/pidgin-2.10.7-CVE-2013-6482.patch b/SOURCES/pidgin-2.10.7-CVE-2013-6482.patch new file mode 100644 index 0000000..c573f0d --- /dev/null +++ b/SOURCES/pidgin-2.10.7-CVE-2013-6482.patch @@ -0,0 +1,147 @@ +diff -up pidgin-2.10.7/libpurple/protocols/msn/msg.c.CVE-2013-6482 pidgin-2.10.7/libpurple/protocols/msn/msg.c +--- pidgin-2.10.7/libpurple/protocols/msn/msg.c.CVE-2013-6482 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/msn/msg.c 2014-01-29 09:20:02.125156089 -0500 +@@ -178,6 +178,8 @@ msn_message_parse_payload(MsnMessage *ms + g_free(tmp_base); + g_return_if_reached(); + } ++ ++ /* NUL-terminate the end of the headers - it'll get skipped over below */ + *end = '\0'; + + /* Split the headers and parse each one */ +@@ -195,10 +197,12 @@ msn_message_parse_payload(MsnMessage *ms + + /* The only one I care about is 'boundary' (which is folded from + the key 'Content-Type'), so only process that. */ +- if (!strcmp(key, "boundary")) { ++ if (!strcmp(key, "boundary") && value) { + char *end = strchr(value, '\"'); +- *end = '\0'; +- msn_message_set_header(msg, key, value); ++ if (end) { ++ *end = '\0'; ++ msn_message_set_header(msg, key, value); ++ } + } + + g_strfreev(tokens); +@@ -210,18 +214,15 @@ msn_message_parse_payload(MsnMessage *ms + key = tokens[0]; + value = tokens[1]; + +- /*if not MIME content ,then return*/ + if (!strcmp(key, "MIME-Version")) + { +- g_strfreev(tokens); +- continue; ++ /* Ignore MIME-Version header */ + } +- +- if (!strcmp(key, "Content-Type")) ++ else if (!strcmp(key, "Content-Type")) + { + char *charset, *c; + +- if ((c = strchr(value, ';')) != NULL) ++ if (value && (c = strchr(value, ';')) != NULL) + { + if ((charset = strchr(c, '=')) != NULL) + { +diff -up pidgin-2.10.7/libpurple/protocols/msn/oim.c.CVE-2013-6482 pidgin-2.10.7/libpurple/protocols/msn/oim.c +--- pidgin-2.10.7/libpurple/protocols/msn/oim.c.CVE-2013-6482 2014-01-29 09:20:03.696153312 -0500 ++++ pidgin-2.10.7/libpurple/protocols/msn/oim.c 2014-01-29 09:20:04.713151523 -0500 +@@ -362,11 +362,12 @@ msn_oim_send_read_cb(MsnSoapMessage *req + if (faultcode) { + char *faultcode_str = xmlnode_get_data(faultcode); + +- if (g_str_equal(faultcode_str, "q0:AuthenticationFailed")) { ++ if (faultcode_str && g_str_equal(faultcode_str, "q0:AuthenticationFailed")) { + xmlnode *challengeNode = xmlnode_get_child(faultNode, + "detail/LockKeyChallenge"); ++ char *challenge = NULL; + +- if (challengeNode == NULL) { ++ if (challengeNode == NULL || (challenge = xmlnode_get_data(challengeNode)) == NULL) { + if (oim->challenge) { + g_free(oim->challenge); + oim->challenge = NULL; +@@ -384,7 +385,6 @@ msn_oim_send_read_cb(MsnSoapMessage *req + } else { + char buf[33]; + +- char *challenge = xmlnode_get_data(challengeNode); + msn_handle_chl(challenge, buf); + + g_free(oim->challenge); +@@ -400,22 +400,23 @@ msn_oim_send_read_cb(MsnSoapMessage *req + } + } else { + /* Report the error */ +- const char *str_reason; ++ const char *str_reason = NULL; + +- if (g_str_equal(faultcode_str, "q0:SystemUnavailable")) { +- str_reason = _("Message was not sent because the system is " +- "unavailable. This normally happens when the " +- "user is blocked or does not exist."); +- +- } else if (g_str_equal(faultcode_str, "q0:SenderThrottleLimitExceeded")) { +- str_reason = _("Message was not sent because messages " +- "are being sent too quickly."); +- +- } else if (g_str_equal(faultcode_str, "q0:InvalidContent")) { +- str_reason = _("Message was not sent because an unknown " +- "encoding error occurred."); ++ if (faultcode_str) { ++ if (g_str_equal(faultcode_str, "q0:SystemUnavailable")) { ++ str_reason = _("Message was not sent because the system is " ++ "unavailable. This normally happens when the " ++ "user is blocked or does not exist."); ++ } else if (g_str_equal(faultcode_str, "q0:SenderThrottleLimitExceeded")) { ++ str_reason = _("Message was not sent because messages " ++ "are being sent too quickly."); ++ } else if (g_str_equal(faultcode_str, "q0:InvalidContent")) { ++ str_reason = _("Message was not sent because an unknown " ++ "encoding error occurred."); ++ } ++ } + +- } else { ++ if (str_reason == NULL) { + str_reason = _("Message was not sent because an unknown " + "error occurred."); + } +diff -up pidgin-2.10.7/libpurple/protocols/msn/soap.c.CVE-2013-6482 pidgin-2.10.7/libpurple/protocols/msn/soap.c +--- pidgin-2.10.7/libpurple/protocols/msn/soap.c.CVE-2013-6482 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/msn/soap.c 2014-01-29 09:20:04.714151533 -0500 +@@ -304,21 +304,25 @@ msn_soap_handle_body(MsnSoapConnection * + if (faultcode != NULL) { + char *faultdata = xmlnode_get_data(faultcode); + +- if (g_str_equal(faultdata, "psf:Redirect")) { ++ if (faultdata && g_str_equal(faultdata, "psf:Redirect")) { + xmlnode *url = xmlnode_get_child(fault, "redirectUrl"); + + if (url) { + char *urldata = xmlnode_get_data(url); +- msn_soap_handle_redirect(conn, urldata); ++ if (urldata) ++ msn_soap_handle_redirect(conn, urldata); + g_free(urldata); + } + + g_free(faultdata); + msn_soap_message_destroy(response); + return TRUE; +- } else if (g_str_equal(faultdata, "wsse:FailedAuthentication")) { ++ } else if (faultdata && g_str_equal(faultdata, "wsse:FailedAuthentication")) { + xmlnode *reason = xmlnode_get_child(fault, "faultstring"); +- char *reasondata = xmlnode_get_data(reason); ++ char *reasondata = NULL; ++ ++ if (reason) ++ reasondata = xmlnode_get_data(reason); + + msn_soap_connection_sanitize(conn, TRUE); + msn_session_set_error(conn->session, MSN_ERROR_AUTH, diff --git a/SOURCES/pidgin-2.10.7-CVE-2013-6483-regression.patch b/SOURCES/pidgin-2.10.7-CVE-2013-6483-regression.patch new file mode 100644 index 0000000..881fb7f --- /dev/null +++ b/SOURCES/pidgin-2.10.7-CVE-2013-6483-regression.patch @@ -0,0 +1,133 @@ +diff -up pidgin-2.10.7/libpurple/protocols/jabber/iq.c.CVE-2013-6483-regression pidgin-2.10.7/libpurple/protocols/jabber/iq.c +--- pidgin-2.10.7/libpurple/protocols/jabber/iq.c.CVE-2013-6483-regression 2014-02-03 09:49:18.556521925 -0500 ++++ pidgin-2.10.7/libpurple/protocols/jabber/iq.c 2014-02-03 09:49:29.904554588 -0500 +@@ -283,6 +283,52 @@ void jabber_iq_remove_callback_by_id(Jab + g_hash_table_remove(js->iq_callbacks, id); + } + ++/** ++ * Verify that the 'from' attribute of an IQ reply is a valid match for ++ * a given IQ request. The expected behavior is outlined in section ++ * 8.1.2.1 of the XMPP CORE spec (RFC 6120). We consider the reply to ++ * be a valid match if any of the following is true: ++ * - Request 'to' matches reply 'from' (including the case where ++ * neither are set). ++ * - Request 'to' was empty and reply 'from' is server JID. ++ * - Request 'to' was empty and reply 'from' is my JID. The spec says ++ * we should only allow bare JID, but we also allow full JID for ++ * compatibility with some servers. ++ * ++ * These rules should allow valid IQ replies while preventing spoofed ++ * ones. ++ * ++ * For more discussion see the "Spoofing of iq ids and misbehaving ++ * servers" email thread from January 2014 on the jdev and security ++ * mailing lists. ++ * ++ * @return TRUE if this reply is valid for the given request. ++ */ ++static gboolean does_reply_from_match_request_to(JabberStream *js, JabberID *to, JabberID *from) ++{ ++ if (jabber_id_equal(to, from)) { ++ /* Request 'to' matches reply 'from' */ ++ return TRUE; ++ } ++ ++ if (!to && purple_strequal(from->domain, js->user->domain)) { ++ /* Request 'to' is empty and reply 'from' domain matches our domain */ ++ ++ if (!from->node && !from->resource) { ++ /* Reply 'from' is server bare JID */ ++ return TRUE; ++ } ++ ++ if (purple_strequal(from->node, js->user->node) ++ && (!from->resource || purple_strequal(from->resource, js->user->resource))) { ++ /* Reply 'from' is my full or bare JID */ ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ + void jabber_iq_parse(JabberStream *js, xmlnode *packet) + { + JabberIqCallbackData *jcd; +@@ -377,8 +423,9 @@ void jabber_iq_parse(JabberStream *js, x + + /* First, lets see if a special callback got registered */ + if(type == JABBER_IQ_RESULT || type == JABBER_IQ_ERROR) { +- if((jcd = g_hash_table_lookup(js->iq_callbacks, id))) { +- if(jabber_id_equal(js, jcd->to, from_id)) { ++ jcd = g_hash_table_lookup(js->iq_callbacks, id); ++ if (jcd) { ++ if (does_reply_from_match_request_to(js, jcd->to, from_id)) { + jcd->callback(js, from, type, id, packet, jcd->data); + jabber_iq_remove_callback_by_id(js, id); + jabber_id_free(from_id); +diff -up pidgin-2.10.7/libpurple/protocols/jabber/jutil.c.CVE-2013-6483-regression pidgin-2.10.7/libpurple/protocols/jabber/jutil.c +--- pidgin-2.10.7/libpurple/protocols/jabber/jutil.c.CVE-2013-6483-regression 2014-02-03 09:49:18.558521926 -0500 ++++ pidgin-2.10.7/libpurple/protocols/jabber/jutil.c 2014-02-03 09:49:29.904554588 -0500 +@@ -510,30 +510,21 @@ jabber_id_free(JabberID *jid) + + + gboolean +-jabber_id_equal(JabberStream *js, const JabberID *jid1, const JabberID *jid2) ++jabber_id_equal(const JabberID *jid1, const JabberID *jid2) + { +- const JabberID *j1, *j2; +- JabberID *bare_user_jid; +- gboolean equal; +- +- /* If an outgoing stanza has no 'to', or an incoming has no 'from', +- * then those are "the server acting as my account". This function will +- * handle that correctly. +- */ +- if (!jid1 && !jid2) ++ if (!jid1 && !jid2) { ++ /* Both are null therefore equal */ + return TRUE; ++ } + +- bare_user_jid = jabber_id_to_bare_jid(js->user); +- j1 = jid1 ? jid1 : bare_user_jid; +- j2 = jid2 ? jid2 : bare_user_jid; +- +- equal = purple_strequal(j1->node, j2->node) && +- purple_strequal(j1->domain, j2->domain) && +- purple_strequal(j1->resource, j2->resource); +- +- jabber_id_free(bare_user_jid); +- +- return equal; ++ if (!jid1 || !jid2) { ++ /* One is null, other is non-null, therefore not equal */ ++ return FALSE; ++ } ++ ++ return purple_strequal(jid1->node, jid2->node) && ++ purple_strequal(jid1->domain, jid2->domain) && ++ purple_strequal(jid1->resource, jid2->resource); + } + + char *jabber_get_domain(const char *in) +diff -up pidgin-2.10.7/libpurple/protocols/jabber/jutil.h.CVE-2013-6483-regression pidgin-2.10.7/libpurple/protocols/jabber/jutil.h +--- pidgin-2.10.7/libpurple/protocols/jabber/jutil.h.CVE-2013-6483-regression 2014-02-03 09:49:18.559521925 -0500 ++++ pidgin-2.10.7/libpurple/protocols/jabber/jutil.h 2014-02-03 09:49:29.904554588 -0500 +@@ -46,12 +46,10 @@ typedef enum { + JabberID* jabber_id_new(const char *str); + + /** +- * Compare two JIDs for equality. +- * +- * Warning: If either JID is NULL then this function uses the user's +- * bare JID, instead! ++ * Compare two JIDs for equality. In addition to the node and domain, ++ * the resources of the two JIDs must also be equal (or both absent). + */ +-gboolean jabber_id_equal(JabberStream *js, const JabberID *jid1, const JabberID *jid2); ++gboolean jabber_id_equal(const JabberID *jid1, const JabberID *jid2); + + void jabber_id_free(JabberID *jid); + diff --git a/SOURCES/pidgin-2.10.7-CVE-2013-6483.patch b/SOURCES/pidgin-2.10.7-CVE-2013-6483.patch new file mode 100644 index 0000000..13ed6b9 --- /dev/null +++ b/SOURCES/pidgin-2.10.7-CVE-2013-6483.patch @@ -0,0 +1,297 @@ +diff -up pidgin-2.10.7/libpurple/protocols/jabber/iq.c.CVE-2013-6483 pidgin-2.10.7/libpurple/protocols/jabber/iq.c +--- pidgin-2.10.7/libpurple/protocols/jabber/iq.c.CVE-2013-6483 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/jabber/iq.c 2014-01-29 10:06:23.876656091 -0500 +@@ -49,6 +49,18 @@ + static GHashTable *iq_handlers = NULL; + static GHashTable *signal_iq_handlers = NULL; + ++struct _JabberIqCallbackData { ++ JabberIqCallback *callback; ++ gpointer data; ++ JabberID *to; ++}; ++ ++void jabber_iq_callbackdata_free(JabberIqCallbackData *jcd) ++{ ++ jabber_id_free(jcd->to); ++ g_free(jcd); ++} ++ + JabberIq *jabber_iq_new(JabberStream *js, JabberIqType type) + { + JabberIq *iq; +@@ -98,11 +110,6 @@ JabberIq *jabber_iq_new_query(JabberStre + return iq; + } + +-typedef struct _JabberCallbackData { +- JabberIqCallback *callback; +- gpointer data; +-} JabberCallbackData; +- + void + jabber_iq_set_callback(JabberIq *iq, JabberIqCallback *callback, gpointer data) + { +@@ -125,15 +132,17 @@ void jabber_iq_set_id(JabberIq *iq, cons + + void jabber_iq_send(JabberIq *iq) + { +- JabberCallbackData *jcd; ++ JabberIqCallbackData *jcd; + g_return_if_fail(iq != NULL); + + jabber_send(iq->js, iq->node); + + if(iq->id && iq->callback) { +- jcd = g_new0(JabberCallbackData, 1); ++ jcd = g_new0(JabberIqCallbackData, 1); + jcd->callback = iq->callback; + jcd->data = iq->callback_data; ++ jcd->to = jabber_id_new(xmlnode_get_attrib(iq->node, "to")); ++ + g_hash_table_insert(iq->js->iq_callbacks, g_strdup(iq->id), jcd); + } + +@@ -276,18 +285,30 @@ void jabber_iq_remove_callback_by_id(Jab + + void jabber_iq_parse(JabberStream *js, xmlnode *packet) + { +- JabberCallbackData *jcd; ++ JabberIqCallbackData *jcd; + xmlnode *child, *error, *x; + const char *xmlns; + const char *iq_type, *id, *from; + JabberIqType type = JABBER_IQ_NONE; + gboolean signal_return; ++ JabberID *from_id; + + from = xmlnode_get_attrib(packet, "from"); + id = xmlnode_get_attrib(packet, "id"); + iq_type = xmlnode_get_attrib(packet, "type"); + + /* ++ * Ensure the 'from' attribute is valid. No point in handling a stanza ++ * of which we don't understand where it came from. ++ */ ++ from_id = jabber_id_new(from); ++ ++ if (from && !from_id) { ++ purple_debug_error("jabber", "Received an iq with an invalid from: %s\n", from); ++ return; ++ } ++ ++ /* + * child will be either the first tag child or NULL if there is no child. + * Historically, we used just the 'query' subchild, but newer XEPs use + * differently named children. Grabbing the first child is (for the time +@@ -312,6 +333,7 @@ void jabber_iq_parse(JabberStream *js, x + if (type == JABBER_IQ_NONE) { + purple_debug_error("jabber", "IQ with invalid type ('%s') - ignoring.\n", + iq_type ? iq_type : "(null)"); ++ jabber_id_free(from_id); + return; + } + +@@ -342,20 +364,38 @@ void jabber_iq_parse(JabberStream *js, x + purple_debug_error("jabber", "IQ of type '%s' missing id - ignoring.\n", + iq_type); + ++ jabber_id_free(from_id); + return; + } + + signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_connection_get_prpl(js->gc), + "jabber-receiving-iq", js->gc, iq_type, id, from, packet)); +- if (signal_return) ++ if (signal_return) { ++ jabber_id_free(from_id); + return; ++ } + + /* First, lets see if a special callback got registered */ + if(type == JABBER_IQ_RESULT || type == JABBER_IQ_ERROR) { + if((jcd = g_hash_table_lookup(js->iq_callbacks, id))) { +- jcd->callback(js, from, type, id, packet, jcd->data); +- jabber_iq_remove_callback_by_id(js, id); +- return; ++ if(jabber_id_equal(js, jcd->to, from_id)) { ++ jcd->callback(js, from, type, id, packet, jcd->data); ++ jabber_iq_remove_callback_by_id(js, id); ++ jabber_id_free(from_id); ++ return; ++ } else { ++ char *expected_to; ++ ++ if (jcd->to) { ++ expected_to = jabber_id_get_full_jid(jcd->to); ++ } else { ++ expected_to = jabber_id_get_bare_jid(js->user); ++ } ++ ++ purple_debug_error("jabber", "Got a result iq with id %s from %s instead of expected %s!\n", id, from ? from : "(null)", expected_to); ++ ++ g_free(expected_to); ++ } + } + } + +@@ -372,12 +412,15 @@ void jabber_iq_parse(JabberStream *js, x + if (signal_ref > 0) { + signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_connection_get_prpl(js->gc), "jabber-watched-iq", + js->gc, iq_type, id, from, child)); +- if (signal_return) ++ if (signal_return) { ++ jabber_id_free(from_id); + return; ++ } + } + + if(jih) { + jih(js, from, type, id, child); ++ jabber_id_free(from_id); + return; + } + } +@@ -404,6 +447,8 @@ void jabber_iq_parse(JabberStream *js, x + + jabber_iq_send(iq); + } ++ ++ jabber_id_free(from_id); + } + + void jabber_iq_register_handler(const char *node, const char *xmlns, JabberIqHandler *handlerfunc) +diff -up pidgin-2.10.7/libpurple/protocols/jabber/iq.h.CVE-2013-6483 pidgin-2.10.7/libpurple/protocols/jabber/iq.h +--- pidgin-2.10.7/libpurple/protocols/jabber/iq.h.CVE-2013-6483 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/jabber/iq.h 2014-01-29 10:06:23.877656064 -0500 +@@ -36,6 +36,7 @@ typedef enum { + #include "connection.h" + + typedef struct _JabberIq JabberIq; ++typedef struct _JabberIqCallbackData JabberIqCallbackData; + + /** + * A JabberIqHandler is called to process an incoming IQ stanza. +@@ -96,6 +97,7 @@ JabberIq *jabber_iq_new_query(JabberStre + + void jabber_iq_parse(JabberStream *js, xmlnode *packet); + ++void jabber_iq_callbackdata_free(JabberIqCallbackData *jcd); + void jabber_iq_remove_callback_by_id(JabberStream *js, const char *id); + void jabber_iq_set_callback(JabberIq *iq, JabberIqCallback *cb, gpointer data); + void jabber_iq_set_id(JabberIq *iq, const char *id); +diff -up pidgin-2.10.7/libpurple/protocols/jabber/jabber.c.CVE-2013-6483 pidgin-2.10.7/libpurple/protocols/jabber/jabber.c +--- pidgin-2.10.7/libpurple/protocols/jabber/jabber.c.CVE-2013-6483 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/jabber/jabber.c 2014-01-29 10:06:23.878656039 -0500 +@@ -988,7 +988,7 @@ jabber_stream_new(PurpleAccount *account + js->user_jb->subscription |= JABBER_SUB_BOTH; + + js->iq_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, +- g_free, g_free); ++ g_free, (GDestroyNotify)jabber_iq_callbackdata_free); + js->chats = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, (GDestroyNotify)jabber_chat_free); + js->next_id = g_random_int(); +diff -up pidgin-2.10.7/libpurple/protocols/jabber/jutil.c.CVE-2013-6483 pidgin-2.10.7/libpurple/protocols/jabber/jutil.c +--- pidgin-2.10.7/libpurple/protocols/jabber/jutil.c.CVE-2013-6483 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/jabber/jutil.c 2014-01-29 10:06:23.879656015 -0500 +@@ -508,6 +508,34 @@ jabber_id_free(JabberID *jid) + } + } + ++ ++gboolean ++jabber_id_equal(JabberStream *js, const JabberID *jid1, const JabberID *jid2) ++{ ++ const JabberID *j1, *j2; ++ JabberID *bare_user_jid; ++ gboolean equal; ++ ++ /* If an outgoing stanza has no 'to', or an incoming has no 'from', ++ * then those are "the server acting as my account". This function will ++ * handle that correctly. ++ */ ++ if (!jid1 && !jid2) ++ return TRUE; ++ ++ bare_user_jid = jabber_id_to_bare_jid(js->user); ++ j1 = jid1 ? jid1 : bare_user_jid; ++ j2 = jid2 ? jid2 : bare_user_jid; ++ ++ equal = purple_strequal(j1->node, j2->node) && ++ purple_strequal(j1->domain, j2->domain) && ++ purple_strequal(j1->resource, j2->resource); ++ ++ jabber_id_free(bare_user_jid); ++ ++ return equal; ++} ++ + char *jabber_get_domain(const char *in) + { + JabberID *jid = jabber_id_new(in); +@@ -536,6 +564,17 @@ char *jabber_get_resource(const char *in + return out; + } + ++JabberID * ++jabber_id_to_bare_jid(const JabberID *jid) ++{ ++ JabberID *result = g_new0(JabberID, 1); ++ ++ result->node = g_strdup(jid->node); ++ result->domain = g_strdup(jid->domain); ++ ++ return result; ++} ++ + char * + jabber_get_bare_jid(const char *in) + { +@@ -561,6 +600,19 @@ jabber_id_get_bare_jid(const JabberID *j + NULL); + } + ++char * ++jabber_id_get_full_jid(const JabberID *jid) ++{ ++ g_return_val_if_fail(jid != NULL, NULL); ++ ++ return g_strconcat(jid->node ? jid->node : "", ++ jid->node ? "@" : "", ++ jid->domain, ++ jid->resource ? "/" : "", ++ jid->resource ? jid->resource : "", ++ NULL); ++} ++ + gboolean + jabber_jid_is_domain(const char *jid) + { +diff -up pidgin-2.10.7/libpurple/protocols/jabber/jutil.h.CVE-2013-6483 pidgin-2.10.7/libpurple/protocols/jabber/jutil.h +--- pidgin-2.10.7/libpurple/protocols/jabber/jutil.h.CVE-2013-6483 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/jabber/jutil.h 2014-01-29 10:06:23.879656015 -0500 +@@ -44,12 +44,23 @@ typedef enum { + #include "jabber.h" + + JabberID* jabber_id_new(const char *str); ++ ++/** ++ * Compare two JIDs for equality. ++ * ++ * Warning: If either JID is NULL then this function uses the user's ++ * bare JID, instead! ++ */ ++gboolean jabber_id_equal(JabberStream *js, const JabberID *jid1, const JabberID *jid2); ++ + void jabber_id_free(JabberID *jid); + + char *jabber_get_domain(const char *jid); + char *jabber_get_resource(const char *jid); + char *jabber_get_bare_jid(const char *jid); + char *jabber_id_get_bare_jid(const JabberID *jid); ++char *jabber_id_get_full_jid(const JabberID *jid); ++JabberID *jabber_id_to_bare_jid(const JabberID *jid); + + gboolean jabber_jid_is_domain(const char *jid); + diff --git a/SOURCES/pidgin-2.10.7-CVE-2013-6484.patch b/SOURCES/pidgin-2.10.7-CVE-2013-6484.patch new file mode 100644 index 0000000..22038a1 --- /dev/null +++ b/SOURCES/pidgin-2.10.7-CVE-2013-6484.patch @@ -0,0 +1,12 @@ +diff -up pidgin-2.10.7/libpurple/stun.c.CVE-2013-6484 pidgin-2.10.7/libpurple/stun.c +--- pidgin-2.10.7/libpurple/stun.c.CVE-2013-6484 2013-02-11 04:16:53.000000000 -0500 ++++ pidgin-2.10.7/libpurple/stun.c 2014-01-29 13:08:18.835817422 -0500 +@@ -175,7 +175,7 @@ static void reply_cb(gpointer data, gint + struct sockaddr_in *sinptr; + + len = recv(source, buffer, sizeof(buffer) - 1, 0); +- if (!len) { ++ if (len < 0) { + purple_debug_warning("stun", "unable to read stun response\n"); + return; + } diff --git a/SOURCES/pidgin-2.10.7-CVE-2013-6485.patch b/SOURCES/pidgin-2.10.7-CVE-2013-6485.patch new file mode 100644 index 0000000..8f81e57 --- /dev/null +++ b/SOURCES/pidgin-2.10.7-CVE-2013-6485.patch @@ -0,0 +1,35 @@ +diff -up pidgin-2.10.7/libpurple/util.c.CVE-2013-6485 pidgin-2.10.7/libpurple/util.c +--- pidgin-2.10.7/libpurple/util.c.CVE-2013-6485 2014-01-28 19:09:20.896950189 -0500 ++++ pidgin-2.10.7/libpurple/util.c 2014-01-29 16:48:35.033699646 -0500 +@@ -37,6 +37,8 @@ + specified a length) */ + #define DEFAULT_MAX_HTTP_DOWNLOAD (512 * 1024) + ++#define MAX_HTTP_CHUNK_SIZE (10 * 1024 * 1024) ++ + struct _PurpleUtilFetchUrlData + { + PurpleUtilFetchUrlCallback callback; +@@ -3780,11 +3782,12 @@ process_chunked_data(char *data, gsize * + break; + s += 2; + +- if (s + sz > data + *len) { ++ if (sz > MAX_HTTP_CHUNK_SIZE || s + sz > data + *len) { + purple_debug_error("util", "Error processing chunked data: " + "Chunk size %" G_GSIZE_FORMAT " bytes was longer " + "than the data remaining in the buffer (%" + G_GSIZE_FORMAT " bytes)\n", sz, data + *len - s); ++ break; + } + + /* Move all data overtop of the chunk length that we read in earlier */ +@@ -3792,7 +3795,7 @@ process_chunked_data(char *data, gsize * + p += sz; + s += sz; + newlen += sz; +- if (*s != '\r' && *(s + 1) != '\n') { ++ if (*s == '\0' || (*s != '\r' && *(s + 1) != '\n')) { + purple_debug_error("util", "Error processing chunked data: " + "Expected \\r\\n, found: %s\n", s); + break; diff --git a/SOURCES/pidgin-2.10.7-CVE-2013-6487.patch b/SOURCES/pidgin-2.10.7-CVE-2013-6487.patch new file mode 100644 index 0000000..b408212 --- /dev/null +++ b/SOURCES/pidgin-2.10.7-CVE-2013-6487.patch @@ -0,0 +1,24 @@ +diff -up pidgin-2.10.7/libpurple/protocols/gg/lib/http.c.CVE-2013-6487 pidgin-2.10.7/libpurple/protocols/gg/lib/http.c +--- pidgin-2.10.7/libpurple/protocols/gg/lib/http.c.CVE-2013-6487 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/gg/lib/http.c 2014-01-29 20:52:59.629513642 -0500 +@@ -47,6 +47,8 @@ + #include + #include + ++#define GG_HTTP_MAX_LENGTH 1000000000 ++ + /** + * Rozpoczyna połączenie HTTP. + * +@@ -364,6 +366,11 @@ int gg_http_watch_fd(struct gg_http *h) + h->body_size = left; + } + ++ if (h->body_size > GG_HTTP_MAX_LENGTH) { ++ gg_debug(GG_DEBUG_MISC, "=> http, content-length too big\n"); ++ h->body_size = GG_HTTP_MAX_LENGTH; ++ } ++ + if (left > h->body_size) { + gg_debug(GG_DEBUG_MISC, "=> http, oversized reply (%d bytes needed, %d bytes left)\n", h->body_size, left); + h->body_size = left; diff --git a/SOURCES/pidgin-2.10.7-CVE-2013-6489.patch b/SOURCES/pidgin-2.10.7-CVE-2013-6489.patch new file mode 100644 index 0000000..afa45d5 --- /dev/null +++ b/SOURCES/pidgin-2.10.7-CVE-2013-6489.patch @@ -0,0 +1,35 @@ +diff -up pidgin-2.10.7/libpurple/protocols/mxit/markup.c.CVE-2013-6489 pidgin-2.10.7/libpurple/protocols/mxit/markup.c +--- pidgin-2.10.7/libpurple/protocols/mxit/markup.c.CVE-2013-6489 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/mxit/markup.c 2014-01-29 20:55:34.239345911 -0500 +@@ -204,7 +204,8 @@ static unsigned int asn_getlength( const + */ + static int asn_getUtf8( const char* data, char type, char** utf8 ) + { +- int len; ++ unsigned int len; ++ gchar *out_str; + + /* validate the field type [1 byte] */ + if ( data[0] != type ) { +@@ -213,10 +214,17 @@ static int asn_getUtf8( const char* data + return -1; + } + +- len = data[1]; /* length field [1 bytes] */ +- *utf8 = g_malloc( len + 1 ); +- memcpy( *utf8, &data[2], len ); /* data field */ +- (*utf8)[len] = '\0'; ++ len = (uint8_t)data[1]; /* length field [1 byte] */ ++ out_str = g_malloc(len + 1); ++ if (out_str == NULL) { ++ purple_debug_fatal(MXIT_PLUGIN_ID, "asn_getUtf8: out of memory"); ++ return -1; ++ } ++ ++ memcpy(out_str, &data[2], len); /* data field */ ++ out_str[len] = '\0'; ++ ++ *utf8 = out_str; + + return ( len + 2 ); + } diff --git a/SOURCES/pidgin-2.10.7-CVE-2013-6490.patch b/SOURCES/pidgin-2.10.7-CVE-2013-6490.patch new file mode 100644 index 0000000..3df77a8 --- /dev/null +++ b/SOURCES/pidgin-2.10.7-CVE-2013-6490.patch @@ -0,0 +1,27 @@ +diff -up pidgin-2.10.7/libpurple/protocols/simple/simple.c.CVE-2013-6490 pidgin-2.10.7/libpurple/protocols/simple/simple.c +--- pidgin-2.10.7/libpurple/protocols/simple/simple.c.CVE-2013-6490 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/simple/simple.c 2014-01-29 22:27:25.222516679 -0500 +@@ -1640,7 +1640,7 @@ static void process_input(struct simple_ + cur += 2; + restlen = conn->inbufused - (cur - conn->inbuf); + if(restlen >= msg->bodylen) { +- dummy = g_malloc(msg->bodylen + 1); ++ dummy = g_new(char, msg->bodylen + 1); + memcpy(dummy, cur, msg->bodylen); + dummy[msg->bodylen] = '\0'; + msg->body = dummy; +diff -up pidgin-2.10.7/libpurple/protocols/simple/sipmsg.c.CVE-2013-6490 pidgin-2.10.7/libpurple/protocols/simple/sipmsg.c +--- pidgin-2.10.7/libpurple/protocols/simple/sipmsg.c.CVE-2013-6490 2013-02-11 04:16:52.000000000 -0500 ++++ pidgin-2.10.7/libpurple/protocols/simple/sipmsg.c 2014-01-29 22:27:25.223516732 -0500 +@@ -114,6 +114,11 @@ struct sipmsg *sipmsg_parse_header(const + tmp2 = sipmsg_find_header(msg, "Content-Length"); + if (tmp2 != NULL) + msg->bodylen = strtol(tmp2, NULL, 10); ++ if (msg->bodylen < 0) { ++ purple_debug_warning("simple", "Invalid body length: %d", ++ msg->bodylen); ++ msg->bodylen = 0; ++ } + + if(msg->response) { + tmp2 = sipmsg_find_header(msg, "CSeq"); diff --git a/SOURCES/pidgin-2.10.7-CVE-2014-0020.patch b/SOURCES/pidgin-2.10.7-CVE-2014-0020.patch new file mode 100644 index 0000000..87d3dfa --- /dev/null +++ b/SOURCES/pidgin-2.10.7-CVE-2014-0020.patch @@ -0,0 +1,600 @@ +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]); + } diff --git a/SPECS/pidgin.spec b/SPECS/pidgin.spec index 8267d80..b46ae61 100644 --- a/SPECS/pidgin.spec +++ b/SPECS/pidgin.spec @@ -123,7 +123,7 @@ Name: pidgin Version: 2.10.7 -Release: 4%{?dist} +Release: 22%{?dist} License: GPLv2+ and GPLv2 and MIT # GPLv2+ - libpurple, gnt, finch, pidgin, most prpls # GPLv2 - silc & novell prpls @@ -164,6 +164,46 @@ Patch1: pidgin-2.10.7-drop-gadu-gadu.patch Patch100: pidgin-2.10.1-fix-msn-ft-crashes.patch Patch101: pidgin-2.10.7-link-libirc-to-libsasl2.patch +# CVE-2012-6152 +Patch102: pidgin-2.10.7-CVE-2012-6152.patch + +# CVE-2013-6477 +Patch103: pidgin-2.10.7-CVE-2013-6477.patch + +# CVE-2013-6478 +Patch104: pidgin-2.10.7-CVE-2013-6478.patch + +# CVE-2013-6479 +Patch105: pidgin-2.10.7-CVE-2013-6479.patch + +# CVE-2013-6481 +Patch106: pidgin-2.10.7-CVE-2013-6481.patch + +# CVE-2013-6482 +Patch107: pidgin-2.10.7-CVE-2013-6482.patch + +# CVE-2013-6483 +Patch108: pidgin-2.10.7-CVE-2013-6483.patch +Patch109: pidgin-2.10.7-CVE-2013-6483-regression.patch + +# CVE-2013-6484 +Patch110: pidgin-2.10.7-CVE-2013-6484.patch + +# CVE-2013-6485 +Patch111: pidgin-2.10.7-CVE-2013-6485.patch + +# CVE-2013-6487 +Patch112: pidgin-2.10.7-CVE-2013-6487.patch + +# CVE-2013-6489 +Patch113: pidgin-2.10.7-CVE-2013-6489.patch + +# CVE-2013-6490 +Patch114: pidgin-2.10.7-CVE-2013-6490.patch + +# CVE-2014-0020 +Patch115: pidgin-2.10.7-CVE-2014-0020.patch + BuildRoot: %{_tmppath}/%{name}-%{version}-root Summary: A Gtk+ based multiprotocol instant messaging client @@ -464,6 +504,21 @@ echo "FEDORA=%{fedora} RHEL=%{rhel}" # https://developer.pidgin.im/ticket/15517 %patch101 -p1 -b .irc-sasl +%patch102 -p1 -b .CVE-2012-6152 +%patch103 -p1 -b .CVE-2013-6477 +%patch104 -p1 -b .CVE-2013-6478 +%patch105 -p1 -b .CVE-2013-6479 +%patch106 -p1 -b .CVE-2013-6481 +%patch107 -p1 -b .CVE-2013-6482 +%patch108 -p1 -b .CVE-2013-6483 +%patch109 -p1 -b .CVE-2013-6483-regression +%patch110 -p1 -b .CVE-2013-6484 +%patch111 -p1 -b .CVE-2013-6485 +%patch112 -p1 -b .CVE-2013-6487 +%patch113 -p1 -b .CVE-2013-6489 +%patch114 -p1 -b .CVE-2013-6490 +%patch115 -p1 -b .CVE-2014-0020 + # Our preferences cp %{SOURCE1} prefs.xml @@ -523,7 +578,8 @@ SWITCHES="--with-extraversion=%{release}" %endif # FC5+ automatic -fstack-protector-all switch -export RPM_OPT_FLAGS=${RPM_OPT_FLAGS//-fstack-protector/-fstack-protector-all} +# RHEL7+ uses -fstack-protector-strong +export RPM_OPT_FLAGS=${RPM_OPT_FLAGS//-fstack-protector /-fstack-protector-all } export CFLAGS="$RPM_OPT_FLAGS" # remove after irc-sasl patch has been merged upstream @@ -751,6 +807,61 @@ rm -rf $RPM_BUILD_ROOT %endif %changelog +* Mon Feb 03 2014 Matthew Barnes - 2.10.7-22.el7 +- Fix regression in CVE-2013-6483. + +* Wed Jan 29 2014 Matthew Barnes - 2.10.7-21.el7 +- Add patch for CVE-2014-0020 (RH bug #1058243). + +* Wed Jan 29 2014 Matthew Barnes - 2.10.7-20.el7 +- Add patch for CVE-2013-6490 (RH bug #1058243). + +* Wed Jan 29 2014 Matthew Barnes - 2.10.7-19.el7 +- Add patch for CVE-2013-6489 (RH bug #1058243). + +* Wed Jan 29 2014 Matthew Barnes - 2.10.7-18.el7 +- Add patch for CVE-2013-6487 (RH bug #1058243). + +* Wed Jan 29 2014 Matthew Barnes - 2.10.7-17.el7 +- Add patch for CVE-2013-6477 (RH bug #1058243). + +* Wed Jan 29 2014 Matthew Barnes - 2.10.7-16.el7 +- Add patch for CVE-2013-6485 (RH bug #1058243). + +* Wed Jan 29 2014 Matthew Barnes - 2.10.7-15.el7 +- Add patch for CVE-2013-6484 (RH bug #1058243). + +* Wed Jan 29 2014 Matthew Barnes - 2.10.7-14.el7 +- Add patch for CVE-2013-6483 (RH bug #1058243). + +* Wed Jan 29 2014 Matthew Barnes - 2.10.7-13.el7 +- Add patch for CVE-2013-6482 (RH bug #1058243). + +* Tue Jan 28 2014 Matthew Barnes - 2.10.7-12.el7 +- Add patch for CVE-2013-6481 (RH bug #1058243). + +* Tue Jan 28 2014 Matthew Barnes - 2.10.7-11.el7 +- Add patch for CVE-2013-6479 (RH bug #1058243). + +* Tue Jan 28 2014 Matthew Barnes - 2.10.7-10.el7 +- Turns out the previous patch is actually for CVE-2013-6478. + +* Mon Jan 27 2014 Matthew Barnes - 2.10.7-9.el7 +- Add patch for CVE-2013-6477 (RH bug #1058243). + +* Mon Jan 27 2014 Matthew Barnes - 2.10.7-8.el7 +- Add patch for CVE-2012-6152 (RH bug #1058243). + +* Fri Jan 24 2014 Daniel Mach - 2.10.7-7.el7 +- Mass rebuild 2014-01-24 + +* Mon Jan 13 2014 Debarshi Ray - 2.10.7-6 +- Fix setting -fstack-protector on RHEL7+, use -fstack-protector-strong there +- Resolves: #1048893 + +* Fri Dec 27 2013 Daniel Mach - 2.10.7-5.el7 +- Mass rebuild 2013-12-27 + * Thu Nov 07 2013 Debarshi Ray - 2.10.7-4 - Drop Gadu-Gadu support in RHEL (Red Hat #1026505)