1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/smn_banning.cpp Sun Mar 30 07:00:22 2008 +0000
1.3 @@ -0,0 +1,401 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourceMod
1.8 + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify it under
1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + *
1.32 + * Version: $Id$
1.33 + */
1.34 +
1.35 +#include "sm_globals.h"
1.36 +#include "sm_stringutil.h"
1.37 +#include "HalfLife2.h"
1.38 +#include "PlayerManager.h"
1.39 +#include "ForwardSys.h"
1.40 +
1.41 +#define BANFLAG_AUTO (1<<0) /**< Auto-detects whether to ban by steamid or IP */
1.42 +#define BANFLAG_IP (1<<1) /**< Always ban by IP address */
1.43 +#define BANFLAG_AUTHID (1<<2) /**< Ban by SteamID */
1.44 +#define BANFLAG_NOKICK (1<<3) /**< Does not kick the client */
1.45 +#define BANFLAG_NOWRITE (1<<4) /**< Ban is not written to SourceDS's files if permanent */
1.46 +
1.47 +IForward *g_pOnBanClient = NULL;
1.48 +IForward *g_pOnBanIdentity = NULL;
1.49 +IForward *g_pOnRemoveBan = NULL;
1.50 +
1.51 +class BanNativeHelpers : public SMGlobalClass
1.52 +{
1.53 +public:
1.54 + void OnSourceModAllInitialized()
1.55 + {
1.56 + g_pOnBanClient = g_Forwards.CreateForward(
1.57 + "OnBanClient",
1.58 + ET_Event,
1.59 + 7,
1.60 + NULL,
1.61 + Param_Cell,
1.62 + Param_Cell,
1.63 + Param_Cell,
1.64 + Param_String,
1.65 + Param_String,
1.66 + Param_String,
1.67 + Param_Cell);
1.68 + g_pOnBanIdentity = g_Forwards.CreateForward(
1.69 + "OnBanIdentity",
1.70 + ET_Event,
1.71 + 6,
1.72 + NULL,
1.73 + Param_String,
1.74 + Param_Cell,
1.75 + Param_Cell,
1.76 + Param_String,
1.77 + Param_String,
1.78 + Param_Cell);
1.79 + g_pOnRemoveBan = g_Forwards.CreateForward(
1.80 + "OnRemoveBan",
1.81 + ET_Event,
1.82 + 4,
1.83 + NULL,
1.84 + Param_String,
1.85 + Param_Cell,
1.86 + Param_String,
1.87 + Param_Cell);
1.88 + }
1.89 + void OnSourceModShutdown()
1.90 + {
1.91 + g_Forwards.ReleaseForward(g_pOnBanClient);
1.92 + g_Forwards.ReleaseForward(g_pOnBanIdentity);
1.93 + g_Forwards.ReleaseForward(g_pOnRemoveBan);
1.94 +
1.95 + g_pOnBanClient = NULL;
1.96 + g_pOnBanIdentity = NULL;
1.97 + g_pOnRemoveBan = NULL;
1.98 + }
1.99 +} s_BanNativeHelpers;
1.100 +
1.101 +
1.102 +static cell_t BanIdentity(IPluginContext *pContext, const cell_t *params)
1.103 +{
1.104 + char *r_identity, *ban_reason, *ban_cmd;
1.105 + int ban_time, ban_flags, ban_source;
1.106 +
1.107 + pContext->LocalToString(params[1], &r_identity);
1.108 + pContext->LocalToString(params[4], &ban_reason);
1.109 + pContext->LocalToString(params[5], &ban_cmd);
1.110 + ban_time = params[2];
1.111 + ban_flags = params[3];
1.112 + ban_source = params[6];
1.113 +
1.114 + /* Make sure we can ban by one of the two methods! */
1.115 + bool ban_by_ip = ((ban_flags & BANFLAG_IP) == BANFLAG_IP);
1.116 + if (!ban_by_ip && ((ban_flags & BANFLAG_AUTHID) != BANFLAG_AUTHID))
1.117 + {
1.118 + return pContext->ThrowNativeError("No valid ban flags specified");
1.119 + }
1.120 +
1.121 + /* Sanitize the input */
1.122 + char identity[64];
1.123 + strncopy(identity, r_identity, sizeof(identity));
1.124 + UTIL_ReplaceAll(identity, sizeof(identity), ";", "");
1.125 +
1.126 + cell_t handled = 0;
1.127 + if (ban_cmd[0] != '\0' && g_pOnBanIdentity->GetFunctionCount() > 0)
1.128 + {
1.129 + g_pOnBanIdentity->PushString(identity);
1.130 + g_pOnBanIdentity->PushCell(ban_time);
1.131 + g_pOnBanIdentity->PushCell(ban_flags);
1.132 + g_pOnBanIdentity->PushString(ban_reason);
1.133 + g_pOnBanIdentity->PushString(ban_cmd);
1.134 + g_pOnBanIdentity->PushCell(ban_source);
1.135 + g_pOnBanIdentity->Execute(&handled);
1.136 + }
1.137 +
1.138 + if (!handled)
1.139 + {
1.140 + bool write_ban = ((ban_flags & BANFLAG_NOWRITE) != BANFLAG_NOWRITE);
1.141 +
1.142 + char command[256];
1.143 + if (ban_by_ip)
1.144 + {
1.145 + UTIL_Format(
1.146 + command,
1.147 + sizeof(command),
1.148 + "addip %d %s\n",
1.149 + ban_time,
1.150 + identity);
1.151 + engine->ServerCommand(command);
1.152 +
1.153 + if (write_ban && ban_time == 0)
1.154 + {
1.155 + engine->ServerCommand("writeip\n");
1.156 + }
1.157 + }
1.158 + else if (!g_HL2.IsLANServer())
1.159 + {
1.160 + UTIL_Format(
1.161 + command,
1.162 + sizeof(command),
1.163 + "banid %d %s\n",
1.164 + ban_time,
1.165 + identity);
1.166 + engine->ServerCommand(command);
1.167 +
1.168 + if (write_ban && ban_time == 0)
1.169 + {
1.170 + engine->ServerCommand("writeid\n");
1.171 + }
1.172 + }
1.173 + else
1.174 + {
1.175 + return 0;
1.176 + }
1.177 + }
1.178 +
1.179 + return 1;
1.180 +}
1.181 +
1.182 +static cell_t RemoveBan(IPluginContext *pContext, const cell_t *params)
1.183 +{
1.184 + char *r_identity, *ban_cmd;
1.185 + int ban_flags, ban_source;
1.186 +
1.187 + pContext->LocalToString(params[1], &r_identity);
1.188 + pContext->LocalToString(params[3], &ban_cmd);
1.189 + ban_flags = params[2];
1.190 + ban_source = params[4];
1.191 +
1.192 + /* Make sure we can ban by one of the two methods! */
1.193 + bool ban_by_ip = ((ban_flags & BANFLAG_IP) == BANFLAG_IP);
1.194 + if (!ban_by_ip && ((ban_flags & BANFLAG_AUTHID) != BANFLAG_AUTHID))
1.195 + {
1.196 + return pContext->ThrowNativeError("No valid ban flags specified");
1.197 + }
1.198 +
1.199 + char identity[64];
1.200 + strncopy(identity, r_identity, sizeof(identity));
1.201 + UTIL_ReplaceAll(identity, sizeof(identity), ";", "");
1.202 +
1.203 + cell_t handled = 0;
1.204 + if (ban_cmd[0] != '\0' && g_pOnRemoveBan->GetFunctionCount() > 0)
1.205 + {
1.206 + g_pOnRemoveBan->PushString(identity);
1.207 + g_pOnRemoveBan->PushCell(ban_flags);
1.208 + g_pOnRemoveBan->PushString(ban_cmd);
1.209 + g_pOnRemoveBan->PushCell(ban_source);
1.210 + g_pOnRemoveBan->Execute(&handled);
1.211 + }
1.212 +
1.213 + char command[256];
1.214 + if (ban_by_ip)
1.215 + {
1.216 + if (!handled)
1.217 + {
1.218 + UTIL_Format(
1.219 + command,
1.220 + sizeof(command),
1.221 + "removeip %s\n",
1.222 + identity);
1.223 + engine->ServerCommand(command);
1.224 + engine->ServerCommand("writeip\n");
1.225 + }
1.226 + }
1.227 + else if (!g_HL2.IsLANServer())
1.228 + {
1.229 + if (!handled)
1.230 + {
1.231 + UTIL_Format(
1.232 + command,
1.233 + sizeof(command),
1.234 + "removeid %s\n",
1.235 + identity);
1.236 + engine->ServerCommand(command);
1.237 + engine->ServerCommand("writeid\n");
1.238 + }
1.239 + }
1.240 + else
1.241 + {
1.242 + return 0;
1.243 + }
1.244 +
1.245 + return 1;
1.246 +}
1.247 +
1.248 +static cell_t BanClient(IPluginContext *pContext, const cell_t *params)
1.249 +{
1.250 + const char *kick_message;
1.251 + char *ban_reason, *ban_cmd;
1.252 + int client, ban_flags, ban_source, ban_time;
1.253 +
1.254 + client = params[1];
1.255 +
1.256 + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
1.257 + if (!pPlayer || !pPlayer->IsConnected())
1.258 + {
1.259 + return pContext->ThrowNativeError("Client index %d is invalid", client);
1.260 + }
1.261 +
1.262 + if (pPlayer->IsFakeClient())
1.263 + {
1.264 + return pContext->ThrowNativeError("Cannot ban fake client %d", client);
1.265 + }
1.266 +
1.267 + pContext->LocalToString(params[4], &ban_reason);
1.268 + pContext->LocalToString(params[5], (char **)&kick_message);
1.269 + pContext->LocalToString(params[6], &ban_cmd);
1.270 + ban_time = params[2];
1.271 + ban_flags = params[3];
1.272 + ban_source = params[7];
1.273 +
1.274 + /* Check how we should ban the player */
1.275 + if ((ban_flags & BANFLAG_AUTO) == BANFLAG_AUTO)
1.276 + {
1.277 + if (g_HL2.IsLANServer() || !pPlayer->IsAuthorized())
1.278 + {
1.279 + ban_flags |= BANFLAG_IP;
1.280 + ban_flags &= ~BANFLAG_AUTHID;
1.281 + }
1.282 + else
1.283 + {
1.284 + ban_flags |= BANFLAG_AUTHID;
1.285 + ban_flags &= ~BANFLAG_IP;
1.286 + }
1.287 + }
1.288 + else if ((ban_flags & BANFLAG_IP) == BANFLAG_IP)
1.289 + {
1.290 + ban_flags |= BANFLAG_IP;
1.291 + ban_flags &= ~BANFLAG_AUTHID;
1.292 + }
1.293 + else if ((ban_flags & BANFLAG_AUTHID) == BANFLAG_AUTHID)
1.294 + {
1.295 + if (pPlayer->IsAuthorized())
1.296 + {
1.297 + ban_flags |= BANFLAG_AUTHID;
1.298 + ban_flags &= ~BANFLAG_IP;
1.299 + }
1.300 + else
1.301 + {
1.302 + return 0;
1.303 + }
1.304 + }
1.305 + else
1.306 + {
1.307 + return pContext->ThrowNativeError("No valid ban method flags specified");
1.308 + }
1.309 +
1.310 + cell_t handled = 0;
1.311 + if (ban_cmd[0] != '\0' && g_pOnBanClient->GetFunctionCount() > 0)
1.312 + {
1.313 + g_pOnBanClient->PushCell(client);
1.314 + g_pOnBanClient->PushCell(ban_time);
1.315 + g_pOnBanClient->PushCell(ban_flags);
1.316 + g_pOnBanClient->PushString(ban_reason);
1.317 + g_pOnBanClient->PushString(kick_message);
1.318 + g_pOnBanClient->PushString(ban_cmd);
1.319 + g_pOnBanClient->PushCell(ban_source);
1.320 + g_pOnBanClient->Execute(&handled);
1.321 + }
1.322 +
1.323 + /* Sanitize the kick message */
1.324 + if (kick_message[0] == '\0')
1.325 + {
1.326 + kick_message = "Kicked";
1.327 + }
1.328 +
1.329 + if (!handled)
1.330 + {
1.331 + if ((ban_flags & BANFLAG_IP) == BANFLAG_IP)
1.332 + {
1.333 + /* Get the IP address and strip the port */
1.334 + char ip[24], *ptr;
1.335 + strncopy(ip, pPlayer->GetIPAddress(), sizeof(ip));
1.336 + if ((ptr = strchr(ip, ':')) != NULL)
1.337 + {
1.338 + *ptr = '\0';
1.339 + }
1.340 +
1.341 + /* Tell the server to ban the ip */
1.342 + char command[256];
1.343 + UTIL_Format(
1.344 + command,
1.345 + sizeof(command),
1.346 + "addip %d %s\n",
1.347 + ban_time,
1.348 + ip);
1.349 +
1.350 + /* Kick, then ban */
1.351 + if ((ban_flags & BANFLAG_NOKICK) != BANFLAG_NOKICK)
1.352 + {
1.353 + pPlayer->Kick(kick_message);
1.354 + }
1.355 + engine->ServerCommand(command);
1.356 +
1.357 + /* Physically write the ban */
1.358 + if ((ban_time == 0) && ((ban_flags & BANFLAG_NOWRITE) != BANFLAG_NOWRITE))
1.359 + {
1.360 + engine->ServerCommand("writeip\n");
1.361 + }
1.362 + }
1.363 + else if ((ban_flags & BANFLAG_AUTHID) == BANFLAG_AUTHID)
1.364 + {
1.365 + /* Tell the server to ban the auth string */
1.366 + char command[256];
1.367 + UTIL_Format(
1.368 + command,
1.369 + sizeof(command),
1.370 + "banid %d %s\n",
1.371 + ban_time,
1.372 + pPlayer->GetAuthString());
1.373 +
1.374 + /* Kick, then ban */
1.375 + if ((ban_flags & BANFLAG_NOKICK) != BANFLAG_NOKICK)
1.376 + {
1.377 + pPlayer->Kick(kick_message);
1.378 + }
1.379 + engine->ServerCommand(command);
1.380 +
1.381 + /* Physically write the ban if it's permanent */
1.382 + if ((ban_time == 0) && ((ban_flags & BANFLAG_NOWRITE) != BANFLAG_NOWRITE))
1.383 + {
1.384 + engine->ServerCommand("writeid\n");
1.385 + }
1.386 + }
1.387 + }
1.388 + else if ((ban_flags & BANFLAG_NOKICK) != BANFLAG_NOKICK)
1.389 + {
1.390 + pPlayer->Kick(kick_message);
1.391 + }
1.392 +
1.393 +
1.394 + return 1;
1.395 +}
1.396 +
1.397 +REGISTER_NATIVES(banNatives)
1.398 +{
1.399 + {"BanClient", BanClient},
1.400 + {"BanIdentity", BanIdentity},
1.401 + {"RemoveBan", RemoveBan},
1.402 + {NULL, NULL}
1.403 +};
1.404 +