core/AdminCache.cpp
author David Anderson <dvander@alliedmods.net>
Mon Jan 29 04:19:14 2007 +0000 (2007-01-29)
changeset 404 673ccd0935ba
parent 370 d3a484f98f6d
child 405 3e5727a37caa
permissions -rw-r--r--
initial import of finished admin api
     1 /**
     2  * ===============================================================
     3  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     4  * ===============================================================
     5  *
     6  * This file is not open source and may not be copied without explicit
     7  * written permission of AlliedModders LLC.  This file may not be redistributed 
     8  * in whole or significant part.
     9  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    10  *
    11  * Version: $Id$
    12  */
    13 
    14 #include <string.h>
    15 #include <assert.h>
    16 #include "AdminCache.h"
    17 #include "ShareSys.h"
    18 #include "ForwardSys.h"
    19 
    20 AdminCache g_Admins;
    21 
    22 AdminCache::AdminCache()
    23 {
    24 	m_pCmdOverrides = NULL;
    25 	m_pCmdGrpOverrides = NULL;
    26 	m_pStrings = new BaseStringTable(1024);
    27 	m_pMemory = m_pStrings->GetMemTable();
    28 	m_FreeGroupList = m_FirstGroup = m_LastGroup = INVALID_GROUP_ID;
    29 	m_FreeUserList = m_FirstUser = m_LastUser = INVALID_ADMIN_ID;
    30 	m_pGroups = sm_trie_create();
    31 	m_pCacheFwd = NULL;
    32 	m_FirstGroup = -1;
    33 }
    34 
    35 AdminCache::~AdminCache()
    36 {
    37 	if (m_pCmdGrpOverrides)
    38 	{
    39 		sm_trie_destroy(m_pCmdGrpOverrides);
    40 	}
    41 
    42 	if (m_pCmdOverrides)
    43 	{
    44 		sm_trie_destroy(m_pCmdOverrides);
    45 	}
    46 
    47 	InvalidateGroupCache();
    48 
    49 	if (m_pGroups)
    50 	{
    51 		sm_trie_destroy(m_pGroups);
    52 	}
    53 
    54 	delete m_pStrings;
    55 }
    56 
    57 void AdminCache::OnSourceModStartup(bool late)
    58 {
    59 	RegisterAuthIdentType("steam");
    60 	RegisterAuthIdentType("name");
    61 	RegisterAuthIdentType("ip");
    62 }
    63 
    64 void AdminCache::OnSourceModAllInitialized()
    65 {
    66 	m_pCacheFwd = g_Forwards.CreateForward("OnRebuildAdminCache", ET_Ignore, 1, NULL, Param_Cell);
    67 	g_ShareSys.AddInterface(NULL, this);
    68 }
    69 
    70 void AdminCache::OnSourceModShutdown()
    71 {
    72 	g_Forwards.ReleaseForward(m_pCacheFwd);
    73 	m_pCacheFwd = NULL;
    74 }
    75 
    76 void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, AdminFlag flag)
    77 {
    78 	if (type == Override_Command)
    79 	{
    80 		_AddCommandOverride(cmd, flag);
    81 	} else if (type == Override_CommandGroup) {
    82 		_AddCommandGroupOverride(cmd, flag);
    83 	}
    84 }
    85 
    86 bool AdminCache::GetCommandOverride(const char *cmd, OverrideType type, AdminFlag *pFlag)
    87 {
    88 	if (type == Override_Command)
    89 	{
    90 		return _GetCommandOverride(cmd, pFlag);
    91 	} else if (type == Override_CommandGroup) {
    92 		return _GetCommandGroupOverride(cmd, pFlag);
    93 	}
    94 
    95 	return false;
    96 }
    97 
    98 void AdminCache::UnsetCommandOverride(const char *cmd, OverrideType type)
    99 {
   100 	if (type == Override_Command)
   101 	{
   102 		return _UnsetCommandOverride(cmd);
   103 	} else if (type == Override_CommandGroup) {
   104 		return _UnsetCommandGroupOverride(cmd);
   105 	}
   106 }
   107 
   108 void AdminCache::_AddCommandGroupOverride(const char *group, AdminFlag flag)
   109 {
   110 	if (!m_pCmdGrpOverrides)
   111 	{
   112 		m_pCmdGrpOverrides = sm_trie_create();
   113 	}
   114 
   115 	/* :TODO: Notify command system */
   116 
   117 	sm_trie_insert(m_pCmdGrpOverrides, group, (void *)flag);
   118 }
   119 
   120 void AdminCache::_AddCommandOverride(const char *cmd, AdminFlag flag)
   121 {
   122 	if (!m_pCmdOverrides)
   123 	{
   124 		m_pCmdOverrides = sm_trie_create();
   125 	}
   126 
   127 	/* :TODO: Notify command system */
   128 
   129 	sm_trie_insert(m_pCmdOverrides, cmd, (void *)flag);
   130 }
   131 
   132 bool AdminCache::_GetCommandGroupOverride(const char *cmd, AdminFlag *pFlag)
   133 {
   134 	if (!m_pCmdGrpOverrides)
   135 	{
   136 		return false;
   137 	}
   138 
   139 	if (!pFlag)
   140 	{
   141 		return sm_trie_retrieve(m_pCmdGrpOverrides, cmd, NULL);
   142 	} else {
   143 		void *object;
   144 		bool ret;
   145 		if (ret=sm_trie_retrieve(m_pCmdGrpOverrides, cmd, &object))
   146 		{
   147 			*pFlag = (AdminFlag)(int)object;
   148 		}
   149 		return ret;
   150 	}
   151 }
   152 
   153 bool AdminCache::_GetCommandOverride(const char *cmd, AdminFlag *pFlag)
   154 {
   155 	if (!m_pCmdOverrides)
   156 	{
   157 		return false;
   158 	}
   159 
   160 	if (!pFlag)
   161 	{
   162 		return sm_trie_retrieve(m_pCmdOverrides, cmd, NULL);
   163 	} else {
   164 		void *object;
   165 		bool ret;
   166 		if (ret=sm_trie_retrieve(m_pCmdOverrides, cmd, &object))
   167 		{
   168 			*pFlag = (AdminFlag)(int)object;
   169 		}
   170 		return ret;
   171 	}
   172 }
   173 
   174 void AdminCache::_UnsetCommandGroupOverride(const char *group)
   175 {
   176 	if (!m_pCmdGrpOverrides)
   177 	{
   178 		return;
   179 	}
   180 
   181 	/* :TODO: Notify command system */
   182 
   183 	sm_trie_delete(m_pCmdGrpOverrides, group);
   184 }
   185 
   186 void AdminCache::_UnsetCommandOverride(const char *cmd)
   187 {
   188 	if (!m_pCmdOverrides)
   189 	{
   190 		return;
   191 	}
   192 
   193 	/* :TODO: Notify command system */
   194 
   195 	sm_trie_delete(m_pCmdOverrides, cmd);
   196 }
   197 
   198 void AdminCache::DumpCommandOverrideCache(OverrideType type)
   199 {
   200 	if (type == Override_Command && m_pCmdOverrides)
   201 	{
   202 		sm_trie_clear(m_pCmdOverrides);
   203 	} else if (type == Override_CommandGroup && m_pCmdGrpOverrides) {
   204 		sm_trie_clear(m_pCmdGrpOverrides);
   205 	}
   206 }
   207 
   208 AdminId AdminCache::CreateAdmin(const char *name)
   209 {
   210 	AdminId id;
   211 	AdminUser *pUser;
   212 
   213 	if (m_FreeUserList != INVALID_ADMIN_ID)
   214 	{
   215 		pUser = (AdminUser *)m_pMemory->GetAddress(m_FreeUserList);
   216 		assert(pUser->magic == USR_MAGIC_UNSET);
   217 		id = m_FreeUserList;
   218 		m_FreeUserList = pUser->next_user;
   219 	} else {
   220 		id = m_pMemory->CreateMem(sizeof(AdminUser), (void **)&pUser);
   221 		pUser->grp_size = 0;
   222 		pUser->grp_table = -1;
   223 		pUser->auth_size = 0;
   224 		pUser->auth_table = -1;
   225 	}
   226 
   227 	memset(pUser->flags, 0, sizeof(pUser->flags));
   228 	memset(pUser->eflags, 0, sizeof(pUser->flags));
   229 	pUser->grp_count = 0;
   230 	pUser->auth_count = 0;
   231 	pUser->password = -1;
   232 	pUser->magic = USR_MAGIC_SET;
   233 
   234 	if (m_FirstUser == INVALID_ADMIN_ID)
   235 	{
   236 		m_FirstUser = id;
   237 		m_LastUser = id;
   238 	} else {
   239 		AdminUser *pPrev = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
   240 		pPrev->next_user = id;
   241 		pUser->prev_user = m_LastUser;
   242 		m_LastUser = id;
   243 	}
   244 
   245 	if (name && name[0] != '\0')
   246 	{
   247 		pUser->nameidx = m_pStrings->AddString(name);
   248 	}
   249 
   250 	return id;
   251 }
   252 
   253 GroupId AdminCache::AddGroup(const char *group_name)
   254 {
   255 	if (sm_trie_retrieve(m_pGroups, group_name, NULL))
   256 	{
   257 		return INVALID_GROUP_ID;
   258 	}
   259 
   260 	GroupId id;
   261 	AdminGroup *pGroup;
   262 	if (m_FreeGroupList != INVALID_GROUP_ID)
   263 	{
   264 		pGroup = (AdminGroup *)m_pMemory->GetAddress(m_FreeGroupList);
   265 		assert(pGroup->magic == GRP_MAGIC_UNSET);
   266 		id = m_FreeGroupList;
   267 		m_FreeGroupList = pGroup->next_grp;
   268 	} else {
   269 		id = m_pMemory->CreateMem(sizeof(AdminGroup), (void **)&pGroup);
   270 	}
   271 
   272 	pGroup->immune_default = false;
   273 	pGroup->immune_global = false;
   274 	pGroup->immune_table = -1;
   275 	pGroup->magic = GRP_MAGIC_SET;
   276 	pGroup->next_grp = INVALID_GROUP_ID;
   277 	pGroup->pCmdGrpTable = NULL;
   278 	pGroup->pCmdTable = NULL;
   279 	memset(pGroup->addflags, 0, sizeof(AdminFlag) * AdminFlags_TOTAL);
   280 
   281 	if (m_FirstGroup == INVALID_GROUP_ID)
   282 	{
   283 		m_FirstGroup = id;
   284 		m_LastGroup = id;
   285 		pGroup->prev_grp = INVALID_GROUP_ID;
   286 	} else {
   287 		AdminGroup *pPrev = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
   288 		assert(pPrev->magic == GRP_MAGIC_SET);
   289 		pPrev->next_grp = id;
   290 		pGroup->prev_grp = m_LastGroup;
   291 		m_LastGroup = id;
   292 	}
   293 
   294 	pGroup->nameidx = m_pStrings->AddString(group_name);
   295 
   296 	sm_trie_insert(m_pGroups, group_name, (void *)id);
   297 
   298 	return id;
   299 }
   300 
   301 GroupId AdminCache::FindGroupByName(const char *group_name)
   302 {
   303 	void *object;
   304 
   305 	if (!sm_trie_retrieve(m_pGroups, group_name, &object))
   306 	{
   307 		return INVALID_GROUP_ID;
   308 	}
   309 
   310 	GroupId id = (GroupId)object;
   311 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   312 
   313 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   314 	{
   315 		return INVALID_GROUP_ID;
   316 	}
   317 
   318 	return id;
   319 }
   320 
   321 void AdminCache::SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled)
   322 {
   323 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   324 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   325 	{
   326 		return;
   327 	}
   328 
   329 	if (flag < Admin_None || flag >= AdminFlags_TOTAL)
   330 	{
   331 		return;
   332 	}
   333 
   334 	pGroup->addflags[flag] = enabled;
   335 }
   336 
   337 bool AdminCache::GetGroupAddFlag(GroupId id, AdminFlag flag)
   338 {
   339 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   340 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   341 	{
   342 		return false;
   343 	}
   344 
   345 	if (flag < Admin_None || flag >= AdminFlags_TOTAL)
   346 	{
   347 		return false;
   348 	}
   349 
   350 	return pGroup->addflags[flag];
   351 }
   352 
   353 unsigned int AdminCache::GetGroupAddFlagBits(GroupId id, bool flags[], unsigned int total)
   354 {
   355 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   356 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   357 	{
   358 		return 0;
   359 	}
   360 
   361 	unsigned int i;
   362 
   363 	for (i = Admin_None;
   364 		 i < AdminFlags_TOTAL && i < total;
   365 		 i++)
   366 	{
   367 		flags[i] = pGroup->addflags[i];
   368 	}
   369 
   370 	return i;
   371 }
   372 
   373 void AdminCache::SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled)
   374 {
   375 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   376 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   377 	{
   378 		return;
   379 	}
   380 
   381 	if (type == Immunity_Default)
   382 	{
   383 		pGroup->immune_default = enabled;
   384 	} else if (type == Immunity_Global) {
   385 		pGroup->immune_global = enabled;
   386 	} 
   387 }
   388 
   389 bool AdminCache::GetGroupGenericImmunity(GroupId id, ImmunityType type)
   390 {
   391 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   392 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   393 	{
   394 		return false;
   395 	}
   396 
   397 	if (type == Immunity_Default)
   398 	{
   399 		return pGroup->immune_default;
   400 	} else if (type == Immunity_Global) {
   401 		return pGroup->immune_global;
   402 	}
   403 
   404 	return false;
   405 }
   406 
   407 void AdminCache::AddGroupImmunity(GroupId id, GroupId other_id)
   408 {
   409 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   410 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   411 	{
   412 		return;
   413 	}
   414 
   415 	AdminGroup *pOther = (AdminGroup *)m_pMemory->GetAddress(id);
   416 	if (!pOther || pOther->magic != GRP_MAGIC_SET)
   417 	{
   418 		return;
   419 	}
   420 
   421 	/* We always need to resize the immunity table */
   422 	int *table, tblidx;
   423 	if (pOther->immune_table == -1)
   424 	{
   425 		tblidx = m_pMemory->CreateMem(sizeof(int) * 2, (void **)&table);
   426 		table[0] = 0;
   427 	} else {
   428 		int *old_table = (int *)m_pMemory->GetAddress(pOther->immune_table);
   429 		tblidx = m_pMemory->CreateMem(sizeof(int) * (old_table[0] + 2), (void **)&table);
   430 		/* Get the old address again in caes of resize */
   431 		old_table = (int *)m_pMemory->GetAddress(pOther->immune_table);
   432 		table[0] = old_table[0];
   433 		for (unsigned int i=1; i<=(unsigned int)old_table[0]; i++)
   434 		{
   435 			table[i] = old_table[i];
   436 		}
   437 	}
   438 
   439 	/* Assign */
   440 	pOther->immune_table = tblidx;
   441 
   442 	/* Add to the array */
   443 	table[0]++;
   444 	table[table[0]] = other_id;
   445 }
   446 
   447 unsigned int AdminCache::GetGroupImmunityCount(GroupId id)
   448 {
   449 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   450 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   451 	{
   452 		return 0;
   453 	}
   454 
   455 	if (pGroup->immune_table == -1)
   456 	{
   457 		return 0;
   458 	}
   459 
   460 	int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
   461 
   462 	return table[0];
   463 }
   464 
   465 GroupId AdminCache::GetGroupImmunity(GroupId id, unsigned int number)
   466 {
   467 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   468 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   469 	{
   470 		return INVALID_GROUP_ID;
   471 	}
   472 
   473 	if (pGroup->immune_table == -1)
   474 	{
   475 		return INVALID_GROUP_ID;
   476 	}
   477 
   478 	int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
   479 	if (number >= (unsigned int)table[0])
   480 	{
   481 		return INVALID_GROUP_ID;
   482 	}
   483 
   484 	return table[1 + number];
   485 }
   486 
   487 void AdminCache::AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule)
   488 {
   489 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   490 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   491 	{
   492 		return;
   493 	}
   494 
   495 	Trie *pTrie = NULL;
   496 	if (type == Override_Command)
   497 	{
   498 		if (pGroup->pCmdTable == NULL)
   499 		{
   500 			pGroup->pCmdTable = sm_trie_create();
   501 		}
   502 		pTrie = pGroup->pCmdTable;
   503 	} else if (type == Override_CommandGroup) {
   504 		if (pGroup->pCmdGrpTable == NULL)
   505 		{
   506 			pGroup->pCmdGrpTable = sm_trie_create();
   507 		}
   508 		pTrie = pGroup->pCmdGrpTable;
   509 	} else {
   510 		return;
   511 	}
   512 
   513 	sm_trie_insert(pTrie, name, (void *)(int)rule);
   514 }
   515 
   516 bool AdminCache::GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule)
   517 {
   518 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   519 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   520 	{
   521 		return false;
   522 	}
   523 
   524 	Trie *pTrie = NULL;
   525 	if (type == Override_Command)
   526 	{
   527 		if (pGroup->pCmdTable == NULL)
   528 		{
   529 			return false;
   530 		}
   531 		pTrie = pGroup->pCmdTable;
   532 	} else if (type == Override_CommandGroup) {
   533 		if (pGroup->pCmdGrpTable == NULL)
   534 		{
   535 			return false;
   536 		}
   537 		pTrie = pGroup->pCmdGrpTable;
   538 	} else {
   539 		return false;
   540 	}
   541 
   542 	void *object;
   543 	if (!sm_trie_retrieve(pTrie, name, &object))
   544 	{
   545 		return false;
   546 	}
   547 
   548 	if (pRule)
   549 	{
   550 		*pRule = (OverrideRule)(int)object;
   551 	}
   552 	
   553 	return true;
   554 }
   555 
   556 Trie *AdminCache::GetMethodByIndex(unsigned int index)
   557 {
   558 	List<AuthMethod>::iterator iter;
   559 	for (iter=m_AuthMethods.begin();
   560 		 iter!=m_AuthMethods.end();
   561 		 iter++)
   562 	{
   563 		if (index-- == 0)
   564 		{
   565 			return (*iter).table;
   566 		}
   567 	}
   568 
   569 	return NULL;
   570 }
   571 
   572 bool AdminCache::InvalidateAdmin(AdminId id)
   573 {
   574 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
   575 	AdminUser *pOther;
   576 	if (!pUser || pUser->magic != USR_MAGIC_SET)
   577 	{
   578 		return false;
   579 	}
   580 
   581 	/* Unlink from the dbl link list */
   582 	if (id == m_FirstUser && id == m_LastUser)
   583 	{
   584 		m_FirstUser = INVALID_ADMIN_ID;
   585 		m_LastUser = INVALID_ADMIN_ID;
   586 	} else if (id == m_FirstUser) {
   587 		m_FirstUser = pUser->next_user;
   588 		pOther = (AdminUser *)m_pMemory->GetAddress(m_FirstUser);
   589 		pOther->prev_user = INVALID_ADMIN_ID;
   590 	} else if (id == m_LastUser) {
   591 		m_LastUser = pUser->prev_user;
   592 		pOther = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
   593 		pOther->next_user = INVALID_ADMIN_ID;
   594 	} else {
   595 		pOther = (AdminUser *)m_pMemory->GetAddress(pUser->prev_user);
   596 		pOther->next_user = pUser->next_user;
   597 		pOther = (AdminUser *)m_pMemory->GetAddress(pUser->next_user);
   598 		pOther->prev_user = pUser->prev_user;
   599 	}
   600 
   601 	/* Unlink from auth tables */
   602 	if (pUser->auth_count > 0)
   603 	{
   604 		UserAuth *pAuth = (UserAuth *)m_pMemory->GetAddress(pUser->auth_table);
   605 		Trie *pTrie;
   606 		for (unsigned int i=0; i<pUser->auth_count; i++)
   607 		{
   608 			pTrie = GetMethodByIndex(pAuth[i].index);
   609 			if (!pTrie)
   610 			{
   611 				continue;
   612 			}
   613 			sm_trie_delete(pTrie, m_pStrings->GetString(pAuth->identidx));
   614 		}
   615 	}
   616 
   617 	/* Clear table counts */
   618 	pUser->grp_count = 0;
   619 	pUser->auth_count = 0;
   620 
   621 	/* Link into free list */
   622 	pUser->magic = USR_MAGIC_UNSET;
   623 	pUser->next_user = m_FreeUserList;
   624 	m_FreeUserList = id;
   625 
   626 	return true;
   627 }
   628 
   629 
   630 void AdminCache::InvalidateGroup(GroupId id)
   631 {
   632 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   633 	AdminGroup *pOther;
   634 
   635 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   636 	{
   637 		return;
   638 	}
   639 
   640 	const char *str = m_pStrings->GetString(pGroup->nameidx);
   641 	sm_trie_delete(m_pGroups, str);
   642 
   643 	/* Unlink from the live dbllink list */
   644 	if (id == m_FirstGroup && id == m_LastGroup)
   645 	{
   646 		m_LastGroup = INVALID_GROUP_ID;
   647 		m_FirstGroup = INVALID_GROUP_ID;
   648 	} else if (id == m_FirstGroup) {
   649 		m_FirstGroup = pGroup->next_grp;
   650 		pOther = (AdminGroup *)m_pMemory->GetAddress(m_FirstGroup);
   651 		pOther->prev_grp = INVALID_GROUP_ID;
   652 	} else if (id == m_LastGroup) {
   653 		m_LastGroup = pGroup->prev_grp;
   654 		pOther = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
   655 		pOther->next_grp = INVALID_GROUP_ID;
   656 	} else {
   657 		pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->prev_grp);
   658 		pOther->next_grp = pGroup->next_grp;
   659 		pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->next_grp);
   660 		pOther->prev_grp = pGroup->prev_grp;
   661 	}
   662 
   663 	/* Free any used memory to be safe */
   664 	if (pGroup->pCmdGrpTable)
   665 	{
   666 		sm_trie_destroy(pGroup->pCmdGrpTable);
   667 		pGroup->pCmdGrpTable = NULL;
   668 	}
   669 	if (pGroup->pCmdTable)
   670 	{
   671 		sm_trie_destroy(pGroup->pCmdTable);
   672 		pGroup->pCmdTable = NULL;
   673 	}
   674 
   675 	/* Link into the free list */
   676 	pGroup->magic = GRP_MAGIC_UNSET;
   677 	pGroup->next_grp = m_FreeGroupList;
   678 	m_FreeGroupList = id;
   679 
   680 	int idx = m_FirstUser;
   681 	AdminUser *pUser;
   682 	int *table;
   683 	while (idx != INVALID_ADMIN_ID)
   684 	{
   685 		pUser = (AdminUser *)m_pMemory->GetAddress(idx);
   686 		if (pUser->grp_count > 0)
   687 		{
   688 			table = (int *)m_pMemory->GetAddress(pUser->grp_table);
   689 			for (unsigned int i=0; i<pUser->grp_count; i++)
   690 			{
   691 				if (table[i] == id)
   692 				{
   693 					/* We have to remove this entry */
   694 					for (unsigned int j=i+1; j<pUser->grp_count; j++)
   695 					{
   696 						/* Move everything down by one */
   697 						table[j-1] = table[j];
   698 					}
   699 					/* Decrease count */
   700 					pUser->grp_count--;
   701 					/* Recalculate effective flags */
   702 					memset(pUser->eflags, 0, sizeof(pUser->eflags));
   703 					for (unsigned int j=0; j<pUser->grp_count; j++)
   704 					{
   705 						pOther = (AdminGroup *)m_pMemory->GetAddress(table[j]);
   706 						for (unsigned int k=0; k<AdminFlags_TOTAL; k++)
   707 						{
   708 							pUser->eflags[k] = (pUser->flags[k] || pOther->addflags[k]);
   709 						}
   710 					}
   711 					/* Break now, duplicates aren't allowed */
   712 					break;
   713 				}
   714 			}
   715 		}
   716 		idx = pUser->next_user;
   717 	}
   718 }
   719 
   720 void AdminCache::InvalidateGroupCache()
   721 {
   722 	/* Nuke the free list */
   723 	m_FreeGroupList = -1;
   724 
   725 	/* Nuke reverse lookups */
   726 	sm_trie_clear(m_pGroups);
   727 
   728 	/* Free memory on groups */
   729 	GroupId cur = m_FirstGroup;
   730 	AdminGroup *pGroup;
   731 	while (cur != INVALID_GROUP_ID)
   732 	{
   733 		pGroup = (AdminGroup *)m_pMemory->GetAddress(cur);
   734 		assert(pGroup->magic == GRP_MAGIC_SET);
   735 		if (pGroup->pCmdGrpTable)
   736 		{
   737 			sm_trie_destroy(pGroup->pCmdGrpTable);
   738 		}
   739 		if (pGroup->pCmdTable)
   740 		{
   741 			sm_trie_destroy(pGroup->pCmdTable);
   742 		}
   743 		cur = pGroup->next_grp;
   744 	}
   745 
   746 	m_FirstGroup = INVALID_GROUP_ID;
   747 	m_LastGroup = INVALID_GROUP_ID;
   748 
   749 	InvalidateAdminCache(false);
   750 
   751 	/* Reset the memory table */
   752 	m_pMemory->Reset();
   753 }
   754 
   755 void AdminCache::AddAdminListener(IAdminListener *pListener)
   756 {
   757 	m_hooks.push_back(pListener);
   758 }
   759 
   760 void AdminCache::RemoveAdminListener(IAdminListener *pListener)
   761 {
   762 	m_hooks.remove(pListener);
   763 }
   764 
   765 void AdminCache::RegisterAuthIdentType(const char *name)
   766 {
   767 	if (sm_trie_retrieve(m_pAuthTables, name, NULL))
   768 	{
   769 		return;
   770 	}
   771 
   772 	Trie *pAuth = sm_trie_create();
   773 
   774 	AuthMethod method;
   775 	method.name.assign(name);
   776 	method.table = pAuth;
   777 
   778 	m_AuthMethods.push_back(method);
   779 
   780 	sm_trie_insert(m_pAuthTables, name, pAuth);
   781 }
   782 
   783 void AdminCache::InvalidateAdminCache(bool unlink_admins)
   784 {
   785 	/* Wipe the identity cache first */
   786 	List<AuthMethod>::iterator iter;
   787 	for (iter=m_AuthMethods.begin();
   788 		 iter!=m_AuthMethods.end();
   789 		 iter++)
   790 	{
   791 		sm_trie_clear((*iter).table);
   792 	}
   793 	
   794 	while (m_FirstUser != INVALID_ADMIN_ID)
   795 	{
   796 		InvalidateAdmin(m_FirstUser);
   797 	}
   798 }
   799 
   800 void AdminCache::DumpAdminCache(int cache_flags, bool rebuild)
   801 {
   802 	if (cache_flags & ADMIN_CACHE_OVERRIDES)
   803 	{
   804 		DumpCommandOverrideCache(Override_Command);
   805 		DumpCommandOverrideCache(Override_CommandGroup);
   806 	}
   807 
   808 	/* This will auto-invalidate the admin cache */
   809 	if (cache_flags & ADMIN_CACHE_GROUPS)
   810 	{
   811 		InvalidateGroupCache();
   812 	}
   813 
   814 	/* If we only requested an admin rebuild, re-use the internal memory */
   815 	if ((cache_flags & ADMIN_CACHE_ADMINS) &&
   816 		!(cache_flags & ADMIN_CACHE_GROUPS))
   817 	{
   818 		InvalidateAdminCache(true);
   819 	}
   820 
   821 	if (rebuild)
   822 	{
   823 		List<IAdminListener *>::iterator iter;
   824 		IAdminListener *pListener;
   825 		cell_t result;
   826 		for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   827 		{
   828 			pListener = (*iter);
   829 			pListener->OnRebuildAdminCache(cache_flags);
   830 		}
   831 		m_pCacheFwd->PushCell(cache_flags);
   832 		m_pCacheFwd->Execute(&result);
   833 	}
   834 }
   835 
   836 const char *AdminCache::GetAdminName(AdminId id)
   837 {
   838 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
   839 	if (!pUser || pUser->magic != USR_MAGIC_SET)
   840 	{
   841 		return NULL;
   842 	}
   843 
   844 	return m_pStrings->GetString(pUser->nameidx);
   845 }
   846 
   847 bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ident)
   848 {
   849 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
   850 	if (!pUser || pUser->magic != USR_MAGIC_SET)
   851 	{
   852 		return false;
   853 	}
   854 
   855 	Trie *pTable;
   856 	if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
   857 	{
   858 		return false;
   859 	}
   860 
   861 	if (sm_trie_retrieve(pTable, ident, NULL))
   862 	{
   863 		return false;
   864 	}
   865 
   866 	return sm_trie_insert(pTable, ident, (void **)id);
   867 }
   868 
   869 AdminId AdminCache::FindAdminByIdentity(const char *auth, const char *identity)
   870 {
   871 	Trie *pTable;
   872 	if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
   873 	{
   874 		return INVALID_ADMIN_ID;
   875 	}
   876 
   877 	void *object;
   878 	if (!sm_trie_retrieve(pTable, identity, &object))
   879 	{
   880 		return INVALID_ADMIN_ID;
   881 	}
   882 
   883 	return (AdminId)object;
   884 }
   885 
   886 void AdminCache::SetAdminFlag(AdminId id, AdminFlag flag, bool enabled)
   887 {
   888 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
   889 	if (!pUser || pUser->magic != USR_MAGIC_SET)
   890 	{
   891 		return;
   892 	}
   893 
   894 	if (flag < Admin_None
   895 		|| flag >= AdminFlags_TOTAL)
   896 	{
   897 		return;
   898 	}
   899 
   900 	pUser->flags[enabled] = false;
   901 }
   902 
   903 bool AdminCache::GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode)
   904 {
   905 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
   906 	if (!pUser || pUser->magic != USR_MAGIC_SET)
   907 	{
   908 		return false;
   909 	}
   910 
   911 	if (flag < Admin_None
   912 		|| flag >= AdminFlags_TOTAL)
   913 	{
   914 		return false;
   915 	}
   916 
   917 	if (mode == Access_Real)
   918 	{
   919 		return pUser->flags[flag];
   920 	} else if (mode == Access_Effective) {
   921 		return (pUser->flags[flag] || pUser->eflags[flag]);
   922 	}
   923 
   924 	return false;
   925 }
   926 
   927 unsigned int AdminCache::GetAdminFlags(AdminId id, bool flags[], unsigned int total, AccessMode mode)
   928 {
   929 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
   930 	if (!pUser || pUser->magic != USR_MAGIC_SET)
   931 	{
   932 		return 0;
   933 	}
   934 
   935 	unsigned int i = 0;
   936 	if (mode == Access_Real)
   937 	{
   938 		for (i=0; i<AdminFlags_TOTAL && i<total; i++)
   939 		{
   940 			flags[i] = pUser->flags[i];
   941 		}
   942 	} else if (mode == Access_Effective) {
   943 		for (i=0; i<AdminFlags_TOTAL && i<total; i++)
   944 		{
   945 			flags[i] = (pUser->flags[i] || pUser->eflags[i]);
   946 		}
   947 	}
   948 
   949 	return i;
   950 }
   951 
   952 bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid)
   953 {
   954 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
   955 	if (!pUser || pUser->magic != USR_MAGIC_SET)
   956 	{
   957 		return false;
   958 	}
   959 
   960 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
   961 	if (!pGroup || pGroup->magic != USR_MAGIC_SET)
   962 	{
   963 		return false;
   964 	}
   965 
   966 	int *table;
   967 	if (pUser->grp_count + 1 > pUser->grp_size)
   968 	{
   969 		int new_size = 0;
   970 		int tblidx;
   971 		
   972 		if (pUser->grp_size == 0)
   973 		{
   974 			new_size = 2;
   975 		} else {
   976 			new_size = pUser->grp_size * 2;
   977 		}
   978 		
   979 		/* Create and refresh pointers */
   980 		tblidx = m_pMemory->CreateMem(new_size * sizeof(int), (void **)&table);
   981 		pUser = (AdminUser *)m_pMemory->GetAddress(id);
   982 		pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
   983 
   984 		/* Copy old data if necessary */
   985 		if (pUser->grp_table != -1)
   986 		{
   987 			int *old_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
   988 			memcpy(table, old_table, sizeof(int) * pUser->grp_count);
   989 		}
   990 		pUser->grp_table = tblidx;
   991 		pUser->grp_size = new_size;
   992 	} else {
   993 		table = (int *)m_pMemory->GetAddress(pUser->grp_table);
   994 	}
   995 
   996 	for (unsigned int i=0; i<pUser->grp_count; i++)
   997 	{
   998 		if (table[i] == gid)
   999 		{
  1000 			return false;
  1001 		}
  1002 	}
  1003 
  1004 	table[pUser->grp_count] = gid;
  1005 	pUser->grp_count++;
  1006 
  1007 	/* Compute new effective flags */
  1008 	for (unsigned int i=Admin_None;
  1009 		 i<AdminFlags_TOTAL;
  1010 		 i++)
  1011 	{
  1012 		/* Only inherit flags additive flags we don't have */
  1013 		if (!pUser->eflags[i])
  1014 		{
  1015 			pUser->eflags[i] = pGroup->addflags[i];
  1016 		}
  1017 	}
  1018 
  1019 	return true;
  1020 }
  1021 
  1022 unsigned int AdminCache::GetAdminGroupCount(AdminId id)
  1023 {
  1024 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
  1025 	if (!pUser || pUser->magic != USR_MAGIC_SET)
  1026 	{
  1027 		return 0;
  1028 	}
  1029 
  1030 	return pUser->grp_count;
  1031 }
  1032 
  1033 GroupId AdminCache::GetAdminGroup(AdminId id, unsigned int index, const char **name)
  1034 {
  1035 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
  1036 	if (!pUser || pUser->magic != USR_MAGIC_SET || index >= pUser->grp_count)
  1037 	{
  1038 		return INVALID_GROUP_ID;
  1039 	}
  1040 
  1041 	int *table = (int *)m_pMemory->GetAddress(pUser->grp_table);
  1042 
  1043 	return table[index];
  1044 }
  1045 
  1046 const char *AdminCache::GetAdminPassword(AdminId id)
  1047 {
  1048 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
  1049 	if (!pUser || pUser->magic != USR_MAGIC_SET)
  1050 	{
  1051 		return NULL;
  1052 	}
  1053 
  1054 	return m_pStrings->GetString(pUser->password);
  1055 }
  1056 
  1057 void AdminCache::SetAdminPassword(AdminId id, const char *password)
  1058 {	
  1059 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
  1060 	if (!pUser || pUser->magic != USR_MAGIC_SET)
  1061 	{
  1062 		return;
  1063 	}
  1064 
  1065 	pUser->password = m_pStrings->AddString(password);
  1066 }
  1067