GameSpyBanList.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Renegade *
  23. * *
  24. * $Archive:: /Commando/Code/Commando/GameSpyBanList.cpp $*
  25. * *
  26. * Original Author:: Brian Hayes *
  27. * *
  28. * $Author:: Bhayes $*
  29. * *
  30. * $Modtime:: 3/15/02 2:55p $*
  31. * *
  32. * $Revision:: 3 $*
  33. * *
  34. *---------------------------------------------------------------------------------------------*
  35. * Functions: *
  36. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  37. //
  38. // Filename: GameSpyBanList.cpp
  39. // Author: Brian Hayes
  40. // Date: Mar 2002
  41. // Description: Maintains a list of banned nicknames/hashes/ipaddresses for GameSpy Servers
  42. //
  43. #include "cnetwork.h"
  44. #include "listnode.h"
  45. #include "GameSpyBanList.h"
  46. #include "ini.h"
  47. #include "registry.h"
  48. #include "rawfile.h"
  49. #include "gamespyauthmgr.h"
  50. #include "sctextobj.h"
  51. #include "consolemode.h"
  52. #include "gamesideservercontrol.h"
  53. cGameSpyBanList GameSpyBanList;
  54. BanEntry::BanEntry(const char *name, const char *ip, const char *hash_id, const char *ip_mask, bool rtype) {
  55. memset(nickname, 0, sizeof(nickname));
  56. ipaddress = 0;
  57. ipmask = 0xffffffff;
  58. memset(hashid, 0, sizeof(hashid));
  59. ruletype = rtype;
  60. if (name) {
  61. strncpy(nickname, name, sizeof(nickname) - 1);
  62. }
  63. if (ip) ipaddress = inet_addr(ip);
  64. if (hash_id) {
  65. strncpy(hashid, hash_id, sizeof(hashid) - 1);
  66. }
  67. if (ip_mask) {
  68. ipmask = inet_addr(ip_mask);
  69. if (!ipmask) ipmask = 0xffffffff;
  70. }
  71. }
  72. cGameSpyBanList::cGameSpyBanList() : BanList(NULL) {
  73. BanList = new List<BanEntry *> ();
  74. }
  75. cGameSpyBanList::~cGameSpyBanList() {
  76. BanList->Delete();
  77. delete BanList;
  78. }
  79. void cGameSpyBanList::Ban_User(const char *nickname, const char *challenge_response, DWORD ipaddr) {
  80. char *buff = NULL;
  81. char *q = NULL;
  82. FILE *outf = NULL;
  83. BanEntry *t = NULL;
  84. if (nickname && !challenge_response) {
  85. q = buff = new char[(strlen(nickname)*2)+1];
  86. const char *n = nickname;
  87. while (*n) {
  88. if (*n == '%') *q++ = '%';
  89. *q++ = *n++;
  90. }
  91. *q = 0;
  92. t = new BanEntry(buff);
  93. delete [] buff;
  94. } else if (challenge_response) {
  95. t = new BanEntry(NULL, NULL, challenge_response);
  96. } else if (ipaddr) {
  97. t = new BanEntry(NULL, cNetUtil::Address_To_String(ipaddr));
  98. } else {
  99. return;
  100. }
  101. BanList->Add_Tail(t);
  102. outf = fopen("banlist.txt", "at");
  103. if (outf) {
  104. fprintf(outf, "\"%s\" \"%s\" \"%s\" \"%s\" \"%s\"; \"%s\" console BAN\n", t->Get_Rule_Type() ? "Allow" : "Deny",
  105. t->Get_Nick_Name(), t->Get_Hash_ID(),
  106. t->Get_Ip_Address() ? cNetUtil::Address_To_String(t->Get_Ip_Address()) : "",
  107. t->Get_Ip_Address() ? "255.255.255.255" : "", nickname ? nickname : "");
  108. fclose(outf);
  109. }
  110. }
  111. void cGameSpyBanList::Think(void) {
  112. cPlayer *player = NULL;
  113. for (SLNode<cPlayer> *player_node = cPlayerManager::Get_Player_Object_List ()->Head ()
  114. ; player_node != NULL; player_node = player_node->Next ()) {
  115. player = player_node->Data ();
  116. WWASSERT (player != NULL);
  117. if (player->Get_Is_Active().Is_False() || !player->Is_Human()) {
  118. continue;
  119. }
  120. if (player->Get_GameSpy_Kick_State() == GAMESPY_KICK_STATE_BEGIN &&
  121. TIMEGETTIME() - player->Get_GameSpy_Kick_State_Entry_Time_Ms() > 3000) {
  122. Final_Player_Kick(player->Get_Id());
  123. } else if (player->Get_GameSpy_Kick_State() == GAMESPY_KICK_STATE_INITIAL &&
  124. player->Get_GameSpy_Auth_State() == GAMESPY_AUTH_STATE_ACCEPTED) {
  125. if (Is_User_Banned(StringClass(player->Get_Name()), player->Get_GameSpy_Hash_Id(),
  126. player->Get_Ip_Address())) {
  127. Begin_Player_Kick(player->Get_Id());
  128. } else {
  129. player->Set_GameSpy_Kick_State(GAMESPY_KICK_STATE_APPROVED);
  130. }
  131. }
  132. }
  133. }
  134. bool cGameSpyBanList::Begin_Player_Kick(int id) {
  135. cPlayer *player = cPlayerManager::Find_Player(id);
  136. if (player && player->Get_Is_Active().Is_True() && player->Is_Human()) {
  137. cScTextObj * p_message = new cScTextObj;
  138. p_message->Init(L"You've been kicked from the server. Please quit.", TEXT_MESSAGE_PRIVATE, true, HOST_TEXT_SENDER, player->Get_Id());
  139. player->Set_GameSpy_Kick_State(GAMESPY_KICK_STATE_BEGIN);
  140. return true;
  141. }
  142. return false;
  143. }
  144. bool cGameSpyBanList::Final_Player_Kick(int id) {
  145. cPlayer *player = cPlayerManager::Find_Player(id);
  146. if (player && player->Get_Is_Active().Is_True() && player->Is_Human()) {
  147. StringClass user_name = player->Get_Name();
  148. ConsoleBox.Print("%s was kicked\n", user_name);
  149. player->Set_GameSpy_Kick_State(GAMESPY_KICK_STATE_KICKED);
  150. cNetwork::Server_Kill_Connection(id);
  151. cNetwork::Cleanup_After_Client(id);
  152. return true;
  153. }
  154. return false;
  155. }
  156. bool cGameSpyBanList::Is_User_Banned(const char *nickname, const char *challenge_response,
  157. DWORD ipaddress) {
  158. BanEntry *t = BanList->First();
  159. bool ret = false;
  160. for (;t && t->Is_Valid(); t = t->Next()) {
  161. if (challenge_response && *challenge_response &&
  162. strcmp(challenge_response, t->Get_Hash_ID()) == 0) {
  163. ret = true;
  164. } else if (t->Get_Hash_ID() && strlen(t->Get_Hash_ID())){
  165. ret = false;
  166. continue;
  167. }
  168. if (ipaddress && t->Get_Ip_Address() && ((ipaddress & t->Get_Ip_Netmask()) ==
  169. (t->Get_Ip_Address() & t->Get_Ip_Netmask()))) {
  170. ret = true;
  171. } else if (t->Get_Ip_Address()) {
  172. ret = false;
  173. continue;
  174. }
  175. if (t->Get_Nick_Name() && nickname && strlen(t->Get_Nick_Name()) && strlen(nickname)) {
  176. char *a = strdup(t->Get_Nick_Name());
  177. char *b = strdup(nickname);
  178. _strupr(a); _strupr(b);
  179. //
  180. // This code means that you can put a BAN name in as
  181. // "%foo" == match on "foo" at the end of the string
  182. // "foo%" == match on "foo" at the beginning of the string
  183. // "%foo%" == match on "foo" anywhere in the string
  184. //
  185. // to match on a literal % in the nickname use %%
  186. //
  187. // Note the use of small var names to make it even more confusing
  188. if ( ((a[0] == '%') && (a[1] != '%')) &&
  189. ((a[strlen(a)-1] == '%') && (a[strlen(a)-2] != '%')) ) {
  190. a[0] = 0;
  191. a[strlen(&a[1])] = 0;
  192. Strip_Escapes(&a[1]);
  193. ret = (strstr(b, &a[1]) != NULL);
  194. } else if ((a[0] == '%') && (a[1] != '%')) {
  195. a[0] = 0;
  196. Strip_Escapes(&a[1]);
  197. if (strlen(b) > (strlen(&a[1])-1)) {
  198. ret = (strcmp(&b[strlen(b)-strlen(&a[1])], &a[1]) == 0);
  199. }
  200. } else if (strlen(a) > 1 && (a[strlen(a)-1] == '%') && (a[strlen(a)-2] != '%')) {
  201. a[strlen(a)-1] = 0;
  202. Strip_Escapes(a);
  203. if (strlen(b) > (strlen(a)-1)) {
  204. b[strlen(a)] = 0;
  205. ret = (strcmp(b, a) == 0);
  206. }
  207. } else {
  208. Strip_Escapes(a);
  209. ret = (strcmp(b, a) == 0);
  210. }
  211. free(a); free(b);
  212. }
  213. if (ret) {
  214. ret = !t->Get_Rule_Type();
  215. break;
  216. }
  217. }
  218. if (t && t->Is_Valid()) {
  219. // matched on a rule
  220. return ret;
  221. } else {
  222. // Everyone is good if they don't match a rule
  223. return false;
  224. }
  225. }
  226. void cGameSpyBanList::Strip_Escapes(char *var) {
  227. char *q = (char *)var;
  228. while ((q = strstr(q, "%%")) != NULL) {
  229. memmove(q, q+1, strlen(q));
  230. q++;
  231. }
  232. }
  233. void cGameSpyBanList::LoadBans(void) {
  234. char buff[512];
  235. FILE *outf = NULL;
  236. if (!BanList->Is_Empty()) BanList->Delete();
  237. outf = fopen("banlist.txt", "rt");
  238. if (!outf) return;
  239. buff[sizeof(buff)-1] = 0;
  240. while (fgets(buff, sizeof(buff)-1, outf)) {
  241. // Format of each line "ruletype" "nickname" "hashid" "ip" "netmask"
  242. char *nickname = NULL;
  243. char *ruletype = NULL;
  244. char *ip = NULL;
  245. char *hashid = NULL;
  246. char *ipmask = NULL;
  247. if (strlen(buff) < 3) continue;
  248. if (buff[0] == ';') continue;
  249. char *s = strchr(buff, '"');
  250. if (!s) continue;
  251. *s++ = 0;
  252. char *q = strchr(s, '"');
  253. if (!q) continue;
  254. *q++ = 0;
  255. ruletype = s;
  256. s = strchr(q, '"');
  257. if (!s) continue;
  258. *s++ = 0;
  259. q = strchr(s, '"');
  260. if (!q) continue;
  261. *q++ = 0;
  262. nickname = s;
  263. while (q) {
  264. s = strchr(q, '"');
  265. if (!s) break;
  266. *s++ = 0;
  267. q = strchr(s, '"');
  268. if (!q) break;
  269. *q++ = 0;
  270. hashid = s;
  271. s = strchr(q, '"');
  272. if (!s) break;
  273. *s++ = 0;
  274. q = strchr(s, '"');
  275. if (!q) break;
  276. *q++ = 0;
  277. ip = s;
  278. s = strchr(q, '"');
  279. if (!s) break;
  280. *s++ = 0;
  281. q = strchr(s, '"');
  282. if (!q) break;
  283. *q++ = 0;
  284. ipmask = s;
  285. break;
  286. }
  287. BanEntry *t = new BanEntry(nickname, ip, hashid, ipmask, stricmp(ruletype, "Allow") == 0);
  288. BanList->Add_Tail(t);
  289. }
  290. fclose(outf);
  291. }