From 84811bcfe875d6c42cd8271bbdae757f0b5d445b Mon Sep 17 00:00:00 2001
From: HarpyWar <harpywar@gmail.com>
Date: Sun, 29 Apr 2012 11:02:07 +0400
Subject: [PATCH] Fixed Warcraft 3 ICON SWITCH hack
 http://forums.harpywar.com/viewtopic.php?pid=3786

---
 pvpgn/src/bnetd/handle_anongame.cpp | 93 +++++++++++++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/pvpgn/src/bnetd/handle_anongame.cpp b/pvpgn/src/bnetd/handle_anongame.cpp
index 2d5a303..0de1760 100644
--- a/pvpgn/src/bnetd/handle_anongame.cpp
+++ b/pvpgn/src/bnetd/handle_anongame.cpp
@@ -58,6 +58,7 @@ namespace bnetd
 /* 0x08 */ static int _client_anongame_profile_clan(t_connection * c, t_packet const * const packet);
 /* 0x09 */ static int _client_anongame_get_icon(t_connection * c, t_packet const * const packet);
 /* 0x0A */ static int _client_anongame_set_icon(t_connection * c, t_packet const * const packet);
+static int check_user_icon(t_account * account, const char * user_icon);
 
 /* misc functions used by _client_anongame_tournament() */
 static unsigned int _tournament_time_convert(unsigned int time);
@@ -539,11 +540,45 @@ static int _client_anongame_get_icon(t_connection * c, t_packet const * const pa
     return 0;
 }
 
+
+
+
+
+//static int _client_anongame_set_icon(t_connection * c, t_packet const * const packet)
+//{
+//    //BlacKDicK 04/20/2003
+//    unsigned int desired_icon;
+//    char user_icon[5];
+//
+//    /*FIXME: In this case we do not get a 'count' but insted of it we get the icon
+//    that the client wants to set.'W3H2' for an example. For now it is ok, since they share
+//    the same position	on the packet*/
+//    desired_icon=bn_int_get(packet->u.client_findanongame.count);
+//    user_icon[4]=0;
+//    if (desired_icon==0){
+//	std::strcpy(user_icon,"NULL");
+//	eventlog(eventlog_level_info,__FUNCTION__,"[%d] Set icon packet to DEFAULT ICON [%4.4s]",conn_get_socket(c),user_icon);
+//    }else{
+//	std::memcpy(user_icon,&desired_icon,4);
+//	eventlog(eventlog_level_info,__FUNCTION__,"[%d] Set icon packet to ICON [%s]",conn_get_socket(c),user_icon);
+//    }
+//
+//    account_set_user_icon(conn_get_account(c),conn_get_clienttag(c),user_icon);
+//    //FIXME: Still need a way to 'refresh the user/channel'
+//    //_handle_rejoin_command(conn_get_account(c),"");
+//    /* ??? channel_update_userflags() */
+//	conn_update_w3_playerinfo(c);
+//
+//    channel_rejoin(c);
+//    return 0;
+//}
 static int _client_anongame_set_icon(t_connection * c, t_packet const * const packet)
 {
     //BlacKDicK 04/20/2003
     unsigned int desired_icon;
     char user_icon[5];
+	t_account * account;
+	t_clienttag ctag;
 
     /*FIXME: In this case we do not get a 'count' but insted of it we get the icon
     that the client wants to set.'W3H2' for an example. For now it is ok, since they share
@@ -558,6 +593,15 @@ static int _client_anongame_set_icon(t_connection * c, t_packet const * const pa
 	eventlog(eventlog_level_info,__FUNCTION__,"[%d] Set icon packet to ICON [%s]",conn_get_socket(c),user_icon);
     }
 
+	account = conn_get_account(c);
+
+	if (check_user_icon(account,user_icon) == 0)
+	{
+		eventlog(eventlog_level_info,__FUNCTION__,"[%s] \"%s\" ICON SWITCH hack attempt, icon set to default ", conn_get_username(c),user_icon);
+		std::strcpy(user_icon,"NULL"); // set icon to default
+		conn_set_state(c,conn_state_destroy); // kill user session
+	}
+
     account_set_user_icon(conn_get_account(c),conn_get_clienttag(c),user_icon);
     //FIXME: Still need a way to 'refresh the user/channel'
     //_handle_rejoin_command(conn_get_account(c),"");
@@ -568,6 +612,55 @@ static int _client_anongame_set_icon(t_connection * c, t_packet const * const pa
     return 0;
 }
 
+// check user for illegal icon
+static int check_user_icon(t_account * account, const char * user_icon)
+{
+	unsigned int i, len;
+    char temp_str[2];
+	char user_race;
+	int number;
+
+    len = std::strlen(user_icon);
+    if (len != 4)
+	eventlog(eventlog_level_error,__FUNCTION__,"got invalid user icon '%s'",user_icon);
+
+    for (i=0; i<len && i < 2; i++)
+	    temp_str[i] = user_icon[i];
+
+	number = temp_str[0]-'0';
+    user_race = temp_str[1];
+
+
+	int race[]={W3_RACE_RANDOM,W3_RACE_HUMANS,W3_RACE_ORCS,W3_RACE_UNDEAD,W3_RACE_NIGHTELVES,W3_RACE_DEMONS};
+	char race_char[6] = {'R','H','O','U','N','D'};
+    int icon_pos[5] = {2,3,4,5,6};
+    int icon_req_wins[5] = {25, 150, 350, 750, 1500};
+
+	for (int i = 0; i < sizeof(race_char); i++)
+	{
+		if (user_race == race_char[i])
+		{
+			for (int j = 0; j < sizeof(icon_pos); j++)
+			{
+				if (number == icon_pos[j])
+				{
+					// compare account race wins and require wins
+					if (account_get_racewins( account, race[i], account_get_ll_clienttag(account) ) >= icon_req_wins[j])
+						return 1;
+
+					return 0;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+
+
+
+
+
 static int _client_anongame_infos(t_connection * c, t_packet const * const packet)
 {
     t_packet * rpacket;