1.1 --- a/core/PlayerManager.cpp Wed Aug 08 15:08:01 2007 +0000
1.2 +++ b/core/PlayerManager.cpp Wed Aug 08 16:22:51 2007 +0000
1.3 @@ -45,6 +45,8 @@
1.4
1.5 PlayerManager g_Players;
1.6 bool g_OnMapStarted = false;
1.7 +IForward *PreAdminCheck = NULL;
1.8 +IForward *PostAdminCheck = NULL;
1.9
1.10 SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char *, const char *, char *, int);
1.11 SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, const char *);
1.12 @@ -112,6 +114,9 @@
1.13 m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String);
1.14 m_onActivate = g_Forwards.CreateForward("OnServerLoad", ET_Ignore, 0, NULL);
1.15 m_onActivate2 = g_Forwards.CreateForward("OnMapStart", ET_Ignore, 0, NULL);
1.16 +
1.17 + PreAdminCheck = g_Forwards.CreateForward("OnClientPreAdminCheck", ET_Event, 1, p1);
1.18 + PostAdminCheck = g_Forwards.CreateForward("OnClientPostAdminCheck", ET_Ignore, 1, p1);
1.19 }
1.20
1.21 void PlayerManager::OnSourceModShutdown()
1.22 @@ -135,6 +140,9 @@
1.23 g_Forwards.ReleaseForward(m_onActivate);
1.24 g_Forwards.ReleaseForward(m_onActivate2);
1.25
1.26 + g_Forwards.ReleaseForward(PreAdminCheck);
1.27 + g_Forwards.ReleaseForward(PostAdminCheck);
1.28 +
1.29 delete [] m_Players;
1.30 }
1.31
1.32 @@ -751,6 +759,7 @@
1.33 m_Admin = INVALID_ADMIN_ID;
1.34 m_TempAdmin = false;
1.35 m_Info = NULL;
1.36 + m_bAdminCheckSignalled = false;
1.37 m_LastPassword.clear();
1.38 }
1.39
1.40 @@ -760,6 +769,7 @@
1.41 m_Name.assign(name);
1.42 m_Ip.assign(ip);
1.43 m_pEdict = pEntity;
1.44 + m_iIndex = engine->IndexOfEdict(pEntity);
1.45
1.46 char ip2[24], *ptr;
1.47 strncopy(ip2, ip, sizeof(ip2));
1.48 @@ -791,7 +801,7 @@
1.49
1.50 if (m_IsAuthorized)
1.51 {
1.52 - DoBasicAdminChecks();
1.53 + DoPostConnectAuthorization();
1.54 }
1.55 }
1.56
1.57 @@ -817,6 +827,7 @@
1.58 m_AuthID.clear();
1.59 m_pEdict = NULL;
1.60 m_Info = NULL;
1.61 + m_bAdminCheckSignalled = false;
1.62 }
1.63
1.64 void CPlayer::SetName(const char *name)
1.65 @@ -902,8 +913,7 @@
1.66
1.67 void CPlayer::Kick(const char *str)
1.68 {
1.69 - int client = engine->IndexOfEdict(m_pEdict);
1.70 - INetChannel *pNetChan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(client));
1.71 + INetChannel *pNetChan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(m_iIndex));
1.72 IClient *pClient = static_cast<IClient *>(pNetChan->GetMsgHandler());
1.73 pClient->Disconnect("%s", str);
1.74 }
1.75 @@ -912,8 +922,47 @@
1.76 {
1.77 if (m_IsInGame)
1.78 {
1.79 - DoBasicAdminChecks();
1.80 + DoPostConnectAuthorization();
1.81 + }
1.82 +}
1.83 +
1.84 +void CPlayer::DoPostConnectAuthorization()
1.85 +{
1.86 + cell_t result;
1.87 + PreAdminCheck->PushCell(m_iIndex);
1.88 + PreAdminCheck->Execute(&result);
1.89 +
1.90 + /* Defer, for better or worse */
1.91 + if ((ResultType)result >= Pl_Handled)
1.92 + {
1.93 + return;
1.94 + }
1.95 +
1.96 + /* Sanity check */
1.97 + if (!IsConnected())
1.98 + {
1.99 + return;
1.100 }
1.101 +
1.102 + /* Otherwise, go ahead and do admin checks */
1.103 + DoBasicAdminChecks();
1.104 +
1.105 + /* Send the notification out */
1.106 + NotifyPostAdminChecks();
1.107 +}
1.108 +
1.109 +void CPlayer::NotifyPostAdminChecks()
1.110 +{
1.111 + if (m_bAdminCheckSignalled)
1.112 + {
1.113 + return;
1.114 + }
1.115 +
1.116 + /* Block beforehand so they can't double-call */
1.117 + m_bAdminCheckSignalled = true;
1.118 +
1.119 + PostAdminCheck->PushCell(m_iIndex);
1.120 + PostAdminCheck->Execute(NULL);
1.121 }
1.122
1.123 void CPlayer::DoBasicAdminChecks()
2.1 --- a/core/PlayerManager.h Wed Aug 08 15:08:01 2007 +0000
2.2 +++ b/core/PlayerManager.h Wed Aug 08 16:22:51 2007 +0000
2.3 @@ -62,8 +62,10 @@
2.4 void SetAdminId(AdminId id, bool temporary);
2.5 AdminId GetAdminId();
2.6 void Kick(const char *str);
2.7 + IPlayerInfo *GetPlayerInfo();
2.8 public:
2.9 - IPlayerInfo *GetPlayerInfo();
2.10 + void NotifyPostAdminChecks();
2.11 + void DoBasicAdminChecks();
2.12 private:
2.13 void Initialize(const char *name, const char *ip, edict_t *pEntity);
2.14 void Connect();
2.15 @@ -72,7 +74,7 @@
2.16 void DumpAdmin(bool deleting);
2.17 void Authorize(const char *auth);
2.18 void Authorize_Post();
2.19 - void DoBasicAdminChecks();
2.20 + void DoPostConnectAuthorization();
2.21 private:
2.22 bool m_IsConnected;
2.23 bool m_IsInGame;
2.24 @@ -86,6 +88,8 @@
2.25 edict_t *m_pEdict;
2.26 IPlayerInfo *m_Info;
2.27 String m_LastPassword;
2.28 + bool m_bAdminCheckSignalled;
2.29 + int m_iIndex;
2.30 };
2.31
2.32 class PlayerManager :
3.1 --- a/core/smn_console.cpp Wed Aug 08 15:08:01 2007 +0000
3.2 +++ b/core/smn_console.cpp Wed Aug 08 16:22:51 2007 +0000
3.3 @@ -702,10 +702,15 @@
3.4
3.5 static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
3.6 {
3.7 + g_SourceMod.SetGlobalTarget(LANG_SERVER);
3.8 +
3.9 char buffer[1024];
3.10 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
3.11
3.12 - g_SourceMod.SetGlobalTarget(LANG_SERVER);
3.13 + if (pContext->GetContext()->n_err != SP_ERROR_NONE)
3.14 + {
3.15 + return 0;
3.16 + }
3.17
3.18 /* One byte for null terminator, one for newline */
3.19 buffer[len++] = '\n';
3.20 @@ -718,10 +723,15 @@
3.21
3.22 static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
3.23 {
3.24 + g_SourceMod.SetGlobalTarget(LANG_SERVER);
3.25 +
3.26 char buffer[1024];
3.27 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
3.28
3.29 - g_SourceMod.SetGlobalTarget(LANG_SERVER);
3.30 + if (pContext->GetContext()->n_err != SP_ERROR_NONE)
3.31 + {
3.32 + return 0;
3.33 + }
3.34
3.35 /* One byte for null terminator, one for newline */
3.36 buffer[len++] = '\n';
3.37 @@ -758,6 +768,11 @@
3.38 char buffer[256];
3.39 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
3.40
3.41 + if (pContext->GetContext()->n_err != SP_ERROR_NONE)
3.42 + {
3.43 + return 0;
3.44 + }
3.45 +
3.46 engine->ClientCommand(pPlayer->GetEdict(), "%s", buffer);
3.47
3.48 return 1;
3.49 @@ -781,6 +796,11 @@
3.50 char buffer[256];
3.51 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
3.52
3.53 + if (pContext->GetContext()->n_err != SP_ERROR_NONE)
3.54 + {
3.55 + return 0;
3.56 + }
3.57 +
3.58 unsigned int old = g_ChatTriggers.SetReplyTo(SM_REPLY_CONSOLE);
3.59 serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer);
3.60 g_ChatTriggers.SetReplyTo(old);
3.61 @@ -796,6 +816,11 @@
3.62 char buffer[1024];
3.63 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2);
3.64
3.65 + if (pContext->GetContext()->n_err != SP_ERROR_NONE)
3.66 + {
3.67 + return 0;
3.68 + }
3.69 +
3.70 /* If we're printing to the server, shortcut out */
3.71 if (params[1] == 0)
3.72 {
4.1 --- a/core/smn_player.cpp Wed Aug 08 15:08:01 2007 +0000
4.2 +++ b/core/smn_player.cpp Wed Aug 08 16:22:51 2007 +0000
4.3 @@ -1020,6 +1020,11 @@
4.4 char buffer[256];
4.5 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
4.6
4.7 + if (pContext->GetContext()->n_err != SP_ERROR_NONE)
4.8 + {
4.9 + return 0;
4.10 + }
4.11 +
4.12 pClient->Disconnect("%s", buffer);
4.13
4.14 return 1;
4.15 @@ -1048,6 +1053,45 @@
4.16 return 1;
4.17 }
4.18
4.19 +static cell_t RunAdminCacheChecks(IPluginContext *pContext, const cell_t *params)
4.20 +{
4.21 + int client = params[1];
4.22 +
4.23 + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
4.24 + if (!pPlayer)
4.25 + {
4.26 + return pContext->ThrowNativeError("Client index %d is invalid", client);
4.27 + } else if (!pPlayer->IsInGame()) {
4.28 + return pContext->ThrowNativeError("Client %d is not in game", client);
4.29 + } else if (!pPlayer->IsAuthorized()) {
4.30 + return pContext->ThrowNativeError("Client %d is not authorized", client);
4.31 + }
4.32 +
4.33 + AdminId id = pPlayer->GetAdminId();
4.34 + pPlayer->DoBasicAdminChecks();
4.35 +
4.36 + return (id != pPlayer->GetAdminId()) ? 1 : 0;
4.37 +}
4.38 +
4.39 +static cell_t NotifyPostAdminCheck(IPluginContext *pContext, const cell_t *params)
4.40 +{
4.41 + int client = params[1];
4.42 +
4.43 + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
4.44 + if (!pPlayer)
4.45 + {
4.46 + return pContext->ThrowNativeError("Client index %d is invalid", client);
4.47 + } else if (!pPlayer->IsInGame()) {
4.48 + return pContext->ThrowNativeError("Client %d is not in game", client);
4.49 + } else if (!pPlayer->IsAuthorized()) {
4.50 + return pContext->ThrowNativeError("Client %d is not authorized", client);
4.51 + }
4.52 +
4.53 + pPlayer->NotifyPostAdminChecks();
4.54 +
4.55 + return 1;
4.56 +}
4.57 +
4.58 REGISTER_NATIVES(playernatives)
4.59 {
4.60 {"AddUserFlags", AddUserFlags},
4.61 @@ -1095,5 +1139,7 @@
4.62 {"ShowActivity", ShowActivity},
4.63 {"ShowActivityEx", ShowActivityEx},
4.64 {"KickClient", KickClient},
4.65 + {"RunAdminCacheChecks", RunAdminCacheChecks},
4.66 + {"NotifyPostAdminCheck", NotifyPostAdminCheck},
4.67 {NULL, NULL}
4.68 };
5.1 --- a/plugins/include/clients.inc Wed Aug 08 15:08:01 2007 +0000
5.2 +++ b/plugins/include/clients.inc Wed Aug 08 16:22:51 2007 +0000
5.3 @@ -30,7 +30,7 @@
5.4 /**
5.5 * Called on client connection.
5.6 *
5.7 - * @param client Player index.
5.8 + * @param client Client index.
5.9 * @param rejectmsg Buffer to store the rejection message when the connection is refused.
5.10 * @param maxlen Maximum number of characters for rejection buffer.
5.11 * @return True to validate client's connection, false to refuse it.
5.12 @@ -40,7 +40,7 @@
5.13 /**
5.14 * Called when a client is entering to the game.
5.15 *
5.16 - * @param client Player index.
5.17 + * @param client Client index.
5.18 * @noreturn
5.19 */
5.20 forward OnClientPutInServer(client);
5.21 @@ -48,7 +48,7 @@
5.22 /**
5.23 * Called when a client is disconnecting from the server.
5.24 *
5.25 - * @param client Player index.
5.26 + * @param client Client index.
5.27 * @noreturn
5.28 */
5.29 forward OnClientDisconnect(client);
5.30 @@ -56,7 +56,7 @@
5.31 /**
5.32 * Called when a client is disconnected from the server.
5.33 *
5.34 - * @param client Player index.
5.35 + * @param client Client index.
5.36 * @noreturn
5.37 */
5.38 forward OnClientDisconnect_Post(client);
5.39 @@ -64,7 +64,7 @@
5.40 /**
5.41 * Called when a client is sending a command.
5.42 *
5.43 - * @param client Player index.
5.44 + * @param client Client index.
5.45 * @param args Number of arguments.
5.46 * @noreturn
5.47 */
5.48 @@ -73,21 +73,46 @@
5.49 /**
5.50 * Called whenever the client's settings are changed.
5.51 *
5.52 - * @param client Player index.
5.53 + * @param client Client index.
5.54 * @noreturn
5.55 */
5.56 forward OnClientSettingsChanged(client);
5.57
5.58 /**
5.59 * Called when a client receives a Steam ID.
5.60 - * @note This is called by bots, but the ID will be "BOT"
5.61 +
5.62 + * Admin properties are not assigned here, but on OnClientPostAdminCheck().
5.63 + * This is called by bots, but the ID will be "BOT".
5.64 *
5.65 - * @param client Player index.
5.66 - * @param auth Player auth string.
5.67 + * @param client Client index.
5.68 + * @param auth Client auth string.
5.69 + * @noreturn
5.70 */
5.71 forward OnClientAuthorized(client, const String:auth[]);
5.72
5.73 /**
5.74 + * Called once a client is authorized and fully in-game, but
5.75 + * before admin checks are done. This can be used to override
5.76 + * the default admin checks for a client.
5.77 + *
5.78 + * Note: If handled/blocked, PostAdminCheck must be signalled
5.79 + * manually via NotifyPostAdminCheck().
5.80 + *
5.81 + * @param client Client index.
5.82 + * @return Plugin_Handled to block admin checks.
5.83 + */
5.84 +forward Action:OnClientPreAdminCheck(client);
5.85 +
5.86 +/**
5.87 + * Called once a client is authorized and fully in-game, and
5.88 + * after all post-connection authorizations have been performed.
5.89 + *
5.90 + * @param client Client index.
5.91 + * @noreturn
5.92 + */
5.93 +forward OnClientPostAdminCheck(client);
5.94 +
5.95 +/**
5.96 * Returns the maximum number of clients allowed on the server.
5.97 *
5.98 * @return Maximum number of clients allowed.
5.99 @@ -290,6 +315,30 @@
5.100 */
5.101 native bool:CanUserTarget(client, target);
5.102
5.103 +/**
5.104 + * Runs through the Core-defined admin authorization checks on a player.
5.105 + * Has no effect if the player is already an admin.
5.106 + *
5.107 + * Note: This function is based on the internal cache only.
5.108 + *
5.109 + * @param client Client index.
5.110 + * @return True if access was changed, false if it did not.
5.111 + * @error Invalid client index or client not in-game AND authorized.
5.112 + */
5.113 +native bool:RunAdminCacheChecks(client);
5.114 +
5.115 +/**
5.116 + * Signals that a player has completed post-connection admin checks.
5.117 + * Has no effect if the player has already had this event signalled.
5.118 + *
5.119 + * Note: This must be sent even if no admin id was assigned.
5.120 + *
5.121 + * @param client Client index.
5.122 + * @noreturn
5.123 + * @error Invalid client index or client not in-game AND authorized.
5.124 + */
5.125 +native NotifyPostAdminCheck(client);
5.126 +
5.127 /**
5.128 * Creates a fake client.
5.129 *
6.1 --- a/plugins/reservedslots.sp Wed Aug 08 15:08:01 2007 +0000
6.2 +++ b/plugins/reservedslots.sp Wed Aug 08 16:22:51 2007 +0000
6.3 @@ -63,7 +63,7 @@
6.4 }
6.5 }
6.6
6.7 -public OnClientAuthorized(client, const String:auth[])
6.8 +public OnClientPostAdminCheck(client)
6.9 {
6.10 new reserved = GetConVarInt(sm_reserved_slots);
6.11