diff --git a/code/controllers/subsystem/stickyban.dm b/code/controllers/subsystem/stickyban.dm index 9b463b219f6..6d1d1088126 100644 --- a/code/controllers/subsystem/stickyban.dm +++ b/code/controllers/subsystem/stickyban.dm @@ -42,11 +42,11 @@ SUBSYSTEM_DEF(stickyban) /datum/controller/subsystem/stickyban/proc/Populatedbcache() var/newdbcache = list() //so if we runtime or the db connection dies we don't kill the existing cache - var/datum/DBQuery/query_stickybans = SSdbcore.NewQuery("SELECT ckey, reason, banning_admin, datetime FROM [format_table_name("stickyban")] ORDERED BY ckey") + var/datum/DBQuery/query_stickybans = SSdbcore.NewQuery("SELECT ckey, reason, banning_admin, datetime FROM [format_table_name("stickyban")] ORDER BY ckey") if (!query_stickybans.warn_execute()) return - var/datum/DBQuery/query_stickyban_matches = SSdbcore.NewQuery("SELECT stickyban, matched_ckey, first_matched, exempt FROM [format_table_name("stickyban_matrched_ckey")]") + var/datum/DBQuery/query_stickyban_matches = SSdbcore.NewQuery("SELECT stickyban, matched_ckey, first_matched, exempt FROM [format_table_name("stickyban_matched_ckey")] ORDER BY first_matched") if (!query_stickyban_matches.warn_execute()) return query_stickyban_matches.SetConversion(4, SSdbcore.NUMBER_CONV) //read exempt as a number, not a string @@ -55,9 +55,11 @@ SUBSYSTEM_DEF(stickyban) var/list/ban = list() ban["ckey"] = query_stickybans.item[1] - ban["reason"] = query_stickybans.item[2] - ban["banning_admin"] = query_stickybans.item[3] + ban["message"] = query_stickybans.item[2] + ban["reason"] = "(InGameBan)([query_stickybans.item[3]])" + ban["admin"] = query_stickybans.item[3] ban["datetime"] = query_stickybans.item[4] + ban["type"] = list("sticky") newdbcache["[query_stickybans.item[1]]"] = ban @@ -70,13 +72,13 @@ SUBSYSTEM_DEF(stickyban) match["first_matched"] = query_stickyban_matches.item[3] match["exempt"] = query_stickyban_matches.item[4] - var/ban = newdbcache[match["stickyban"]] + var/ban = newdbcache[query_stickyban_matches.item[1]] if (!ban) continue var/keys = ban["keys"] if (!keys) keys = ban["keys"] = list() - keys[match["matched_ckey"]] = match + keys[query_stickyban_matches.item[2]] = match dbcache = newdbcache dbcacheexpire = world.time+STICKYBAN_DB_CACHE_TIME diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index 19a3fbc3249..b3ee7851545 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -7,6 +7,7 @@ #define STICKYBAN_MAX_ADMIN_MATCHES 1 /world/IsBanned(key, address, computer_id, type, real_bans_only=FALSE) + debug_world_log("isbanned(): '[args.Join("', '")]'") if (!key || (!real_bans_only && (!address || !computer_id))) if(real_bans_only) return FALSE @@ -16,18 +17,27 @@ if (text2num(computer_id) == 2147483647) //this cid causes stickybans to go haywire log_access("Failed Login (invalid cid): [key] [address]-[computer_id]") return list("reason"="invalid login data", "desc"="Error: Could not check ban status, Please try again. Error message: Your computer provided an invalid Computer ID.)") - var/admin = 0 + + + var/admin = FALSE var/ckey = ckey(key) + + //isBanned can get re-called on a user in certain situations, this prevents that leading to repeated messages to admins. + var/static/list/checkedckeys = list() + //magic voodo to check for a key in a list while also adding that key to the list without having to do two associated lookups + var/message = !checkedckeys[ckey]++ + if(GLOB.admin_datums[ckey] || GLOB.deadmins[ckey]) - admin = 1 + admin = TRUE //Whitelist if(CONFIG_GET(flag/usewhitelist)) if(!check_whitelist(ckey)) if (admin) log_admin("The admin [key] has been allowed to bypass the whitelist") - message_admins("The admin [key] has been allowed to bypass the whitelist") - addclientmessage(ckey,"You have been allowed to bypass the whitelist") + if (message) + message_admins("The admin [key] has been allowed to bypass the whitelist") + addclientmessage(ckey,"You have been allowed to bypass the whitelist") else log_access("Failed Login: [key] - Not on whitelist") return list("reason"="whitelist", "desc" = "\nReason: You are not on the white list for this server") @@ -46,6 +56,7 @@ if(!real_bans_only && extreme_popcap && living_player_count() >= extreme_popcap && !admin) log_access("Failed Login: [key] - Population cap reached") return list("reason"="popcap", "desc"= "\nReason: [CONFIG_GET(string/extreme_popcap_message)]") + if(CONFIG_GET(flag/sql_enabled)) if(!SSdbcore.Connect()) var/msg = "Ban database connection failure. Key [ckey] not checked" @@ -74,6 +85,7 @@ [expires]"} log_access("Failed Login: [key] [computer_id] [address] - Banned (#[i["id"]])") return list("reason"="Banned","desc"="[desc]") + var/list/ban = ..() //default pager ban stuff if (ban) var/bannedckey = "ERROR" @@ -86,12 +98,19 @@ if (!CONFIG_GET(flag/ban_legacy_system) && (SSdbcore.Connect() || length(SSstickyban.dbcache))) ban = get_stickyban_from_ckey(bannedckey) var/list/bancache = list() + + //we need to re-add exempted bans but the exempt code needs to return when a user is exempt + // so we spawn now since bancache is a reference and will have the entries we add later. + spawn(1) + for(var/bancacheckey in bancache) + world.SetConfig("ban", bancacheckey, bancache[bancacheckey]) + while (ban["ckey"] && ban["keys"] && ban["keys"][ckey] && ban["keys"][ckey]["exempt"]) - if (C || SSstickyban.confirmed_exempt[ckey]) //modifing/re-adding a stickyban makes it re-match everybody + if (C || SSstickyban.confirmed_exempt[ckey]) //When we re-add the stickyban isbanned() will run on that user again. This avoids the unintentional recursion. return bancache[ban["ckey"]] = world.GetConfig("ban", ban["ckey"]) //Hacky way to ensure somebody exempt from one stickyban doesn't get exempt from all stickybans - world.SetConfig("ban", bannedckey, null) + world.SetConfig("ban", ban["ckey"], null) var/list/newban = ..() if (!newban || newban["ckey"] == ban["ckey"]) SSstickyban.confirmed_exempt[ckey] = TRUE @@ -101,12 +120,8 @@ break ban = get_stickyban_from_ckey(ban["ckey"]) - spawn() - for(var/bancacheckey in bancache) - world.SetConfig("ban", bancacheckey, bancache[bancacheckey]) - //rogue ban in the process of being reverted. - if (cachedban && cachedban["reverting"] || cachedban["timeout"]) + if (cachedban && (cachedban["reverting"] || cachedban["timeout"])) world.SetConfig("ban", bannedckey, null) return null @@ -158,6 +173,7 @@ world.SetConfig("ban", bannedckey, null) + //we always report this log_game("Stickyban on [bannedckey] detected as rogue, [action]") message_admins("Stickyban on [bannedckey] detected as rogue, [action]") //do not convert to timer. @@ -177,7 +193,7 @@ if (ban["fromdb"]) if(!CONFIG_GET(flag/ban_legacy_system) && SSdbcore.Connect()) - var/datum/DBQuery/query_add_match = SSdbcore.NewQuery("INSERT IGNORE INTO [format_table_name("stickyban_matched_ckey")] (matchedckey, stickyban) VALUES ('[sanitizeSQL(ckey)]', '[sanitizeSQL(bannedckey)]')") + var/datum/DBQuery/query_add_match = SSdbcore.NewQuery("INSERT IGNORE INTO [format_table_name("stickyban_matched_ckey")] (matched_ckey, stickyban) VALUES ('[sanitizeSQL(ckey)]', '[sanitizeSQL(bannedckey)]')") query_add_match.warn_execute() //byond will not trigger isbanned() for "global" host bans, @@ -185,8 +201,9 @@ //So it's safe to let admins walk thru host/sticky bans here if (admin) log_admin("The admin [key] has been allowed to bypass a matching host/sticky ban on [bannedckey]") - message_admins("The admin [key] has been allowed to bypass a matching host/sticky ban on [bannedckey]") - addclientmessage(ckey,"You have been allowed to bypass a matching host/sticky ban on [bannedckey]") + if (message) + message_admins("The admin [key] has been allowed to bypass a matching host/sticky ban on [bannedckey]") + addclientmessage(ckey,"You have been allowed to bypass a matching host/sticky ban on [bannedckey]") return null if (C) //user is already connected!. diff --git a/code/modules/admin/stickyban.dm b/code/modules/admin/stickyban.dm index 0cfc9a7ff3e..cfa889903c1 100644 --- a/code/modules/admin/stickyban.dm +++ b/code/modules/admin/stickyban.dm @@ -103,7 +103,7 @@ SSstickyban.cache[ckey] = ban if (!CONFIG_GET(flag/ban_legacy_system) && SSdbcore.Connect()) - var/datum/DBQuery/query_remove_stickyban_alt = SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE ckey = '[sanitizeSQL(ckey)]' AND matched_ckey = '[sanitizeSQL(alt)]'") + var/datum/DBQuery/query_remove_stickyban_alt = SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = '[sanitizeSQL(ckey)]' AND matched_ckey = '[sanitizeSQL(alt)]'") query_remove_stickyban_alt.warn_execute() log_admin_private("[key_name(usr)] has disassociated [alt] from [ckey]'s sticky ban") @@ -145,7 +145,7 @@ var/ckey = data["ckey"] if (!data["alt"]) return - if (!CONFIG_GET(flag/ban_legacy_system) || !SSdbcore.Connect()) + if (CONFIG_GET(flag/ban_legacy_system) || !SSdbcore.Connect()) to_chat(usr, "No database connection!") return var/alt = ckey(data["alt"]) @@ -180,7 +180,7 @@ SSstickyban.cache[ckey] = ban - var/datum/DBQuery/query_exempt_stickyban_alt = SSdbcore.NewQuery("UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 1 WHERE stickyban = ckey = '[sanitizeSQL(ckey)]' AND matched_ckey = '[sanitizeSQL(alt)]'") + var/datum/DBQuery/query_exempt_stickyban_alt = SSdbcore.NewQuery("UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 1 WHERE stickyban = '[sanitizeSQL(ckey)]' AND matched_ckey = '[sanitizeSQL(alt)]'") query_exempt_stickyban_alt.warn_execute() log_admin_private("[key_name(usr)] has exempted [alt] from [ckey]'s sticky ban") @@ -192,7 +192,7 @@ var/ckey = data["ckey"] if (!data["alt"]) return - if (!CONFIG_GET(flag/ban_legacy_system) || !SSdbcore.Connect()) + if (CONFIG_GET(flag/ban_legacy_system) || !SSdbcore.Connect()) to_chat(usr, "No database connection!") return var/alt = ckey(data["alt"]) @@ -227,7 +227,7 @@ SSstickyban.cache[ckey] = ban - var/datum/DBQuery/query_unexempt_stickyban_alt = SSdbcore.NewQuery("UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 0 WHERE stickyban = ckey = '[sanitizeSQL(ckey)]' AND matched_ckey = '[sanitizeSQL(alt)]'") + var/datum/DBQuery/query_unexempt_stickyban_alt = SSdbcore.NewQuery("UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 0 WHERE stickyban = '[sanitizeSQL(ckey)]' AND matched_ckey = '[sanitizeSQL(alt)]'") query_unexempt_stickyban_alt.warn_execute() log_admin_private("[key_name(usr)] has unexempted [alt] from [ckey]'s sticky ban") @@ -381,17 +381,21 @@ SSstickyban.Populatedbcache() if (SSstickyban.dbcacheexpire) . = SSstickyban.dbcache[ckey] - var/list/cachedban = SSstickyban.cache["ckey"]["timeout"] - if (cachedban) - .["timeout"] = cachedban["timeout"] - .["fromdb"] = TRUE + //reset the cache incase its a newer ban (but only if we didn't update the cache + if (!. && SSstickyban.dbcacheexpire != world.time+STICKYBAN_DB_CACHE_TIME) + SSstickyban.dbcacheexpire = 1 + SSstickyban.Populatedbcache() + . = SSstickyban.dbcache[ckey] + if (.) + var/list/cachedban = SSstickyban.cache["[ckey]"] + if (cachedban) + .["timeout"] = cachedban["timeout"] + + .["fromdb"] = TRUE return . = stickyban2list(world.GetConfig("ban", ckey)) || stickyban2list(world.GetConfig("ban", ckey(ckey))) || list() - if (!length(.) && ckey != ckey(ckey)) //say that 10 times fast - . = stickyban2list(world.GetConfig("ban", ckey(ckey))) - if (!length(.)) return null @@ -422,6 +426,10 @@ . -= "reverting" . -= "fromdb" + . -= "matches_this_round" + . -= "existing_user_matches_this_round" + . -= "admin_matches_this_round" + . -= "pending_matches_this_round" //storing these can sometimes cause sticky bans to start matching everybody // and isn't even needed for sticky ban matching, as the hub tracks these separately