/// <summary> /// Returns a list of mod commands used in every zone /// </summary> static public void history(Player player, Player recipient, string payload, int bong) { int page; string name = ""; string[] args = payload.Split(':'); bool IsNumeric = Regex.IsMatch(args[0], @"^[0-9]+$"); if (String.IsNullOrEmpty(payload)) { page = 0; } else { //Are we just typing a page number? if (IsNumeric) { try { page = Convert.ToInt32(payload); } catch { page = 0; } } else { //We are typing a name first name = args[0].Trim(); page = 0; if (payload.Contains(':')) { page = Convert.ToInt32(args[1]); } } } CS_ChatQuery <Data.Database> pkt = new CS_ChatQuery <Data.Database>(); pkt.sender = player._alias; pkt.queryType = CS_ChatQuery <Data.Database> .QueryType.history; if (!String.IsNullOrEmpty(name)) { pkt.payload = String.Join(":", payload, page.ToString()); } else { pkt.payload = page.ToString(); } player._server._db.send(pkt); }
/// <summary> /// Returns a list of mod commands used in every zone /// </summary> static public void history(Player player, Player recipient, string payload, int bong) { int page = 0; string name = string.Empty; string[] args = payload.Split(':'); bool pageIsFirst = Regex.IsMatch(args[0], @"^[0-9]+$"); if (!String.IsNullOrWhiteSpace(payload)) { if (pageIsFirst) { try { page = Convert.ToInt32(args[0]); } catch { page = 0; //Convert doesn't do negative numbers } } else { //We are typing a name first name = args[0].Trim(); if (payload.Contains(':')) { try { page = Convert.ToInt32(args[1]); } catch { page = 0; //Convert doesn't do negative numbers } } } } // convert 1-indexed human entries to 0-indexed if (page > 0) { page--; } CS_ChatQuery <Data.Database> pkt = new CS_ChatQuery <Data.Database>(); pkt.sender = player._alias; pkt.queryType = CS_ChatQuery <Data.Database> .QueryType.history; pkt.payload = String.Join(":", name, page.ToString()); player._server._db.send(pkt); }
/// <summary> /// Returns a list of admins currently powered /// </summary> static public void admins(Player player, Player recipient, string payload, int bong) { if (String.IsNullOrEmpty(payload) || payload.ToLower().Contains("list")) { //They just want to see a list of admins CS_ChatQuery <Data.Database> query = new CS_ChatQuery <Data.Database>(); query.queryType = CS_ChatQuery <Data.Database> .QueryType.adminlist; query.sender = player._alias; query.payload = "list"; player._server._db.send(query); return; } }
/// <summary> /// Creates a new packet based on the typeID and the received content /// inside the buffer. The user has to create an own implementation /// of this interface. /// </summary> public PacketBase createPacket(NetworkClient client, ushort typeID, byte[] buffer, int offset, int size) { //Ready our packet base PacketBase packet = null; size--; //Was it a system packet? if (buffer[offset++] == 0) { //Yes, find the appropriate type return(createSystemPacket(typeID, buffer, offset, size)); } //So what was the typeid? switch (typeID) { case CS_Auth <T> .TypeID: packet = new CS_Auth <T>(typeID, buffer, offset, size); break; case CS_PlayerLogin <T> .TypeID: packet = new CS_PlayerLogin <T>(typeID, buffer, offset, size); break; case CS_PlayerUpdate <T> .TypeID: packet = new CS_PlayerUpdate <T>(typeID, buffer, offset, size); break; case CS_PlayerLeave <T> .TypeID: packet = new CS_PlayerLeave <T>(typeID, buffer, offset, size); break; case CS_PlayerBanner <T> .TypeID: packet = new CS_PlayerBanner <T>(typeID, buffer, offset, size); break; case CS_PlayerStatsRequest <T> .TypeID: packet = new CS_PlayerStatsRequest <T>(typeID, buffer, offset, size); break; case CS_Whisper <T> .TypeID: packet = new CS_Whisper <T>(typeID, buffer, offset, size); break; case CS_JoinChat <T> .TypeID: packet = new CS_JoinChat <T>(typeID, buffer, offset, size); break; case CS_LeaveChat <T> .TypeID: packet = new CS_LeaveChat <T>(typeID, buffer, offset, size); break; case CS_PrivateChat <T> .TypeID: packet = new CS_PrivateChat <T>(typeID, buffer, offset, size); break; case CS_ModCommand <T> .TypeID: packet = new CS_ModCommand <T>(typeID, buffer, offset, size); break; case CS_Squads <T> .TypeID: packet = new CS_Squads <T>(typeID, buffer, offset, size); break; case CS_ChatQuery <T> .TypeID: packet = new CS_ChatQuery <T>(typeID, buffer, offset, size); break; case Disconnect <T> .TypeID: packet = new Disconnect <T>(typeID, buffer, offset, size); break; case CS_Ban <T> .TypeID: packet = new CS_Ban <T>(typeID, buffer, offset, size); break; case CS_SquadMatch <T> .TypeID: packet = new CS_SquadMatch <T>(typeID, buffer, offset, size); break; case CS_ModQuery <T> .TypeID: packet = new CS_ModQuery <T>(typeID, buffer, offset, size); break; case CS_ChatCommand <T> .TypeID: packet = new CS_ChatCommand <T>(typeID, buffer, offset, size); break; case CS_StatsUpdate <T> .TypeID: packet = new CS_StatsUpdate <T>(typeID, buffer, offset, size); break; case CS_ArenaUpdate <T> .TypeID: packet = new CS_ArenaUpdate <T>(typeID, buffer, offset, size); break; default: //An undefined packet. packet = new PacketDummy(typeID, buffer, offset, size); break; } return(packet); }
/// <summary> /// Triggered when the client is attempting to enter the game and sends his security reply /// </summary> static public void Handle_CS_Environment(CS_Environment pkt, Player player) { //Does he have a target ready to receive the information? Player target = player.getVar("envReq") as Player; List <string> badPrograms = new List <string>(); badPrograms.Add("cheat engine 6.2"); badPrograms.Add("ollydbg"); badPrograms.Add("cheat engine"); badPrograms.Add("cheatengine"); badPrograms.Add("ollydbg.exe"); badPrograms.Add("wireshark"); badPrograms.Add("wireshark.exe"); badPrograms.Add("speederxp"); badPrograms.Add("L. Spiro"); badPrograms.Add("spiro"); badPrograms.Add("mhs"); badPrograms.Add("hex editor"); if (target == null) {//It was a request by the server //Check the processes foreach (string element in pkt.processes) { if (badPrograms.Contains(Logic_Text.RemoveIllegalCharacters(element).ToLower()) && player._permissionStatic != Data.PlayerPermission.Sysop) {//They have a cheat running or debugger, kick them out and inform mods if (!player._server.IsStandalone) { CS_ChatQuery <Data.Database> pktquery = new CS_ChatQuery <Data.Database>(); pktquery.queryType = CS_ChatQuery <Data.Database> .QueryType.alert; pktquery.sender = player._alias; pktquery.payload = String.Format("&ALERT - Player Kicked: (Zone={0}, Arena={1}, Player={2}) Reason=Using a hack or cheat engine. Program={3}", player._server.Name, player._arena._name, player._alias, Logic_Text.RemoveIllegalCharacters(element).ToLower()); //Send it! player._server._db.send(pktquery); } else { foreach (Player ppl in player._arena.Players.ToList()) { if (ppl.PermissionLevelLocal >= Data.PlayerPermission.ArenaMod) { ppl.sendMessage(-1, String.Format("&ALERT - Player Kicked: (Zone={0}, Arena={1}, Player={2}) Reason=Using a hack or cheat engine. Program={3}", player._server.Name, player._arena._name, player._alias, Logic_Text.RemoveIllegalCharacters(element).ToLower())); } } } Log.write(TLog.Security, String.Format("Player Kicked: (Zone={0}, Arena={1}, Player={2}) Reason=Using a hack or cheat engine. Program={3}", player._server.Name, player._arena._name, player._alias, Logic_Text.RemoveIllegalCharacters(element).ToLower())); player.disconnect(); return; } } //Check the windows foreach (string element in pkt.windows) { if (badPrograms.Contains(Logic_Text.RemoveIllegalCharacters(element).ToLower()) && player._permissionStatic != Data.PlayerPermission.Sysop) {//They have a cheat running or debugger, kick them out and inform mods if (!player._server.IsStandalone) { CS_ChatQuery <Data.Database> pktquery = new CS_ChatQuery <Data.Database>(); pktquery.queryType = CS_ChatQuery <Data.Database> .QueryType.alert; pktquery.sender = player._alias; pktquery.payload = String.Format("&ALERT - Player Kicked: (Zone={0}, Arena={1}, Player={2}) Reason=Using a hack or cheat engine. Program={3}", player._server.Name, player._arena._name, player._alias, Logic_Text.RemoveIllegalCharacters(element).ToLower()); //Send it! player._server._db.send(pktquery); } else { foreach (Player ppl in player._arena.Players.ToList()) { if (ppl.PermissionLevelLocal >= Data.PlayerPermission.ArenaMod) { ppl.sendMessage(-1, String.Format("&ALERT - Player Kicked: (Zone={0}, Arena={1}, Player={2}) Reason=Using a hack or cheat engine.", player._server.Name, player._arena._name, player._alias)); } } } player.disconnect(); } } return; } player.setVar("envReq", null); //Display to him the results target.sendMessage(0, "&Processes:"); foreach (string element in pkt.processes) { target.sendMessage(0, "*" + Logic_Text.RemoveIllegalCharacters(element)); } target.sendMessage(0, "&Windows:"); foreach (string element in pkt.windows) { target.sendMessage(0, "*" + Logic_Text.RemoveIllegalCharacters(element)); } // TODO: Write these out to a file so that later we can compare them. if (!String.IsNullOrWhiteSpace(player.getVar("envReqParams") as String)) { var filename = ""; // read envReqParams // Write out to a file. } }
/// <summary> /// Triggered when the client has responsed to a security request /// </summary> static public void Handle_CS_Security(CS_SecurityCheck pkt, Player player) { //Don't do in private arenas until i figure out if it can f**k things up if (player != null && player._arena.IsPrivate) { return; } Player reliablePlayer = player.getVar("reliable") as Player; Player target = player.getVar("secReq") as Player; // if (player._alias == "kon") // return; if (target == null) { //Server is checking assets if (reliablePlayer != null && reliablePlayer == player) { //Lets use the mods asset checksum player._server._reliableChecksum = pkt.Unk3; Log.write(TLog.Security, "Reliable client checksum " + pkt.Unk3 + " set by " + player._alias); player.setVar("reliable", null); return; } //Not a mod if (pkt.Unk3 != player._server._reliableChecksum && player._server._reliableChecksum != 0 && player._permissionStatic != Data.PlayerPermission.Sysop) {//Mismatch Log.write(TLog.Security, "Checksum mismatch: " + pkt.Unk3 + " vs " + player._server._reliableChecksum); if (!player._server.IsStandalone) { CS_ChatQuery <Data.Database> pktquery = new CS_ChatQuery <Data.Database>(); pktquery.queryType = CS_ChatQuery <Data.Database> .QueryType.alert; pktquery.sender = player._alias; pktquery.payload = String.Format("&ALERT - Player Kicked: (Zone={0}, Arena={1}, Player={2}, Checksum={3}, Reliable={4}) Reason=Client checksum mismatch.", player._server.Name, player._arena._name, player._alias, pkt.Unk3, player._server._reliableChecksum); //Send it! player._server._db.send(pktquery); player.disconnect(); } else { foreach (Player ppl in player._arena.Players.ToList()) { if (ppl.PermissionLevelLocal >= Data.PlayerPermission.ArenaMod) { ppl.sendMessage(-1, String.Format("&ALERT - Player Kicked: (Zone={0}, Arena={1}, Player={2}, Checksum={3}, Reliable={4}) Reason=Client checksum mismatch.", player._server.Name, player._arena._name, player._alias, pkt.Unk3, player._server._reliableChecksum)); } } player.disconnect(); } } return; } if (target == player) { reliable = pkt.Unk3; player._server._reliableChecksum = pkt.Unk3; } player.setVar("secReq", null); //Check pkt.Unk3 against reliable source here if (pkt.Unk3 != reliable && reliable != 0) {//Message any mod that used this command target.sendMessage(0, "@**Mismatch for player: " + player._alias.ToString()); target.sendMessage(0, "@**Expected: " + reliable + " Received: " + pkt.Unk3); //player.disconnect(); //Write and inform mods here } else { target.sendMessage(0, "Player " + player._alias.ToString() + " :: " + pkt.Unk3); //In-Memory Asset checksum } }
/// <summary> /// Handles a moderator command received from a player /// </summary> public void playerModCommand(Player from, Player recipient, string command, string payload, int bong) { //Attempt to find the appropriate handler HandlerDescriptor handler; if (!_commandRegistrar._modCommands.TryGetValue(command.ToLower(), out handler)) { if (String.IsNullOrEmpty(command) && !String.IsNullOrWhiteSpace(payload) && from.PermissionLevelLocal > Data.PlayerPermission.Normal) { //Mod chat if (_server.IsStandalone) { foreach (Player p in Players) { if (p != from && p.PermissionLevelLocal >= Data.PlayerPermission.ArenaMod) { p.sendMessage(0, String.Format("&[ModChat] [{0}]> {1}", from._alias, payload)); } } } else { //For arena owners only foreach (Player p in Players) { if (p != from && p._permissionTemp >= Data.PlayerPermission.ArenaMod) { p.sendMessage(0, String.Format("&[ModChat] [{0}]> {1}", from._alias, payload)); } } //For all other mods CS_ChatQuery <Data.Database> pkt = new CS_ChatQuery <Data.Database>(); pkt.queryType = CS_ChatQuery <Data.Database> .QueryType.modChat; pkt.sender = from._alias; pkt.payload = String.Format("&[ModChat] [{0}]> {1}", from._alias, payload); //Send it! _server._db.send(pkt); } } else { //Possibly a scripted mod command, lets pass it from._arena.handlePlayerModCommand(from, recipient, command, payload); } return; } //Are they a developer? if (!from._developer) { //No //Check the permission levels if ((int)from.PermissionLevelLocal < (int)handler.permissionLevel) { //Not going to happen. return; } } else { //They are, is this a dev command? if (!handler.isDevCommand) { return; } //Do they have the power? if ((int)from.PermissionLevelLocal < (int)handler.permissionLevel) { //Nope return; } } //Command logging (ignore normal player permission commands like *help, etc) if (from.PermissionLevelLocal != Data.PlayerPermission.Normal) { //Notify his superiors in the arena string sRecipient; foreach (Player p in Players) { if (p != from && !p._watchMod) { //We have watchmod commands off, bypass this player continue; } if (p != from && (int)from.PermissionLevelLocal <= (int)p.PermissionLevelLocal) { p.sendMessage(0, String.Format("&[Arena: {0}] {1}>{2} *{3} {4}", from._arena._name, from._alias, sRecipient = (recipient != null) ? " :" + recipient._alias + ":" : String.Empty, command, payload)); } //Developer? else if (from._developer) { if (p.PermissionLevelLocal >= Data.PlayerPermission.Mod && p != from) { p.sendMessage(0, String.Format("&[Arena: {0}] {1}>{2} *{3} {4}", from._arena._name, from._alias, sRecipient = (recipient != null) ? " :" + recipient._alias + ":" : String.Empty, command, payload)); } } } //Log it in the history database if (!_server.IsStandalone) { CS_ModCommand <Data.Database> pkt = new CS_ModCommand <Data.Database>(); pkt.sender = from._alias; pkt.recipient = (recipient != null) ? recipient._alias : "none"; pkt.zone = from._server.Name; pkt.arena = from._arena._name; pkt.command = command + " " + payload; //Send it! from._server._db.send(pkt); } } try { //Security hole fix //Lets check their level and their arena if (from.PermissionLevel < Data.PlayerPermission.SMod) { if (recipient != null && !recipient._arena._name.Equals(from._arena._name, StringComparison.OrdinalIgnoreCase)) { from.sendMessage(-1, "You cannot use commands from one arena to another."); return; } } //Handle it! handler.handler(from, recipient, payload, bong); } catch (Exception ex) { if (recipient != null) { Log.write(TLog.Exception, "Exception while executing mod command '{0}' from '{1}' to '{2}'.\r\nPayload: {3}\r\n{4}", command, from, recipient, payload, ex); } else { Log.write(TLog.Exception, "Exception while executing mod command '{0}' from '{1}'.\r\nPayload: {2}\r\n{3}", command, from, payload, ex); } } }
/// <summary> /// Displays account related information about a player or IP address /// </summary> public static void whois(Player player, Player recipient, string payload, int bong) { //Sanity checks if (player._server.IsStandalone) { player.sendMessage(-1, "Server is in stand-alone mode."); return; } if (String.IsNullOrEmpty(payload) && recipient == null) { player.sendMessage(-1, "Recipient/payload can not be empty. (*whois alias, *whois #id or *whois ipaddress(with or without wildcard *) or ::*whois)"); return; } string queryBan; //Create a new query packet. CS_ChatQuery <Data.Database> query = new CS_ChatQuery <Data.Database>(); query.queryType = CS_ChatQuery <Data.Database> .QueryType.whois; query.sender = player._alias; if (recipient != null) { query.payload = recipient._alias; } else if (payload.Length > 0) { if (payload == "*" || payload == "#") { player.sendMessage(-1, "Error: wildcard cannot be the only argument."); return; } //Are we looking for the account id? if (payload.StartsWith("#")) { long id; string trim = payload.TrimStart('#'); if (!Int64.TryParse(trim, out id)) { player.sendMessage(-1, "That is not a valid number."); return; } //Do nothing here, query.payload will already be set to payload } else { //Nope, check wildcard lookups //Since db is reversed sides on wildcard lookups, lets snap it correctly for us if (payload.StartsWith("*") && !payload.EndsWith("*")) { payload = payload.TrimStart('*'); payload += "*"; } else if (payload.EndsWith("*") && !payload.StartsWith("*")) { if (!payload.Contains(".")) { payload = payload.TrimEnd('*'); payload = String.Format("*{0}", payload); } else { string[] check = payload.Split('.'); if (!Helpers.IsNumeric(check[0].Trim())) { payload = payload.TrimEnd('*'); payload = String.Format("*{0}", payload); } } } } query.payload = payload; } else { player.sendMessage(-1, "Syntax: *whois alias(with or without wildcard *), *whois #id, *whois ipaddress(with or without wildcard *) or ::*whois"); return; } //Snap the string before sending it //For ban lookup queryBan = query.payload; //Send it! player._server._db.send(query); //Added - shows bans //Create a ban query packet CS_ChatQuery <Data.Database> ban = new CS_ChatQuery <Data.Database>(); ban.queryType = CS_ChatQuery <Data.Database> .QueryType.ban; ban.sender = player._alias; ban.payload = queryBan; //Send it! player._server._db.send(ban); }
/// <summary> /// Triggered when the client is attempting to join an arena, complete with security credentials /// </summary> static public void Handle_CS_ArenaJoin(CS_ArenaJoin pkt, Player player) { //If the player isn't logged in, ignore if (!player._bLoggedIn) { //Log and abort Log.write(TLog.Warning, "Player {0} tried to send security update while not logged in.", player); player.disconnect(); return; } //If he's in an arena, get him out of it if (player._arena != null) { player.leftArena(); } //Does he have a specific arena to join? Arena match = null; if (pkt.ArenaName != "" && pkt.ArenaName != "-2") { match = player._server.playerJoinArena(player, pkt.ArenaName); } if (match == null) { //We need to find our player an arena to inhabit.. match = player._server.allocatePlayer(player); } //If we're unable to find an arena, abort if (match == null) { Log.write(TLog.Warning, "Unable to allocate player '{0}' an arena.", player._alias); player.disconnect(); return; } //Add him to the arena match.newPlayer(player); //TODO: Compare to the server's checksum instead. if (player._assetCS == 0) { player._assetCS = pkt.AssetChecksum; } else { //What the tomfoolery is goin' here? if (player._assetCS != pkt.AssetChecksum) { //Kick the f****r and alert mods if (!player._server.IsStandalone) { CS_ChatQuery <Data.Database> pktquery = new CS_ChatQuery <Data.Database>(); pktquery.queryType = CS_ChatQuery <Data.Database> .QueryType.alert; pktquery.sender = player._alias; pktquery.payload = String.Format("![Security] Player {0} kicked. Checksum mismatch - (Original={1} New={2})", player._alias, player._assetCS, pkt.AssetChecksum); //Send it! player._server._db.send(pktquery); } else { //Alert any moderators foreach (Player p in player._arena.Players) { if (p.PermissionLevelLocal > Data.PlayerPermission.Normal) { p.sendMessage(0, String.Format("![Security] Player {0} kicked. Checksum mismatch - (Original={1} New={2})", player._alias, player._assetCS, pkt.AssetChecksum)); } } } //Log it Log.write(TLog.Security, "[Security] Player {0} kicked. Checksum mismatch - (Original={1} New={2})", player._alias, player._assetCS, pkt.AssetChecksum); //Bye! player.disconnect(); } //Passed the first one, lets try the server difference // UInt32 checksum = (AssetManager.Manager.checkSum()); /* * if (player._assetCS != checksum) * { * //Kick the f****r and alert mods * if (!player._server.IsStandalone) * { * CS_Query<Data.Database> pktquery = new CS_Query<Data.Database>(); * pktquery.queryType = CS_Query<Data.Database>.QueryType.alert; * pktquery.sender = player._alias; * pktquery.payload = String.Format("![Security] Player {0} kicked. Checksum mismatch - (Players={1} Servers={2} New={3})", player._alias, player._assetCS, checksum, pkt.AssetChecksum); * //Send it! * player._server._db.send(pktquery); * } * else * { * //Alert any moderators * foreach (Player p in player._arena.Players) * if (p.PermissionLevelLocal > Data.PlayerPermission.Normal) * p.sendMessage(0, String.Format("![Security] Player {0} kicked. Checksum mismatch - (Players={1} Servers={2} New={3})", player._alias, player._assetCS, checksum, pkt.AssetChecksum)); * } * * //Log it * Log.write(TLog.Security, "[Security] Player {0} kicked. Checksum mismatch - (Players={1} Servers={2} New={2})", player._alias, player._assetCS, checksum, pkt.AssetChecksum); * * //Bye! * player.disconnect(); * }*/ } }