1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/AdminCache.cpp Sun Jul 06 04:49:55 2008 +0000
1.3 @@ -0,0 +1,2081 @@
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 <string.h>
1.36 +#include <assert.h>
1.37 +#include <ITextParsers.h>
1.38 +#include "AdminCache.h"
1.39 +#include "ShareSys.h"
1.40 +#include "ForwardSys.h"
1.41 +#include "PlayerManager.h"
1.42 +#include "ConCmdManager.h"
1.43 +#include "Logger.h"
1.44 +#include "sourcemod.h"
1.45 +#include "sm_stringutil.h"
1.46 +#include "sourcemm_api.h"
1.47 +#include "sm_srvcmds.h"
1.48 +
1.49 +#define LEVEL_STATE_NONE 0
1.50 +#define LEVEL_STATE_LEVELS 1
1.51 +#define LEVEL_STATE_FLAGS 2
1.52 +
1.53 +AdminCache g_Admins;
1.54 +char g_ReverseFlags[26];
1.55 +AdminFlag g_FlagLetters[26];
1.56 +bool g_FlagSet[26];
1.57 +
1.58 +ConVar sm_immunity_mode("sm_immunity_mode", "1", FCVAR_SPONLY, "Mode for deciding immunity protection");
1.59 +
1.60 +/* Default flags */
1.61 +AdminFlag g_DefaultFlags[26] =
1.62 +{
1.63 + Admin_Reservation, Admin_Generic, Admin_Kick, Admin_Ban, Admin_Unban,
1.64 + Admin_Slay, Admin_Changemap, Admin_Convars, Admin_Config, Admin_Chat,
1.65 + Admin_Vote, Admin_Password, Admin_RCON, Admin_Cheats, Admin_Custom1,
1.66 + Admin_Custom2, Admin_Custom3, Admin_Custom4, Admin_Custom5, Admin_Custom6,
1.67 + Admin_Generic, Admin_Generic, Admin_Generic, Admin_Generic, Admin_Generic,
1.68 + Admin_Root
1.69 +};
1.70 +
1.71 +
1.72 +class FlagReader : public ITextListener_SMC
1.73 +{
1.74 +public:
1.75 + void LoadLevels()
1.76 + {
1.77 + if (!Parse())
1.78 + {
1.79 + memcpy(g_FlagLetters, g_DefaultFlags, sizeof(AdminFlag) * 26);
1.80 + for (unsigned int i=0; i<20; i++)
1.81 + {
1.82 + g_FlagSet[i] = true;
1.83 + }
1.84 + g_FlagSet[25] = true;
1.85 + }
1.86 + }
1.87 +private:
1.88 + bool Parse()
1.89 + {
1.90 + SMCStates states;
1.91 + SMCError error;
1.92 +
1.93 + m_bFileNameLogged = false;
1.94 + g_SourceMod.BuildPath(Path_SM, m_File, sizeof(m_File), "configs/admin_levels.cfg");
1.95 +
1.96 + if ((error = textparsers->ParseFile_SMC(m_File, this, &states))
1.97 + != SMCError_Okay)
1.98 + {
1.99 + const char *err_string = textparsers->GetSMCErrorString(error);
1.100 + if (!err_string)
1.101 + {
1.102 + err_string = "Unknown error";
1.103 + }
1.104 + ParseError(NULL, "Error %d (%s)", error, err_string);
1.105 + return false;
1.106 + }
1.107 +
1.108 + return true;
1.109 + }
1.110 + void ReadSMC_ParseStart()
1.111 + {
1.112 + m_LevelState = LEVEL_STATE_NONE;
1.113 + m_IgnoreLevel = 0;
1.114 + memset(g_FlagSet, 0, sizeof(g_FlagSet));
1.115 + }
1.116 + SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name)
1.117 + {
1.118 + if (m_IgnoreLevel)
1.119 + {
1.120 + m_IgnoreLevel++;
1.121 + return SMCResult_Continue;
1.122 + }
1.123 +
1.124 + if (m_LevelState == LEVEL_STATE_NONE)
1.125 + {
1.126 + if (strcmp(name, "Levels") == 0)
1.127 + {
1.128 + m_LevelState = LEVEL_STATE_LEVELS;
1.129 + }
1.130 + else
1.131 + {
1.132 + m_IgnoreLevel++;
1.133 + }
1.134 + } else if (m_LevelState == LEVEL_STATE_LEVELS) {
1.135 + if (strcmp(name, "Flags") == 0)
1.136 + {
1.137 + m_LevelState = LEVEL_STATE_FLAGS;
1.138 + }
1.139 + else
1.140 + {
1.141 + m_IgnoreLevel++;
1.142 + }
1.143 + }
1.144 + else
1.145 + {
1.146 + m_IgnoreLevel++;
1.147 + }
1.148 +
1.149 + return SMCResult_Continue;
1.150 + }
1.151 + SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
1.152 + {
1.153 + if (m_LevelState != LEVEL_STATE_FLAGS || m_IgnoreLevel)
1.154 + {
1.155 + return SMCResult_Continue;
1.156 + }
1.157 +
1.158 + unsigned char c = (unsigned)value[0];
1.159 +
1.160 + if (c < (unsigned)'a' || c > (unsigned)'z')
1.161 + {
1.162 + ParseError(states, "Flag \"%c\" is not a lower-case ASCII letter", c);
1.163 + return SMCResult_Continue;
1.164 + }
1.165 +
1.166 + c -= (unsigned)'a';
1.167 +
1.168 + if (!g_Admins.FindFlag(key, &g_FlagLetters[c]))
1.169 + {
1.170 + ParseError(states, "Unrecognized admin level \"%s\"", key);
1.171 + return SMCResult_Continue;
1.172 + }
1.173 +
1.174 + g_FlagSet[c] = true;
1.175 +
1.176 + return SMCResult_Continue;
1.177 + }
1.178 + SMCResult ReadSMC_LeavingSection(const SMCStates *states)
1.179 + {
1.180 + if (m_IgnoreLevel)
1.181 + {
1.182 + m_IgnoreLevel--;
1.183 + return SMCResult_Continue;
1.184 + }
1.185 +
1.186 + if (m_LevelState == LEVEL_STATE_FLAGS)
1.187 + {
1.188 + m_LevelState = LEVEL_STATE_LEVELS;
1.189 + return SMCResult_Halt;
1.190 + }
1.191 + else if (m_LevelState == LEVEL_STATE_LEVELS)
1.192 + {
1.193 + m_LevelState = LEVEL_STATE_NONE;
1.194 + }
1.195 +
1.196 + return SMCResult_Continue;
1.197 + }
1.198 + void ParseError(const SMCStates *states, const char *message, ...)
1.199 + {
1.200 + va_list ap;
1.201 + char buffer[256];
1.202 +
1.203 + va_start(ap, message);
1.204 + UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
1.205 + va_end(ap);
1.206 +
1.207 + if (!m_bFileNameLogged)
1.208 + {
1.209 + g_Logger.LogError("[SM] Parse error(s) detected in file \"%s\":", m_File);
1.210 + m_bFileNameLogged = true;
1.211 + }
1.212 +
1.213 + g_Logger.LogError("[SM] (Line %d): %s", states ? states->line : 0, buffer);
1.214 + }
1.215 +private:
1.216 + bool m_bFileNameLogged;
1.217 + char m_File[PLATFORM_MAX_PATH];
1.218 + int m_LevelState;
1.219 + int m_IgnoreLevel;
1.220 +} s_FlagReader;
1.221 +
1.222 +AdminCache::AdminCache()
1.223 +{
1.224 + m_pCmdOverrides = sm_trie_create();
1.225 + m_pCmdGrpOverrides = sm_trie_create();
1.226 + m_pStrings = new BaseStringTable(1024);
1.227 + m_pMemory = m_pStrings->GetMemTable();
1.228 + m_FreeGroupList = m_FirstGroup = m_LastGroup = INVALID_GROUP_ID;
1.229 + m_FreeUserList = m_FirstUser = m_LastUser = INVALID_ADMIN_ID;
1.230 + m_pGroups = sm_trie_create();
1.231 + m_pCacheFwd = NULL;
1.232 + m_FirstGroup = -1;
1.233 + m_pAuthTables = sm_trie_create();
1.234 + m_InvalidatingAdmins = false;
1.235 + m_destroying = false;
1.236 + m_pLevelNames = sm_trie_create();
1.237 +}
1.238 +
1.239 +AdminCache::~AdminCache()
1.240 +{
1.241 + m_destroying = true;
1.242 + DumpAdminCache(AdminCache_Overrides, false);
1.243 + DumpAdminCache(AdminCache_Groups, false);
1.244 +
1.245 + sm_trie_destroy(m_pCmdGrpOverrides);
1.246 + sm_trie_destroy(m_pCmdOverrides);
1.247 +
1.248 + if (m_pGroups)
1.249 + {
1.250 + sm_trie_destroy(m_pGroups);
1.251 + }
1.252 +
1.253 + List<AuthMethod>::iterator iter;
1.254 + for (iter=m_AuthMethods.begin();
1.255 + iter!=m_AuthMethods.end();
1.256 + iter++)
1.257 + {
1.258 + sm_trie_destroy((*iter).table);
1.259 + }
1.260 +
1.261 + sm_trie_destroy(m_pAuthTables);
1.262 +
1.263 + delete m_pStrings;
1.264 +
1.265 + sm_trie_destroy(m_pLevelNames);
1.266 +}
1.267 +
1.268 +void AdminCache::OnSourceModStartup(bool late)
1.269 +{
1.270 + RegisterAuthIdentType("steam");
1.271 + RegisterAuthIdentType("name");
1.272 + RegisterAuthIdentType("ip");
1.273 +
1.274 + NameFlag("reservation", Admin_Reservation);
1.275 + NameFlag("kick", Admin_Kick);
1.276 + NameFlag("generic", Admin_Generic);
1.277 + NameFlag("ban", Admin_Ban);
1.278 + NameFlag("unban", Admin_Unban);
1.279 + NameFlag("slay", Admin_Slay);
1.280 + NameFlag("changemap", Admin_Changemap);
1.281 + NameFlag("cvars", Admin_Convars);
1.282 + NameFlag("config", Admin_Config);
1.283 + NameFlag("chat", Admin_Chat);
1.284 + NameFlag("vote", Admin_Vote);
1.285 + NameFlag("password", Admin_Password);
1.286 + NameFlag("rcon", Admin_RCON);
1.287 + NameFlag("cheats", Admin_Cheats);
1.288 + NameFlag("root", Admin_Root);
1.289 + NameFlag("custom1", Admin_Custom1);
1.290 + NameFlag("custom2", Admin_Custom2);
1.291 + NameFlag("custom3", Admin_Custom3);
1.292 + NameFlag("custom4", Admin_Custom4);
1.293 + NameFlag("custom5", Admin_Custom5);
1.294 + NameFlag("custom6", Admin_Custom6);
1.295 +}
1.296 +
1.297 +void AdminCache::OnSourceModAllInitialized()
1.298 +{
1.299 + m_pCacheFwd = g_Forwards.CreateForward("OnRebuildAdminCache", ET_Ignore, 1, NULL, Param_Cell);
1.300 + g_ShareSys.AddInterface(NULL, this);
1.301 +}
1.302 +
1.303 +void AdminCache::OnSourceModLevelChange(const char *mapName)
1.304 +{
1.305 + int i;
1.306 + AdminFlag flag;
1.307 +
1.308 + /* For now, we only read these once per level. */
1.309 + s_FlagReader.LoadLevels();
1.310 +
1.311 + for (i = 0; i < 26; i++)
1.312 + {
1.313 + if (FindFlag('a' + i, &flag))
1.314 + {
1.315 + g_ReverseFlags[flag] = 'a' + i;
1.316 + }
1.317 + else
1.318 + {
1.319 + g_ReverseFlags[flag] = '?';
1.320 + }
1.321 + }
1.322 +}
1.323 +
1.324 +void AdminCache::OnSourceModShutdown()
1.325 +{
1.326 + g_Forwards.ReleaseForward(m_pCacheFwd);
1.327 + m_pCacheFwd = NULL;
1.328 +}
1.329 +
1.330 +void AdminCache::OnSourceModPluginsLoaded()
1.331 +{
1.332 + DumpAdminCache(AdminCache_Overrides, true);
1.333 + DumpAdminCache(AdminCache_Groups, true);
1.334 +}
1.335 +
1.336 +void AdminCache::NameFlag(const char *str, AdminFlag flag)
1.337 +{
1.338 + sm_trie_insert(m_pLevelNames, str, (void *)flag);
1.339 +}
1.340 +
1.341 +bool AdminCache::FindFlag(const char *str, AdminFlag *pFlag)
1.342 +{
1.343 + void *obj;
1.344 + if (!sm_trie_retrieve(m_pLevelNames, str, &obj))
1.345 + {
1.346 + return false;
1.347 + }
1.348 +
1.349 + if (pFlag)
1.350 + {
1.351 + *pFlag = (AdminFlag)(int)obj;
1.352 + }
1.353 +
1.354 + return true;
1.355 +}
1.356 +
1.357 +void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, FlagBits flags)
1.358 +{
1.359 + Trie *pTrie = NULL;
1.360 + if (type == Override_Command)
1.361 + {
1.362 + pTrie = m_pCmdOverrides;
1.363 + } else if (type == Override_CommandGroup) {
1.364 + pTrie = m_pCmdGrpOverrides;
1.365 + } else {
1.366 + return;
1.367 + }
1.368 +
1.369 + sm_trie_insert(pTrie, cmd, (void *)(unsigned int)flags);
1.370 +
1.371 + g_ConCmds.UpdateAdminCmdFlags(cmd, type, flags, false);
1.372 +}
1.373 +
1.374 +bool AdminCache::GetCommandOverride(const char *cmd, OverrideType type, FlagBits *pFlags)
1.375 +{
1.376 + Trie *pTrie = NULL;
1.377 +
1.378 + if (type == Override_Command)
1.379 + {
1.380 + pTrie = m_pCmdOverrides;
1.381 + } else if (type == Override_CommandGroup) {
1.382 + pTrie = m_pCmdGrpOverrides;
1.383 + } else {
1.384 + return false;
1.385 + }
1.386 +
1.387 + void *object;
1.388 + if (sm_trie_retrieve(pTrie, cmd, &object))
1.389 + {
1.390 + if (pFlags)
1.391 + {
1.392 + *pFlags = (FlagBits)object;
1.393 + }
1.394 + return true;
1.395 + }
1.396 +
1.397 + return false;
1.398 +}
1.399 +
1.400 +void AdminCache::UnsetCommandOverride(const char *cmd, OverrideType type)
1.401 +{
1.402 + if (type == Override_Command)
1.403 + {
1.404 + return _UnsetCommandOverride(cmd);
1.405 + } else if (type == Override_CommandGroup) {
1.406 + return _UnsetCommandGroupOverride(cmd);
1.407 + }
1.408 +}
1.409 +
1.410 +void AdminCache::_UnsetCommandGroupOverride(const char *group)
1.411 +{
1.412 + if (!m_pCmdGrpOverrides)
1.413 + {
1.414 + return;
1.415 + }
1.416 +
1.417 + sm_trie_delete(m_pCmdGrpOverrides, group);
1.418 +
1.419 + g_ConCmds.UpdateAdminCmdFlags(group, Override_CommandGroup, 0, true);
1.420 +}
1.421 +
1.422 +void AdminCache::_UnsetCommandOverride(const char *cmd)
1.423 +{
1.424 + if (!m_pCmdOverrides)
1.425 + {
1.426 + return;
1.427 + }
1.428 +
1.429 + sm_trie_delete(m_pCmdOverrides, cmd);
1.430 +
1.431 + g_ConCmds.UpdateAdminCmdFlags(cmd, Override_Command, 0, true);
1.432 +}
1.433 +
1.434 +void AdminCache::DumpCommandOverrideCache(OverrideType type)
1.435 +{
1.436 + if (type == Override_Command && m_pCmdOverrides)
1.437 + {
1.438 + sm_trie_clear(m_pCmdOverrides);
1.439 + } else if (type == Override_CommandGroup && m_pCmdGrpOverrides) {
1.440 + sm_trie_clear(m_pCmdGrpOverrides);
1.441 + }
1.442 +}
1.443 +
1.444 +AdminId AdminCache::CreateAdmin(const char *name)
1.445 +{
1.446 + AdminId id;
1.447 + AdminUser *pUser;
1.448 +
1.449 + if (m_FreeUserList != INVALID_ADMIN_ID)
1.450 + {
1.451 + pUser = (AdminUser *)m_pMemory->GetAddress(m_FreeUserList);
1.452 + assert(pUser->magic == USR_MAGIC_UNSET);
1.453 + id = m_FreeUserList;
1.454 + m_FreeUserList = pUser->next_user;
1.455 + }
1.456 + else
1.457 + {
1.458 + id = m_pMemory->CreateMem(sizeof(AdminUser), (void **)&pUser);
1.459 + pUser->grp_size = 0;
1.460 + pUser->grp_table = -1;
1.461 + }
1.462 +
1.463 + pUser->flags = 0;
1.464 + pUser->eflags = 0;
1.465 + pUser->grp_count = 0;
1.466 + pUser->password = -1;
1.467 + pUser->magic = USR_MAGIC_SET;
1.468 + pUser->auth.identidx = -1;
1.469 + pUser->auth.index = 0;
1.470 + pUser->immunity_level = 0;
1.471 + pUser->serialchange = 1;
1.472 +
1.473 + if (m_FirstUser == INVALID_ADMIN_ID)
1.474 + {
1.475 + m_FirstUser = id;
1.476 + m_LastUser = id;
1.477 + }
1.478 + else
1.479 + {
1.480 + AdminUser *pPrev = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
1.481 + pPrev->next_user = id;
1.482 + pUser->prev_user = m_LastUser;
1.483 + m_LastUser = id;
1.484 + }
1.485 +
1.486 + /* Since we always append to the tail, we should invalidate their next */
1.487 + pUser->next_user = -1;
1.488 +
1.489 + if (name && name[0] != '\0')
1.490 + {
1.491 + int nameidx = m_pStrings->AddString(name);
1.492 + pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.493 + pUser->nameidx = nameidx;
1.494 + }
1.495 + else
1.496 + {
1.497 + pUser->nameidx = -1;
1.498 + }
1.499 +
1.500 + return id;
1.501 +}
1.502 +
1.503 +GroupId AdminCache::AddGroup(const char *group_name)
1.504 +{
1.505 + if (sm_trie_retrieve(m_pGroups, group_name, NULL))
1.506 + {
1.507 + return INVALID_GROUP_ID;
1.508 + }
1.509 +
1.510 + GroupId id;
1.511 + AdminGroup *pGroup;
1.512 + if (m_FreeGroupList != INVALID_GROUP_ID)
1.513 + {
1.514 + pGroup = (AdminGroup *)m_pMemory->GetAddress(m_FreeGroupList);
1.515 + assert(pGroup->magic == GRP_MAGIC_UNSET);
1.516 + id = m_FreeGroupList;
1.517 + m_FreeGroupList = pGroup->next_grp;
1.518 + } else {
1.519 + id = m_pMemory->CreateMem(sizeof(AdminGroup), (void **)&pGroup);
1.520 + }
1.521 +
1.522 + pGroup->immunity_level = 0;
1.523 + pGroup->immune_table = -1;
1.524 + pGroup->magic = GRP_MAGIC_SET;
1.525 + pGroup->next_grp = INVALID_GROUP_ID;
1.526 + pGroup->pCmdGrpTable = NULL;
1.527 + pGroup->pCmdTable = NULL;
1.528 + pGroup->addflags = 0;
1.529 +
1.530 + if (m_FirstGroup == INVALID_GROUP_ID)
1.531 + {
1.532 + m_FirstGroup = id;
1.533 + m_LastGroup = id;
1.534 + pGroup->prev_grp = INVALID_GROUP_ID;
1.535 + } else {
1.536 + AdminGroup *pPrev = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
1.537 + assert(pPrev->magic == GRP_MAGIC_SET);
1.538 + pPrev->next_grp = id;
1.539 + pGroup->prev_grp = m_LastGroup;
1.540 + m_LastGroup = id;
1.541 + }
1.542 +
1.543 + int nameidx = m_pStrings->AddString(group_name);
1.544 + pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
1.545 + pGroup->nameidx = nameidx;
1.546 +
1.547 + sm_trie_insert(m_pGroups, group_name, (void *)id);
1.548 +
1.549 + return id;
1.550 +}
1.551 +
1.552 +GroupId AdminCache::FindGroupByName(const char *group_name)
1.553 +{
1.554 + void *object;
1.555 +
1.556 + if (!sm_trie_retrieve(m_pGroups, group_name, &object))
1.557 + {
1.558 + return INVALID_GROUP_ID;
1.559 + }
1.560 +
1.561 + GroupId id = (GroupId)object;
1.562 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
1.563 +
1.564 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.565 + {
1.566 + return INVALID_GROUP_ID;
1.567 + }
1.568 +
1.569 + return id;
1.570 +}
1.571 +
1.572 +void AdminCache::SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled)
1.573 +{
1.574 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
1.575 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.576 + {
1.577 + return;
1.578 + }
1.579 +
1.580 + if (flag < Admin_Reservation || flag >= AdminFlags_TOTAL)
1.581 + {
1.582 + return;
1.583 + }
1.584 +
1.585 + FlagBits bits = (1<<(FlagBits)flag);
1.586 +
1.587 + if (enabled)
1.588 + {
1.589 + pGroup->addflags |= bits;
1.590 + } else {
1.591 + pGroup->addflags &= ~bits;
1.592 + }
1.593 +}
1.594 +
1.595 +bool AdminCache::GetGroupAddFlag(GroupId id, AdminFlag flag)
1.596 +{
1.597 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
1.598 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.599 + {
1.600 + return false;
1.601 + }
1.602 +
1.603 + if (flag < Admin_Reservation || flag >= AdminFlags_TOTAL)
1.604 + {
1.605 + return false;
1.606 + }
1.607 +
1.608 + FlagBits bit = 1<<(FlagBits)flag;
1.609 + return ((pGroup->addflags & bit) == bit);
1.610 +}
1.611 +
1.612 +FlagBits AdminCache::GetGroupAddFlags(GroupId id)
1.613 +{
1.614 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
1.615 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.616 + {
1.617 + return 0;
1.618 + }
1.619 +
1.620 + return pGroup->addflags;
1.621 +}
1.622 +
1.623 +const char *AdminCache::GetGroupName(GroupId gid)
1.624 +{
1.625 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
1.626 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.627 + {
1.628 + return NULL;
1.629 + }
1.630 +
1.631 + return m_pStrings->GetString(pGroup->nameidx);
1.632 +}
1.633 +
1.634 +void AdminCache::SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled)
1.635 +{
1.636 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
1.637 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.638 + {
1.639 + return;
1.640 + }
1.641 +
1.642 + unsigned int level = 0;
1.643 +
1.644 + if (enabled)
1.645 + {
1.646 + if (type == Immunity_Default)
1.647 + {
1.648 + level = 1;
1.649 + } else if (type == Immunity_Global) {
1.650 + level = 2;
1.651 + }
1.652 + if (level > pGroup->immunity_level)
1.653 + {
1.654 + pGroup->immunity_level = level;
1.655 + }
1.656 + } else {
1.657 + pGroup->immunity_level = 0;
1.658 + }
1.659 +}
1.660 +
1.661 +bool AdminCache::GetGroupGenericImmunity(GroupId id, ImmunityType type)
1.662 +{
1.663 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
1.664 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.665 + {
1.666 + return false;
1.667 + }
1.668 +
1.669 + if (type == Immunity_Default && pGroup->immunity_level >= 1)
1.670 + {
1.671 + return true;
1.672 + } else if (type == Immunity_Global && pGroup->immunity_level >= 2) {
1.673 + return true;
1.674 + }
1.675 +
1.676 + return false;
1.677 +}
1.678 +
1.679 +void AdminCache::AddGroupImmunity(GroupId id, GroupId other_id)
1.680 +{
1.681 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(other_id);
1.682 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.683 + {
1.684 + return;
1.685 + }
1.686 +
1.687 + pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
1.688 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.689 + {
1.690 + return;
1.691 + }
1.692 +
1.693 + /* We always need to resize the immunity table */
1.694 + int *table, tblidx;
1.695 + if (pGroup->immune_table == -1)
1.696 + {
1.697 + tblidx = m_pMemory->CreateMem(sizeof(int) * 2, (void **)&table);
1.698 + pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
1.699 + table[0] = 0;
1.700 + } else {
1.701 + int *old_table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
1.702 + /* Break out if this group is already in the list */
1.703 + for (int i=0; i<old_table[0]; i++)
1.704 + {
1.705 + if (old_table[1+i] == other_id)
1.706 + {
1.707 + return;
1.708 + }
1.709 + }
1.710 + tblidx = m_pMemory->CreateMem(sizeof(int) * (old_table[0] + 2), (void **)&table);
1.711 + /* Get the old address again in case of resize */
1.712 + pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
1.713 + old_table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
1.714 + table[0] = old_table[0];
1.715 + for (unsigned int i=1; i<=(unsigned int)old_table[0]; i++)
1.716 + {
1.717 + table[i] = old_table[i];
1.718 + }
1.719 + }
1.720 +
1.721 + /* Assign */
1.722 + pGroup->immune_table = tblidx;
1.723 +
1.724 + /* Add to the array */
1.725 + table[0]++;
1.726 + table[table[0]] = other_id;
1.727 +}
1.728 +
1.729 +unsigned int AdminCache::GetGroupImmunityCount(GroupId id)
1.730 +{
1.731 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
1.732 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.733 + {
1.734 + return 0;
1.735 + }
1.736 +
1.737 + if (pGroup->immune_table == -1)
1.738 + {
1.739 + return 0;
1.740 + }
1.741 +
1.742 + int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
1.743 +
1.744 + return table[0];
1.745 +}
1.746 +
1.747 +GroupId AdminCache::GetGroupImmunity(GroupId id, unsigned int number)
1.748 +{
1.749 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
1.750 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.751 + {
1.752 + return INVALID_GROUP_ID;
1.753 + }
1.754 +
1.755 + if (pGroup->immune_table == -1)
1.756 + {
1.757 + return INVALID_GROUP_ID;
1.758 + }
1.759 +
1.760 + int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
1.761 + if (number >= (unsigned int)table[0])
1.762 + {
1.763 + return INVALID_GROUP_ID;
1.764 + }
1.765 +
1.766 + return table[1 + number];
1.767 +}
1.768 +
1.769 +void AdminCache::AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule)
1.770 +{
1.771 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
1.772 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.773 + {
1.774 + return;
1.775 + }
1.776 +
1.777 + Trie *pTrie = NULL;
1.778 + if (type == Override_Command)
1.779 + {
1.780 + if (pGroup->pCmdTable == NULL)
1.781 + {
1.782 + pGroup->pCmdTable = sm_trie_create();
1.783 + }
1.784 + pTrie = pGroup->pCmdTable;
1.785 + } else if (type == Override_CommandGroup) {
1.786 + if (pGroup->pCmdGrpTable == NULL)
1.787 + {
1.788 + pGroup->pCmdGrpTable = sm_trie_create();
1.789 + }
1.790 + pTrie = pGroup->pCmdGrpTable;
1.791 + } else {
1.792 + return;
1.793 + }
1.794 +
1.795 + sm_trie_insert(pTrie, name, (void *)(int)rule);
1.796 +}
1.797 +
1.798 +bool AdminCache::GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule)
1.799 +{
1.800 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
1.801 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.802 + {
1.803 + return false;
1.804 + }
1.805 +
1.806 + Trie *pTrie = NULL;
1.807 + if (type == Override_Command)
1.808 + {
1.809 + if (pGroup->pCmdTable == NULL)
1.810 + {
1.811 + return false;
1.812 + }
1.813 + pTrie = pGroup->pCmdTable;
1.814 + } else if (type == Override_CommandGroup) {
1.815 + if (pGroup->pCmdGrpTable == NULL)
1.816 + {
1.817 + return false;
1.818 + }
1.819 + pTrie = pGroup->pCmdGrpTable;
1.820 + } else {
1.821 + return false;
1.822 + }
1.823 +
1.824 + void *object;
1.825 + if (!sm_trie_retrieve(pTrie, name, &object))
1.826 + {
1.827 + return false;
1.828 + }
1.829 +
1.830 + if (pRule)
1.831 + {
1.832 + *pRule = (OverrideRule)(int)object;
1.833 + }
1.834 +
1.835 + return true;
1.836 +}
1.837 +
1.838 +Trie *AdminCache::GetMethodByIndex(unsigned int index)
1.839 +{
1.840 + List<AuthMethod>::iterator iter;
1.841 + for (iter=m_AuthMethods.begin();
1.842 + iter!=m_AuthMethods.end();
1.843 + iter++)
1.844 + {
1.845 + if (index-- == 0)
1.846 + {
1.847 + return (*iter).table;
1.848 + }
1.849 + }
1.850 +
1.851 + return NULL;
1.852 +}
1.853 +
1.854 +bool AdminCache::InvalidateAdmin(AdminId id)
1.855 +{
1.856 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.857 + AdminUser *pOther;
1.858 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.859 + {
1.860 + return false;
1.861 + }
1.862 +
1.863 + if (!m_InvalidatingAdmins && !m_destroying)
1.864 + {
1.865 + g_Players.ClearAdminId(id);
1.866 + }
1.867 +
1.868 + /* Unlink from the dbl link list */
1.869 + if (id == m_FirstUser && id == m_LastUser)
1.870 + {
1.871 + m_FirstUser = INVALID_ADMIN_ID;
1.872 + m_LastUser = INVALID_ADMIN_ID;
1.873 + } else if (id == m_FirstUser) {
1.874 + m_FirstUser = pUser->next_user;
1.875 + pOther = (AdminUser *)m_pMemory->GetAddress(m_FirstUser);
1.876 + pOther->prev_user = INVALID_ADMIN_ID;
1.877 + } else if (id == m_LastUser) {
1.878 + m_LastUser = pUser->prev_user;
1.879 + pOther = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
1.880 + pOther->next_user = INVALID_ADMIN_ID;
1.881 + } else {
1.882 + pOther = (AdminUser *)m_pMemory->GetAddress(pUser->prev_user);
1.883 + pOther->next_user = pUser->next_user;
1.884 + pOther = (AdminUser *)m_pMemory->GetAddress(pUser->next_user);
1.885 + pOther->prev_user = pUser->prev_user;
1.886 + }
1.887 +
1.888 + /* Unlink from auth tables */
1.889 + if (pUser->auth.identidx != -1)
1.890 + {
1.891 + Trie *pTrie = GetMethodByIndex(pUser->auth.index);
1.892 + if (pTrie)
1.893 + {
1.894 + sm_trie_delete(pTrie, m_pStrings->GetString(pUser->auth.identidx));
1.895 + }
1.896 + }
1.897 +
1.898 + /* Clear table counts */
1.899 + pUser->grp_count = 0;
1.900 +
1.901 + /* Link into free list */
1.902 + pUser->magic = USR_MAGIC_UNSET;
1.903 + pUser->next_user = m_FreeUserList;
1.904 + m_FreeUserList = id;
1.905 +
1.906 + /* Unset serial change */
1.907 + pUser->serialchange = 0;
1.908 +
1.909 + return true;
1.910 +}
1.911 +
1.912 +
1.913 +void AdminCache::InvalidateGroup(GroupId id)
1.914 +{
1.915 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
1.916 + AdminGroup *pOther;
1.917 +
1.918 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.919 + {
1.920 + return;
1.921 + }
1.922 +
1.923 + const char *str = m_pStrings->GetString(pGroup->nameidx);
1.924 + sm_trie_delete(m_pGroups, str);
1.925 +
1.926 + /* Unlink from the live dbllink list */
1.927 + if (id == m_FirstGroup && id == m_LastGroup)
1.928 + {
1.929 + m_LastGroup = INVALID_GROUP_ID;
1.930 + m_FirstGroup = INVALID_GROUP_ID;
1.931 + } else if (id == m_FirstGroup) {
1.932 + m_FirstGroup = pGroup->next_grp;
1.933 + pOther = (AdminGroup *)m_pMemory->GetAddress(m_FirstGroup);
1.934 + pOther->prev_grp = INVALID_GROUP_ID;
1.935 + } else if (id == m_LastGroup) {
1.936 + m_LastGroup = pGroup->prev_grp;
1.937 + pOther = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
1.938 + pOther->next_grp = INVALID_GROUP_ID;
1.939 + } else {
1.940 + pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->prev_grp);
1.941 + pOther->next_grp = pGroup->next_grp;
1.942 + pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->next_grp);
1.943 + pOther->prev_grp = pGroup->prev_grp;
1.944 + }
1.945 +
1.946 + /* Free any used memory to be safe */
1.947 + if (pGroup->pCmdGrpTable)
1.948 + {
1.949 + sm_trie_destroy(pGroup->pCmdGrpTable);
1.950 + pGroup->pCmdGrpTable = NULL;
1.951 + }
1.952 + if (pGroup->pCmdTable)
1.953 + {
1.954 + sm_trie_destroy(pGroup->pCmdTable);
1.955 + pGroup->pCmdTable = NULL;
1.956 + }
1.957 +
1.958 + /* Link into the free list */
1.959 + pGroup->magic = GRP_MAGIC_UNSET;
1.960 + pGroup->next_grp = m_FreeGroupList;
1.961 + m_FreeGroupList = id;
1.962 +
1.963 + int idx = m_FirstUser;
1.964 + AdminUser *pUser;
1.965 + int *table;
1.966 + while (idx != INVALID_ADMIN_ID)
1.967 + {
1.968 + pUser = (AdminUser *)m_pMemory->GetAddress(idx);
1.969 + if (pUser->grp_count > 0)
1.970 + {
1.971 + table = (int *)m_pMemory->GetAddress(pUser->grp_table);
1.972 + for (unsigned int i=0; i<pUser->grp_count; i++)
1.973 + {
1.974 + if (table[i] == id)
1.975 + {
1.976 + /* We have to remove this entry */
1.977 + for (unsigned int j=i+1; j<pUser->grp_count; j++)
1.978 + {
1.979 + /* Move everything down by one */
1.980 + table[j-1] = table[j];
1.981 + }
1.982 + /* Decrease count */
1.983 + pUser->grp_count--;
1.984 + /* Recalculate effective flags */
1.985 + pUser->eflags = pUser->flags;
1.986 + for (unsigned int j=0; j<pUser->grp_count; j++)
1.987 + {
1.988 + pOther = (AdminGroup *)m_pMemory->GetAddress(table[j]);
1.989 + pUser->eflags |= pOther->addflags;
1.990 + }
1.991 + /* Mark as changed */
1.992 + pUser->serialchange++;
1.993 + /* Break now, duplicates aren't allowed */
1.994 + break;
1.995 + }
1.996 + }
1.997 + }
1.998 + idx = pUser->next_user;
1.999 + }
1.1000 +}
1.1001 +
1.1002 +void AdminCache::InvalidateGroupCache()
1.1003 +{
1.1004 + /* Nuke the free list */
1.1005 + m_FreeGroupList = -1;
1.1006 +
1.1007 + /* Nuke reverse lookups */
1.1008 + sm_trie_clear(m_pGroups);
1.1009 +
1.1010 + /* Free memory on groups */
1.1011 + GroupId cur = m_FirstGroup;
1.1012 + AdminGroup *pGroup;
1.1013 + while (cur != INVALID_GROUP_ID)
1.1014 + {
1.1015 + pGroup = (AdminGroup *)m_pMemory->GetAddress(cur);
1.1016 + assert(pGroup->magic == GRP_MAGIC_SET);
1.1017 + if (pGroup->pCmdGrpTable)
1.1018 + {
1.1019 + sm_trie_destroy(pGroup->pCmdGrpTable);
1.1020 + }
1.1021 + if (pGroup->pCmdTable)
1.1022 + {
1.1023 + sm_trie_destroy(pGroup->pCmdTable);
1.1024 + }
1.1025 + cur = pGroup->next_grp;
1.1026 + }
1.1027 +
1.1028 + m_FirstGroup = INVALID_GROUP_ID;
1.1029 + m_LastGroup = INVALID_GROUP_ID;
1.1030 +
1.1031 + InvalidateAdminCache(false);
1.1032 +
1.1033 + /* Reset the memory table */
1.1034 + m_pMemory->Reset();
1.1035 +}
1.1036 +
1.1037 +void AdminCache::AddAdminListener(IAdminListener *pListener)
1.1038 +{
1.1039 + m_hooks.push_back(pListener);
1.1040 +}
1.1041 +
1.1042 +void AdminCache::RemoveAdminListener(IAdminListener *pListener)
1.1043 +{
1.1044 + m_hooks.remove(pListener);
1.1045 +}
1.1046 +
1.1047 +void AdminCache::RegisterAuthIdentType(const char *name)
1.1048 +{
1.1049 + if (sm_trie_retrieve(m_pAuthTables, name, NULL))
1.1050 + {
1.1051 + return;
1.1052 + }
1.1053 +
1.1054 + Trie *pAuth = sm_trie_create();
1.1055 +
1.1056 + AuthMethod method;
1.1057 + method.name.assign(name);
1.1058 + method.table = pAuth;
1.1059 +
1.1060 + m_AuthMethods.push_back(method);
1.1061 +
1.1062 + sm_trie_insert(m_pAuthTables, name, pAuth);
1.1063 +}
1.1064 +
1.1065 +void AdminCache::InvalidateAdminCache(bool unlink_admins)
1.1066 +{
1.1067 + m_InvalidatingAdmins = true;
1.1068 + if (!m_destroying)
1.1069 + {
1.1070 + g_Players.ClearAllAdmins();
1.1071 + }
1.1072 + /* Wipe the identity cache first */
1.1073 + List<AuthMethod>::iterator iter;
1.1074 + for (iter=m_AuthMethods.begin();
1.1075 + iter!=m_AuthMethods.end();
1.1076 + iter++)
1.1077 + {
1.1078 + sm_trie_clear((*iter).table);
1.1079 + }
1.1080 +
1.1081 + if (unlink_admins)
1.1082 + {
1.1083 + while (m_FirstUser != INVALID_ADMIN_ID)
1.1084 + {
1.1085 + InvalidateAdmin(m_FirstUser);
1.1086 + }
1.1087 + } else {
1.1088 + m_FirstUser = -1;
1.1089 + m_LastUser = -1;
1.1090 + m_FreeUserList = -1;
1.1091 + }
1.1092 + m_InvalidatingAdmins = false;
1.1093 +}
1.1094 +
1.1095 +void AdminCache::DumpAdminCache(AdminCachePart part, bool rebuild)
1.1096 +{
1.1097 + List<IAdminListener *>::iterator iter;
1.1098 + IAdminListener *pListener;
1.1099 + cell_t result;
1.1100 +
1.1101 + if (part == AdminCache_Overrides)
1.1102 + {
1.1103 + DumpCommandOverrideCache(Override_Command);
1.1104 + DumpCommandOverrideCache(Override_CommandGroup);
1.1105 + if (rebuild && !m_destroying)
1.1106 + {
1.1107 + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
1.1108 + {
1.1109 + pListener = (*iter);
1.1110 + pListener->OnRebuildOverrideCache();
1.1111 + }
1.1112 + m_pCacheFwd->PushCell(part);
1.1113 + m_pCacheFwd->Execute(&result);
1.1114 + }
1.1115 + } else if (part == AdminCache_Groups || part == AdminCache_Admins) {
1.1116 + if (part == AdminCache_Groups)
1.1117 + {
1.1118 + InvalidateGroupCache();
1.1119 + if (rebuild && !m_destroying)
1.1120 + {
1.1121 + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
1.1122 + {
1.1123 + pListener = (*iter);
1.1124 + pListener->OnRebuildGroupCache();
1.1125 + }
1.1126 + m_pCacheFwd->PushCell(part);
1.1127 + m_pCacheFwd->Execute(&result);
1.1128 + }
1.1129 + }
1.1130 + InvalidateAdminCache(true);
1.1131 + if (rebuild && !m_destroying)
1.1132 + {
1.1133 + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
1.1134 + {
1.1135 + pListener = (*iter);
1.1136 + pListener->OnRebuildAdminCache((part == AdminCache_Groups));
1.1137 + }
1.1138 + m_pCacheFwd->PushCell(AdminCache_Admins);
1.1139 + m_pCacheFwd->Execute(&result);
1.1140 + g_Players.RecheckAnyAdmins();
1.1141 + }
1.1142 + }
1.1143 +}
1.1144 +
1.1145 +const char *AdminCache::GetAdminName(AdminId id)
1.1146 +{
1.1147 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1148 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.1149 + {
1.1150 + return NULL;
1.1151 + }
1.1152 +
1.1153 + return m_pStrings->GetString(pUser->nameidx);
1.1154 +}
1.1155 +
1.1156 +bool AdminCache::GetMethodIndex(const char *name, unsigned int *_index)
1.1157 +{
1.1158 + List<AuthMethod>::iterator iter;
1.1159 + unsigned int index = 0;
1.1160 + for (iter=m_AuthMethods.begin();
1.1161 + iter!=m_AuthMethods.end();
1.1162 + iter++,index++)
1.1163 + {
1.1164 + if ((*iter).name.compare(name) == 0)
1.1165 + {
1.1166 + *_index = index;
1.1167 + return true;
1.1168 + }
1.1169 + }
1.1170 +
1.1171 + return false;
1.1172 +}
1.1173 +
1.1174 +bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ident)
1.1175 +{
1.1176 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1177 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.1178 + {
1.1179 + return false;
1.1180 + }
1.1181 +
1.1182 + Trie *pTable;
1.1183 + if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
1.1184 + {
1.1185 + return false;
1.1186 + }
1.1187 +
1.1188 + if (sm_trie_retrieve(pTable, ident, NULL))
1.1189 + {
1.1190 + return false;
1.1191 + }
1.1192 +
1.1193 + int i_ident = m_pStrings->AddString(ident);
1.1194 +
1.1195 + pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1196 + pUser->auth.identidx = i_ident;
1.1197 + GetMethodIndex(auth, &pUser->auth.index);
1.1198 +
1.1199 + return sm_trie_insert(pTable, ident, (void **)id);
1.1200 +}
1.1201 +
1.1202 +AdminId AdminCache::FindAdminByIdentity(const char *auth, const char *identity)
1.1203 +{
1.1204 + Trie *pTable;
1.1205 + if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
1.1206 + {
1.1207 + return INVALID_ADMIN_ID;
1.1208 + }
1.1209 +
1.1210 + void *object;
1.1211 + if (!sm_trie_retrieve(pTable, identity, &object))
1.1212 + {
1.1213 + return INVALID_ADMIN_ID;
1.1214 + }
1.1215 +
1.1216 + return (AdminId)object;
1.1217 +}
1.1218 +
1.1219 +void AdminCache::SetAdminFlag(AdminId id, AdminFlag flag, bool enabled)
1.1220 +{
1.1221 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1222 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.1223 + {
1.1224 + return;
1.1225 + }
1.1226 +
1.1227 + if (flag < Admin_Reservation
1.1228 + || flag >= AdminFlags_TOTAL)
1.1229 + {
1.1230 + return;
1.1231 + }
1.1232 +
1.1233 + FlagBits bits = (1<<(FlagBits)flag);
1.1234 +
1.1235 + if (enabled)
1.1236 + {
1.1237 + pUser->flags |= bits;
1.1238 + pUser->eflags |= bits;
1.1239 + } else {
1.1240 + pUser->flags &= ~bits;
1.1241 + pUser->eflags &= ~bits;
1.1242 + }
1.1243 +
1.1244 + pUser->serialchange++;
1.1245 +}
1.1246 +
1.1247 +bool AdminCache::GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode)
1.1248 +{
1.1249 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1250 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.1251 + {
1.1252 + return false;
1.1253 + }
1.1254 +
1.1255 + if (flag < Admin_Reservation
1.1256 + || flag >= AdminFlags_TOTAL)
1.1257 + {
1.1258 + return false;
1.1259 + }
1.1260 +
1.1261 + FlagBits bit = (1<<(FlagBits)flag);
1.1262 +
1.1263 + if (mode == Access_Real)
1.1264 + {
1.1265 + return ((pUser->flags & bit) == bit);
1.1266 + } else if (mode == Access_Effective) {
1.1267 + bool has_bit = ((pUser->eflags & bit) == bit);
1.1268 + if (!has_bit && flag != Admin_Root && ((pUser->eflags & ADMFLAG_ROOT) == ADMFLAG_ROOT))
1.1269 + {
1.1270 + has_bit = true;
1.1271 + }
1.1272 + return has_bit;
1.1273 + }
1.1274 +
1.1275 + return false;
1.1276 +}
1.1277 +
1.1278 +FlagBits AdminCache::GetAdminFlags(AdminId id, AccessMode mode)
1.1279 +{
1.1280 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1281 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.1282 + {
1.1283 + return 0;
1.1284 + }
1.1285 +
1.1286 + if (mode == Access_Real)
1.1287 + {
1.1288 + return pUser->flags;
1.1289 + } else if (mode == Access_Effective) {
1.1290 + return pUser->eflags;
1.1291 + }
1.1292 +
1.1293 + return 0;
1.1294 +}
1.1295 +
1.1296 +void AdminCache::SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits)
1.1297 +{
1.1298 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1299 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.1300 + {
1.1301 + return;
1.1302 + }
1.1303 +
1.1304 + if (mode == Access_Real)
1.1305 + {
1.1306 + pUser->flags = bits;
1.1307 + pUser->eflags = bits;
1.1308 + } else if (mode == Access_Effective) {
1.1309 + pUser->eflags = bits;
1.1310 + }
1.1311 +
1.1312 + pUser->serialchange++;
1.1313 +}
1.1314 +
1.1315 +bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid)
1.1316 +{
1.1317 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1318 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.1319 + {
1.1320 + return false;
1.1321 + }
1.1322 +
1.1323 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
1.1324 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.1325 + {
1.1326 + return false;
1.1327 + }
1.1328 +
1.1329 + /* First check for duplicates */
1.1330 + if (pUser->grp_count != 0)
1.1331 + {
1.1332 + int *temp_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
1.1333 + for (unsigned int i=0; i<pUser->grp_count; i++)
1.1334 + {
1.1335 + if (temp_table[i] == gid)
1.1336 + {
1.1337 + return false;
1.1338 + }
1.1339 + }
1.1340 + }
1.1341 +
1.1342 + int *table;
1.1343 + if (pUser->grp_count + 1 > pUser->grp_size)
1.1344 + {
1.1345 + int new_size = 0;
1.1346 + int tblidx;
1.1347 +
1.1348 + if (pUser->grp_size == 0)
1.1349 + {
1.1350 + new_size = 2;
1.1351 + } else {
1.1352 + new_size = pUser->grp_size * 2;
1.1353 + }
1.1354 +
1.1355 + /* Create and refresh pointers */
1.1356 + tblidx = m_pMemory->CreateMem(new_size * sizeof(int), (void **)&table);
1.1357 + pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1358 + pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
1.1359 +
1.1360 + /* Copy old data if necessary */
1.1361 + if (pUser->grp_table != -1)
1.1362 + {
1.1363 + int *old_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
1.1364 + memcpy(table, old_table, sizeof(int) * pUser->grp_count);
1.1365 + }
1.1366 + pUser->grp_table = tblidx;
1.1367 + pUser->grp_size = new_size;
1.1368 + } else {
1.1369 + table = (int *)m_pMemory->GetAddress(pUser->grp_table);
1.1370 + }
1.1371 +
1.1372 + table[pUser->grp_count] = gid;
1.1373 + pUser->grp_count++;
1.1374 +
1.1375 + /* Compute new effective permissions */
1.1376 + pUser->eflags |= pGroup->addflags;
1.1377 +
1.1378 + if (pGroup->immunity_level > pUser->immunity_level)
1.1379 + {
1.1380 + pUser->immunity_level = pGroup->immunity_level;
1.1381 + }
1.1382 +
1.1383 + pUser->serialchange++;
1.1384 +
1.1385 + return true;
1.1386 +}
1.1387 +
1.1388 +bool AdminCache::IsValidAdmin(AdminId id)
1.1389 +{
1.1390 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1391 + return (pUser != NULL && pUser->magic == USR_MAGIC_SET);
1.1392 +}
1.1393 +
1.1394 +unsigned int AdminCache::GetAdminGroupCount(AdminId id)
1.1395 +{
1.1396 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1397 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.1398 + {
1.1399 + return 0;
1.1400 + }
1.1401 +
1.1402 + return pUser->grp_count;
1.1403 +}
1.1404 +
1.1405 +GroupId AdminCache::GetAdminGroup(AdminId id, unsigned int index, const char **name)
1.1406 +{
1.1407 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1408 + if (!pUser || pUser->magic != USR_MAGIC_SET || index >= pUser->grp_count)
1.1409 + {
1.1410 + return INVALID_GROUP_ID;
1.1411 + }
1.1412 +
1.1413 + int *table = (int *)m_pMemory->GetAddress(pUser->grp_table);
1.1414 +
1.1415 + GroupId gid = table[index];
1.1416 +
1.1417 + if (name)
1.1418 + {
1.1419 + *name = GetGroupName(gid);
1.1420 + }
1.1421 +
1.1422 + return gid;
1.1423 +}
1.1424 +
1.1425 +const char *AdminCache::GetAdminPassword(AdminId id)
1.1426 +{
1.1427 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1428 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.1429 + {
1.1430 + return NULL;
1.1431 + }
1.1432 +
1.1433 + return m_pStrings->GetString(pUser->password);
1.1434 +}
1.1435 +
1.1436 +void AdminCache::SetAdminPassword(AdminId id, const char *password)
1.1437 +{
1.1438 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1439 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.1440 + {
1.1441 + return;
1.1442 + }
1.1443 +
1.1444 + if (password[0] == '\0')
1.1445 + {
1.1446 + pUser->password = -1;
1.1447 + return;
1.1448 + }
1.1449 +
1.1450 + int i_password = m_pStrings->AddString(password);
1.1451 + pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1452 + pUser->password = i_password;
1.1453 +}
1.1454 +
1.1455 +unsigned int AdminCache::FlagBitsToBitArray(FlagBits bits, bool array[], unsigned int maxSize)
1.1456 +{
1.1457 + unsigned int i;
1.1458 + for (i=0; i<maxSize && i<AdminFlags_TOTAL; i++)
1.1459 + {
1.1460 + array[i] = ((bits & (1<<i)) == (unsigned)(1<<i));
1.1461 + }
1.1462 +
1.1463 + return i;
1.1464 +}
1.1465 +
1.1466 +FlagBits AdminCache::FlagBitArrayToBits(const bool array[], unsigned int maxSize)
1.1467 +{
1.1468 + FlagBits bits = 0;
1.1469 + for (unsigned int i=0; i<maxSize && i<AdminFlags_TOTAL; i++)
1.1470 + {
1.1471 + if (array[i])
1.1472 + {
1.1473 + bits |= (1<<i);
1.1474 + }
1.1475 + }
1.1476 +
1.1477 + return bits;
1.1478 +}
1.1479 +
1.1480 +FlagBits AdminCache::FlagArrayToBits(const AdminFlag array[], unsigned int numFlags)
1.1481 +{
1.1482 + FlagBits bits = 0;
1.1483 + for (unsigned int i=0; i<numFlags && i<AdminFlags_TOTAL; i++)
1.1484 + {
1.1485 + bits |= (1 << (FlagBits)array[i]);
1.1486 + }
1.1487 +
1.1488 + return bits;
1.1489 +}
1.1490 +
1.1491 +unsigned int AdminCache::FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize)
1.1492 +{
1.1493 + unsigned int i, num=0;
1.1494 + for (i=0; num<maxSize && i<AdminFlags_TOTAL; i++)
1.1495 + {
1.1496 + if ((bits & (1<<i)) == (unsigned)(1<<i))
1.1497 + {
1.1498 + array[num++] = (AdminFlag)i;
1.1499 + }
1.1500 + }
1.1501 +
1.1502 + return num;
1.1503 +}
1.1504 +
1.1505 +bool AdminCache::CheckAdminFlags(AdminId id, FlagBits bits)
1.1506 +{
1.1507 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1508 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.1509 + {
1.1510 + return false;
1.1511 + }
1.1512 +
1.1513 + return ((pUser->eflags & bits) == bits);
1.1514 +}
1.1515 +
1.1516 +bool AdminCache::CanAdminTarget(AdminId id, AdminId target)
1.1517 +{
1.1518 + /**
1.1519 + * Zeroth, if the targeting AdminId is INVALID_ADMIN_ID, targeting fails.
1.1520 + * First, if the targeted AdminId is INVALID_ADMIN_ID, targeting succeeds.
1.1521 + */
1.1522 +
1.1523 + if (id == INVALID_ADMIN_ID)
1.1524 + {
1.1525 + return false;
1.1526 + }
1.1527 +
1.1528 + if (target == INVALID_ADMIN_ID)
1.1529 + {
1.1530 + return true;
1.1531 + }
1.1532 +
1.1533 + if (id == target)
1.1534 + {
1.1535 + return true;
1.1536 + }
1.1537 +
1.1538 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1539 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.1540 + {
1.1541 + return false;
1.1542 + }
1.1543 +
1.1544 + AdminUser *pTarget = (AdminUser *)m_pMemory->GetAddress(target);
1.1545 + if (!pTarget || pTarget->magic != USR_MAGIC_SET)
1.1546 + {
1.1547 + return false;
1.1548 + }
1.1549 +
1.1550 + /**
1.1551 + * Second, if the targeting admin is root, targeting succeeds.
1.1552 + */
1.1553 + if (pUser->eflags & ADMFLAG_ROOT)
1.1554 + {
1.1555 + return true;
1.1556 + }
1.1557 +
1.1558 + /** Fourth, if the targeted admin is immune from targeting admin. */
1.1559 + int mode = sm_immunity_mode.GetInt();
1.1560 + switch (mode)
1.1561 + {
1.1562 + case 1:
1.1563 + {
1.1564 + if (pTarget->immunity_level > pUser->immunity_level)
1.1565 + {
1.1566 + return false;
1.1567 + }
1.1568 + break;
1.1569 + }
1.1570 + case 3:
1.1571 + {
1.1572 + /* If neither has any immunity, let this pass. */
1.1573 + if (!pUser->immunity_level && !pTarget->immunity_level)
1.1574 + {
1.1575 + return true;
1.1576 + }
1.1577 + /* Don't break, go to the next case. */
1.1578 + }
1.1579 + case 2:
1.1580 + {
1.1581 + if (pTarget->immunity_level >= pUser->immunity_level)
1.1582 + {
1.1583 + return false;
1.1584 + }
1.1585 + break;
1.1586 + }
1.1587 + }
1.1588 +
1.1589 + /**
1.1590 + * Fifth, if the targeted admin has specific immunity from the
1.1591 + * targeting admin via group immunities, targeting fails.
1.1592 + */
1.1593 + //:TODO: speed this up... maybe with trie hacks.
1.1594 + //idea is to insert %d.%d in the trie after computing this and use it as a cache lookup.
1.1595 + //problem is the trie cannot delete prefixes, so we'd have a problem with invalidations.
1.1596 + if (pTarget->grp_count > 0 && pUser->grp_count > 0)
1.1597 + {
1.1598 + int *grp_table = (int *)m_pMemory->GetAddress(pTarget->grp_table);
1.1599 + int *src_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
1.1600 + GroupId id, other;
1.1601 + unsigned int num;
1.1602 + for (unsigned int i=0; i<pTarget->grp_count; i++)
1.1603 + {
1.1604 + id = grp_table[i];
1.1605 + num = GetGroupImmunityCount(id);
1.1606 + for (unsigned int j=0; j<num; i++)
1.1607 + {
1.1608 + other = GetGroupImmunity(id, j);
1.1609 + for (unsigned int k=0; k<pUser->grp_count; k++)
1.1610 + {
1.1611 + if (other == src_table[k])
1.1612 + {
1.1613 + return false;
1.1614 + }
1.1615 + }
1.1616 + }
1.1617 + }
1.1618 + }
1.1619 +
1.1620 + return true;
1.1621 +}
1.1622 +
1.1623 +bool AdminCache::FindFlag(char c, AdminFlag *pAdmFlag)
1.1624 +{
1.1625 + if (c < 'a'
1.1626 + || c > 'z'
1.1627 + || !g_FlagSet[(unsigned)c - (unsigned)'a'])
1.1628 + {
1.1629 + return false;
1.1630 + }
1.1631 +
1.1632 + if (pAdmFlag)
1.1633 + {
1.1634 + *pAdmFlag = g_FlagLetters[(unsigned)c - (unsigned)'a'];
1.1635 + }
1.1636 +
1.1637 + return true;
1.1638 +}
1.1639 +
1.1640 +bool AdminCache::FindFlagChar(AdminFlag flag, char *c)
1.1641 +{
1.1642 + if (!g_FlagSet[flag])
1.1643 + {
1.1644 + return false;
1.1645 + }
1.1646 +
1.1647 + if (c)
1.1648 + {
1.1649 + *c = g_ReverseFlags[flag];
1.1650 + }
1.1651 +
1.1652 + return true;
1.1653 +}
1.1654 +
1.1655 +FlagBits AdminCache::ReadFlagString(const char *flags, const char **end)
1.1656 +{
1.1657 + FlagBits bits = 0;
1.1658 +
1.1659 + while (flags && (*flags != '\0'))
1.1660 + {
1.1661 + AdminFlag flag;
1.1662 + if (!FindFlag(*flags, &flag))
1.1663 + {
1.1664 + break;
1.1665 + }
1.1666 + bits |= FlagArrayToBits(&flag, 1);
1.1667 + flags++;
1.1668 + }
1.1669 +
1.1670 + if (end)
1.1671 + {
1.1672 + *end = flags;
1.1673 + }
1.1674 +
1.1675 + return bits;
1.1676 +}
1.1677 +
1.1678 +unsigned int AdminCache::GetAdminSerialChange(AdminId id)
1.1679 +{
1.1680 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1681 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.1682 + {
1.1683 + return 0;
1.1684 + }
1.1685 +
1.1686 + return pUser->serialchange;
1.1687 +}
1.1688 +
1.1689 +bool AdminCache::CanAdminUseCommand(int client, const char *cmd)
1.1690 +{
1.1691 + FlagBits bits;
1.1692 + OverrideType otype = Override_Command;
1.1693 +
1.1694 + if (cmd[0] == '@')
1.1695 + {
1.1696 + otype = Override_CommandGroup;
1.1697 + cmd++;
1.1698 + }
1.1699 +
1.1700 + if (!g_ConCmds.LookForCommandAdminFlags(cmd, &bits))
1.1701 + {
1.1702 + if (!GetCommandOverride(cmd, otype, &bits))
1.1703 + {
1.1704 + bits = 0;
1.1705 + }
1.1706 + }
1.1707 +
1.1708 + return g_ConCmds.CheckCommandAccess(client, cmd, bits);
1.1709 +}
1.1710 +
1.1711 +unsigned int AdminCache::SetGroupImmunityLevel(GroupId gid, unsigned int level)
1.1712 +{
1.1713 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
1.1714 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.1715 + {
1.1716 + return 0;
1.1717 + }
1.1718 +
1.1719 + unsigned int old_level = pGroup->immunity_level;
1.1720 +
1.1721 + pGroup->immunity_level = level;
1.1722 +
1.1723 + return old_level;
1.1724 +}
1.1725 +
1.1726 +unsigned int AdminCache::GetGroupImmunityLevel(GroupId gid)
1.1727 +{
1.1728 + AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
1.1729 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.1730 + {
1.1731 + return 0;
1.1732 + }
1.1733 +
1.1734 + return pGroup->immunity_level;
1.1735 +}
1.1736 +
1.1737 +unsigned int AdminCache::SetAdminImmunityLevel(AdminId id, unsigned int level)
1.1738 +{
1.1739 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1740 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.1741 + {
1.1742 + return 0;
1.1743 + }
1.1744 +
1.1745 + unsigned int old_level = pUser->immunity_level;
1.1746 +
1.1747 + pUser->immunity_level = level;
1.1748 +
1.1749 + return old_level;
1.1750 +}
1.1751 +
1.1752 +unsigned int AdminCache::GetAdminImmunityLevel(AdminId id)
1.1753 +{
1.1754 + AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
1.1755 + if (!pUser || pUser->magic != USR_MAGIC_SET)
1.1756 + {
1.1757 + return 0;
1.1758 + }
1.1759 +
1.1760 + return pUser->immunity_level;
1.1761 +}
1.1762 +
1.1763 +bool AdminCache::CheckAccess(int client, const char *cmd, FlagBits flags, bool override_only)
1.1764 +{
1.1765 + if (client == 0)
1.1766 + {
1.1767 + return true;
1.1768 + }
1.1769 +
1.1770 + /* Auto-detect a command if we can */
1.1771 + FlagBits bits = flags;
1.1772 + bool found_command = false;
1.1773 + if (!override_only)
1.1774 + {
1.1775 + found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
1.1776 + }
1.1777 +
1.1778 + if (!found_command)
1.1779 + {
1.1780 + GetCommandOverride(cmd, Override_Command, &bits);
1.1781 + }
1.1782 +
1.1783 + return g_ConCmds.CheckCommandAccess(client, cmd, bits) ? 1 : 0;
1.1784 +}
1.1785 +
1.1786 +void iterator_glob_basic_override(Trie *pTrie, const char *key, void **value, void *data)
1.1787 +{
1.1788 + FILE *fp;
1.1789 + int flags;
1.1790 + char flagstr[64];
1.1791 +
1.1792 + fp = (FILE *)data;
1.1793 + flags = (int)*value;
1.1794 + g_Admins.FillFlagString(flags, flagstr, sizeof(flagstr));
1.1795 +
1.1796 + fprintf(fp, "\t\"%s\"\t\t\"%s\"\n", key, flagstr);
1.1797 +}
1.1798 +
1.1799 +void iterator_glob_grp_override(Trie *pTrie, const char *key, void **value, void *data)
1.1800 +{
1.1801 + FILE *fp;
1.1802 + int flags;
1.1803 + char flagstr[64];
1.1804 +
1.1805 + fp = (FILE *)data;
1.1806 + flags = (int)*value;
1.1807 + g_Admins.FillFlagString(flags, flagstr, sizeof(flagstr));
1.1808 +
1.1809 + fprintf(fp, "\t\"@%s\"\t\t\"%s\"\n", key, flagstr);
1.1810 +}
1.1811 +
1.1812 +void iterator_group_basic_override(Trie *pTrie, const char *key, void **value, void *data)
1.1813 +{
1.1814 + FILE *fp;
1.1815 + int flags;
1.1816 + char flagstr[64];
1.1817 +
1.1818 + fp = (FILE *)data;
1.1819 + flags = (int)*value;
1.1820 + g_Admins.FillFlagString(flags, flagstr, sizeof(flagstr));
1.1821 +
1.1822 + fprintf(fp, "\t\t\t\"%s\"\t\t\"%s\"\n", key, flagstr);
1.1823 +}
1.1824 +
1.1825 +void iterator_group_grp_override(Trie *pTrie, const char *key, void **value, void *data)
1.1826 +{
1.1827 + FILE *fp;
1.1828 + int flags;
1.1829 + char flagstr[64];
1.1830 +
1.1831 + fp = (FILE *)data;
1.1832 + flags = (int)*value;
1.1833 + g_Admins.FillFlagString(flags, flagstr, sizeof(flagstr));
1.1834 +
1.1835 + fprintf(fp, "\t\t\t\"@%s\"\t\t\"%s\"\n", key, flagstr);
1.1836 +}
1.1837 +
1.1838 +void AdminCache::DumpCache(FILE *fp)
1.1839 +{
1.1840 + int *itable;
1.1841 + AdminId aid;
1.1842 + GroupId gid;
1.1843 + char flagstr[64];
1.1844 + unsigned int num;
1.1845 + AdminUser *pAdmin;
1.1846 + AdminGroup *pGroup;
1.1847 + char name_buffer[512];
1.1848 +
1.1849 + fprintf(fp, "\"Groups\"\n{\n");
1.1850 +
1.1851 + num = 0;
1.1852 + gid = m_FirstGroup;
1.1853 + while (gid != INVALID_GROUP_ID
1.1854 + && (pGroup = GetGroup(gid)) != NULL)
1.1855 + {
1.1856 + num++;
1.1857 + FillFlagString(pGroup->addflags, flagstr, sizeof(flagstr));
1.1858 +
1.1859 + fprintf(fp, "\t/* num = %d, gid = 0x%X */\n", num, gid);
1.1860 + fprintf(fp, "\t\"%s\"\n\t{\n", GetString(pGroup->nameidx));
1.1861 + fprintf(fp, "\t\t\"flags\"\t\t\t\"%s\"\n", flagstr);
1.1862 + fprintf(fp, "\t\t\"immunity\"\t\t\"%d\"\n", pGroup->immunity_level);
1.1863 +
1.1864 + if (pGroup->immune_table != -1
1.1865 + && (itable = (int *)m_pMemory->GetAddress(pGroup->immune_table)) != NULL)
1.1866 + {
1.1867 + AdminGroup *pAltGroup;
1.1868 + const char *gname, *mod;
1.1869 +
1.1870 + for (int i = 1; i <= itable[0]; i++)
1.1871 + {
1.1872 + if ((pAltGroup = GetGroup(itable[i])) == NULL)
1.1873 + {
1.1874 + /* Assume the rest of the table is corrupt */
1.1875 + break;
1.1876 + }
1.1877 + gname = GetString(pAltGroup->nameidx);
1.1878 + if (atoi(gname) != 0)
1.1879 + {
1.1880 + mod = "@";
1.1881 + }
1.1882 + else
1.1883 + {
1.1884 + mod = "";
1.1885 + }
1.1886 + fprintf(fp, "\t\t\"immunity\"\t\t\"%s%s\"\n", mod, gname);
1.1887 + }
1.1888 + }
1.1889 +
1.1890 + fprintf(fp, "\n\t\t\"Overrides\"\n\t\t{\n");
1.1891 + if (pGroup->pCmdGrpTable != NULL)
1.1892 + {
1.1893 + sm_trie_bad_iterator(pGroup->pCmdGrpTable,
1.1894 + name_buffer,
1.1895 + sizeof(name_buffer),
1.1896 + iterator_group_grp_override,
1.1897 + fp);
1.1898 + }
1.1899 + if (pGroup->pCmdTable != NULL)
1.1900 + {
1.1901 + sm_trie_bad_iterator(pGroup->pCmdTable,
1.1902 + name_buffer,
1.1903 + sizeof(name_buffer),
1.1904 + iterator_group_basic_override,
1.1905 + fp);
1.1906 + }
1.1907 + fprintf(fp, "\t\t}\n");
1.1908 +
1.1909 + fprintf(fp, "\t}\n");
1.1910 +
1.1911 + if ((gid = pGroup->next_grp) != INVALID_GROUP_ID)
1.1912 + {
1.1913 + fprintf(fp, "\n");
1.1914 + }
1.1915 + }
1.1916 +
1.1917 + fprintf(fp, "}\n\n");
1.1918 + fprintf(fp, "\"Admins\"\n{\n");
1.1919 +
1.1920 + num = 0;
1.1921 + aid = m_FirstUser;
1.1922 + while (aid != INVALID_ADMIN_ID
1.1923 + && (pAdmin = GetUser(aid)) != NULL)
1.1924 + {
1.1925 + num++;
1.1926 + FillFlagString(pAdmin->flags, flagstr, sizeof(flagstr));
1.1927 +
1.1928 + fprintf(fp, "\t/* num = %d, aid = 0x%X, serialno = 0x%X*/\n", num, aid, pAdmin->serialchange);
1.1929 +
1.1930 + if (pAdmin->nameidx != -1)
1.1931 + {
1.1932 + fprintf(fp, "\t\"%s\"\n\t{\n", GetString(pAdmin->nameidx));
1.1933 + }
1.1934 + else
1.1935 + {
1.1936 + fprintf(fp, "\t\"\"\n\t{\n");
1.1937 + }
1.1938 +
1.1939 + if (pAdmin->auth.identidx != -1)
1.1940 + {
1.1941 + fprintf(fp, "\t\t\"auth\"\t\t\t\"%s\"\n", GetMethodName(pAdmin->auth.index));
1.1942 + fprintf(fp, "\t\t\"identity\"\t\t\"%s\"\n", GetString(pAdmin->auth.identidx));
1.1943 + }
1.1944 + if (pAdmin->password != -1)
1.1945 + {
1.1946 + fprintf(fp, "\t\t\"password\"\t\t\"%s\"\n", GetString(pAdmin->password));
1.1947 + }
1.1948 + fprintf(fp, "\t\t\"flags\"\t\t\t\"%s\"\n", flagstr);
1.1949 + fprintf(fp, "\t\t\"immunity\"\t\t\"%d\"\n", pAdmin->immunity_level);
1.1950 +
1.1951 + if (pAdmin->grp_count != 0
1.1952 + && pAdmin->grp_table != -1
1.1953 + && (itable = (int *)m_pMemory->GetAddress(pAdmin->grp_table)) != NULL)
1.1954 + {
1.1955 + unsigned int i;
1.1956 +
1.1957 + for (i = 0; i < pAdmin->grp_count; i++)
1.1958 + {
1.1959 + if ((pGroup = GetGroup(itable[i])) == NULL)
1.1960 + {
1.1961 + /* Assume the rest of the table is corrupt */
1.1962 + break;
1.1963 + }
1.1964 + fprintf(fp, "\t\t\"group\"\t\t\t\"%s\"\n", GetString(pGroup->nameidx));
1.1965 + }
1.1966 + }
1.1967 +
1.1968 + fprintf(fp, "\t}\n");
1.1969 +
1.1970 + if ((aid = pAdmin->next_user) != INVALID_ADMIN_ID)
1.1971 + {
1.1972 + fprintf(fp, "\n");
1.1973 + }
1.1974 + }
1.1975 +
1.1976 + fprintf(fp, "}\n\n");
1.1977 +
1.1978 + fprintf(fp, "\"Overrides\"\n{\n");
1.1979 + if (m_pCmdGrpOverrides != NULL)
1.1980 + {
1.1981 + sm_trie_bad_iterator(m_pCmdGrpOverrides,
1.1982 + name_buffer,
1.1983 + sizeof(name_buffer),
1.1984 + iterator_glob_grp_override,
1.1985 + fp);
1.1986 + }
1.1987 + if (m_pCmdOverrides != NULL)
1.1988 + {
1.1989 + sm_trie_bad_iterator(m_pCmdOverrides,
1.1990 + name_buffer,
1.1991 + sizeof(name_buffer),
1.1992 + iterator_glob_basic_override,
1.1993 + fp);
1.1994 + }
1.1995 + fprintf(fp, "}\n");
1.1996 +}
1.1997 +
1.1998 +AdminGroup *AdminCache::GetGroup(GroupId gid)
1.1999 +{
1.2000 + AdminGroup *pGroup;
1.2001 +
1.2002 + pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
1.2003 + if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
1.2004 + {
1.2005 + return NULL;
1.2006 + }
1.2007 +
1.2008 + return pGroup;
1.2009 +}
1.2010 +
1.2011 +AdminUser *AdminCache::GetUser(AdminId aid)
1.2012 +{
1.2013 + AdminUser *pAdmin;
1.2014 +
1.2015 + pAdmin = (AdminUser *)m_pMemory->GetAddress(aid);
1.2016 + if (!pAdmin || pAdmin->magic != USR_MAGIC_SET)
1.2017 + {
1.2018 + return NULL;
1.2019 + }
1.2020 +
1.2021 + return pAdmin;
1.2022 +}
1.2023 +
1.2024 +const char *AdminCache::GetMethodName(unsigned int index)
1.2025 +{
1.2026 + List<AuthMethod>::iterator iter;
1.2027 + for (iter=m_AuthMethods.begin();
1.2028 + iter!=m_AuthMethods.end();
1.2029 + iter++)
1.2030 + {
1.2031 + if (index-- == 0)
1.2032 + {
1.2033 + return (*iter).name.c_str();
1.2034 + }
1.2035 + }
1.2036 +
1.2037 + return NULL;
1.2038 +}
1.2039 +
1.2040 +const char *AdminCache::GetString(int idx)
1.2041 +{
1.2042 + return m_pStrings->GetString(idx);
1.2043 +}
1.2044 +
1.2045 +size_t AdminCache::FillFlagString(FlagBits bits, char *buffer, size_t maxlen)
1.2046 +{
1.2047 + size_t pos;
1.2048 + unsigned int i, num_flags;
1.2049 + AdminFlag flags[AdminFlags_TOTAL];
1.2050 +
1.2051 + num_flags = FlagBitsToArray(bits, flags, AdminFlags_TOTAL);
1.2052 +
1.2053 + pos = 0;
1.2054 + for (i = 0; pos < maxlen && i < num_flags; i++)
1.2055 + {
1.2056 + if (FindFlagChar(flags[i], &buffer[pos]))
1.2057 + {
1.2058 + pos++;
1.2059 + }
1.2060 + }
1.2061 + buffer[pos] = '\0';
1.2062 +
1.2063 + return pos;
1.2064 +}
1.2065 +
1.2066 +CON_COMMAND(sm_dump_admcache, "Dumps the admin cache for debugging")
1.2067 +{
1.2068 + FILE *fp;
1.2069 + char buffer[PLATFORM_MAX_PATH];
1.2070 +
1.2071 + g_SourceMod.BuildPath(Path_SM, buffer, sizeof(buffer), "data/admin_cache_dump.txt");
1.2072 +
1.2073 + if ((fp = fopen(buffer, "wt")) == NULL)
1.2074 + {
1.2075 + g_RootMenu.ConsolePrint("Could not open file for writing: %s", buffer);
1.2076 + return;
1.2077 + }
1.2078 +
1.2079 + g_Admins.DumpCache(fp);
1.2080 +
1.2081 + g_RootMenu.ConsolePrint("Admin cache dumped to: %s", buffer);
1.2082 +
1.2083 + fclose(fp);
1.2084 +}