core/smn_banning.cpp
author Borja Ferrer <faluco@alliedmods.net>
Sat Feb 23 20:18:49 2008 +0000 (2008-02-23)
changeset 1894 e6efc8ffa47a
parent 1832 1f97873475e8
child 1947 e73a1e51833b
permissions -rw-r--r--
Executable memory is now provided by MM:S's allocator, this should reduce virtual memory usage.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "sm_globals.h"
    33 #include "sm_stringutil.h"
    34 #include "HalfLife2.h"
    35 #include "PlayerManager.h"
    36 #include "ForwardSys.h"
    37 
    38 #define BANFLAG_AUTO	(1<<0)	/**< Auto-detects whether to ban by steamid or IP */
    39 #define BANFLAG_IP   	(1<<1)	/**< Always ban by IP address */
    40 #define BANFLAG_AUTHID	(1<<2)	/**< Ban by SteamID */
    41 #define BANFLAG_NOKICK	(1<<3)	/**< Does not kick the client */
    42 #define BANFLAG_NOWRITE	(1<<4)	/**< Ban is not written to SourceDS's files if permanent */
    43 
    44 IForward *g_pOnBanClient = NULL;
    45 IForward *g_pOnBanIdentity = NULL;
    46 IForward *g_pOnRemoveBan = NULL;
    47 
    48 class BanNativeHelpers : public SMGlobalClass
    49 {
    50 public:
    51 	void OnSourceModAllInitialized()
    52 	{
    53 		g_pOnBanClient = g_Forwards.CreateForward(
    54 			"OnBanClient",
    55 			ET_Event,
    56 			7,
    57 			NULL,
    58 			Param_Cell,
    59 			Param_Cell,
    60 			Param_Cell,
    61 			Param_String,
    62 			Param_String,
    63 			Param_String,
    64 			Param_Cell);
    65 		g_pOnBanIdentity = g_Forwards.CreateForward(
    66 			"OnBanIdentity",
    67 			ET_Event,
    68 			6,
    69 			NULL,
    70 			Param_String,
    71 			Param_Cell,
    72 			Param_Cell,
    73 			Param_String,
    74 			Param_String,
    75 			Param_Cell);
    76 		g_pOnRemoveBan = g_Forwards.CreateForward(
    77 			"OnRemoveBan",
    78 			ET_Event,
    79 			4,
    80 			NULL,
    81 			Param_String,
    82 			Param_Cell,
    83 			Param_String,
    84 			Param_Cell);
    85 	}
    86 	void OnSourceModShutdown()
    87 	{
    88 		g_Forwards.ReleaseForward(g_pOnBanClient);
    89 		g_Forwards.ReleaseForward(g_pOnBanIdentity);
    90 		g_Forwards.ReleaseForward(g_pOnRemoveBan);
    91 
    92 		g_pOnBanClient = NULL;
    93 		g_pOnBanIdentity = NULL;
    94 		g_pOnRemoveBan = NULL;
    95 	}
    96 } s_BanNativeHelpers;
    97 
    98 
    99 static cell_t BanIdentity(IPluginContext *pContext, const cell_t *params)
   100 {
   101 	char *r_identity, *ban_reason, *ban_cmd;
   102 	int ban_time, ban_flags, ban_source;
   103 
   104 	pContext->LocalToString(params[1], &r_identity);
   105 	pContext->LocalToString(params[4], &ban_reason);
   106 	pContext->LocalToString(params[5], &ban_cmd);
   107 	ban_time = params[2];
   108 	ban_flags = params[3];
   109 	ban_source = params[6];
   110 
   111 	/* Make sure we can ban by one of the two methods! */
   112 	bool ban_by_ip = ((ban_flags & BANFLAG_IP) == BANFLAG_IP);
   113 	if (!ban_by_ip && ((ban_flags & BANFLAG_AUTHID) != BANFLAG_AUTHID))
   114 	{
   115 		return pContext->ThrowNativeError("No valid ban flags specified");
   116 	}
   117 
   118 	/* Sanitize the input */
   119 	char identity[64];
   120 	strncopy(identity, r_identity, sizeof(identity));
   121 	UTIL_ReplaceAll(identity, sizeof(identity), ";", "");
   122 
   123 	cell_t handled = 0;
   124 	if (ban_cmd[0] != '\0' && g_pOnBanIdentity->GetFunctionCount() > 0)
   125 	{
   126 		g_pOnBanIdentity->PushString(identity);
   127 		g_pOnBanIdentity->PushCell(ban_time);
   128 		g_pOnBanIdentity->PushCell(ban_flags);
   129 		g_pOnBanIdentity->PushString(ban_reason);
   130 		g_pOnBanIdentity->PushString(ban_cmd);
   131 		g_pOnBanIdentity->PushCell(ban_source);
   132 		g_pOnBanIdentity->Execute(&handled);
   133 	}
   134 
   135 	if (!handled)
   136 	{
   137 		bool write_ban = ((ban_flags & BANFLAG_NOWRITE) != BANFLAG_NOWRITE);
   138 
   139 		char command[256];
   140 		if (ban_by_ip)
   141 		{
   142 			UTIL_Format(
   143 				command,
   144 				sizeof(command),
   145 				"addip %d %s\n",
   146 				ban_time,
   147 				identity);
   148 			engine->ServerCommand(command);
   149 	
   150 			if (write_ban && ban_time == 0)
   151 			{
   152 				engine->ServerCommand("writeip\n");
   153 			}
   154 		}
   155 		else if (!g_HL2.IsLANServer())
   156 		{
   157 			UTIL_Format(
   158 				command,
   159 				sizeof(command),
   160 				"banid %d %s\n",
   161 				ban_time,
   162 				identity);
   163 			engine->ServerCommand(command);
   164 	
   165 			if (write_ban && ban_time == 0)
   166 			{
   167 				engine->ServerCommand("writeid\n");
   168 			}
   169 		}
   170 		else
   171 		{
   172 			return 0;
   173 		}
   174 	}
   175 
   176 	return 1;
   177 }
   178 
   179 static cell_t RemoveBan(IPluginContext *pContext, const cell_t *params)
   180 {
   181 	char *r_identity, *ban_cmd;
   182 	int ban_flags, ban_source;
   183 
   184 	pContext->LocalToString(params[1], &r_identity);
   185 	pContext->LocalToString(params[3], &ban_cmd);
   186 	ban_flags = params[2];
   187 	ban_source = params[4];
   188 
   189 	/* Make sure we can ban by one of the two methods! */
   190 	bool ban_by_ip = ((ban_flags & BANFLAG_IP) == BANFLAG_IP);
   191 	if (!ban_by_ip && ((ban_flags & BANFLAG_AUTHID) != BANFLAG_AUTHID))
   192 	{
   193 		return pContext->ThrowNativeError("No valid ban flags specified");
   194 	}
   195 
   196 	char identity[64];
   197 	strncopy(identity, r_identity, sizeof(identity));
   198 	UTIL_ReplaceAll(identity, sizeof(identity), ";", "");
   199 
   200 	cell_t handled = 0;
   201 	if (ban_cmd[0] != '\0' && g_pOnRemoveBan->GetFunctionCount() > 0)
   202 	{
   203 		g_pOnRemoveBan->PushString(identity);
   204 		g_pOnRemoveBan->PushCell(ban_flags);
   205 		g_pOnRemoveBan->PushString(ban_cmd);
   206 		g_pOnRemoveBan->PushCell(ban_source);
   207 		g_pOnRemoveBan->Execute(&handled);
   208 	}
   209 
   210 	char command[256];
   211 	if (ban_by_ip)
   212 	{
   213 		if (!handled)
   214 		{
   215 			UTIL_Format(
   216 				command,
   217 				sizeof(command),
   218 				"removeip %s\n",
   219 				identity);
   220 			engine->ServerCommand(command);	
   221 			engine->ServerCommand("writeip\n");
   222 		}
   223 	}
   224 	else if (!g_HL2.IsLANServer())
   225 	{
   226 		if (!handled)
   227 		{
   228 			UTIL_Format(
   229 				command,
   230 				sizeof(command),
   231 				"removeid %s\n",
   232 				identity);
   233 			engine->ServerCommand(command);
   234 			engine->ServerCommand("writeid\n");
   235 		}
   236 	}
   237 	else
   238 	{
   239 		return 0;
   240 	}
   241 
   242 	return 1;
   243 }
   244 
   245 static cell_t BanClient(IPluginContext *pContext, const cell_t *params)
   246 {
   247 	const char *kick_message;
   248 	char *ban_reason, *ban_cmd;
   249 	int client, ban_flags, ban_source, ban_time;
   250 
   251 	client = params[1];
   252 
   253 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   254 	if (!pPlayer || !pPlayer->IsConnected())
   255 	{
   256 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   257 	}
   258 
   259 	if (pPlayer->IsFakeClient())
   260 	{
   261 		return pContext->ThrowNativeError("Cannot ban fake client %d", client);
   262 	}
   263 
   264 	pContext->LocalToString(params[4], &ban_reason);
   265 	pContext->LocalToString(params[5], (char **)&kick_message);
   266 	pContext->LocalToString(params[6], &ban_cmd);
   267 	ban_time = params[2];
   268 	ban_flags = params[3];
   269 	ban_source = params[7];
   270 
   271 	/* Check how we should ban the player */
   272 	if ((ban_flags & BANFLAG_AUTO) == BANFLAG_AUTO)
   273 	{
   274 		if (g_HL2.IsLANServer() || !pPlayer->IsAuthorized())
   275 		{
   276 			ban_flags |= BANFLAG_IP;
   277 			ban_flags &= ~BANFLAG_AUTHID;
   278 		}
   279 		else
   280 		{
   281 			ban_flags |= BANFLAG_AUTHID;
   282 			ban_flags &= ~BANFLAG_IP;
   283 		}
   284 	}
   285 	else if ((ban_flags & BANFLAG_IP) == BANFLAG_IP)
   286 	{
   287 		ban_flags |= BANFLAG_IP;
   288 		ban_flags &= ~BANFLAG_AUTHID;
   289 	}
   290 	else if ((ban_flags & BANFLAG_AUTHID) == BANFLAG_AUTHID)
   291 	{
   292 		if (pPlayer->IsAuthorized())
   293 		{
   294 			ban_flags |= BANFLAG_AUTHID;
   295 			ban_flags &= ~BANFLAG_IP;
   296 		}
   297 		else
   298 		{
   299 			return 0;
   300 		}
   301 	}
   302 	else
   303 	{
   304 		return pContext->ThrowNativeError("No valid ban method flags specified");
   305 	}
   306 
   307 	cell_t handled = 0;
   308 	if (ban_cmd[0] != '\0' && g_pOnBanClient->GetFunctionCount() > 0)
   309 	{
   310 		g_pOnBanClient->PushCell(client);
   311 		g_pOnBanClient->PushCell(ban_time);
   312 		g_pOnBanClient->PushCell(ban_flags);
   313 		g_pOnBanClient->PushString(ban_reason);
   314 		g_pOnBanClient->PushString(kick_message);
   315 		g_pOnBanClient->PushString(ban_cmd);
   316 		g_pOnBanClient->PushCell(ban_source);
   317 		g_pOnBanClient->Execute(&handled);
   318 	}
   319 
   320 	/* Sanitize the kick message */
   321 	if (kick_message[0] == '\0')
   322 	{
   323 		kick_message = "Kicked";
   324 	}
   325 
   326 	if (!handled)
   327 	{
   328 		if ((ban_flags & BANFLAG_IP) == BANFLAG_IP)
   329 		{
   330 			/* Get the IP address and strip the port */
   331 			char ip[24], *ptr;
   332 			strncopy(ip, pPlayer->GetIPAddress(), sizeof(ip));
   333 			if ((ptr = strchr(ip, ':')) != NULL)
   334 			{
   335 				*ptr = '\0';
   336 			}
   337 		
   338 			/* Tell the server to ban the ip */
   339 			char command[256];
   340 			UTIL_Format(
   341 				command,
   342 				sizeof(command),
   343 				"addip %d %s\n",
   344 				ban_time,
   345 				ip);
   346 	
   347 			/* Kick, then ban */
   348 			if ((ban_flags & BANFLAG_NOKICK) != BANFLAG_NOKICK)
   349 			{
   350    		 		pPlayer->Kick(kick_message);
   351 			}
   352 			engine->ServerCommand(command);
   353 	
   354 			/* Physically write the ban */
   355 			if ((ban_time == 0) && ((ban_flags & BANFLAG_NOWRITE) != BANFLAG_NOWRITE))
   356 			{
   357 				engine->ServerCommand("writeip\n");
   358 			}	
   359 		} 
   360 		else if ((ban_flags & BANFLAG_AUTHID) == BANFLAG_AUTHID)
   361 		{
   362 			/* Tell the server to ban the auth string */
   363 			char command[256];
   364 			UTIL_Format(
   365 				command, 
   366 				sizeof(command), 
   367 				"banid %d %s\n", 
   368 				ban_time,
   369 				pPlayer->GetAuthString());
   370 	
   371 			/* Kick, then ban */
   372 			if ((ban_flags & BANFLAG_NOKICK) != BANFLAG_NOKICK)
   373 			{
   374    		 		pPlayer->Kick(kick_message);
   375 			}
   376 			engine->ServerCommand(command);
   377 
   378 			/* Physically write the ban if it's permanent */
   379 			if ((ban_time == 0) && ((ban_flags & BANFLAG_NOWRITE) != BANFLAG_NOWRITE))
   380 			{
   381 				engine->ServerCommand("writeid\n");
   382 			}
   383 		}
   384 	}
   385 	else if ((ban_flags & BANFLAG_NOKICK) != BANFLAG_NOKICK)
   386 	{
   387 		pPlayer->Kick(kick_message);	
   388 	}
   389 
   390 
   391 	return 1;
   392 }
   393 
   394 REGISTER_NATIVES(banNatives)
   395 {
   396 	{"BanClient",				BanClient},
   397 	{"BanIdentity",				BanIdentity},
   398 	{"RemoveBan",				RemoveBan},
   399 	{NULL,						NULL}
   400 };
   401