core/AdminCache.cpp
author David Anderson <dvander@alliedmods.net>
Wed Sep 26 02:14:05 2007 +0000 (2007-09-26)
changeset 1477 b2d8f676a902
parent 1473 f3f39075066d
child 1656 b0b86d57530c
permissions -rw-r--r--
fixed CheckAccess() in IAdminSystem having the wrong parameter type
dvander@370
     1
/**
ds@653
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
dvander@1231
     4
 * SourceMod
dvander@1231
     5
 * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
dvander@370
     7
 *
ds@1330
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1330
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330
    10
 * Free Software Foundation.
dvander@1231
    11
 * 
ds@1330
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1330
    15
 * details.
dvander@1231
    16
 *
ds@1330
    17
 * You should have received a copy of the GNU General Public License along with
ds@1330
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1231
    19
 *
ds@1330
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1330
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1330
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1330
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@370
    28
 *
dvander@370
    29
 * Version: $Id$
dvander@370
    30
 */
dvander@370
    31
dvander@335
    32
#include <string.h>
dvander@335
    33
#include <assert.h>
dvander@1406
    34
#include <ITextParsers.h>
dvander@335
    35
#include "AdminCache.h"
dvander@335
    36
#include "ShareSys.h"
dvander@336
    37
#include "ForwardSys.h"
dvander@591
    38
#include "PlayerManager.h"
dvander@583
    39
#include "ConCmdManager.h"
dvander@1298
    40
#include "Logger.h"
dvander@1298
    41
#include "sourcemod.h"
dvander@1298
    42
#include "sm_stringutil.h"
dvander@1403
    43
#include "sourcemm_api.h"
dvander@1298
    44
dvander@1298
    45
#define LEVEL_STATE_NONE		0
dvander@1298
    46
#define LEVEL_STATE_LEVELS		1
dvander@1298
    47
#define LEVEL_STATE_FLAGS		2
dvander@335
    48
dvander@335
    49
AdminCache g_Admins;
dvander@1298
    50
AdminFlag g_FlagLetters[26];
dvander@1298
    51
bool g_FlagSet[26];
dvander@1298
    52
dvander@1403
    53
ConVar sm_immunity_mode("sm_immunity_mode", "1", FCVAR_SPONLY|FCVAR_PROTECTED, "Mode for deciding immunity protection");
dvander@1403
    54
dvander@1298
    55
/* Default flags */
dvander@1298
    56
AdminFlag g_DefaultFlags[26] = 
dvander@1298
    57
{
dvander@1298
    58
	Admin_Reservation, Admin_Generic, Admin_Kick, Admin_Ban, Admin_Unban,
dvander@1298
    59
	Admin_Slay, Admin_Changemap, Admin_Convars, Admin_Config, Admin_Chat,
dvander@1298
    60
	Admin_Vote, Admin_Password, Admin_RCON, Admin_Cheats, Admin_Custom1, 
dvander@1298
    61
	Admin_Custom2, Admin_Custom3, Admin_Custom4, Admin_Custom5, Admin_Custom6,
dvander@1298
    62
	Admin_Generic, Admin_Generic, Admin_Generic, Admin_Generic, Admin_Generic,
dvander@1298
    63
	Admin_Root
dvander@1298
    64
};
dvander@1298
    65
dvander@1298
    66
dvander@1298
    67
class FlagReader : public ITextListener_SMC
dvander@1298
    68
{
dvander@1298
    69
public:
dvander@1298
    70
	void LoadLevels()
dvander@1298
    71
	{
dvander@1298
    72
		if (!Parse())
dvander@1298
    73
		{
dvander@1298
    74
			memcpy(g_FlagLetters, g_DefaultFlags, sizeof(AdminFlag) * 26);
dvander@1298
    75
			for (unsigned int i=0; i<20; i++)
dvander@1298
    76
			{
dvander@1298
    77
				g_FlagSet[i] = true;
dvander@1298
    78
			}
dvander@1298
    79
			g_FlagSet[25] = true;
dvander@1298
    80
		}
dvander@1298
    81
	}
dvander@1298
    82
private:
dvander@1298
    83
	bool Parse()
dvander@1298
    84
	{
dvander@1298
    85
		unsigned int line = 0;
dvander@1298
    86
		SMCParseError error;
dvander@1298
    87
dvander@1298
    88
		m_Line = 0;
dvander@1298
    89
		m_bFileNameLogged = false;
dvander@1298
    90
		g_SourceMod.BuildPath(Path_SM, m_File, sizeof(m_File), "configs/admin_levels.cfg");
dvander@1298
    91
dvander@1406
    92
		if ((error = textparsers->ParseFile_SMC(m_File, this, &line, NULL))
dvander@1298
    93
			!= SMCParse_Okay)
dvander@1298
    94
		{
dvander@1406
    95
			const char *err_string = textparsers->GetSMCErrorString(error);
dvander@1298
    96
			if (!err_string)
dvander@1298
    97
			{
dvander@1298
    98
				err_string = "Unknown error";
dvander@1298
    99
			}
dvander@1298
   100
			ParseError("Error %d (%s)", error, err_string);
dvander@1298
   101
			return false;
dvander@1298
   102
		}
dvander@1298
   103
dvander@1298
   104
		return true;
dvander@1298
   105
	}
dvander@1298
   106
	void ReadSMC_ParseStart()
dvander@1298
   107
	{
dvander@1298
   108
		m_LevelState = LEVEL_STATE_NONE;
dvander@1298
   109
		m_IgnoreLevel = 0;
dvander@1298
   110
		memset(g_FlagSet, 0, sizeof(g_FlagSet));
dvander@1298
   111
	}
dvander@1298
   112
	SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes)
dvander@1298
   113
	{
dvander@1298
   114
		if (m_IgnoreLevel)
dvander@1298
   115
		{
dvander@1298
   116
			m_IgnoreLevel++;
dvander@1298
   117
			return SMCParse_Continue;
dvander@1298
   118
		}
dvander@1298
   119
dvander@1298
   120
		if (m_LevelState == LEVEL_STATE_NONE)
dvander@1298
   121
		{
dvander@1298
   122
			if (strcmp(name, "Levels") == 0)
dvander@1298
   123
			{
dvander@1299
   124
				m_LevelState = LEVEL_STATE_LEVELS;
dvander@1298
   125
			} else {
dvander@1298
   126
				m_IgnoreLevel++;
dvander@1298
   127
			}
dvander@1299
   128
		} else if (m_LevelState == LEVEL_STATE_LEVELS) {
dvander@1298
   129
			if (strcmp(name, "Flags") == 0)
dvander@1298
   130
			{
dvander@1299
   131
				m_LevelState = LEVEL_STATE_FLAGS;
dvander@1298
   132
			} else {
dvander@1298
   133
				m_IgnoreLevel++;
dvander@1298
   134
			}
dvander@1298
   135
		} else {
dvander@1298
   136
			m_IgnoreLevel++;
dvander@1298
   137
		}
dvander@1298
   138
dvander@1298
   139
		return SMCParse_Continue;
dvander@1298
   140
	}
dvander@1298
   141
	SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
dvander@1298
   142
	{
dvander@1299
   143
		if (m_LevelState != LEVEL_STATE_FLAGS || m_IgnoreLevel)
dvander@1298
   144
		{
dvander@1298
   145
			return SMCParse_Continue;
dvander@1298
   146
		}
dvander@1298
   147
dvander@1298
   148
		unsigned char c = (unsigned)value[0];
dvander@1298
   149
dvander@1298
   150
		if (c < (unsigned)'a' || c > (unsigned)'z')
dvander@1298
   151
		{
dvander@1298
   152
			ParseError("Flag \"%c\" is not a lower-case ASCII letter", c);
dvander@1298
   153
			return SMCParse_Continue;
dvander@1298
   154
		}
dvander@1298
   155
dvander@1298
   156
		c -= (unsigned)'a';
dvander@1298
   157
dvander@1298
   158
		assert(c >= 0 && c < 26);
dvander@1298
   159
dvander@1298
   160
		if (!g_Admins.FindFlag(key, &g_FlagLetters[c]))
dvander@1298
   161
		{
dvander@1298
   162
			ParseError("Unrecognized admin level \"%s\"", key);
dvander@1298
   163
			return SMCParse_Continue;
dvander@1298
   164
		}
dvander@1298
   165
dvander@1298
   166
		g_FlagSet[c] = true;
dvander@1298
   167
dvander@1298
   168
		return SMCParse_Continue;
dvander@1298
   169
	}
dvander@1298
   170
	SMCParseResult ReadSMC_LeavingSection()
dvander@1298
   171
	{
dvander@1298
   172
		if (m_IgnoreLevel)
dvander@1298
   173
		{
dvander@1298
   174
			m_IgnoreLevel--;
dvander@1298
   175
			return SMCParse_Continue;
dvander@1298
   176
		}
dvander@1298
   177
dvander@1298
   178
		if (m_LevelState == LEVEL_STATE_FLAGS)
dvander@1298
   179
		{
dvander@1298
   180
			m_LevelState = LEVEL_STATE_LEVELS;
dvander@1298
   181
			return SMCParse_Halt;
dvander@1298
   182
		} else if (m_LevelState == LEVEL_STATE_LEVELS) {
dvander@1298
   183
			m_LevelState = LEVEL_STATE_NONE;
dvander@1298
   184
		}
dvander@1298
   185
dvander@1298
   186
		return SMCParse_Continue;
dvander@1298
   187
	}
dvander@1298
   188
	SMCParseResult ReadSMC_RawLine(const char *line, unsigned int curline)
dvander@1298
   189
	{
dvander@1298
   190
		m_Line = curline;
dvander@1298
   191
		return SMCParse_Continue;
dvander@1298
   192
	}
dvander@1298
   193
	void ParseError(const char *message, ...)
dvander@1298
   194
	{
dvander@1298
   195
		va_list ap;
dvander@1298
   196
		char buffer[256];
dvander@1298
   197
dvander@1298
   198
		va_start(ap, message);
dvander@1298
   199
		UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
dvander@1298
   200
		va_end(ap);
dvander@1298
   201
dvander@1298
   202
		if (!m_bFileNameLogged)
dvander@1298
   203
		{
dvander@1298
   204
			g_Logger.LogError("[SM] Parse error(s) detected in file \"%s\":", m_File);
dvander@1298
   205
			m_bFileNameLogged = true;
dvander@1298
   206
		}
dvander@1298
   207
dvander@1298
   208
		g_Logger.LogError("[SM] (Line %d): %s", m_Line, buffer);
dvander@1298
   209
	}
dvander@1298
   210
private:
dvander@1298
   211
	bool m_bFileNameLogged;
dvander@1298
   212
	char m_File[PLATFORM_MAX_PATH];
dvander@1298
   213
	int m_LevelState;
dvander@1298
   214
	int m_IgnoreLevel;
dvander@1298
   215
	unsigned int m_Line;
dvander@1298
   216
} s_FlagReader;
dvander@335
   217
dvander@335
   218
AdminCache::AdminCache()
dvander@335
   219
{
dvander@433
   220
	m_pCmdOverrides = sm_trie_create();
dvander@433
   221
	m_pCmdGrpOverrides = sm_trie_create();
dvander@335
   222
	m_pStrings = new BaseStringTable(1024);
dvander@335
   223
	m_pMemory = m_pStrings->GetMemTable();
dvander@335
   224
	m_FreeGroupList = m_FirstGroup = m_LastGroup = INVALID_GROUP_ID;
dvander@404
   225
	m_FreeUserList = m_FirstUser = m_LastUser = INVALID_ADMIN_ID;
dvander@335
   226
	m_pGroups = sm_trie_create();
dvander@336
   227
	m_pCacheFwd = NULL;
dvander@404
   228
	m_FirstGroup = -1;
dvander@405
   229
	m_pAuthTables = sm_trie_create();
dvander@458
   230
	m_InvalidatingAdmins = false;
dvander@520
   231
	m_destroying = false;
dvander@1298
   232
	m_pLevelNames = sm_trie_create();
dvander@335
   233
}
dvander@335
   234
dvander@335
   235
AdminCache::~AdminCache()
dvander@335
   236
{
dvander@520
   237
	m_destroying = true;
dvander@438
   238
	DumpAdminCache(AdminCache_Overrides, false);
dvander@438
   239
	DumpAdminCache(AdminCache_Groups, false);
dvander@438
   240
dvander@434
   241
	sm_trie_destroy(m_pCmdGrpOverrides);
dvander@434
   242
	sm_trie_destroy(m_pCmdOverrides);
dvander@335
   243
dvander@335
   244
	if (m_pGroups)
dvander@335
   245
	{
dvander@335
   246
		sm_trie_destroy(m_pGroups);
dvander@335
   247
	}
dvander@335
   248
dvander@405
   249
	List<AuthMethod>::iterator iter;
dvander@405
   250
	for (iter=m_AuthMethods.begin();
dvander@405
   251
		 iter!=m_AuthMethods.end();
dvander@405
   252
		 iter++)
dvander@405
   253
	{
dvander@405
   254
		sm_trie_destroy((*iter).table);
dvander@405
   255
	}
dvander@405
   256
dvander@405
   257
	sm_trie_destroy(m_pAuthTables);
dvander@405
   258
dvander@335
   259
	delete m_pStrings;
dvander@1298
   260
dvander@1298
   261
	sm_trie_destroy(m_pLevelNames);
dvander@335
   262
}
dvander@335
   263
dvander@404
   264
void AdminCache::OnSourceModStartup(bool late)
dvander@404
   265
{
dvander@404
   266
	RegisterAuthIdentType("steam");
dvander@404
   267
	RegisterAuthIdentType("name");
dvander@404
   268
	RegisterAuthIdentType("ip");
dvander@1298
   269
dvander@1298
   270
	NameFlag("reservation", Admin_Reservation);
dvander@1298
   271
	NameFlag("kick", Admin_Kick);
dvander@1298
   272
	NameFlag("generic", Admin_Generic);
dvander@1298
   273
	NameFlag("ban", Admin_Ban);
dvander@1298
   274
	NameFlag("unban", Admin_Unban);
dvander@1298
   275
	NameFlag("slay", Admin_Slay);
dvander@1298
   276
	NameFlag("changemap", Admin_Changemap);
dvander@1298
   277
	NameFlag("cvars", Admin_Convars);
dvander@1298
   278
	NameFlag("config", Admin_Config);
dvander@1298
   279
	NameFlag("chat", Admin_Chat);
dvander@1298
   280
	NameFlag("vote", Admin_Vote);
dvander@1298
   281
	NameFlag("password", Admin_Password);
dvander@1298
   282
	NameFlag("rcon", Admin_RCON);
dvander@1298
   283
	NameFlag("cheats", Admin_Cheats);
dvander@1298
   284
	NameFlag("root", Admin_Root);
dvander@1298
   285
	NameFlag("custom1", Admin_Custom1);
dvander@1298
   286
	NameFlag("custom2", Admin_Custom2);
dvander@1298
   287
	NameFlag("custom3", Admin_Custom3);
dvander@1298
   288
	NameFlag("custom4", Admin_Custom4);
dvander@1298
   289
	NameFlag("custom5", Admin_Custom5);
dvander@1298
   290
	NameFlag("custom6", Admin_Custom6);
dvander@404
   291
}
dvander@404
   292
dvander@335
   293
void AdminCache::OnSourceModAllInitialized()
dvander@335
   294
{
dvander@336
   295
	m_pCacheFwd = g_Forwards.CreateForward("OnRebuildAdminCache", ET_Ignore, 1, NULL, Param_Cell);
dvander@335
   296
	g_ShareSys.AddInterface(NULL, this);
dvander@335
   297
}
dvander@335
   298
dvander@1298
   299
void AdminCache::OnSourceModLevelChange(const char *mapName)
dvander@1298
   300
{
dvander@1298
   301
	/* For now, we only read these once per level. */
dvander@1298
   302
	s_FlagReader.LoadLevels();
dvander@1298
   303
}
dvander@1298
   304
dvander@336
   305
void AdminCache::OnSourceModShutdown()
dvander@336
   306
{
dvander@336
   307
	g_Forwards.ReleaseForward(m_pCacheFwd);
dvander@336
   308
	m_pCacheFwd = NULL;
dvander@336
   309
}
dvander@336
   310
dvander@673
   311
void AdminCache::OnSourceModPluginsLoaded()
dvander@673
   312
{
dvander@673
   313
	DumpAdminCache(AdminCache_Overrides, true);
dvander@673
   314
	DumpAdminCache(AdminCache_Groups, true);
dvander@673
   315
}
dvander@673
   316
dvander@1298
   317
void AdminCache::NameFlag(const char *str, AdminFlag flag)
dvander@1298
   318
{
dvander@1298
   319
	sm_trie_insert(m_pLevelNames, str, (void *)flag);
dvander@1298
   320
}
dvander@1298
   321
dvander@1298
   322
bool AdminCache::FindFlag(const char *str, AdminFlag *pFlag)
dvander@1298
   323
{
dvander@1298
   324
	void *obj;
dvander@1298
   325
	if (!sm_trie_retrieve(m_pLevelNames, str, &obj))
dvander@1298
   326
	{
dvander@1298
   327
		return false;
dvander@1298
   328
	}
dvander@1298
   329
dvander@1298
   330
	if (pFlag)
dvander@1298
   331
	{
dvander@1298
   332
		*pFlag = (AdminFlag)(int)obj;
dvander@1298
   333
	}
dvander@1298
   334
dvander@1298
   335
	return true;
dvander@1298
   336
}
dvander@1298
   337
dvander@433
   338
void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, FlagBits flags)
dvander@335
   339
{
dvander@433
   340
	Trie *pTrie = NULL;
dvander@335
   341
	if (type == Override_Command)
dvander@335
   342
	{
dvander@433
   343
		pTrie = m_pCmdOverrides;
dvander@335
   344
	} else if (type == Override_CommandGroup) {
dvander@433
   345
		pTrie = m_pCmdGrpOverrides;
dvander@433
   346
	} else {
dvander@433
   347
		return;
dvander@335
   348
	}
dvander@433
   349
dvander@433
   350
	sm_trie_insert(pTrie, cmd, (void *)(unsigned int)flags);
dvander@514
   351
dvander@1435
   352
	g_ConCmds.UpdateAdminCmdFlags(cmd, type, flags, false);
dvander@335
   353
}
dvander@335
   354
dvander@433
   355
bool AdminCache::GetCommandOverride(const char *cmd, OverrideType type, FlagBits *pFlags)
dvander@335
   356
{
dvander@433
   357
	Trie *pTrie = NULL;
dvander@433
   358
dvander@335
   359
	if (type == Override_Command)
dvander@335
   360
	{
dvander@433
   361
		pTrie = m_pCmdOverrides;
dvander@335
   362
	} else if (type == Override_CommandGroup) {
dvander@433
   363
		pTrie = m_pCmdGrpOverrides;
dvander@433
   364
	} else {
dvander@433
   365
		return false;
dvander@433
   366
	}
dvander@433
   367
dvander@433
   368
	void *object;
dvander@433
   369
	if (sm_trie_retrieve(pTrie, cmd, &object))
dvander@433
   370
	{
dvander@433
   371
		if (pFlags)
dvander@433
   372
		{
dvander@433
   373
			*pFlags = (FlagBits)object;
dvander@433
   374
		}
dvander@433
   375
		return true;
dvander@335
   376
	}
dvander@335
   377
dvander@335
   378
	return false;
dvander@335
   379
}
dvander@335
   380
dvander@335
   381
void AdminCache::UnsetCommandOverride(const char *cmd, OverrideType type)
dvander@335
   382
{
dvander@335
   383
	if (type == Override_Command)
dvander@335
   384
	{
dvander@335
   385
		return _UnsetCommandOverride(cmd);
dvander@335
   386
	} else if (type == Override_CommandGroup) {
dvander@335
   387
		return _UnsetCommandGroupOverride(cmd);
dvander@335
   388
	}
dvander@335
   389
}
dvander@335
   390
dvander@335
   391
void AdminCache::_UnsetCommandGroupOverride(const char *group)
dvander@335
   392
{
dvander@335
   393
	if (!m_pCmdGrpOverrides)
dvander@335
   394
	{
dvander@335
   395
		return;
dvander@335
   396
	}
dvander@335
   397
dvander@514
   398
	sm_trie_delete(m_pCmdGrpOverrides, group);
dvander@335
   399
dvander@1435
   400
	g_ConCmds.UpdateAdminCmdFlags(group, Override_CommandGroup, 0, true);
dvander@335
   401
}
dvander@335
   402
dvander@335
   403
void AdminCache::_UnsetCommandOverride(const char *cmd)
dvander@335
   404
{
dvander@335
   405
	if (!m_pCmdOverrides)
dvander@335
   406
	{
dvander@335
   407
		return;
dvander@335
   408
	}
dvander@335
   409
dvander@514
   410
	sm_trie_delete(m_pCmdOverrides, cmd);
dvander@335
   411
dvander@1435
   412
	g_ConCmds.UpdateAdminCmdFlags(cmd, Override_Command, 0, true);
dvander@335
   413
}
dvander@335
   414
dvander@335
   415
void AdminCache::DumpCommandOverrideCache(OverrideType type)
dvander@335
   416
{
dvander@335
   417
	if (type == Override_Command && m_pCmdOverrides)
dvander@335
   418
	{
dvander@335
   419
		sm_trie_clear(m_pCmdOverrides);
dvander@335
   420
	} else if (type == Override_CommandGroup && m_pCmdGrpOverrides) {
dvander@335
   421
		sm_trie_clear(m_pCmdGrpOverrides);
dvander@335
   422
	}
dvander@335
   423
}
dvander@335
   424
dvander@404
   425
AdminId AdminCache::CreateAdmin(const char *name)
dvander@404
   426
{
dvander@404
   427
	AdminId id;
dvander@404
   428
	AdminUser *pUser;
dvander@404
   429
dvander@404
   430
	if (m_FreeUserList != INVALID_ADMIN_ID)
dvander@404
   431
	{
dvander@404
   432
		pUser = (AdminUser *)m_pMemory->GetAddress(m_FreeUserList);
dvander@404
   433
		assert(pUser->magic == USR_MAGIC_UNSET);
dvander@404
   434
		id = m_FreeUserList;
dvander@404
   435
		m_FreeUserList = pUser->next_user;
dvander@404
   436
	} else {
dvander@404
   437
		id = m_pMemory->CreateMem(sizeof(AdminUser), (void **)&pUser);
dvander@404
   438
		pUser->grp_size = 0;
dvander@404
   439
		pUser->grp_table = -1;
dvander@404
   440
	}
dvander@404
   441
dvander@433
   442
	pUser->flags = 0;
dvander@433
   443
	pUser->eflags = 0;
dvander@404
   444
	pUser->grp_count = 0;
dvander@404
   445
	pUser->password = -1;
dvander@404
   446
	pUser->magic = USR_MAGIC_SET;
dvander@405
   447
	pUser->auth.identidx = -1;
dvander@405
   448
	pUser->auth.index = 0;
dvander@1403
   449
	pUser->immunity_level = 0;
dvander@1349
   450
	pUser->serialchange = 1;
dvander@404
   451
dvander@404
   452
	if (m_FirstUser == INVALID_ADMIN_ID)
dvander@404
   453
	{
dvander@404
   454
		m_FirstUser = id;
dvander@404
   455
		m_LastUser = id;
dvander@404
   456
	} else {
dvander@404
   457
		AdminUser *pPrev = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
dvander@404
   458
		pPrev->next_user = id;
dvander@404
   459
		pUser->prev_user = m_LastUser;
dvander@404
   460
		m_LastUser = id;
dvander@404
   461
	}
dvander@404
   462
dvander@404
   463
	if (name && name[0] != '\0')
dvander@404
   464
	{
dvander@1356
   465
		int nameidx = m_pStrings->AddString(name);
dvander@1356
   466
		pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@1356
   467
		pUser->nameidx = nameidx;
dvander@404
   468
	}
dvander@404
   469
dvander@404
   470
	return id;
dvander@404
   471
}
dvander@404
   472
dvander@335
   473
GroupId AdminCache::AddGroup(const char *group_name)
dvander@335
   474
{
dvander@335
   475
	if (sm_trie_retrieve(m_pGroups, group_name, NULL))
dvander@335
   476
	{
dvander@335
   477
		return INVALID_GROUP_ID;
dvander@335
   478
	}
dvander@335
   479
dvander@335
   480
	GroupId id;
dvander@335
   481
	AdminGroup *pGroup;
dvander@335
   482
	if (m_FreeGroupList != INVALID_GROUP_ID)
dvander@335
   483
	{
dvander@335
   484
		pGroup = (AdminGroup *)m_pMemory->GetAddress(m_FreeGroupList);
dvander@335
   485
		assert(pGroup->magic == GRP_MAGIC_UNSET);
dvander@335
   486
		id = m_FreeGroupList;
dvander@335
   487
		m_FreeGroupList = pGroup->next_grp;
dvander@335
   488
	} else {
dvander@335
   489
		id = m_pMemory->CreateMem(sizeof(AdminGroup), (void **)&pGroup);
dvander@335
   490
	}
dvander@335
   491
dvander@1403
   492
	pGroup->immunity_level = 0;
dvander@335
   493
	pGroup->immune_table = -1;
dvander@335
   494
	pGroup->magic = GRP_MAGIC_SET;
dvander@335
   495
	pGroup->next_grp = INVALID_GROUP_ID;
dvander@335
   496
	pGroup->pCmdGrpTable = NULL;
dvander@335
   497
	pGroup->pCmdTable = NULL;
dvander@433
   498
	pGroup->addflags = 0;
dvander@335
   499
dvander@335
   500
	if (m_FirstGroup == INVALID_GROUP_ID)
dvander@335
   501
	{
dvander@335
   502
		m_FirstGroup = id;
dvander@335
   503
		m_LastGroup = id;
dvander@335
   504
		pGroup->prev_grp = INVALID_GROUP_ID;
dvander@335
   505
	} else {
dvander@335
   506
		AdminGroup *pPrev = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
dvander@335
   507
		assert(pPrev->magic == GRP_MAGIC_SET);
dvander@335
   508
		pPrev->next_grp = id;
dvander@335
   509
		pGroup->prev_grp = m_LastGroup;
dvander@335
   510
		m_LastGroup = id;
dvander@335
   511
	}
dvander@335
   512
dvander@1356
   513
	int nameidx = m_pStrings->AddString(group_name);
dvander@1356
   514
	pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@1356
   515
	pGroup->nameidx = nameidx;
dvander@404
   516
dvander@335
   517
	sm_trie_insert(m_pGroups, group_name, (void *)id);
dvander@335
   518
dvander@335
   519
	return id;
dvander@335
   520
}
dvander@335
   521
dvander@335
   522
GroupId AdminCache::FindGroupByName(const char *group_name)
dvander@335
   523
{
dvander@335
   524
	void *object;
dvander@335
   525
dvander@335
   526
	if (!sm_trie_retrieve(m_pGroups, group_name, &object))
dvander@335
   527
	{
dvander@335
   528
		return INVALID_GROUP_ID;
dvander@335
   529
	}
dvander@335
   530
dvander@335
   531
	GroupId id = (GroupId)object;
dvander@335
   532
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   533
dvander@335
   534
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   535
	{
dvander@335
   536
		return INVALID_GROUP_ID;
dvander@335
   537
	}
dvander@335
   538
dvander@335
   539
	return id;
dvander@335
   540
}
dvander@335
   541
dvander@335
   542
void AdminCache::SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled)
dvander@335
   543
{
dvander@335
   544
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   545
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   546
	{
dvander@335
   547
		return;
dvander@335
   548
	}
dvander@335
   549
dvander@433
   550
	if (flag < Admin_Reservation || flag >= AdminFlags_TOTAL)
dvander@335
   551
	{
dvander@335
   552
		return;
dvander@335
   553
	}
dvander@335
   554
dvander@436
   555
	FlagBits bits = (1<<(FlagBits)flag);
dvander@436
   556
dvander@436
   557
	if (enabled)
dvander@436
   558
	{
dvander@436
   559
		pGroup->addflags |= bits;
dvander@436
   560
	} else {
dvander@436
   561
		pGroup->addflags &= ~bits;
dvander@436
   562
	}
dvander@335
   563
}
dvander@335
   564
dvander@335
   565
bool AdminCache::GetGroupAddFlag(GroupId id, AdminFlag flag)
dvander@335
   566
{
dvander@335
   567
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   568
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   569
	{
dvander@335
   570
		return false;
dvander@335
   571
	}
dvander@335
   572
dvander@433
   573
	if (flag < Admin_Reservation || flag >= AdminFlags_TOTAL)
dvander@335
   574
	{
dvander@335
   575
		return false;
dvander@335
   576
	}
dvander@335
   577
dvander@433
   578
	FlagBits bit = 1<<(FlagBits)flag;
dvander@433
   579
	return ((pGroup->addflags & bit) == bit);
dvander@335
   580
}
dvander@335
   581
dvander@433
   582
FlagBits AdminCache::GetGroupAddFlags(GroupId id)
dvander@335
   583
{
dvander@335
   584
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   585
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   586
	{
dvander@335
   587
		return 0;
dvander@335
   588
	}
dvander@335
   589
dvander@433
   590
	return pGroup->addflags;
dvander@335
   591
}
dvander@335
   592
dvander@1356
   593
const char *AdminCache::GetGroupName(GroupId gid)
dvander@1356
   594
{
dvander@1356
   595
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
dvander@1356
   596
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@1356
   597
	{
dvander@1403
   598
		return NULL;
dvander@1356
   599
	}
dvander@1356
   600
dvander@1356
   601
	return m_pStrings->GetString(pGroup->nameidx);
dvander@1356
   602
}
dvander@1356
   603
dvander@335
   604
void AdminCache::SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled)
dvander@335
   605
{
dvander@335
   606
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   607
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   608
	{
dvander@335
   609
		return;
dvander@335
   610
	}
dvander@335
   611
dvander@1403
   612
	unsigned int level = 0;
dvander@1403
   613
dvander@1403
   614
	if (enabled)
dvander@335
   615
	{
dvander@1403
   616
		if (type == Immunity_Default)
dvander@1403
   617
		{
dvander@1403
   618
			level = 1;
dvander@1403
   619
		} else if (type == Immunity_Global) {
dvander@1403
   620
			level = 2;
dvander@1403
   621
		}
dvander@1403
   622
		if (level > pGroup->immunity_level)
dvander@1403
   623
		{
dvander@1403
   624
			pGroup->immunity_level = level;
dvander@1403
   625
		}
dvander@1403
   626
	} else {
dvander@1403
   627
		pGroup->immunity_level = 0;
dvander@1403
   628
	}
dvander@335
   629
}
dvander@335
   630
dvander@335
   631
bool AdminCache::GetGroupGenericImmunity(GroupId id, ImmunityType type)
dvander@335
   632
{
dvander@335
   633
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   634
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   635
	{
dvander@335
   636
		return false;
dvander@335
   637
	}
dvander@335
   638
dvander@1403
   639
	if (type == Immunity_Default && pGroup->immunity_level >= 1)
dvander@335
   640
	{
dvander@1403
   641
		return true;
dvander@1403
   642
	} else if (type == Immunity_Global && pGroup->immunity_level >= 2) {
dvander@1403
   643
		return true;
dvander@335
   644
	}
dvander@335
   645
dvander@335
   646
	return false;
dvander@335
   647
}
dvander@335
   648
dvander@335
   649
void AdminCache::AddGroupImmunity(GroupId id, GroupId other_id)
dvander@335
   650
{
dvander@1356
   651
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(other_id);
dvander@335
   652
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   653
	{
dvander@335
   654
		return;
dvander@335
   655
	}
dvander@335
   656
dvander@1356
   657
	pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@1356
   658
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   659
	{
dvander@335
   660
		return;
dvander@335
   661
	}
dvander@335
   662
dvander@335
   663
	/* We always need to resize the immunity table */
dvander@335
   664
	int *table, tblidx;
dvander@1356
   665
	if (pGroup->immune_table == -1)
dvander@335
   666
	{
dvander@335
   667
		tblidx = m_pMemory->CreateMem(sizeof(int) * 2, (void **)&table);
dvander@1356
   668
		pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   669
		table[0] = 0;
dvander@335
   670
	} else {
dvander@1356
   671
		int *old_table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
dvander@433
   672
		/* Break out if this group is already in the list */
dvander@433
   673
		for (int i=0; i<old_table[0]; i++)
dvander@433
   674
		{
dvander@433
   675
			if (old_table[1+i] == other_id)
dvander@433
   676
			{
dvander@433
   677
				return;
dvander@433
   678
			}
dvander@433
   679
		}
dvander@335
   680
		tblidx = m_pMemory->CreateMem(sizeof(int) * (old_table[0] + 2), (void **)&table);
dvander@433
   681
		/* Get the old address again in case of resize */
dvander@1356
   682
		pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@1356
   683
		old_table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
dvander@335
   684
		table[0] = old_table[0];
dvander@335
   685
		for (unsigned int i=1; i<=(unsigned int)old_table[0]; i++)
dvander@335
   686
		{
dvander@335
   687
			table[i] = old_table[i];
dvander@335
   688
		}
dvander@335
   689
	}
dvander@335
   690
dvander@335
   691
	/* Assign */
dvander@1356
   692
	pGroup->immune_table = tblidx;
dvander@335
   693
dvander@335
   694
	/* Add to the array */
dvander@335
   695
	table[0]++;
dvander@335
   696
	table[table[0]] = other_id;
dvander@335
   697
}
dvander@335
   698
dvander@335
   699
unsigned int AdminCache::GetGroupImmunityCount(GroupId id)
dvander@335
   700
{
dvander@335
   701
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   702
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   703
	{
dvander@335
   704
		return 0;
dvander@335
   705
	}
dvander@335
   706
dvander@335
   707
	if (pGroup->immune_table == -1)
dvander@335
   708
	{
dvander@335
   709
		return 0;
dvander@335
   710
	}
dvander@335
   711
dvander@335
   712
	int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
dvander@335
   713
dvander@335
   714
	return table[0];
dvander@335
   715
}
dvander@335
   716
dvander@335
   717
GroupId AdminCache::GetGroupImmunity(GroupId id, unsigned int number)
dvander@335
   718
{
dvander@335
   719
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   720
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   721
	{
dvander@335
   722
		return INVALID_GROUP_ID;
dvander@335
   723
	}
dvander@335
   724
dvander@335
   725
	if (pGroup->immune_table == -1)
dvander@335
   726
	{
dvander@335
   727
		return INVALID_GROUP_ID;
dvander@335
   728
	}
dvander@335
   729
dvander@335
   730
	int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
dvander@335
   731
	if (number >= (unsigned int)table[0])
dvander@335
   732
	{
dvander@335
   733
		return INVALID_GROUP_ID;
dvander@335
   734
	}
dvander@335
   735
dvander@335
   736
	return table[1 + number];
dvander@335
   737
}
dvander@335
   738
dvander@335
   739
void AdminCache::AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule)
dvander@335
   740
{
dvander@335
   741
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   742
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   743
	{
dvander@335
   744
		return;
dvander@335
   745
	}
dvander@335
   746
dvander@335
   747
	Trie *pTrie = NULL;
dvander@335
   748
	if (type == Override_Command)
dvander@335
   749
	{
dvander@335
   750
		if (pGroup->pCmdTable == NULL)
dvander@335
   751
		{
dvander@335
   752
			pGroup->pCmdTable = sm_trie_create();
dvander@335
   753
		}
dvander@335
   754
		pTrie = pGroup->pCmdTable;
dvander@335
   755
	} else if (type == Override_CommandGroup) {
dvander@335
   756
		if (pGroup->pCmdGrpTable == NULL)
dvander@335
   757
		{
dvander@335
   758
			pGroup->pCmdGrpTable = sm_trie_create();
dvander@335
   759
		}
dvander@335
   760
		pTrie = pGroup->pCmdGrpTable;
dvander@335
   761
	} else {
dvander@335
   762
		return;
dvander@335
   763
	}
dvander@335
   764
dvander@335
   765
	sm_trie_insert(pTrie, name, (void *)(int)rule);
dvander@335
   766
}
dvander@335
   767
dvander@335
   768
bool AdminCache::GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule)
dvander@335
   769
{
dvander@335
   770
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   771
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   772
	{
dvander@335
   773
		return false;
dvander@335
   774
	}
dvander@335
   775
dvander@335
   776
	Trie *pTrie = NULL;
dvander@335
   777
	if (type == Override_Command)
dvander@335
   778
	{
dvander@335
   779
		if (pGroup->pCmdTable == NULL)
dvander@335
   780
		{
dvander@335
   781
			return false;
dvander@335
   782
		}
dvander@335
   783
		pTrie = pGroup->pCmdTable;
dvander@335
   784
	} else if (type == Override_CommandGroup) {
dvander@335
   785
		if (pGroup->pCmdGrpTable == NULL)
dvander@335
   786
		{
dvander@335
   787
			return false;
dvander@335
   788
		}
dvander@335
   789
		pTrie = pGroup->pCmdGrpTable;
dvander@335
   790
	} else {
dvander@335
   791
		return false;
dvander@335
   792
	}
dvander@335
   793
dvander@335
   794
	void *object;
dvander@335
   795
	if (!sm_trie_retrieve(pTrie, name, &object))
dvander@335
   796
	{
dvander@335
   797
		return false;
dvander@335
   798
	}
dvander@335
   799
dvander@335
   800
	if (pRule)
dvander@335
   801
	{
dvander@335
   802
		*pRule = (OverrideRule)(int)object;
dvander@335
   803
	}
dvander@335
   804
	
dvander@335
   805
	return true;
dvander@335
   806
}
dvander@335
   807
dvander@404
   808
Trie *AdminCache::GetMethodByIndex(unsigned int index)
dvander@404
   809
{
dvander@404
   810
	List<AuthMethod>::iterator iter;
dvander@404
   811
	for (iter=m_AuthMethods.begin();
dvander@404
   812
		 iter!=m_AuthMethods.end();
dvander@404
   813
		 iter++)
dvander@404
   814
	{
dvander@404
   815
		if (index-- == 0)
dvander@404
   816
		{
dvander@404
   817
			return (*iter).table;
dvander@404
   818
		}
dvander@404
   819
	}
dvander@404
   820
dvander@404
   821
	return NULL;
dvander@404
   822
}
dvander@404
   823
dvander@404
   824
bool AdminCache::InvalidateAdmin(AdminId id)
dvander@404
   825
{
dvander@404
   826
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
   827
	AdminUser *pOther;
dvander@404
   828
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
   829
	{
dvander@404
   830
		return false;
dvander@404
   831
	}
dvander@404
   832
dvander@520
   833
	if (!m_InvalidatingAdmins && !m_destroying)
dvander@458
   834
	{
dvander@458
   835
		g_Players.ClearAdminId(id);
dvander@458
   836
	}
dvander@458
   837
dvander@404
   838
	/* Unlink from the dbl link list */
dvander@404
   839
	if (id == m_FirstUser && id == m_LastUser)
dvander@404
   840
	{
dvander@404
   841
		m_FirstUser = INVALID_ADMIN_ID;
dvander@404
   842
		m_LastUser = INVALID_ADMIN_ID;
dvander@404
   843
	} else if (id == m_FirstUser) {
dvander@404
   844
		m_FirstUser = pUser->next_user;
dvander@404
   845
		pOther = (AdminUser *)m_pMemory->GetAddress(m_FirstUser);
dvander@404
   846
		pOther->prev_user = INVALID_ADMIN_ID;
dvander@404
   847
	} else if (id == m_LastUser) {
dvander@404
   848
		m_LastUser = pUser->prev_user;
dvander@404
   849
		pOther = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
dvander@404
   850
		pOther->next_user = INVALID_ADMIN_ID;
dvander@404
   851
	} else {
dvander@404
   852
		pOther = (AdminUser *)m_pMemory->GetAddress(pUser->prev_user);
dvander@404
   853
		pOther->next_user = pUser->next_user;
dvander@404
   854
		pOther = (AdminUser *)m_pMemory->GetAddress(pUser->next_user);
dvander@404
   855
		pOther->prev_user = pUser->prev_user;
dvander@404
   856
	}
dvander@404
   857
dvander@404
   858
	/* Unlink from auth tables */
dvander@405
   859
	if (pUser->auth.identidx != -1)
dvander@404
   860
	{
dvander@405
   861
		Trie *pTrie = GetMethodByIndex(pUser->auth.index);
dvander@405
   862
		if (pTrie)
dvander@404
   863
		{
dvander@405
   864
			sm_trie_delete(pTrie, m_pStrings->GetString(pUser->auth.identidx));
dvander@404
   865
		}
dvander@404
   866
	}
dvander@404
   867
dvander@404
   868
	/* Clear table counts */
dvander@404
   869
	pUser->grp_count = 0;
dvander@405
   870
	
dvander@404
   871
	/* Link into free list */
dvander@404
   872
	pUser->magic = USR_MAGIC_UNSET;
dvander@404
   873
	pUser->next_user = m_FreeUserList;
dvander@404
   874
	m_FreeUserList = id;
dvander@404
   875
dvander@1349
   876
	/* Unset serial change */
dvander@1349
   877
	pUser->serialchange = 0;
dvander@1349
   878
dvander@404
   879
	return true;
dvander@404
   880
}
dvander@404
   881
dvander@404
   882
dvander@335
   883
void AdminCache::InvalidateGroup(GroupId id)
dvander@335
   884
{
dvander@335
   885
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   886
	AdminGroup *pOther;
dvander@335
   887
dvander@335
   888
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   889
	{
dvander@335
   890
		return;
dvander@335
   891
	}
dvander@335
   892
dvander@335
   893
	const char *str = m_pStrings->GetString(pGroup->nameidx);
dvander@335
   894
	sm_trie_delete(m_pGroups, str);
dvander@335
   895
dvander@335
   896
	/* Unlink from the live dbllink list */
dvander@335
   897
	if (id == m_FirstGroup && id == m_LastGroup)
dvander@335
   898
	{
dvander@335
   899
		m_LastGroup = INVALID_GROUP_ID;
dvander@335
   900
		m_FirstGroup = INVALID_GROUP_ID;
dvander@335
   901
	} else if (id == m_FirstGroup) {
dvander@335
   902
		m_FirstGroup = pGroup->next_grp;
dvander@335
   903
		pOther = (AdminGroup *)m_pMemory->GetAddress(m_FirstGroup);
dvander@335
   904
		pOther->prev_grp = INVALID_GROUP_ID;
dvander@335
   905
	} else if (id == m_LastGroup) {
dvander@335
   906
		m_LastGroup = pGroup->prev_grp;
dvander@335
   907
		pOther = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
dvander@335
   908
		pOther->next_grp = INVALID_GROUP_ID;
dvander@335
   909
	} else {
dvander@335
   910
		pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->prev_grp);
dvander@335
   911
		pOther->next_grp = pGroup->next_grp;
dvander@335
   912
		pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->next_grp);
dvander@335
   913
		pOther->prev_grp = pGroup->prev_grp;
dvander@335
   914
	}
dvander@335
   915
dvander@335
   916
	/* Free any used memory to be safe */
dvander@335
   917
	if (pGroup->pCmdGrpTable)
dvander@335
   918
	{
dvander@335
   919
		sm_trie_destroy(pGroup->pCmdGrpTable);
dvander@335
   920
		pGroup->pCmdGrpTable = NULL;
dvander@335
   921
	}
dvander@335
   922
	if (pGroup->pCmdTable)
dvander@335
   923
	{
dvander@335
   924
		sm_trie_destroy(pGroup->pCmdTable);
dvander@335
   925
		pGroup->pCmdTable = NULL;
dvander@335
   926
	}
dvander@335
   927
dvander@335
   928
	/* Link into the free list */
dvander@335
   929
	pGroup->magic = GRP_MAGIC_UNSET;
dvander@335
   930
	pGroup->next_grp = m_FreeGroupList;
dvander@335
   931
	m_FreeGroupList = id;
dvander@335
   932
dvander@404
   933
	int idx = m_FirstUser;
dvander@404
   934
	AdminUser *pUser;
dvander@404
   935
	int *table;
dvander@404
   936
	while (idx != INVALID_ADMIN_ID)
dvander@404
   937
	{
dvander@404
   938
		pUser = (AdminUser *)m_pMemory->GetAddress(idx);
dvander@404
   939
		if (pUser->grp_count > 0)
dvander@404
   940
		{
dvander@404
   941
			table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
   942
			for (unsigned int i=0; i<pUser->grp_count; i++)
dvander@404
   943
			{
dvander@404
   944
				if (table[i] == id)
dvander@404
   945
				{
dvander@404
   946
					/* We have to remove this entry */
dvander@404
   947
					for (unsigned int j=i+1; j<pUser->grp_count; j++)
dvander@404
   948
					{
dvander@404
   949
						/* Move everything down by one */
dvander@404
   950
						table[j-1] = table[j];
dvander@404
   951
					}
dvander@404
   952
					/* Decrease count */
dvander@404
   953
					pUser->grp_count--;
dvander@404
   954
					/* Recalculate effective flags */
dvander@433
   955
					pUser->eflags = pUser->flags;
dvander@404
   956
					for (unsigned int j=0; j<pUser->grp_count; j++)
dvander@404
   957
					{
dvander@404
   958
						pOther = (AdminGroup *)m_pMemory->GetAddress(table[j]);
dvander@433
   959
						pUser->eflags |= pOther->addflags;
dvander@404
   960
					}
dvander@1349
   961
					/* Mark as changed */
dvander@1349
   962
					pUser->serialchange++;
dvander@404
   963
					/* Break now, duplicates aren't allowed */
dvander@404
   964
					break;
dvander@404
   965
				}
dvander@404
   966
			}
dvander@404
   967
		}
dvander@404
   968
		idx = pUser->next_user;
dvander@404
   969
	}
dvander@335
   970
}
dvander@335
   971
dvander@335
   972
void AdminCache::InvalidateGroupCache()
dvander@335
   973
{
dvander@335
   974
	/* Nuke the free list */
dvander@335
   975
	m_FreeGroupList = -1;
dvander@335
   976
dvander@335
   977
	/* Nuke reverse lookups */
dvander@335
   978
	sm_trie_clear(m_pGroups);
dvander@335
   979
dvander@335
   980
	/* Free memory on groups */
dvander@335
   981
	GroupId cur = m_FirstGroup;
dvander@335
   982
	AdminGroup *pGroup;
dvander@335
   983
	while (cur != INVALID_GROUP_ID)
dvander@335
   984
	{
dvander@335
   985
		pGroup = (AdminGroup *)m_pMemory->GetAddress(cur);
dvander@335
   986
		assert(pGroup->magic == GRP_MAGIC_SET);
dvander@335
   987
		if (pGroup->pCmdGrpTable)
dvander@335
   988
		{
dvander@335
   989
			sm_trie_destroy(pGroup->pCmdGrpTable);
dvander@335
   990
		}
dvander@335
   991
		if (pGroup->pCmdTable)
dvander@335
   992
		{
dvander@335
   993
			sm_trie_destroy(pGroup->pCmdTable);
dvander@335
   994
		}
dvander@335
   995
		cur = pGroup->next_grp;
dvander@335
   996
	}
dvander@335
   997
dvander@335
   998
	m_FirstGroup = INVALID_GROUP_ID;
dvander@335
   999
	m_LastGroup = INVALID_GROUP_ID;
dvander@335
  1000
dvander@404
  1001
	InvalidateAdminCache(false);
dvander@335
  1002
dvander@335
  1003
	/* Reset the memory table */
dvander@335
  1004
	m_pMemory->Reset();
dvander@335
  1005
}
dvander@336
  1006
dvander@336
  1007
void AdminCache::AddAdminListener(IAdminListener *pListener)
dvander@336
  1008
{
dvander@336
  1009
	m_hooks.push_back(pListener);
dvander@336
  1010
}
dvander@336
  1011
dvander@336
  1012
void AdminCache::RemoveAdminListener(IAdminListener *pListener)
dvander@336
  1013
{
dvander@336
  1014
	m_hooks.remove(pListener);
dvander@336
  1015
}
dvander@336
  1016
dvander@404
  1017
void AdminCache::RegisterAuthIdentType(const char *name)
dvander@404
  1018
{
dvander@404
  1019
	if (sm_trie_retrieve(m_pAuthTables, name, NULL))
dvander@404
  1020
	{
dvander@404
  1021
		return;
dvander@404
  1022
	}
dvander@404
  1023
dvander@404
  1024
	Trie *pAuth = sm_trie_create();
dvander@404
  1025
dvander@404
  1026
	AuthMethod method;
dvander@404
  1027
	method.name.assign(name);
dvander@404
  1028
	method.table = pAuth;
dvander@404
  1029
dvander@404
  1030
	m_AuthMethods.push_back(method);
dvander@404
  1031
dvander@404
  1032
	sm_trie_insert(m_pAuthTables, name, pAuth);
dvander@404
  1033
}
dvander@404
  1034
dvander@404
  1035
void AdminCache::InvalidateAdminCache(bool unlink_admins)
dvander@404
  1036
{
dvander@458
  1037
	m_InvalidatingAdmins = true;
dvander@520
  1038
	if (!m_destroying)
dvander@520
  1039
	{
dvander@520
  1040
		g_Players.ClearAllAdmins();
dvander@520
  1041
	}
dvander@404
  1042
	/* Wipe the identity cache first */
dvander@404
  1043
	List<AuthMethod>::iterator iter;
dvander@404
  1044
	for (iter=m_AuthMethods.begin();
dvander@404
  1045
		 iter!=m_AuthMethods.end();
dvander@404
  1046
		 iter++)
dvander@404
  1047
	{
dvander@404
  1048
		sm_trie_clear((*iter).table);
dvander@404
  1049
	}
dvander@404
  1050
	
dvander@405
  1051
	if (unlink_admins)
dvander@404
  1052
	{
dvander@405
  1053
		while (m_FirstUser != INVALID_ADMIN_ID)
dvander@405
  1054
		{
dvander@405
  1055
			InvalidateAdmin(m_FirstUser);
dvander@405
  1056
		}
dvander@405
  1057
	} else {
dvander@405
  1058
		m_FirstUser = -1;
dvander@405
  1059
		m_LastUser = -1;
dvander@405
  1060
		m_FreeUserList = -1;
dvander@404
  1061
	}
dvander@458
  1062
	m_InvalidatingAdmins = false;
dvander@404
  1063
}
dvander@404
  1064
dvander@438
  1065
void AdminCache::DumpAdminCache(AdminCachePart part, bool rebuild)
dvander@336
  1066
{
dvander@438
  1067
	List<IAdminListener *>::iterator iter;
dvander@438
  1068
	IAdminListener *pListener;
dvander@438
  1069
	cell_t result;
dvander@438
  1070
dvander@438
  1071
	if (part == AdminCache_Overrides)
dvander@336
  1072
	{
dvander@336
  1073
		DumpCommandOverrideCache(Override_Command);
dvander@336
  1074
		DumpCommandOverrideCache(Override_CommandGroup);
dvander@520
  1075
		if (rebuild && !m_destroying)
dvander@438
  1076
		{
dvander@438
  1077
			for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
dvander@438
  1078
			{
dvander@438
  1079
				pListener = (*iter);
dvander@438
  1080
				pListener->OnRebuildOverrideCache();
dvander@438
  1081
			}
dvander@438
  1082
			m_pCacheFwd->PushCell(part);
dvander@438
  1083
			m_pCacheFwd->Execute(&result);
dvander@438
  1084
		}
dvander@438
  1085
	} else if (part == AdminCache_Groups || part == AdminCache_Admins) {
dvander@438
  1086
		if (part == AdminCache_Groups)
dvander@438
  1087
		{
dvander@438
  1088
			InvalidateGroupCache();
dvander@520
  1089
			if (rebuild && !m_destroying)
dvander@438
  1090
			{
dvander@438
  1091
				for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
dvander@438
  1092
				{
dvander@438
  1093
					pListener = (*iter);
dvander@438
  1094
					pListener->OnRebuildGroupCache();
dvander@438
  1095
				}
dvander@438
  1096
				m_pCacheFwd->PushCell(part);
dvander@438
  1097
				m_pCacheFwd->Execute(&result);
dvander@438
  1098
			}
dvander@438
  1099
		}
dvander@404
  1100
		InvalidateAdminCache(true);
dvander@520
  1101
		if (rebuild && !m_destroying)
dvander@336
  1102
		{
dvander@438
  1103
			for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
dvander@438
  1104
			{
dvander@438
  1105
				pListener = (*iter);
dvander@438
  1106
				pListener->OnRebuildAdminCache((part == AdminCache_Groups));
dvander@438
  1107
			}
dvander@438
  1108
			m_pCacheFwd->PushCell(AdminCache_Admins);
dvander@438
  1109
			m_pCacheFwd->Execute(&result);
dvander@1165
  1110
			g_Players.RecheckAnyAdmins();
dvander@336
  1111
		}
dvander@336
  1112
	}
dvander@336
  1113
}
dvander@404
  1114
dvander@404
  1115
const char *AdminCache::GetAdminName(AdminId id)
dvander@404
  1116
{
dvander@404
  1117
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1118
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1119
	{
dvander@404
  1120
		return NULL;
dvander@404
  1121
	}
dvander@404
  1122
dvander@404
  1123
	return m_pStrings->GetString(pUser->nameidx);
dvander@404
  1124
}
dvander@404
  1125
dvander@405
  1126
bool AdminCache::GetMethodIndex(const char *name, unsigned int *_index)
dvander@405
  1127
{
dvander@405
  1128
	List<AuthMethod>::iterator iter;
dvander@405
  1129
	unsigned int index = 0;
dvander@405
  1130
	for (iter=m_AuthMethods.begin();
dvander@405
  1131
		 iter!=m_AuthMethods.end();
dvander@405
  1132
		 iter++,index++)
dvander@405
  1133
	{
dvander@405
  1134
		if ((*iter).name.compare(name) == 0)
dvander@405
  1135
		{
dvander@405
  1136
			*_index = index;
dvander@405
  1137
			return true;
dvander@405
  1138
		}
dvander@405
  1139
	}
dvander@405
  1140
dvander@405
  1141
	return false;
dvander@405
  1142
}
dvander@405
  1143
dvander@404
  1144
bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ident)
dvander@404
  1145
{
dvander@404
  1146
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1147
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1148
	{
dvander@404
  1149
		return false;
dvander@404
  1150
	}
dvander@404
  1151
dvander@404
  1152
	Trie *pTable;
dvander@404
  1153
	if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
dvander@404
  1154
	{
dvander@404
  1155
		return false;
dvander@404
  1156
	}
dvander@404
  1157
dvander@404
  1158
	if (sm_trie_retrieve(pTable, ident, NULL))
dvander@404
  1159
	{
dvander@404
  1160
		return false;
dvander@404
  1161
	}
dvander@404
  1162
dvander@1356
  1163
	int i_ident = m_pStrings->AddString(ident);
dvander@1356
  1164
dvander@1356
  1165
	pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@1356
  1166
	pUser->auth.identidx = i_ident;
dvander@405
  1167
	GetMethodIndex(auth, &pUser->auth.index);
dvander@405
  1168
dvander@404
  1169
	return sm_trie_insert(pTable, ident, (void **)id);
dvander@404
  1170
}
dvander@404
  1171
dvander@404
  1172
AdminId AdminCache::FindAdminByIdentity(const char *auth, const char *identity)
dvander@404
  1173
{
dvander@404
  1174
	Trie *pTable;
dvander@404
  1175
	if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
dvander@404
  1176
	{
dvander@404
  1177
		return INVALID_ADMIN_ID;
dvander@404
  1178
	}
dvander@404
  1179
dvander@404
  1180
	void *object;
dvander@404
  1181
	if (!sm_trie_retrieve(pTable, identity, &object))
dvander@404
  1182
	{
dvander@404
  1183
		return INVALID_ADMIN_ID;
dvander@404
  1184
	}
dvander@404
  1185
dvander@404
  1186
	return (AdminId)object;
dvander@404
  1187
}
dvander@404
  1188
dvander@404
  1189
void AdminCache::SetAdminFlag(AdminId id, AdminFlag flag, bool enabled)
dvander@404
  1190
{
dvander@404
  1191
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1192
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1193
	{
dvander@404
  1194
		return;
dvander@404
  1195
	}
dvander@404
  1196
dvander@433
  1197
	if (flag < Admin_Reservation
dvander@404
  1198
		|| flag >= AdminFlags_TOTAL)
dvander@404
  1199
	{
dvander@404
  1200
		return;
dvander@404
  1201
	}
dvander@436
  1202
	
dvander@436
  1203
	FlagBits bits = (1<<(FlagBits)flag);
dvander@404
  1204
dvander@436
  1205
	if (enabled)
dvander@436
  1206
	{
dvander@436
  1207
		pUser->flags |= bits;
dvander@436
  1208
		pUser->eflags |= bits;
dvander@436
  1209
	} else {
dvander@436
  1210
		pUser->flags &= ~bits;
dvander@436
  1211
		pUser->eflags &= ~bits;
dvander@436
  1212
	}
dvander@1349
  1213
dvander@1349
  1214
	pUser->serialchange++;
dvander@404
  1215
}
dvander@404
  1216
dvander@404
  1217
bool AdminCache::GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode)
dvander@404
  1218
{
dvander@404
  1219
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1220
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1221
	{
dvander@404
  1222
		return false;
dvander@404
  1223
	}
dvander@404
  1224
dvander@433
  1225
	if (flag < Admin_Reservation
dvander@404
  1226
		|| flag >= AdminFlags_TOTAL)
dvander@404
  1227
	{
dvander@404
  1228
		return false;
dvander@404
  1229
	}
dvander@404
  1230
dvander@433
  1231
	FlagBits bit = (1<<(FlagBits)flag);
dvander@433
  1232
dvander@404
  1233
	if (mode == Access_Real)
dvander@404
  1234
	{
dvander@433
  1235
		return ((pUser->flags & bit) == bit);
dvander@404
  1236
	} else if (mode == Access_Effective) {
dvander@907
  1237
		bool has_bit = ((pUser->eflags & bit) == bit);
dvander@907
  1238
		if (!has_bit && flag != Admin_Root && ((pUser->eflags & ADMFLAG_ROOT) == ADMFLAG_ROOT))
dvander@907
  1239
		{
dvander@907
  1240
			has_bit = true;
dvander@907
  1241
		}
dvander@907
  1242
		return has_bit;
dvander@404
  1243
	}
dvander@404
  1244
dvander@404
  1245
	return false;
dvander@404
  1246
}
dvander@404
  1247
dvander@433
  1248
FlagBits AdminCache::GetAdminFlags(AdminId id, AccessMode mode)
dvander@404
  1249
{
dvander@404
  1250
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1251
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1252
	{
dvander@404
  1253
		return 0;
dvander@404
  1254
	}
dvander@404
  1255
dvander@404
  1256
	if (mode == Access_Real)
dvander@404
  1257
	{
dvander@433
  1258
		return pUser->flags;
dvander@404
  1259
	} else if (mode == Access_Effective) {
dvander@433
  1260
		return pUser->eflags;
dvander@404
  1261
	}
dvander@404
  1262
dvander@433
  1263
	return 0;
dvander@404
  1264
}
dvander@404
  1265
dvander@458
  1266
void AdminCache::SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits)
dvander@458
  1267
{
dvander@458
  1268
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@458
  1269
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@458
  1270
	{
dvander@458
  1271
		return;
dvander@458
  1272
	}
dvander@458
  1273
dvander@458
  1274
	if (mode == Access_Real)
dvander@458
  1275
	{
dvander@458
  1276
		pUser->flags = bits;
dvander@458
  1277
		pUser->eflags = bits;
dvander@458
  1278
	} else if (mode == Access_Effective) {
dvander@458
  1279
		pUser->eflags = bits;
dvander@458
  1280
	}
dvander@1349
  1281
dvander@1349
  1282
	pUser->serialchange++;
dvander@458
  1283
}
dvander@458
  1284
dvander@404
  1285
bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid)
dvander@404
  1286
{
dvander@404
  1287
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1288
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1289
	{
dvander@404
  1290
		return false;
dvander@404
  1291
	}
dvander@404
  1292
dvander@404
  1293
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
dvander@405
  1294
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@404
  1295
	{
dvander@404
  1296
		return false;
dvander@404
  1297
	}
dvander@404
  1298
dvander@433
  1299
	/* First check for duplicates */
dvander@433
  1300
	if (pUser->grp_count != 0)
dvander@433
  1301
	{
dvander@433
  1302
		int *temp_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@433
  1303
		for (unsigned int i=0; i<pUser->grp_count; i++)
dvander@433
  1304
		{
dvander@433
  1305
			if (temp_table[i] == gid)
dvander@433
  1306
			{
dvander@433
  1307
				return false;
dvander@433
  1308
			}
dvander@433
  1309
		}
dvander@433
  1310
	}
dvander@433
  1311
dvander@404
  1312
	int *table;
dvander@404
  1313
	if (pUser->grp_count + 1 > pUser->grp_size)
dvander@404
  1314
	{
dvander@404
  1315
		int new_size = 0;
dvander@404
  1316
		int tblidx;
dvander@404
  1317
		
dvander@404
  1318
		if (pUser->grp_size == 0)
dvander@404
  1319
		{
dvander@404
  1320
			new_size = 2;
dvander@404
  1321
		} else {
dvander@404
  1322
			new_size = pUser->grp_size * 2;
dvander@404
  1323
		}
dvander@404
  1324
		
dvander@404
  1325
		/* Create and refresh pointers */
dvander@404
  1326
		tblidx = m_pMemory->CreateMem(new_size * sizeof(int), (void **)&table);
dvander@404
  1327
		pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1328
		pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
dvander@404
  1329
dvander@404
  1330
		/* Copy old data if necessary */
dvander@404
  1331
		if (pUser->grp_table != -1)
dvander@404
  1332
		{
dvander@404
  1333
			int *old_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
  1334
			memcpy(table, old_table, sizeof(int) * pUser->grp_count);
dvander@404
  1335
		}
dvander@404
  1336
		pUser->grp_table = tblidx;
dvander@404
  1337
		pUser->grp_size = new_size;
dvander@404
  1338
	} else {
dvander@404
  1339
		table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
  1340
	}
dvander@404
  1341
dvander@404
  1342
	table[pUser->grp_count] = gid;
dvander@404
  1343
	pUser->grp_count++;
dvander@404
  1344
dvander@434
  1345
	/* Compute new effective permissions */
dvander@433
  1346
	pUser->eflags |= pGroup->addflags;
dvander@404
  1347
dvander@1403
  1348
	if (pGroup->immunity_level > pUser->immunity_level)
dvander@434
  1349
	{
dvander@1403
  1350
		pUser->immunity_level = pGroup->immunity_level;
dvander@434
  1351
	}
dvander@434
  1352
dvander@1349
  1353
	pUser->serialchange++;
dvander@1349
  1354
dvander@404
  1355
	return true;
dvander@404
  1356
}
dvander@404
  1357
dvander@458
  1358
bool AdminCache::IsValidAdmin(AdminId id)
dvander@458
  1359
{
dvander@458
  1360
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@458
  1361
	return (pUser != NULL && pUser->magic == USR_MAGIC_SET);
dvander@458
  1362
}
dvander@458
  1363
dvander@404
  1364
unsigned int AdminCache::GetAdminGroupCount(AdminId id)
dvander@404
  1365
{
dvander@404
  1366
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1367
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1368
	{
dvander@404
  1369
		return 0;
dvander@404
  1370
	}
dvander@404
  1371
dvander@404
  1372
	return pUser->grp_count;
dvander@404
  1373
}
dvander@404
  1374
dvander@404
  1375
GroupId AdminCache::GetAdminGroup(AdminId id, unsigned int index, const char **name)
dvander@404
  1376
{
dvander@404
  1377
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1378
	if (!pUser || pUser->magic != USR_MAGIC_SET || index >= pUser->grp_count)
dvander@404
  1379
	{
dvander@404
  1380
		return INVALID_GROUP_ID;
dvander@404
  1381
	}
dvander@404
  1382
dvander@404
  1383
	int *table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
  1384
dvander@1356
  1385
	GroupId gid = table[index];
dvander@1356
  1386
dvander@1356
  1387
	if (name)
dvander@1356
  1388
	{
dvander@1356
  1389
		*name = GetGroupName(gid);
dvander@1356
  1390
	}
dvander@1356
  1391
dvander@1356
  1392
	return gid;
dvander@404
  1393
}
dvander@404
  1394
dvander@404
  1395
const char *AdminCache::GetAdminPassword(AdminId id)
dvander@404
  1396
{
dvander@404
  1397
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1398
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1399
	{
dvander@404
  1400
		return NULL;
dvander@404
  1401
	}
dvander@404
  1402
dvander@404
  1403
	return m_pStrings->GetString(pUser->password);
dvander@404
  1404
}
dvander@404
  1405
dvander@404
  1406
void AdminCache::SetAdminPassword(AdminId id, const char *password)
dvander@404
  1407
{	
dvander@404
  1408
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1409
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1410
	{
dvander@404
  1411
		return;
dvander@404
  1412
	}
dvander@404
  1413
dvander@1356
  1414
	int i_password = m_pStrings->AddString(password);
dvander@1356
  1415
	pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@1356
  1416
	pUser->password = i_password;
dvander@404
  1417
}
dvander@404
  1418
dvander@433
  1419
unsigned int AdminCache::FlagBitsToBitArray(FlagBits bits, bool array[], unsigned int maxSize)
dvander@433
  1420
{
dvander@433
  1421
	unsigned int i;
dvander@433
  1422
	for (i=0; i<maxSize && i<AdminFlags_TOTAL; i++)
dvander@433
  1423
	{
dvander@464
  1424
		array[i] = ((bits & (1<<i)) == (unsigned)(1<<i));
dvander@433
  1425
	}
dvander@433
  1426
dvander@433
  1427
	return i;
dvander@433
  1428
}
dvander@433
  1429
dvander@433
  1430
FlagBits AdminCache::FlagBitArrayToBits(const bool array[], unsigned int maxSize)
dvander@433
  1431
{
dvander@433
  1432
	FlagBits bits = 0;
dvander@433
  1433
	for (unsigned int i=0; i<maxSize && i<AdminFlags_TOTAL; i++)
dvander@433
  1434
	{
dvander@433
  1435
		if (array[i])
dvander@433
  1436
		{
dvander@433
  1437
			bits |= (1<<i);
dvander@433
  1438
		}
dvander@433
  1439
	}
dvander@433
  1440
dvander@433
  1441
	return bits;
dvander@433
  1442
}
dvander@433
  1443
dvander@433
  1444
FlagBits AdminCache::FlagArrayToBits(const AdminFlag array[], unsigned int numFlags)
dvander@433
  1445
{
dvander@433
  1446
	FlagBits bits = 0;
dvander@433
  1447
	for (unsigned int i=0; i<numFlags && i<AdminFlags_TOTAL; i++)
dvander@433
  1448
	{
dvander@433
  1449
		bits |= (1 << (FlagBits)array[i]);
dvander@433
  1450
	}
dvander@433
  1451
dvander@433
  1452
	return bits;
dvander@433
  1453
}
dvander@433
  1454
dvander@433
  1455
unsigned int AdminCache::FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize)
dvander@433
  1456
{
dvander@433
  1457
	unsigned int i, num=0;
dvander@1050
  1458
	for (i=0; num<maxSize && i<AdminFlags_TOTAL; i++)
dvander@433
  1459
	{
dvander@464
  1460
		if ((bits & (1<<i)) == (unsigned)(1<<i))
dvander@433
  1461
		{
dvander@433
  1462
			array[num++] = (AdminFlag)i;
dvander@433
  1463
		}
dvander@433
  1464
	}
dvander@433
  1465
dvander@433
  1466
	return num;
dvander@433
  1467
}
dvander@434
  1468
dvander@434
  1469
bool AdminCache::CheckAdminFlags(AdminId id, FlagBits bits)
dvander@434
  1470
{
dvander@434
  1471
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@434
  1472
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@434
  1473
	{
dvander@434
  1474
		return false;
dvander@434
  1475
	}
dvander@434
  1476
dvander@434
  1477
	return ((pUser->eflags & bits) == bits);
dvander@434
  1478
}
dvander@434
  1479
dvander@434
  1480
bool AdminCache::CanAdminTarget(AdminId id, AdminId target)
dvander@434
  1481
{
dvander@434
  1482
	/** 
dvander@434
  1483
	 * Zeroth, if the targeting AdminId is INVALID_ADMIN_ID, targeting fails.
ds@729
  1484
	 * First, if the targeted AdminId is INVALID_ADMIN_ID, targeting succeeds.
dvander@434
  1485
	 */
dvander@434
  1486
dvander@434
  1487
	if (id == INVALID_ADMIN_ID)
dvander@434
  1488
	{
dvander@434
  1489
		return false;
dvander@434
  1490
	}
dvander@434
  1491
dvander@434
  1492
	if (target == INVALID_ADMIN_ID)
dvander@434
  1493
	{
dvander@434
  1494
		return true;
dvander@434
  1495
	}
dvander@434
  1496
dvander@1403
  1497
	if (id == target)
dvander@1403
  1498
	{
dvander@1403
  1499
		return true;
dvander@1403
  1500
	}
dvander@1403
  1501
dvander@434
  1502
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@434
  1503
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@434
  1504
	{
dvander@434
  1505
		return false;
dvander@434
  1506
	}
dvander@434
  1507
dvander@434
  1508
	AdminUser *pTarget = (AdminUser *)m_pMemory->GetAddress(target);
dvander@434
  1509
	if (!pTarget || pTarget->magic != USR_MAGIC_SET)
dvander@434
  1510
	{
dvander@434
  1511
		return false;
dvander@434
  1512
	}
dvander@434
  1513
dvander@434
  1514
	/** 
ds@729
  1515
	 * Second, if the targeting admin is root, targeting succeeds.
dvander@434
  1516
	 */
dvander@434
  1517
	if (pUser->eflags & ADMFLAG_ROOT)
dvander@434
  1518
	{
dvander@434
  1519
		return true;
dvander@434
  1520
	}
dvander@434
  1521
dvander@1403
  1522
	/** Fourth, if the targeted admin is immune from targeting admin. */
dvander@1403
  1523
	int mode = sm_immunity_mode.GetInt();
dvander@1403
  1524
	switch (mode)
dvander@434
  1525
	{
dvander@1403
  1526
		case 1:
dvander@1403
  1527
		{
dvander@1403
  1528
			if (pTarget->immunity_level > pUser->immunity_level)
dvander@1403
  1529
			{
dvander@1403
  1530
				return false;
dvander@1403
  1531
			}
dvander@1403
  1532
			break;
dvander@1403
  1533
		}
dvander@1403
  1534
		case 3:
dvander@1403
  1535
		{
dvander@1403
  1536
			/* If neither has any immunity, let this pass. */
dvander@1403
  1537
			if (!pUser->immunity_level && !pTarget->immunity_level)
dvander@1403
  1538
			{
dvander@1403
  1539
				return true;
dvander@1403
  1540
			}
dvander@1403
  1541
			/* Don't break, go to the next case. */
dvander@1403
  1542
		}
dvander@1403
  1543
		case 2:
dvander@1403
  1544
		{
dvander@1403
  1545
			if (pTarget->immunity_level >= pUser->immunity_level)
dvander@1403
  1546
			{
dvander@1403
  1547
				return false;
dvander@1403
  1548
			}
dvander@1403
  1549
			break;
dvander@1403
  1550
		}
dvander@434
  1551
	}
dvander@434
  1552
dvander@434
  1553
	/** 
dvander@1403
  1554
	 * Fifth, if the targeted admin has specific immunity from the
dvander@434
  1555
	 *  targeting admin via group immunities, targeting fails.
dvander@434
  1556
	 */
dvander@434
  1557
	//:TODO: speed this up... maybe with trie hacks.
dvander@434
  1558
	//idea is to insert %d.%d in the trie after computing this and use it as a cache lookup.
dvander@434
  1559
	//problem is the trie cannot delete prefixes, so we'd have a problem with invalidations.
dvander@434
  1560
	if (pTarget->grp_count > 0 && pUser->grp_count > 0)
dvander@434
  1561
	{
dvander@434
  1562
		int *grp_table = (int *)m_pMemory->GetAddress(pTarget->grp_table);
dvander@434
  1563
		int *src_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@434
  1564
		GroupId id, other;
dvander@434
  1565
		unsigned int num;
dvander@434
  1566
		for (unsigned int i=0; i<pTarget->grp_count; i++)
dvander@434
  1567
		{
dvander@434
  1568
			id = grp_table[i];
dvander@434
  1569
			num = GetGroupImmunityCount(id);
dvander@434
  1570
			for (unsigned int j=0; j<num; i++)
dvander@434
  1571
			{
dvander@434
  1572
				other = GetGroupImmunity(id, j);
dvander@434
  1573
				for (unsigned int k=0; k<pUser->grp_count; k++)
dvander@434
  1574
				{
dvander@434
  1575
					if (other == src_table[k])
dvander@434
  1576
					{
dvander@434
  1577
						return false;
dvander@434
  1578
					}
dvander@434
  1579
				}
dvander@434
  1580
			}
dvander@434
  1581
		}
dvander@434
  1582
	}
dvander@434
  1583
	
dvander@434
  1584
	return true;
dvander@434
  1585
}
dvander@1298
  1586
dvander@1298
  1587
bool AdminCache::FindFlag(char c, AdminFlag *pAdmFlag)
dvander@1298
  1588
{
dvander@1298
  1589
	if (c < 'a' || c > 'z')
dvander@1298
  1590
	{
dvander@1298
  1591
		return false;
dvander@1298
  1592
	}
dvander@1298
  1593
dvander@1305
  1594
	if (pAdmFlag)
dvander@1298
  1595
	{
dvander@1298
  1596
		*pAdmFlag = g_FlagLetters[(unsigned)c - (unsigned)'a'];
dvander@1298
  1597
	}
dvander@1298
  1598
dvander@1298
  1599
	return true;
dvander@1298
  1600
}
dvander@1298
  1601
dvander@1298
  1602
FlagBits AdminCache::ReadFlagString(const char *flags, const char **end)
dvander@1298
  1603
{
dvander@1298
  1604
	FlagBits bits = 0;
dvander@1298
  1605
dvander@1298
  1606
	while (flags && (*flags != '\0'))
dvander@1298
  1607
	{
dvander@1298
  1608
		AdminFlag flag;
dvander@1298
  1609
		if (!FindFlag(*flags, &flag))
dvander@1298
  1610
		{
dvander@1298
  1611
			break;
dvander@1298
  1612
		}
dvander@1298
  1613
		bits |= FlagArrayToBits(&flag, 1);
dvander@1298
  1614
		flags++;
dvander@1298
  1615
	}
dvander@1298
  1616
dvander@1298
  1617
	if (end)
dvander@1298
  1618
	{
dvander@1298
  1619
		*end = flags;
dvander@1298
  1620
	}
dvander@1298
  1621
dvander@1298
  1622
	return bits;
dvander@1298
  1623
}
dvander@1349
  1624
dvander@1349
  1625
unsigned int AdminCache::GetAdminSerialChange(AdminId id)
dvander@1349
  1626
{
dvander@1349
  1627
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@1349
  1628
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@1349
  1629
	{
dvander@1349
  1630
		return 0;
dvander@1349
  1631
	}
dvander@1349
  1632
dvander@1349
  1633
	return pUser->serialchange;
dvander@1349
  1634
}
dvander@1349
  1635
dvander@1349
  1636
bool AdminCache::CanAdminUseCommand(int client, const char *cmd)
dvander@1349
  1637
{
dvander@1349
  1638
	FlagBits bits;
dvander@1349
  1639
	OverrideType otype = Override_Command;
dvander@1349
  1640
dvander@1349
  1641
	if (cmd[0] == '@')
dvander@1349
  1642
	{
dvander@1349
  1643
		otype = Override_CommandGroup;
dvander@1349
  1644
		cmd++;
dvander@1349
  1645
	}
dvander@1349
  1646
dvander@1349
  1647
	if (!g_ConCmds.LookForCommandAdminFlags(cmd, &bits))
dvander@1349
  1648
	{
dvander@1349
  1649
		if (!GetCommandOverride(cmd, otype, &bits))
dvander@1349
  1650
		{
dvander@1349
  1651
			bits = 0;
dvander@1349
  1652
		}
dvander@1349
  1653
	}
dvander@1349
  1654
dvander@1349
  1655
	return g_ConCmds.CheckCommandAccess(client, cmd, bits);
dvander@1349
  1656
}
dvander@1403
  1657
dvander@1403
  1658
unsigned int AdminCache::SetGroupImmunityLevel(GroupId gid, unsigned int level)
dvander@1403
  1659
{
dvander@1403
  1660
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
dvander@1403
  1661
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@1403
  1662
	{
dvander@1403
  1663
		return 0;
dvander@1403
  1664
	}
dvander@1403
  1665
dvander@1403
  1666
	unsigned int old_level = pGroup->immunity_level;
dvander@1403
  1667
dvander@1403
  1668
	pGroup->immunity_level = level;
dvander@1403
  1669
dvander@1403
  1670
	return old_level;
dvander@1403
  1671
}
dvander@1403
  1672
dvander@1403
  1673
unsigned int AdminCache::GetGroupImmunityLevel(GroupId gid)
dvander@1403
  1674
{
dvander@1403
  1675
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
dvander@1403
  1676
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@1403
  1677
	{
dvander@1403
  1678
		return 0;
dvander@1403
  1679
	}
dvander@1403
  1680
dvander@1403
  1681
	return pGroup->immunity_level;
dvander@1403
  1682
}
dvander@1403
  1683
dvander@1403
  1684
unsigned int AdminCache::SetAdminImmunityLevel(AdminId id, unsigned int level)
dvander@1403
  1685
{
dvander@1403
  1686
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@1403
  1687
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@1403
  1688
	{
dvander@1403
  1689
		return 0;
dvander@1403
  1690
	}
dvander@1403
  1691
dvander@1403
  1692
	unsigned int old_level = pUser->immunity_level;
dvander@1403
  1693
dvander@1403
  1694
	pUser->immunity_level = level;
dvander@1403
  1695
dvander@1403
  1696
	return old_level;
dvander@1403
  1697
}
dvander@1403
  1698
dvander@1403
  1699
unsigned int AdminCache::GetAdminImmunityLevel(AdminId id)
dvander@1403
  1700
{
dvander@1403
  1701
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@1403
  1702
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@1403
  1703
	{
dvander@1403
  1704
		return 0;
dvander@1403
  1705
	}
dvander@1403
  1706
dvander@1403
  1707
	return pUser->immunity_level;
dvander@1403
  1708
}
dvander@1403
  1709
dvander@1477
  1710
bool AdminCache::CheckAccess(int client, const char *cmd, FlagBits flags, bool override_only)
dvander@1473
  1711
{
dvander@1473
  1712
	if (client == 0)
dvander@1473
  1713
	{
dvander@1473
  1714
		return true;
dvander@1473
  1715
	}
dvander@1473
  1716
dvander@1473
  1717
	/* Auto-detect a command if we can */
dvander@1473
  1718
	FlagBits bits = flags;
dvander@1473
  1719
	bool found_command = false;
dvander@1473
  1720
	if (!override_only)
dvander@1473
  1721
	{
dvander@1473
  1722
		found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
dvander@1473
  1723
	}
dvander@1473
  1724
dvander@1473
  1725
	if (!found_command)
dvander@1473
  1726
	{
dvander@1473
  1727
		GetCommandOverride(cmd, Override_Command, &bits);
dvander@1473
  1728
	}
dvander@1473
  1729
dvander@1473
  1730
	return g_ConCmds.CheckCommandAccess(client, cmd, bits) ? 1 : 0;
dvander@1473
  1731
}