- completely overhauled the immunity system

- updated and reorganized database schema files
- changed config files to show new immunity rules
- updated sql-admin-manager so it can update+create tables
- added compile.sh file for building plugins in batch
- deprecated the old admin-cache immunity api relying on ImmunityType
- added a new sm_config table to the schema for storing version numbers

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401409
This commit is contained in:
David Anderson 2007-09-10 23:38:58 +00:00
parent 93581bb296
commit 6aec628ab0
23 changed files with 815 additions and 233 deletions

View File

@ -4,12 +4,15 @@ Groups
* Allowed properties for a group:
*
* "flags" - Flag string.
* "immunity" - Specifies a group to be immune to. Use "*" for all or "$" for users with no group.
* This key may be used multiple times.
* "immunity" - Immunity level number, or a group name.
* If the group name is a number, prepend it with an
* '@' symbol similar to admins_simple.ini. Users
* will only inherit the level number if it's higher
* than their current value.
*/
"Default"
{
"immunity" "$"
"immunity" "1"
}
"Full Admins"
@ -25,6 +28,9 @@ Groups
{
}
"flags" "abcdefghiz"
"immunity" "*"
/* Largish number for lots of in-between values. */
"immunity" "99"
}
}

View File

@ -41,7 +41,8 @@ Levels
/**
* Root is a magic access flag that grants all permissions.
* This should only be given to trusted administrators.
* Root users can only be targetted by other root users.
* Root users can target anyone regardless of immunity,
* however, they themselves are not automatically immune.
*/
"root" "z"
}

View File

@ -14,3 +14,4 @@ Overrides
* any setting that csdm_enable previously had.
*/
}

View File

@ -19,6 +19,10 @@
* "password" - Optional password to require.
* "group" - Adds one group to the user's group table.
* "flags" - Adds one or more flags to the user's permissions.
* "immunity" - Sets the user's immunity level (0 = no immunity).
* Immunity can be any value. Admins with higher
* values cannot be targetted. See sm_immunity_mode
* to tweak the rules. Default value is 0.
*
* Example:
"BAILOPAN"
@ -32,3 +36,4 @@
Admins
{
}

View File

@ -11,11 +11,18 @@
// Flag definitions are in "admin_levels.cfg"
// You can combine flags into a string like this:
// "abcdefgh"
// There is also one additional "magic" flag, $, which gives admins default immunity.
//
// If you want to specify a group instead of a flag, use an @ symbol. Example:
// "@Full Admins"
//
// You can also specify immunity values. Two examples:
// "83:abcdefg" //Immunity is 83, flags are abcefgh
// "6:@Full Admins" //Immunity is 6, group is "Full Admins"
//
// Immunity values can be any number. An admin cannot target an admin with
// a higher access value (see sm_immunity_mode to tweak the rules). Default
// immunity value is 0 (no immunity).
//
// PASSWORDS:
// Passwords are generally not needed unless you have name-based authentication.
// In this case, admins must type this in their console:
@ -28,9 +35,10 @@
// the password being set.
//
////////////////////////////////
// Examples:
// "STEAM_0:1:16" "bce" //kick, ban, slay for this steam ID
// "127.0.0.1" "z" //all permissions for this ip
// Examples: (do not put // in front of real lines, as // means 'comment')
//
// "STEAM_0:1:16" "bce" //kick, ban, slay for this steam ID, no immunity
// "127.0.0.1" "99:z" //all permissions for this ip, immunity value is 99
// "BAILOPAN" "abc" "Gab3n" //name BAILOPAN, password "Gab3n": gets reservation, kick, ban
//
////////////////////////////////

View File

@ -33,6 +33,16 @@ sm_vote_delay 30
// 12 hour format: %m/%d/%Y - %I:%M:%S %p
sm_datetime_format "%m/%d/%Y - %H:%M:%S"
// Sets how SourceMod should check immunity levels when administrators target
// each other.
// 0: Ignore immunity levels (except for specific group immunities).
// 1: Protect from admins of lower access only.
// 2: Protect from admins of equal to or lower access.
// 3: Same as 2, except admins with no immunity can affect each other.
// --
// Default: 1
sm_immunity_mode 1
// Sets how many seconds SourceMod should adjust time values for incorrect
// server clocks. This can be positive or negative and will affect every
// system time in SourceMod, including logging stamps.

View File

@ -6,14 +6,15 @@ CREATE TABLE sm_admins (
password varchar(65),
flags varchar(30) NOT NULL,
name varchar(65) NOT NULL,
immunity int(10) unsigned NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE sm_groups (
id int(10) unsigned NOT NULL auto_increment,
immunity enum('none','global','default') NOT NULL,
flags varchar(30) NOT NULL,
name varchar(120) NOT NULL,
immunity_level int(1) unsigned NOT NULL,
PRIMARY KEY (id)
);
@ -44,3 +45,12 @@ CREATE TABLE sm_admins_groups (
inherit_order int(10) NOT NULL,
PRIMARY KEY (admin_id, group_id)
);
CREATE TABLE IF NOT EXISTS sm_config (
cfg_key varchar(32) NOT NULL,
cfg_value varchar(255) NOT NULL,
PRIMARY KEY (cfg_key)
);
INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409') ON DUPLICATE KEY UPDATE cfg_value = '1.0.0.1409';

View File

@ -0,0 +1,15 @@
ALTER TABLE sm_admins ADD immunity INT UNSIGNED NOT NULL;
ALTER TABLE sm_groups ADD immunity_level INT UNSIGNED NOT NULL;
UPDATE sm_groups SET immunity_level = 2 WHERE immunity = 'default';
UPDATE sm_groups SET immunity_level = 1 WHERE immunity = 'global';
ALTER TABLE sm_groups DROP immunity;
CREATE TABLE sm_config (
cfg_key varchar(32) NOT NULL,
cfg_value varchar(255) NOT NULL,
PRIMARY KEY (cfg_key)
);
INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409') ON DUPLICATE KEY UPDATE cfg_value = '1.0.0.1409';

View File

@ -5,14 +5,15 @@ CREATE TABLE sm_admins (
identity varchar(65) NOT NULL,
password varchar(65),
flags varchar(30) NOT NULL,
name varchar(65) NOT NULL
name varchar(65) NOT NULL,
immunity INTEGER NOT NULL
);
CREATE TABLE sm_groups (
id INTEGER PRIMARY KEY AUTOINCREMENT,
immunity varchar(16) NOT NULL CHECK(immunity IN ('none', 'default', 'global', 'all')),
flags varchar(30) NOT NULL,
name varchar(120) NOT NULL
name varchar(120) NOT NULL,
immunity_level INTEGER NOT NULL
);
CREATE TABLE sm_group_immunity (
@ -42,3 +43,12 @@ CREATE TABLE sm_admins_groups (
inherit_order int(10) NOT NULL,
PRIMARY KEY (admin_id, group_id)
);
CREATE TABLE IF NOT EXISTS sm_config (
cfg_key varchar(32) NOT NULL,
cfg_value varchar(255) NOT NULL,
PRIMARY KEY (cfg_key)
);
REPLACE INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409');

View File

@ -0,0 +1,23 @@
ALTER TABLE sm_admins ADD immunity INTEGER DEFAULT 0 NOT NULL;
CREATE TABLE _sm_groups_temp (
id INTEGER PRIMARY KEY AUTOINCREMENT,
flags varchar(30) NOT NULL,
name varchar(120) NOT NULL,
immunity_level INTEGER DEFAULT 0 NOT NULL
);
INSERT INTO _sm_groups_temp (id, flags, name) SELECT id, flags, name FROM sm_groups;
UPDATE _sm_groups_temp SET immunity_level = 2 WHERE id IN (SELECT g.id FROM sm_groups g WHERE g.immunity = 'global');
UPDATE _sm_groups_temp SET immunity_level = 1 WHERE id IN (SELECT g.id FROM sm_groups g WHERE g.immunity = 'default');
DROP TABLE sm_groups;
ALTER TABLE _sm_groups_temp RENAME TO sm_groups;
CREATE TABLE IF NOT EXISTS sm_config (
cfg_key varchar(32) NOT NULL,
cfg_value varchar(255) NOT NULL,
PRIMARY KEY (cfg_key)
);
REPLACE INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.1409');

View File

@ -40,6 +40,7 @@
#include "Logger.h"
#include "sourcemod.h"
#include "sm_stringutil.h"
#include "sourcemm_api.h"
#define LEVEL_STATE_NONE 0
#define LEVEL_STATE_LEVELS 1
@ -49,6 +50,8 @@ AdminCache g_Admins;
AdminFlag g_FlagLetters[26];
bool g_FlagSet[26];
ConVar sm_immunity_mode("sm_immunity_mode", "1", FCVAR_SPONLY|FCVAR_PROTECTED, "Mode for deciding immunity protection");
/* Default flags */
AdminFlag g_DefaultFlags[26] =
{
@ -443,8 +446,7 @@ AdminId AdminCache::CreateAdmin(const char *name)
pUser->magic = USR_MAGIC_SET;
pUser->auth.identidx = -1;
pUser->auth.index = 0;
pUser->immune_default = false;
pUser->immune_global = false;
pUser->immunity_level = 0;
pUser->serialchange = 1;
if (m_FirstUser == INVALID_ADMIN_ID)
@ -487,8 +489,7 @@ GroupId AdminCache::AddGroup(const char *group_name)
id = m_pMemory->CreateMem(sizeof(AdminGroup), (void **)&pGroup);
}
pGroup->immune_default = false;
pGroup->immune_global = false;
pGroup->immunity_level = 0;
pGroup->immune_table = -1;
pGroup->magic = GRP_MAGIC_SET;
pGroup->next_grp = INVALID_GROUP_ID;
@ -594,7 +595,7 @@ const char *AdminCache::GetGroupName(GroupId gid)
AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
{
return 0;
return NULL;
}
return m_pStrings->GetString(pGroup->nameidx);
@ -608,12 +609,23 @@ void AdminCache::SetGroupGenericImmunity(GroupId id, ImmunityType type, bool ena
return;
}
if (type == Immunity_Default)
unsigned int level = 0;
if (enabled)
{
pGroup->immune_default = enabled;
} else if (type == Immunity_Global) {
pGroup->immune_global = enabled;
}
if (type == Immunity_Default)
{
level = 1;
} else if (type == Immunity_Global) {
level = 2;
}
if (level > pGroup->immunity_level)
{
pGroup->immunity_level = level;
}
} else {
pGroup->immunity_level = 0;
}
}
bool AdminCache::GetGroupGenericImmunity(GroupId id, ImmunityType type)
@ -624,11 +636,11 @@ bool AdminCache::GetGroupGenericImmunity(GroupId id, ImmunityType type)
return false;
}
if (type == Immunity_Default)
if (type == Immunity_Default && pGroup->immunity_level >= 1)
{
return pGroup->immune_default;
} else if (type == Immunity_Global) {
return pGroup->immune_global;
return true;
} else if (type == Immunity_Global && pGroup->immunity_level >= 2) {
return true;
}
return false;
@ -1333,13 +1345,9 @@ bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid)
/* Compute new effective permissions */
pUser->eflags |= pGroup->addflags;
if (pGroup->immune_default)
if (pGroup->immunity_level > pUser->immunity_level)
{
pUser->immune_default = true;
}
if (pGroup->immune_global)
{
pUser->immune_global = true;
pUser->immunity_level = pGroup->immunity_level;
}
pUser->serialchange++;
@ -1486,6 +1494,11 @@ bool AdminCache::CanAdminTarget(AdminId id, AdminId target)
return true;
}
if (id == target)
{
return true;
}
AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
if (!pUser || pUser->magic != USR_MAGIC_SET)
{
@ -1506,23 +1519,39 @@ bool AdminCache::CanAdminTarget(AdminId id, AdminId target)
return true;
}
/** Fourth, if the targeted admin has global immunity, targeting fails. */
if (pTarget->immune_global)
/** Fourth, if the targeted admin is immune from targeting admin. */
int mode = sm_immunity_mode.GetInt();
switch (mode)
{
return false;
case 1:
{
if (pTarget->immunity_level > pUser->immunity_level)
{
return false;
}
break;
}
case 3:
{
/* If neither has any immunity, let this pass. */
if (!pUser->immunity_level && !pTarget->immunity_level)
{
return true;
}
/* Don't break, go to the next case. */
}
case 2:
{
if (pTarget->immunity_level >= pUser->immunity_level)
{
return false;
}
break;
}
}
/**
* Fifth, if the targeted admin has default immunity
* and the admin belongs to no groups, targeting fails.
*/
if (pTarget->immune_default && pUser->grp_count < 1)
{
return false;
}
/**
* Sixth, if the targeted admin has specific immunity from the
* Fifth, if the targeted admin has specific immunity from the
* targeting admin via group immunities, targeting fails.
*/
//:TODO: speed this up... maybe with trie hacks.
@ -1625,3 +1654,56 @@ bool AdminCache::CanAdminUseCommand(int client, const char *cmd)
return g_ConCmds.CheckCommandAccess(client, cmd, bits);
}
unsigned int AdminCache::SetGroupImmunityLevel(GroupId gid, unsigned int level)
{
AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
{
return 0;
}
unsigned int old_level = pGroup->immunity_level;
pGroup->immunity_level = level;
return old_level;
}
unsigned int AdminCache::GetGroupImmunityLevel(GroupId gid)
{
AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
{
return 0;
}
return pGroup->immunity_level;
}
unsigned int AdminCache::SetAdminImmunityLevel(AdminId id, unsigned int level)
{
AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
if (!pUser || pUser->magic != USR_MAGIC_SET)
{
return 0;
}
unsigned int old_level = pUser->immunity_level;
pUser->immunity_level = level;
return old_level;
}
unsigned int AdminCache::GetAdminImmunityLevel(AdminId id)
{
AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
if (!pUser || pUser->magic != USR_MAGIC_SET)
{
return 0;
}
return pUser->immunity_level;
}

View File

@ -50,8 +50,7 @@ using namespace SourceHook;
struct AdminGroup
{
uint32_t magic; /* Magic flag, for memory validation (ugh) */
bool immune_global; /* Global immunity? */
bool immune_default; /* Default immunity? */
unsigned int immunity_level; /* Immunity level */
/* Immune from target table (-1 = nonexistent)
* [0] = number of entries
* [1...N] = immune targets
@ -90,8 +89,7 @@ struct AdminUser
int next_user; /* Next user in the list */
int prev_user; /* Previous user in the list */
UserAuth auth; /* Auth method for this user */
bool immune_global; /* Whether globally immune */
bool immune_default; /* Whether defaultly immune */
unsigned int immunity_level; /* Immunity level */
unsigned int serialchange; /* Serial # for changes */
};
@ -158,6 +156,10 @@ public: //IAdminSystem
unsigned int GetAdminSerialChange(AdminId id);
bool CanAdminUseCommand(int client, const char *cmd);
const char *GetGroupName(GroupId gid);
virtual unsigned int SetGroupImmunityLevel(GroupId gid, unsigned int level);
virtual unsigned int GetGroupImmunityLevel(GroupId gid);
virtual unsigned int SetAdminImmunityLevel(AdminId id, unsigned int level);
virtual unsigned int GetAdminImmunityLevel(AdminId id);
public:
bool IsValidAdmin(AdminId id);
private:

View File

@ -450,6 +450,26 @@ static cell_t CreateAuthMethod(IPluginContext *pContext, const cell_t *params)
return 1;
}
static cell_t SetAdmGroupImmunityLevel(IPluginContext *pContext, const cell_t *params)
{
return g_Admins.SetGroupImmunityLevel(params[1], params[2]);
}
static cell_t GetAdmGroupImmunityLevel(IPluginContext *pContext, const cell_t *params)
{
return g_Admins.GetGroupImmunityLevel(params[1]);
}
static cell_t SetAdminImmunityLevel(IPluginContext *pContext, const cell_t *params)
{
return g_Admins.SetAdminImmunityLevel(params[1], params[2]);
}
static cell_t GetAdminImmunityLevel(IPluginContext *pContext, const cell_t *params)
{
return g_Admins.GetAdminImmunityLevel(params[1]);
}
static cell_t FindFlagByName(IPluginContext *pContext, const cell_t *params)
{
char *flag;
@ -542,6 +562,11 @@ REGISTER_NATIVES(adminNatives)
{"FindFlagByName", FindFlagByName},
{"FindFlagByChar", FindFlagByChar},
{"ReadFlagString", ReadFlagString},
{"GetAdmGroupImmunityLevel",GetAdmGroupImmunityLevel},
{"SetAdmGroupImmunityLevel",SetAdmGroupImmunityLevel},
{"GetAdminImmunityLevel", GetAdminImmunityLevel},
{"SetAdminImmunityLevel", SetAdminImmunityLevel},
/* -------------------------------------------------- */
{NULL, NULL},
};

View File

@ -110,22 +110,7 @@ public SMCResult:ReadGroups_KeyValue(Handle:smc,
SetAdmGroupAddFlag(g_CurGrp, flag, true);
}
} else if (StrEqual(key, "immunity")) {
/* If it's a value we know about, use it */
if (StrEqual(value, "*"))
{
SetAdmGroupImmunity(g_CurGrp, Immunity_Global, true);
} else if (StrEqual(value, "$")) {
SetAdmGroupImmunity(g_CurGrp, Immunity_Default, true);
} else {
/* If we can't find the group, we'll need to schedule a reparse */
new GroupId:id = FindAdmGroup(value);
if (id != INVALID_GROUP_ID)
{
SetAdmGroupImmuneFrom(g_CurGrp, id);
} else {
g_NeedReparse = true;
}
}
g_NeedReparse = true;
}
} else if (g_GroupState == GROUP_STATE_OVERRIDES) {
new OverrideRule:rule = Command_Deny;
@ -147,18 +132,31 @@ public SMCResult:ReadGroups_KeyValue(Handle:smc,
/* Check for immunity again, core should handle double inserts */
if (StrEqual(key, "immunity"))
{
if (StrEqual(value, "$"))
/* If it's a value we know about, use it */
if (StrEqual(value, "*"))
{
SetAdmGroupImmunity(g_CurGrp, Immunity_Default, true);
} else if (StrEqual(value, "*")) {
SetAdmGroupImmunity(g_CurGrp, Immunity_Global, true);
SetAdmGroupImmunityLevel(g_CurGrp, 2);
} else if (StrEqual(value, "$")) {
SetAdmGroupImmunityLevel(g_CurGrp, 1);
} else {
new GroupId:id = FindAdmGroup(value);
if (id != INVALID_GROUP_ID)
new level;
if (StringToIntEx(value, level))
{
SetAdmGroupImmuneFrom(g_CurGrp, id);
SetAdmGroupImmunityLevel(g_CurGrp, level);
} else {
ParseError("Unable to find group: \"%s\"", value);
new GroupId:id;
if (value[0] == '@')
{
id = FindAdmGroup(value[1]);
} else {
id = FindAdmGroup(value);
}
if (id != INVALID_GROUP_ID)
{
SetAdmGroupImmuneFrom(g_CurGrp, id);
} else {
ParseError("Unable to find group: \"%s\"", value);
}
}
}
}

View File

@ -111,30 +111,42 @@ ReadAdminLine(const String:line[])
new String:flags[64];
cur_idx = BreakString(line[idx], flags, sizeof(flags));
idx += cur_idx;
if (flags[0] == '@')
/* Read immunity level, if any */
new level, flag_idx;
if ((flag_idx = StringToIntEx(flags, level)) > 0)
{
new GroupId:gid = FindAdmGroup(flags[1]);
SetAdminImmunityLevel(admin, level);
if (flags[flag_idx] == ':')
{
flag_idx++;
}
}
if (flags[flag_idx] == '@')
{
new GroupId:gid = FindAdmGroup(flags[flag_idx + 1]);
if (gid == INVALID_GROUP_ID)
{
ParseError("Invalid group detected: %s", flags[1]);
ParseError("Invalid group detected: %s", flags[flag_idx + 1]);
return;
}
AdminInheritGroup(admin, gid);
} else {
new len = strlen(flags);
new len = strlen(flags[flag_idx]);
new bool:is_default = false;
for (new i=0; i<len; i++)
{
if (flags[i] == '$')
if (!level && flags[flag_idx + i] == '$')
{
is_default = true;
SetAdminImmunityLevel(admin, 1);
} else {
new AdminFlag:flag;
if (!FindFlagByChar(flags[i], flag))
if (!FindFlagByChar(flags[flag_idx + i], flag))
{
ParseError("Invalid flag detected: %c", flags[i]);
ParseError("Invalid flag detected: %c", flags[flag_idx + i]);
continue;
}
SetAdminFlag(admin, flag, true);
@ -172,3 +184,4 @@ ReadAdminLine(const String:line[])
}
}
}

View File

@ -89,12 +89,18 @@ public SMCResult:ReadUsers_KeyValue(Handle:smc,
{
auth = true;
strcopy(g_CurAuth, sizeof(g_CurAuth), value);
} else if (StrEqual(key, "identity")) {
}
else if (StrEqual(key, "identity"))
{
auth = true;
strcopy(g_CurIdent, sizeof(g_CurIdent), value);
} else if (StrEqual(key, "password")) {
}
else if (StrEqual(key, "password"))
{
SetAdminPassword(g_CurUser, value);
} else if (StrEqual(key, "group")) {
}
else if (StrEqual(key, "group"))
{
new GroupId:id = FindAdmGroup(value);
if (id == INVALID_GROUP_ID)
{
@ -102,7 +108,9 @@ public SMCResult:ReadUsers_KeyValue(Handle:smc,
} else if (!AdminInheritGroup(g_CurUser, id)) {
ParseError("Unable to inherit group \"%s\"", value);
}
} else if (StrEqual(key, "flags")) {
}
else if (StrEqual(key, "flags"))
{
new len = strlen(value);
new AdminFlag:flag;
@ -114,6 +122,11 @@ public SMCResult:ReadUsers_KeyValue(Handle:smc,
}
SetAdminFlag(g_CurUser, flag, true);
}
}
else if (StrEqual(key, "immunity"))
{
new level = StringToInt(value);
SetAdminImmunityLevel(g_CurUser, level);
}
if (auth && g_CurIdent[0] && g_CurAuth[0])

View File

@ -112,7 +112,7 @@ FetchUsers(Handle:db)
decl String:query[255], String:error[255];
new Handle:hQuery, Handle:hGroupQuery;
Format(query, sizeof(query), "SELECT id, authtype, identity, password, flags, name FROM sm_admins");
Format(query, sizeof(query), "SELECT id, authtype, identity, password, flags, name, immunity FROM sm_admins");
if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
{
SQL_GetError(db, error, sizeof(error));
@ -136,6 +136,7 @@ FetchUsers(Handle:db)
decl String:password[80];
decl String:flags[32];
decl String:name[80];
new immunity;
new AdminId:adm, id;
while (SQL_FetchRow(hQuery))
@ -146,6 +147,7 @@ FetchUsers(Handle:db)
SQL_FetchString(hQuery, 3, password, sizeof(password));
SQL_FetchString(hQuery, 4, flags, sizeof(flags));
SQL_FetchString(hQuery, 5, name, sizeof(name));
immunity = SQL_FetchInt(hQuery, 6);
/* Use a pre-existing admin if we can */
if ((adm = FindAdminByIdentity(authtype, identity)) == INVALID_ADMIN_ID)
@ -159,7 +161,7 @@ FetchUsers(Handle:db)
}
#if defined _DEBUG
PrintToServer("Found SQL admin (%d,%s,%s,%s,%s,%s):%d", id, authtype, identity, password, flags, name, adm);
PrintToServer("Found SQL admin (%d,%s,%s,%s,%s,%s,%d):%d", id, authtype, identity, password, flags, name, immunity, adm);
#endif
/* See if this admin wants a password */
@ -179,6 +181,8 @@ FetchUsers(Handle:db)
}
SetAdminFlag(adm, flag, true);
}
SetAdminImmunityLevel(adm, immunity);
/* Look up groups */
if (hGroupQuery != INVALID_HANDLE)
@ -196,7 +200,7 @@ FetchGroups(Handle:db)
decl String:query[255];
new Handle:hQuery;
Format(query, sizeof(query), "SELECT immunity, flags, name FROM sm_groups");
Format(query, sizeof(query), "SELECT flags, name, immunity_level FROM sm_groups");
if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
{
@ -208,17 +212,17 @@ FetchGroups(Handle:db)
}
/* Now start fetching groups */
decl String:immunity[16];
decl String:flags[32];
decl String:name[128];
new immunity;
while (SQL_FetchRow(hQuery))
{
SQL_FetchString(hQuery, 0, immunity, sizeof(immunity));
SQL_FetchString(hQuery, 1, flags, sizeof(flags));
SQL_FetchString(hQuery, 2, name, sizeof(name));
SQL_FetchString(hQuery, 0, flags, sizeof(flags));
SQL_FetchString(hQuery, 1, name, sizeof(name));
immunity = SQL_FetchInt(hQuery, 2);
#if defined _DEBUG
PrintToServer("Adding group (%s, %s, %s)", immunity, flags, name);
PrintToServer("Adding group (%d, %s, %s)", immunity, flags, name);
#endif
/* Find or create the group */
@ -241,15 +245,7 @@ FetchGroups(Handle:db)
}
/* Set the immunity level this group has */
if (StrEqual(immunity, "all"))
{
SetAdmGroupImmunity(gid, Immunity_Default, true);
SetAdmGroupImmunity(gid, Immunity_Global, true);
} else if (StrEqual(immunity, "default")) {
SetAdmGroupImmunity(gid, Immunity_Default, true);
} else if (StrEqual(immunity, "global")) {
SetAdmGroupImmunity(gid, Immunity_Global, true);
}
SetAdmGroupImmunityLevel(gid, immunity);
}
CloseHandle(hQuery);
@ -387,3 +383,4 @@ FetchOverrides(Handle:db)
CloseHandle(hQuery);
}

View File

@ -352,6 +352,7 @@ public OnReceiveUser(Handle:owner, Handle:hndl, const String:error[], any:data)
decl String:flags[32];
decl String:name[80];
new AdminId:adm, id;
new immunity;
/**
* Cache user info -- [0] = db id, [1] = cache id, [2] = groups
@ -367,6 +368,7 @@ public OnReceiveUser(Handle:owner, Handle:hndl, const String:error[], any:data)
SQL_FetchString(hndl, 3, password, sizeof(password));
SQL_FetchString(hndl, 4, flags, sizeof(flags));
SQL_FetchString(hndl, 5, name, sizeof(name));
immunity = SQL_FetchInt(hndl, 7);
/* For dynamic admins we clear anything already in the cache. */
if ((adm = FindAdminByIdentity(authtype, identity)) != INVALID_ADMIN_ID)
@ -387,7 +389,7 @@ public OnReceiveUser(Handle:owner, Handle:hndl, const String:error[], any:data)
total_users++;
#if defined _DEBUG
PrintToServer("Found SQL admin (%d,%s,%s,%s,%s,%s):%d:%d", id, authtype, identity, password, flags, name, adm, user_lookup[total_users-1][2]);
PrintToServer("Found SQL admin (%d,%s,%s,%s,%s,%s,%d):%d:%d", id, authtype, identity, password, flags, name, immunity, adm, user_lookup[total_users-1][2]);
#endif
/* See if this admin wants a password */
@ -395,6 +397,8 @@ public OnReceiveUser(Handle:owner, Handle:hndl, const String:error[], any:data)
{
SetAdminPassword(adm, password);
}
SetAdminImmunityLevel(adm, immunity);
/* Apply each flag */
new len = strlen(flags);
@ -488,7 +492,7 @@ FetchUser(Handle:db, client)
decl String:query[512];
new len = 0;
len += Format(query[len], sizeof(query)-len, "SELECT a.id, a.authtype, a.identity, a.password, a.flags, a.name, COUNT(ag.group_id)");
len += Format(query[len], sizeof(query)-len, "SELECT a.id, a.authtype, a.identity, a.password, a.flags, a.name, COUNT(ag.group_id), immunity");
len += Format(query[len], sizeof(query)-len, " FROM sm_admins a LEFT JOIN sm_admins_groups ag ON a.id = ag.admin_id WHERE ");
len += Format(query[len], sizeof(query)-len, " (a.authtype = 'ip' AND a.identity = '%s')", ipaddr);
len += Format(query[len], sizeof(query)-len, " OR (a.authtype = 'name' AND a.identity = '%s')", safe_name);
@ -710,17 +714,17 @@ public OnReceiveGroups(Handle:owner, Handle:hndl, const String:error[], any:data
/**
* Now start fetching groups.
*/
decl String:immunity[16];
decl String:flags[32];
decl String:name[128];
new immunity;
while (SQL_FetchRow(hndl))
{
SQL_FetchString(hndl, 0, immunity, sizeof(immunity));
SQL_FetchString(hndl, 1, flags, sizeof(flags));
SQL_FetchString(hndl, 2, name, sizeof(name));
SQL_FetchString(hndl, 0, flags, sizeof(flags));
SQL_FetchString(hndl, 1, name, sizeof(name));
immunity = SQL_FetchInt(hndl, 2);
#if defined _DEBUG
PrintToServer("Adding group (%s, %s, %s)", immunity, flags, name);
PrintToServer("Adding group (%d, %s, %s)", immunity, flags, name);
#endif
/* Find or create the group */
@ -729,7 +733,7 @@ public OnReceiveGroups(Handle:owner, Handle:hndl, const String:error[], any:data
{
gid = CreateAdmGroup(name);
}
/* Add flags from the database to the group */
new num_flag_chars = strlen(flags);
for (new i=0; i<num_flag_chars; i++)
@ -742,16 +746,7 @@ public OnReceiveGroups(Handle:owner, Handle:hndl, const String:error[], any:data
SetAdmGroupAddFlag(gid, flag, true);
}
/* Set the immunity level this group has */
if (StrEqual(immunity, "all"))
{
SetAdmGroupImmunity(gid, Immunity_Default, true);
SetAdmGroupImmunity(gid, Immunity_Global, true);
} else if (StrEqual(immunity, "default")) {
SetAdmGroupImmunity(gid, Immunity_Default, true);
} else if (StrEqual(immunity, "global")) {
SetAdmGroupImmunity(gid, Immunity_Global, true);
}
SetAdmGroupImmunityLevel(gid, immunity);
}
/**
@ -774,7 +769,7 @@ FetchGroups(Handle:db, sequence)
decl String:query[255];
new Handle:pk;
Format(query, sizeof(query), "SELECT immunity, flags, name FROM sm_groups");
Format(query, sizeof(query), "SELECT flags, name, immunity_level FROM sm_groups");
pk = CreateDataPack();
WritePackCell(pk, sequence);
@ -858,68 +853,3 @@ FetchOverrides(Handle:db, sequence)
SQL_TQuery(db, OnReceiveOverrides, query, pk, DBPrio_High);
}
/**
* Finds an entry in a temporary group list (used by immunity resolver).
*
* @param group_list Array(3,n) (0=db id, 1=gid, 2=immunity list)
* @param id group database id
* @return GroupId of the database id or INVALID_GROUP_ID.
*/
stock GroupId:UTIL_FindGroupInCache(Handle:group_list, id)
{
new size = GetArraySize(group_list);
for (new i=0; i<size; i++)
{
decl data[3];
GetArrayArray(group_list, i, data);
if (data[0] == id)
{
return GroupId:data[1];
}
}
return INVALID_GROUP_ID;
}
/**
* Breaks a comma-delimited string into a list of numbers, returning a new
* dynamic array.
*
* @param text The string to split.
* @return A new array Handle which must be closed, or
* INVALID_HANDLE on no strings found.
*/
stock Handle:UTIL_ExplodeNumberString(const String:text[])
{
new Handle:array = INVALID_HANDLE;
decl String:buffer[32];
new reloc_idx, idx;
while ((idx = SplitString(text[reloc_idx], ",", buffer, sizeof(buffer))) != -1)
{
reloc_idx += idx;
if (text[reloc_idx] == '\0')
{
break;
}
if (array == INVALID_HANDLE)
{
array = CreateArray();
}
PushArrayCell(array, StringToInt(buffer));
}
if (text[reloc_idx] != '\0')
{
if (array == INVALID_HANDLE)
{
array = CreateArray();
}
PushArrayCell(array, StringToInt(text[reloc_idx]));
}
return array;
}

11
plugins/compile.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash
test -e compiled || mkdir compiled
for sourcefile in *.sp
do
smxfile="`echo $sourcefile | sed -e 's/\.sp$/\.smx/'`"
echo -n "Compiling $sourcefile ..."
./spcomp $sourcefile -ocompiled/$smxfile
done

View File

@ -125,12 +125,12 @@ enum OverrideRule
};
/**
* Immunity types.
* DEPRECATED, do not use.
*/
enum ImmunityType
{
Immunity_Default = 1, /**< Immune from everyone with no immunity */
Immunity_Global, /**< Immune from everyone (except root admins) */
Immunity_Default = 1, /**< Deprecated. */
Immunity_Global, /**< Deprecated. */
};
/**
@ -261,22 +261,15 @@ native bool:GetAdmGroupAddFlag(GroupId:id, AdminFlag:flag);
native GetAdmGroupAddFlags(GroupId:id);
/**
* Toggles a generic immunity type.
*
* @param id Group id.
* @param type Generic immunity type.
* @param enabled True to enable, false otherwise.
* @noreturn
* @deprecated Functionality removed.
*/
#pragma deprecated Use SetAdmGroupImmunityLevel() instead.
native SetAdmGroupImmunity(GroupId:id, ImmunityType:type, bool:enabled);
/**
* Returns whether or not a group has global immunity.
*
* @param id Group id.
* @param type Generic immunity type.
* @return True if the group has this immunity, false otherwise.
* @deprecated Functionality removed.
*/
#pragma deprecated Use GetAdmGroupImmunityLevel() instead.
native bool:GetAdmGroupImmunity(GroupId:id, ImmunityType:type);
/**
@ -535,6 +528,18 @@ native ReadFlagString(const String:flags[], &numchars=0);
/**
* Tests whether one admin can target another.
*
* The hueristics for this check are as follows:
* 0. If the targeting AdminId is INVALID_ADMIN_ID, targeting fails.
* 1. If the targeted AdminId is INVALID_ADMIN_ID, targeting succeeds.
* 2. If the targeted AdminId is the same as the targeting AdminId,
* (self) targeting succeeds.
* 3. If the targeting admin is root, targeting succeeds.
* 4. If the targeted admin has access higher (as interpreted by
* (sm_immunity_mode) than the targeting admin, then targeting fails.
* 5. If the targeted admin has specific immunity from the
* targeting admin via group immunities, targeting fails.
* 6. Targeting succeeds.
*
* @param admin Admin doing the targetting (may be INVALID_ADMIN_ID).
* @param target Target admin (may be INVALID_ADMIN_ID).
* @return True if targetable, false if immune.
@ -550,6 +555,40 @@ native CanAdminTarget(AdminId:admin, AdminId:target);
*/
native bool:CreateAuthMethod(const String:method[]);
/**
* Sets a group's immunity level.
*
* @param gid Group Id.
* @param level Immunity level value.
* @return Old immunity level value.
*/
native SetAdmGroupImmunityLevel(GroupId:gid, level);
/**
* Gets a group's immunity level (defaults to 0).
*
* @param gid Group Id.
* @return Immunity level value.
*/
native GetAdmGroupImmunityLevel(GroupId:gid);
/**
* Sets an admin's immunity level.
*
* @param id Admin Id.
* @param level Immunity level value.
* @return Old immunity level value.
*/
native SetAdminImmunityLevel(AdminId:id, level);
/**
* Gets an admin's immunity level.
*
* @param id Admin Id.
* @return Immunity level value.
*/
native GetAdminImmunityLevel(AdminId:id);
/**
* Converts a flag to its single bit.
*

View File

@ -36,6 +36,11 @@
#include <sourcemod>
#define CURRENT_SCHEMA_VERSION 1409
#define SCHEMA_UPGRADE_1 1409
new current_version[4] = {1, 0, 0, CURRENT_SCHEMA_VERSION};
public Plugin:myinfo =
{
name = "SQL Admin Manager",
@ -55,6 +60,8 @@ public OnPluginStart()
RegAdminCmd("sm_sql_addgroup", Command_AddGroup, ADMFLAG_ROOT, "Adds a group to the SQL database");
RegAdminCmd("sm_sql_delgroup", Command_DelGroup, ADMFLAG_ROOT, "Removes a group from the SQL database");
RegAdminCmd("sm_sql_setadmingroups", Command_SetAdminGroups, ADMFLAG_ROOT, "Sets an admin's groups in the SQL database");
RegServerCmd("sm_create_adm_tables", Command_CreateTables);
RegServerCmd("sm_update_adm_tables", Command_UpdateTables);
}
Handle:Connect()
@ -77,6 +84,310 @@ Handle:Connect()
return db;
}
CreateMySQL(client, Handle:db)
{
new String:queries[7][] =
{
"CREATE TABLE sm_admins (id int(10) unsigned NOT NULL auto_increment, authtype enum('steam','name','ip') NOT NULL, identity varchar(65) NOT NULL, password varchar(65), flags varchar(30) NOT NULL, name varchar(65) NOT NULL, immunity int(10) unsigned NOT NULL, PRIMARY KEY (id))",
"CREATE TABLE sm_groups (id int(10) unsigned NOT NULL auto_increment, flags varchar(30) NOT NULL, name varchar(120) NOT NULL, immunity_level int(1) unsigned NOT NULL, PRIMARY KEY (id))",
"CREATE TABLE sm_group_immunity (group_id int(10) unsigned NOT NULL, other_id int(10) unsigned NOT NULL, PRIMARY KEY (group_id, other_id))",
"CREATE TABLE sm_group_overrides (group_id int(10) unsigned NOT NULL, type enum('command','group') NOT NULL, name varchar(32) NOT NULL, access enum('allow','deny') NOT NULL, PRIMARY KEY (group_id, type, name))",
"CREATE TABLE sm_overrides (type enum('command','group') NOT NULL, name varchar(32) NOT NULL, flags varchar(30) NOT NULL, PRIMARY KEY (type,name))",
"CREATE TABLE sm_admins_groups (admin_id int(10) unsigned NOT NULL, group_id int(10) unsigned NOT NULL, inherit_order int(10) NOT NULL, PRIMARY KEY (admin_id, group_id))",
"CREATE TABLE IF NOT EXISTS sm_config (cfg_key varchar(32) NOT NULL, cfg_value varchar(255) NOT NULL, PRIMARY KEY (cfg_key))"
};
for (new i = 0; i < 7; i++)
{
if (!DoQuery(client, db, queries[i]))
{
return;
}
}
decl String:query[256];
Format(query,
sizeof(query),
"INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.%d') ON DUPLICATE KEY UPDATE cfg_value = '1.0.0.%d'",
CURRENT_SCHEMA_VERSION,
CURRENT_SCHEMA_VERSION);
if (!DoQuery(client, db, query))
{
return;
}
ReplyToCommand(client, "[SM] Admin tables have been created.");
}
CreateSQLite(client, Handle:db)
{
new String:queries[7][] =
{
"CREATE TABLE sm_admins (id INTEGER PRIMARY KEY AUTOINCREMENT, authtype varchar(16) NOT NULL CHECK(authtype IN ('steam', 'ip', 'name')), identity varchar(65) NOT NULL, password varchar(65), flags varchar(30) NOT NULL, name varchar(65) NOT NULL, immunity INTEGER NOT NULL)",
"CREATE TABLE sm_groups (id INTEGER PRIMARY KEY AUTOINCREMENT, flags varchar(30) NOT NULL, name varchar(120) NOT NULL, immunity_level INTEGER NOT NULL)",
"CREATE TABLE sm_group_immunity (group_id INTEGER NOT NULL, other_id INTEGER NOT NULL, PRIMARY KEY (group_id, other_id))",
"CREATE TABLE sm_group_overrides (group_id INTEGER NOT NULL, type varchar(16) NOT NULL CHECK (type IN ('command', 'group')), name varchar(32) NOT NULL, access varchar(16) NOT NULL CHECK (access IN ('allow', 'deny')), PRIMARY KEY (group_id, type, name))",
"CREATE TABLE sm_overrides (type varchar(16) NOT NULL CHECK (type IN ('command', 'group')), name varchar(32) NOT NULL, flags varchar(30) NOT NULL, PRIMARY KEY (type,name))",
"CREATE TABLE sm_admins_groups (admin_id INTEGER NOT NULL, group_id INTEGER NOT NULL, inherit_order int(10) NOT NULL, PRIMARY KEY (admin_id, group_id))",
"CREATE TABLE IF NOT EXISTS sm_config (cfg_key varchar(32) NOT NULL, cfg_value varchar(255) NOT NULL, PRIMARY KEY (cfg_key))"
};
for (new i = 0; i < 7; i++)
{
if (!DoQuery(client, db, queries[i]))
{
return;
}
}
decl String:query[256];
Format(query,
sizeof(query),
"REPLACE INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.%d')",
CURRENT_SCHEMA_VERSION);
if (!DoQuery(client, db, query))
{
return;
}
ReplyToCommand(client, "[SM] Admin tables have been created.");
}
public Action:Command_CreateTables(args)
{
new client = 0;
new Handle:db = Connect();
if (db == INVALID_HANDLE)
{
ReplyToCommand(client, "[SM] %t", "Could not connect to database");
return Plugin_Handled;
}
new String:ident[16];
SQL_ReadDriver(db, ident, sizeof(ident));
if (strcmp(ident, "mysql") == 0)
{
CreateMySQL(client, db);
} else if (strcmp(ident, "sqlite") == 0) {
CreateSQLite(client, db);
} else {
ReplyToCommand(client, "[SM] Unknown driver type '%s', cannot create tables.", ident);
}
CloseHandle(db);
return Plugin_Handled;
}
bool:GetUpdateVersion(client, Handle:db, versions[4])
{
decl String:query[256];
new Handle:hQuery;
Format(query, sizeof(query), "SELECT cfg_value FROM sm_config WHERE cfg_key = 'admin_version'");
if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
{
DoError(client, db, query, "Version lookup query failed");
return false;
}
if (SQL_FetchRow(hQuery))
{
decl String:version_string[255];
SQL_FetchString(hQuery, 0, version_string, sizeof(version_string));
decl String:version_numbers[4][12];
if (ExplodeString(version_string, ".", version_numbers, 4, 12) == 4)
{
for (new i = 0; i < 4; i++)
{
versions[i] = StringToInt(version_numbers[i]);
}
}
}
CloseHandle(hQuery);
if (current_version[3] < versions[3])
{
ReplyToCommand(client, "[SM] The database is newer than the expected version.");
return false;
}
if (current_version[3] == versions[3])
{
ReplyToCommand(client, "[SM] Your tables are already up to date.");
return false;
}
return true;
}
UpdateSQLite(client, Handle:db)
{
decl String:query[512];
new Handle:hQuery;
Format(query, sizeof(query), "SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'sm_config'");
if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
{
DoError(client, db, query, "Table lookup query failed");
return;
}
new bool:found = SQL_FetchRow(hQuery);
CloseHandle(hQuery);
new versions[4];
if (found)
{
if (!GetUpdateVersion(client, db, versions))
{
return;
}
}
/* We only know about one upgrade path right now...
* 0 => 1
*/
if (versions[3] < SCHEMA_UPGRADE_1)
{
new String:queries[8][] =
{
"ALTER TABLE sm_admins ADD immunity INTEGER DEFAULT 0 NOT NULL",
"CREATE TABLE _sm_groups_temp (id INTEGER PRIMARY KEY AUTOINCREMENT, flags varchar(30) NOT NULL, name varchar(120) NOT NULL, immunity_level INTEGER DEFAULT 0 NOT NULL)",
"INSERT INTO _sm_groups_temp (id, flags, name) SELECT id, flags, name FROM sm_groups",
"UPDATE _sm_groups_temp SET immunity_level = 2 WHERE id IN (SELECT g.id FROM sm_groups g WHERE g.immunity = 'global')",
"UPDATE _sm_groups_temp SET immunity_level = 1 WHERE id IN (SELECT g.id FROM sm_groups g WHERE g.immunity = 'default')",
"DROP TABLE sm_groups",
"ALTER TABLE _sm_groups_temp RENAME TO sm_groups",
"CREATE TABLE IF NOT EXISTS sm_config (cfg_key varchar(32) NOT NULL, cfg_value varchar(255) NOT NULL, PRIMARY KEY (cfg_key))"
};
for (new i = 0; i < 8; i++)
{
if (!DoQuery(client, db, queries[i]))
{
return;
}
}
Format(query,
sizeof(query),
"REPLACE INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.%d')",
SCHEMA_UPGRADE_1);
if (!DoQuery(client, db, query))
{
return;
}
versions[3] = SCHEMA_UPGRADE_1;
}
ReplyToCommand(client, "[SM] Your tables are now up to date.");
}
UpdateMySQL(client, Handle:db)
{
decl String:query[512];
new Handle:hQuery;
Format(query, sizeof(query), "SHOW TABLES");
if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
{
DoError(client, db, query, "Table lookup query failed");
return;
}
decl String:table[64];
new bool:found = false;
while (SQL_FetchRow(hQuery))
{
SQL_FetchString(hQuery, 0, table, sizeof(table));
if (strcmp(table, "sm_config") == 0)
{
found = true;
}
}
CloseHandle(hQuery);
new versions[4];
if (found && !GetUpdateVersion(client, db, versions))
{
return;
}
/* We only know about one upgrade path right now...
* 0 => 1
*/
if (versions[3] < SCHEMA_UPGRADE_1)
{
new String:queries[6][] =
{
"CREATE TABLE IF NOT EXISTS sm_config (cfg_key varchar(32) NOT NULL, cfg_value varchar(255) NOT NULL, PRIMARY KEY (cfg_key))",
"ALTER TABLE sm_admins ADD immunity INT UNSIGNED NOT NULL",
"ALTER TABLE sm_groups ADD immunity_level INT UNSIGNED NOT NULL",
"UPDATE sm_groups SET immunity_level = 2 WHERE immunity = 'default'",
"UPDATE sm_groups SET immunity_level = 1 WHERE immunity = 'global'",
"ALTER TABLE sm_groups DROP immunity"
};
for (new i = 0; i < 6; i++)
{
if (!DoQuery(client, db, queries[i]))
{
return;
}
}
decl String:upgr[48];
Format(upgr, sizeof(upgr), "1.0.0.%d", SCHEMA_UPGRADE_1);
Format(query, sizeof(query), "INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '%s') ON DUPLICATE KEY UPDATE cfg_value = '%s'", upgr, upgr);
if (!DoQuery(client, db, query))
{
return;
}
versions[3] = SCHEMA_UPGRADE_1;
}
ReplyToCommand(client, "[SM] Your tables are now up to date.");
}
public Action:Command_UpdateTables(args)
{
new client = 0;
new Handle:db = Connect();
if (db == INVALID_HANDLE)
{
ReplyToCommand(client, "[SM] %t", "Could not connect to database");
return Plugin_Handled;
}
new String:ident[16];
SQL_ReadDriver(db, ident, sizeof(ident));
if (strcmp(ident, "mysql") == 0)
{
UpdateMySQL(client, db);
} else if (strcmp(ident, "sqlite") == 0) {
UpdateSQLite(client, db);
} else {
ReplyToCommand(client, "[SM] Unknown driver type, cannot upgrade.");
}
CloseHandle(db);
return Plugin_Handled;
}
public Action:Command_SetAdminGroups(client, args)
{
if (args < 2)
@ -296,17 +607,15 @@ public Action:Command_AddGroup(client, args)
if (args < 2)
{
ReplyToCommand(client, "[SM] Usage: sm_sql_addgroup <name> <flags> [immunity]");
ReplyToCommand(client, "[SM] %t", "Invalid immunity");
return Plugin_Handled;
}
new String:immunity[32] = "none";
new immunity;
if (args >= 3)
{
GetCmdArg(3, immunity, sizeof(immunity));
if (!StrEqual(immunity, "none")
&& !StrEqual(immunity, "global")
&& !StrEqual(immunity, "default"))
new String:arg3[32];
GetCmdArg(3, arg3, sizeof(arg3));
if (!StringToIntEx(arg3, immunity))
{
ReplyToCommand(client, "[SM] %t", "Invalid immunity");
return Plugin_Handled;
@ -350,10 +659,9 @@ public Action:Command_AddGroup(client, args)
Format(query,
sizeof(query),
"INSERT INTO sm_groups (immunity, flags, name) VALUES ('%s', '%s', '%s')",
immunity,
"INSERT INTO sm_groups (flags, name, immunity_level) VALUES ('%s', '%s', '%d')",
safe_flags,
safe_name);
immunity);
if (!SQL_FastQuery(db, query))
{
@ -448,7 +756,7 @@ public Action:Command_AddAdmin(client, args)
{
if (args < 4)
{
ReplyToCommand(client, "[SM] Usage: sm_sql_addadmin <alias> <authtype> <identity> <flags> [password]");
ReplyToCommand(client, "[SM] Usage: sm_sql_addadmin <alias> <authtype> <identity> <flags> [immunity] [password]");
ReplyToCommand(client, "[SM] %t", "Invalid authtype");
return Plugin_Handled;
}
@ -463,6 +771,18 @@ public Action:Command_AddAdmin(client, args)
ReplyToCommand(client, "[SM] %t", "Invalid authtype");
return Plugin_Handled;
}
new immunity;
if (args >= 5)
{
new String:arg5[32];
GetCmdArg(5, arg5, sizeof(arg5));
if (!StringToIntEx(arg5, immunity))
{
ReplyToCommand(client, "[SM] %t", "Invalid immunity");
return Plugin_Handled;
}
}
decl String:identity[65];
decl String:safe_identity[140];
@ -516,12 +836,12 @@ public Action:Command_AddAdmin(client, args)
}
new len = 0;
len += Format(query[len], sizeof(query)-len, "INSERT INTO sm_admins (authtype, identity, password, flags, name) VALUES");
len += Format(query[len], sizeof(query)-len, "INSERT INTO sm_admins (authtype, identity, password, flags, name, immunity) VALUES");
if (safe_password[0] == '\0')
{
len += Format(query[len], sizeof(query)-len, " ('%s', '%s', NULL, '%s', '%s')", authtype, safe_identity, safe_flags, safe_alias);
len += Format(query[len], sizeof(query)-len, " ('%s', '%s', NULL, '%s', '%s', %d)", authtype, safe_identity, safe_flags, safe_alias, immunity);
} else {
len += Format(query[len], sizeof(query)-len, " ('%s', '%s', '%s', '%s', '%s')", authtype, safe_identity, safe_password, safe_flags, safe_alias);
len += Format(query[len], sizeof(query)-len, " ('%s', '%s', '%s', '%s', '%s', %d)", authtype, safe_identity, safe_password, safe_flags, safe_alias, immunity);
}
if (!SQL_FastQuery(db, query))
@ -536,6 +856,21 @@ public Action:Command_AddAdmin(client, args)
return Plugin_Handled;
}
stock bool:DoQuery(client, Handle:db, const String:query[])
{
if (!SQL_FastQuery(db, query))
{
decl String:error[255];
SQL_GetError(db, error, sizeof(error));
LogError("Query failed: %s", error);
LogError("Query dump: %s", query);
ReplyToCommand(client, "[SM] %t", "Failed to query database");
return false;
}
return true;
}
stock Action:DoError(client, Handle:db, const String:query[], const String:msg[])
{
decl String:error[255];

View File

@ -35,7 +35,7 @@
#include <IShareSys.h>
#define SMINTERFACE_ADMINSYS_NAME "IAdminSys"
#define SMINTERFACE_ADMINSYS_VERSION 3
#define SMINTERFACE_ADMINSYS_VERSION 4
/**
* @file IAdminSystem.h
@ -133,12 +133,12 @@ namespace SourceMod
};
/**
* @brief Specifies a generic immunity type.
* @brief DEPRECATED. Specifies a generic immunity type.
*/
enum ImmunityType
{
Immunity_Default = 1, /**< Immune from everyone with no immunity */
Immunity_Global, /**< Immune from everyone (except root admins) */
Immunity_Default = 1, /**< Immunity value of 1 */
Immunity_Global, /**< Immunity value of 2 */
};
/**
@ -302,20 +302,31 @@ namespace SourceMod
virtual FlagBits GetGroupAddFlags(GroupId id) =0;
/**
* @brief Toggles a generic immunity type.
* @brief DEPRECATED. Sets a group's immunity level using backwards
* compatible types.
*
* If the new level being set is lower than the group's actual immunity
* level, no operation takes place.
*
* @param id Group id.
* @param type Generic immunity type.
* @param enabled True to enable, false otherwise.
* @param type Immunity type which will be converted to a
* numerical level.
* @param enabled True to set the level. False sets the
* group's immunity value to 0.
*/
virtual void SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled) =0;
/**
* @brief Returns whether or not a group has global immunity.
* @brief DEPRECATED. Returns whether a group has an immunity level
* using backwards compatible types.
*
* This simply checks whether the group's immunity value is greater
* than or equal to the new-style value for the old type.
*
* @param id Group id.
* @param type Generic immunity type.
* @return True if the group has this immunity, false otherwise.
* @return True if the group has this immunity, false
* otherwise.
*/
virtual bool GetGroupGenericImmunity(GroupId id, ImmunityType type) =0;
@ -583,15 +594,17 @@ namespace SourceMod
/**
* @brief Checks whether an AdminId can target another AdminId.
*
* Zeroth, if the targeting AdminId is INVALID_ADMIN_ID, targeting fails.
* First, if the targeted AdminId is INVALID_ADMIN_ID, targeting succeeds.
* Second, if the targeting admin is root, targeting succeeds.
* Third, if the targeted admin has global immunity, targeting fails.
* Fourth, if the targeted admin has default immunity,
* and the admin belongs to no groups, targeting fails.
* Fifth, if the targeted admin has specific immunity from the
* targeting admin via group immunities, targeting fails.
* Sixth, targeting succeeds if it passes these tests.
* The hueristics for this check are as follows:
* 0. If the targeting AdminId is INVALID_ADMIN_ID, targeting fails.
* 1. If the targeted AdminId is INVALID_ADMIN_ID, targeting succeeds.
* 2. If the targeted AdminId is the same as the targeting AdminId,
* (self) targeting succeeds.
* 3. If the targeting admin is root, targeting succeeds.
* 4. If the targeted admin has access higher (as interpreted by
* (sm_immunity_mode) than the targeting admin, then targeting fails.
* 5. If the targeted admin has specific immunity from the
* targeting admin via group immunities, targeting fails.
* 6. Targeting succeeds.
*
* @param id AdminId index of admin doing the targeting. Can be INVALID_ADMIN_ID.
* @param target AdminId index of the target admin. Can be INVALID_ADMIN_ID.
@ -655,7 +668,42 @@ namespace SourceMod
* @return Group name, or NULL on failure.
*/
virtual const char *GetGroupName(GroupId gid) =0;
/**
* @brief Sets the immunity level of a group.
*
* @param gid Group Id.
* @param level Immunity level value.
* @return Old immunity level.
*/
virtual unsigned int SetGroupImmunityLevel(GroupId gid, unsigned int level) =0;
/**
* @brief Retrieves the immunity level of a group.
*
* @param gid Group Id.
* @return Immunity level value.
*/
virtual unsigned int GetGroupImmunityLevel(GroupId gid) =0;
/**
* @brief Sets the immunity level of an admin.
*
* @param id Admin Id.
* @param level Immunity level value.
* @return Old immunity level.
*/
virtual unsigned int SetAdminImmunityLevel(AdminId id, unsigned int level) =0;
/**
* @brief Retrieves the immunity level of an admin.
*
* @param id Admin Id.
* @return Immunity level value.
*/
virtual unsigned int GetAdminImmunityLevel(AdminId id) =0;
};
}
#endif //_INCLUDE_SOURCEMOD_ADMINISTRATION_SYSTEM_H_