/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : Renegade * * * * $Archive:: /Commando/Code/Commando/GameSpyBanList.cpp $* * * * Original Author:: Brian Hayes * * * * $Author:: Bhayes $* * * * $Modtime:: 3/15/02 2:55p $* * * * $Revision:: 3 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ // // Filename: GameSpyBanList.cpp // Author: Brian Hayes // Date: Mar 2002 // Description: Maintains a list of banned nicknames/hashes/ipaddresses for GameSpy Servers // #include "cnetwork.h" #include "listnode.h" #include "GameSpyBanList.h" #include "ini.h" #include "registry.h" #include "rawfile.h" #include "gamespyauthmgr.h" #include "sctextobj.h" #include "consolemode.h" #include "gamesideservercontrol.h" cGameSpyBanList GameSpyBanList; BanEntry::BanEntry(const char *name, const char *ip, const char *hash_id, const char *ip_mask, bool rtype) { memset(nickname, 0, sizeof(nickname)); ipaddress = 0; ipmask = 0xffffffff; memset(hashid, 0, sizeof(hashid)); ruletype = rtype; if (name) { strncpy(nickname, name, sizeof(nickname) - 1); } if (ip) ipaddress = inet_addr(ip); if (hash_id) { strncpy(hashid, hash_id, sizeof(hashid) - 1); } if (ip_mask) { ipmask = inet_addr(ip_mask); if (!ipmask) ipmask = 0xffffffff; } } cGameSpyBanList::cGameSpyBanList() : BanList(NULL) { BanList = new List (); } cGameSpyBanList::~cGameSpyBanList() { BanList->Delete(); delete BanList; } void cGameSpyBanList::Ban_User(const char *nickname, const char *challenge_response, DWORD ipaddr) { char *buff = NULL; char *q = NULL; FILE *outf = NULL; BanEntry *t = NULL; if (nickname && !challenge_response) { q = buff = new char[(strlen(nickname)*2)+1]; const char *n = nickname; while (*n) { if (*n == '%') *q++ = '%'; *q++ = *n++; } *q = 0; t = new BanEntry(buff); delete [] buff; } else if (challenge_response) { t = new BanEntry(NULL, NULL, challenge_response); } else if (ipaddr) { t = new BanEntry(NULL, cNetUtil::Address_To_String(ipaddr)); } else { return; } BanList->Add_Tail(t); outf = fopen("banlist.txt", "at"); if (outf) { fprintf(outf, "\"%s\" \"%s\" \"%s\" \"%s\" \"%s\"; \"%s\" console BAN\n", t->Get_Rule_Type() ? "Allow" : "Deny", t->Get_Nick_Name(), t->Get_Hash_ID(), t->Get_Ip_Address() ? cNetUtil::Address_To_String(t->Get_Ip_Address()) : "", t->Get_Ip_Address() ? "255.255.255.255" : "", nickname ? nickname : ""); fclose(outf); } } void cGameSpyBanList::Think(void) { cPlayer *player = NULL; for (SLNode *player_node = cPlayerManager::Get_Player_Object_List ()->Head () ; player_node != NULL; player_node = player_node->Next ()) { player = player_node->Data (); WWASSERT (player != NULL); if (player->Get_Is_Active().Is_False() || !player->Is_Human()) { continue; } if (player->Get_GameSpy_Kick_State() == GAMESPY_KICK_STATE_BEGIN && TIMEGETTIME() - player->Get_GameSpy_Kick_State_Entry_Time_Ms() > 3000) { Final_Player_Kick(player->Get_Id()); } else if (player->Get_GameSpy_Kick_State() == GAMESPY_KICK_STATE_INITIAL && player->Get_GameSpy_Auth_State() == GAMESPY_AUTH_STATE_ACCEPTED) { if (Is_User_Banned(StringClass(player->Get_Name()), player->Get_GameSpy_Hash_Id(), player->Get_Ip_Address())) { Begin_Player_Kick(player->Get_Id()); } else { player->Set_GameSpy_Kick_State(GAMESPY_KICK_STATE_APPROVED); } } } } bool cGameSpyBanList::Begin_Player_Kick(int id) { cPlayer *player = cPlayerManager::Find_Player(id); if (player && player->Get_Is_Active().Is_True() && player->Is_Human()) { cScTextObj * p_message = new cScTextObj; p_message->Init(L"You've been kicked from the server. Please quit.", TEXT_MESSAGE_PRIVATE, true, HOST_TEXT_SENDER, player->Get_Id()); player->Set_GameSpy_Kick_State(GAMESPY_KICK_STATE_BEGIN); return true; } return false; } bool cGameSpyBanList::Final_Player_Kick(int id) { cPlayer *player = cPlayerManager::Find_Player(id); if (player && player->Get_Is_Active().Is_True() && player->Is_Human()) { StringClass user_name = player->Get_Name(); ConsoleBox.Print("%s was kicked\n", user_name); player->Set_GameSpy_Kick_State(GAMESPY_KICK_STATE_KICKED); cNetwork::Server_Kill_Connection(id); cNetwork::Cleanup_After_Client(id); return true; } return false; } bool cGameSpyBanList::Is_User_Banned(const char *nickname, const char *challenge_response, DWORD ipaddress) { BanEntry *t = BanList->First(); bool ret = false; for (;t && t->Is_Valid(); t = t->Next()) { if (challenge_response && *challenge_response && strcmp(challenge_response, t->Get_Hash_ID()) == 0) { ret = true; } else if (t->Get_Hash_ID() && strlen(t->Get_Hash_ID())){ ret = false; continue; } if (ipaddress && t->Get_Ip_Address() && ((ipaddress & t->Get_Ip_Netmask()) == (t->Get_Ip_Address() & t->Get_Ip_Netmask()))) { ret = true; } else if (t->Get_Ip_Address()) { ret = false; continue; } if (t->Get_Nick_Name() && nickname && strlen(t->Get_Nick_Name()) && strlen(nickname)) { char *a = strdup(t->Get_Nick_Name()); char *b = strdup(nickname); _strupr(a); _strupr(b); // // This code means that you can put a BAN name in as // "%foo" == match on "foo" at the end of the string // "foo%" == match on "foo" at the beginning of the string // "%foo%" == match on "foo" anywhere in the string // // to match on a literal % in the nickname use %% // // Note the use of small var names to make it even more confusing if ( ((a[0] == '%') && (a[1] != '%')) && ((a[strlen(a)-1] == '%') && (a[strlen(a)-2] != '%')) ) { a[0] = 0; a[strlen(&a[1])] = 0; Strip_Escapes(&a[1]); ret = (strstr(b, &a[1]) != NULL); } else if ((a[0] == '%') && (a[1] != '%')) { a[0] = 0; Strip_Escapes(&a[1]); if (strlen(b) > (strlen(&a[1])-1)) { ret = (strcmp(&b[strlen(b)-strlen(&a[1])], &a[1]) == 0); } } else if (strlen(a) > 1 && (a[strlen(a)-1] == '%') && (a[strlen(a)-2] != '%')) { a[strlen(a)-1] = 0; Strip_Escapes(a); if (strlen(b) > (strlen(a)-1)) { b[strlen(a)] = 0; ret = (strcmp(b, a) == 0); } } else { Strip_Escapes(a); ret = (strcmp(b, a) == 0); } free(a); free(b); } if (ret) { ret = !t->Get_Rule_Type(); break; } } if (t && t->Is_Valid()) { // matched on a rule return ret; } else { // Everyone is good if they don't match a rule return false; } } void cGameSpyBanList::Strip_Escapes(char *var) { char *q = (char *)var; while ((q = strstr(q, "%%")) != NULL) { memmove(q, q+1, strlen(q)); q++; } } void cGameSpyBanList::LoadBans(void) { char buff[512]; FILE *outf = NULL; if (!BanList->Is_Empty()) BanList->Delete(); outf = fopen("banlist.txt", "rt"); if (!outf) return; buff[sizeof(buff)-1] = 0; while (fgets(buff, sizeof(buff)-1, outf)) { // Format of each line "ruletype" "nickname" "hashid" "ip" "netmask" char *nickname = NULL; char *ruletype = NULL; char *ip = NULL; char *hashid = NULL; char *ipmask = NULL; if (strlen(buff) < 3) continue; if (buff[0] == ';') continue; char *s = strchr(buff, '"'); if (!s) continue; *s++ = 0; char *q = strchr(s, '"'); if (!q) continue; *q++ = 0; ruletype = s; s = strchr(q, '"'); if (!s) continue; *s++ = 0; q = strchr(s, '"'); if (!q) continue; *q++ = 0; nickname = s; while (q) { s = strchr(q, '"'); if (!s) break; *s++ = 0; q = strchr(s, '"'); if (!q) break; *q++ = 0; hashid = s; s = strchr(q, '"'); if (!s) break; *s++ = 0; q = strchr(s, '"'); if (!q) break; *q++ = 0; ip = s; s = strchr(q, '"'); if (!s) break; *s++ = 0; q = strchr(s, '"'); if (!q) break; *q++ = 0; ipmask = s; break; } BanEntry *t = new BanEntry(nickname, ip, hashid, ipmask, stricmp(ruletype, "Allow") == 0); BanList->Add_Tail(t); } fclose(outf); }