core/smn_banning.cpp
author David Anderson <dvander@alliedmods.net>
Fri Oct 02 03:47:42 2009 -0700 (2009-10-02)
changeset 2815 2c7137f077fe
parent 2795 c23fac848eac
permissions -rw-r--r--
Re-enabled PDB files.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 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 = g_HL2.ReferenceToIndex(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 #if SOURCE_ENGINE != SE_DARKMESSIAH
   272 	/* Check how we should ban the player */
   273 	if ((ban_flags & BANFLAG_AUTO) == BANFLAG_AUTO)
   274 	{
   275 		if (g_HL2.IsLANServer() || !pPlayer->IsAuthorized())
   276 		{
   277 			ban_flags |= BANFLAG_IP;
   278 			ban_flags &= ~BANFLAG_AUTHID;
   279 		}
   280 		else
   281 		{
   282 			ban_flags |= BANFLAG_AUTHID;
   283 			ban_flags &= ~BANFLAG_IP;
   284 		}
   285 	}
   286 	else if ((ban_flags & BANFLAG_IP) == BANFLAG_IP)
   287 	{
   288 		ban_flags |= BANFLAG_IP;
   289 		ban_flags &= ~BANFLAG_AUTHID;
   290 	}
   291 	else if ((ban_flags & BANFLAG_AUTHID) == BANFLAG_AUTHID)
   292 	{
   293 		if (pPlayer->IsAuthorized())
   294 		{
   295 			ban_flags |= BANFLAG_AUTHID;
   296 			ban_flags &= ~BANFLAG_IP;
   297 		}
   298 		else
   299 		{
   300 			return 0;
   301 		}
   302 	}
   303 	else
   304 	{
   305 		return pContext->ThrowNativeError("No valid ban method flags specified");
   306 	}
   307 #else
   308 	/* Dark Messiah doesn't have Steam IDs so there is only one ban method to choose */
   309 	ban_flags |= BANFLAG_IP;
   310 	ban_flags &= ~BANFLAG_AUTHID;
   311 #endif
   312 
   313 	cell_t handled = 0;
   314 	if (ban_cmd[0] != '\0' && g_pOnBanClient->GetFunctionCount() > 0)
   315 	{
   316 		g_pOnBanClient->PushCell(client);
   317 		g_pOnBanClient->PushCell(ban_time);
   318 		g_pOnBanClient->PushCell(ban_flags);
   319 		g_pOnBanClient->PushString(ban_reason);
   320 		g_pOnBanClient->PushString(kick_message);
   321 		g_pOnBanClient->PushString(ban_cmd);
   322 		g_pOnBanClient->PushCell(ban_source);
   323 		g_pOnBanClient->Execute(&handled);
   324 	}
   325 
   326 	/* Sanitize the kick message */
   327 	if (kick_message[0] == '\0')
   328 	{
   329 		kick_message = "Kicked";
   330 	}
   331 
   332 	if (!handled)
   333 	{
   334 		if ((ban_flags & BANFLAG_IP) == BANFLAG_IP)
   335 		{
   336 			/* Get the IP address and strip the port */
   337 			char ip[24], *ptr;
   338 			strncopy(ip, pPlayer->GetIPAddress(), sizeof(ip));
   339 			if ((ptr = strchr(ip, ':')) != NULL)
   340 			{
   341 				*ptr = '\0';
   342 			}
   343 		
   344 			/* Tell the server to ban the ip */
   345 			char command[256];
   346 			UTIL_Format(
   347 				command,
   348 				sizeof(command),
   349 				"addip %d %s\n",
   350 				ban_time,
   351 				ip);
   352 	
   353 			/* Kick, then ban */
   354 			if ((ban_flags & BANFLAG_NOKICK) != BANFLAG_NOKICK)
   355 			{
   356    		 		pPlayer->Kick(kick_message);
   357 			}
   358 			engine->ServerCommand(command);
   359 	
   360 			/* Physically write the ban */
   361 			if ((ban_time == 0) && ((ban_flags & BANFLAG_NOWRITE) != BANFLAG_NOWRITE))
   362 			{
   363 				engine->ServerCommand("writeip\n");
   364 			}	
   365 		} 
   366 		else if ((ban_flags & BANFLAG_AUTHID) == BANFLAG_AUTHID)
   367 		{
   368 			/* Tell the server to ban the auth string */
   369 			char command[256];
   370 			UTIL_Format(
   371 				command, 
   372 				sizeof(command), 
   373 				"banid %d %s\n", 
   374 				ban_time,
   375 				pPlayer->GetAuthString());
   376 	
   377 			/* Kick, then ban */
   378 			if ((ban_flags & BANFLAG_NOKICK) != BANFLAG_NOKICK)
   379 			{
   380 				g_HL2.AddDelayedKick(client, pPlayer->GetUserId(), kick_message);
   381 			}
   382 			engine->ServerCommand(command);
   383 
   384 			/* Physically write the ban if it's permanent */
   385 			if ((ban_time == 0) && ((ban_flags & BANFLAG_NOWRITE) != BANFLAG_NOWRITE))
   386 			{
   387 				engine->ServerCommand("writeid\n");
   388 			}
   389 		}
   390 	}
   391 	else if ((ban_flags & BANFLAG_NOKICK) != BANFLAG_NOKICK)
   392 	{
   393 		g_HL2.AddDelayedKick(client, pPlayer->GetUserId(), kick_message);
   394 	}
   395 
   396 
   397 	return 1;
   398 }
   399 
   400 REGISTER_NATIVES(banNatives)
   401 {
   402 	{"BanClient",				BanClient},
   403 	{"BanIdentity",				BanIdentity},
   404 	{"RemoveBan",				RemoveBan},
   405 	{NULL,						NULL}
   406 };
   407