rendered paste body#include <amxmodx>
#include <amxmisc>
#include <sqlx>
#pragma semicolon 1
new cvar_mode;
new cvar_password_field;
new cvar_default_access;
new cvar_sql_table;
new Handle:g_loginData;
new bool:g_isSQLOk = true;
new g_controlNumber = 1;
new g_playerControl[32];
new g_cmdLoopback[16];
new g_queryHolder[512];
new g_debugFilename[] = "adminDebug.txt";
// ----
// -- Init --
// ----
public plugin_init()
{
register_plugin("Extended Admin Base SQL", "0.1d3", "MaximusBrood");
register_dictionary("admin.txt");
register_dictionary("common.txt");
cvar_mode = register_cvar("amx_mode", "1");
cvar_password_field = register_cvar("amx_password_field", "_pw");
cvar_default_access = register_cvar("amx_default_access", "");
register_cvar("amx_vote_ratio", "0.02");
register_cvar("amx_vote_time", "10");
register_cvar("amx_vote_answers", "1");
register_cvar("amx_vote_delay", "60");
register_cvar("amx_last_voting", "0");
register_cvar("amx_show_activity", "2");
register_cvar("amx_votekick_ratio", "0.40");
register_cvar("amx_voteban_ratio", "0.40");
register_cvar("amx_votemap_ratio", "0.40");
cvar_sql_table = register_cvar("amx_sql_table", "admins");
register_cvar("amx_sql_host", "127.0.0.1");
register_cvar("amx_sql_user", "root");
register_cvar("amx_sql_pass", "");
register_cvar("amx_sql_db", "amx");
register_cvar("amx_sql_type", "mysql");
set_cvar_float("amx_last_voting", 0.0);
formatex(g_cmdLoopback, 15, "amxauth%c%c%c%c", random_num('A', 'Z'), random_num('A', 'Z'), random_num('A', 'Z'), random_num('A', 'Z'));
register_srvcmd("amx_sqladmins", "cmd_connectSQL");
register_clcmd(g_cmdLoopback, "cmd_kickSignal");
//Remove the user flag from server rights
remove_user_flags(0, read_flags("z"));
//Execute two config files
new configsDir[64];
get_configsdir(configsDir, 63);
server_cmd("exec %s/amxx.cfg", configsDir);
server_cmd("exec %s/sql.cfg", configsDir);
//Create the tables if they don't already exist
server_cmd("amx_sqladmins");
}
public client_connect(id)
{
g_playerControl[id] = ++g_controlNumber;
}
public client_disconnect(id)
{
g_playerControl[id] = ++g_controlNumber;
}
public client_authorized(id)
{
log_to_file(g_debugFilename, "1");
checkPlayerAccess(id);
}
// --------
// -- Commands --
// --------
public cmd_connectSQL()
{
log_to_file(g_debugFilename, "2");
static table[32], type[12], errorMessage[128], errorNumber;
g_loginData = SQL_MakeStdTuple2(2);
new Handle:connection = SQL_Connect(g_loginData, errorNumber, errorMessage, 127);
if(!connection)
{
log_to_file(g_debugFilename, "3");
connectionErrorHandler(errorNumber, errorMessage);
return PLUGIN_HANDLED;
}
log_to_file(g_debugFilename, "4");
get_pcvar_string(cvar_sql_table, table, 31);
SQL_GetAffinity(type, 11);
g_isSQLOk = true;
if(equali(type, "sqlite") && !sqlite_TableExists(connection, table))
SQL_QueryAndIgnore(connection, "CREATE TABLE %s ( auth TEXT NOT NULL DEFAULT '', password TEXT NOT NULL DEFAULT '', access TEXT NOT NULL DEFAULT '', flags TEXT NOT NULL DEFAULT '' )", table);
else
SQL_QueryAndIgnore(connection, "CREATE TABLE IF NOT EXISTS `%s` ( `auth` VARCHAR( 32 ) NOT NULL, `password` VARCHAR( 32 ) NOT NULL, `access` VARCHAR( 32 ) NOT NULL, `flags` VARCHAR( 32 ) NOT NULL ) COMMENT = 'AMX Mod X Admins'", table);
log_to_file(g_debugFilename, "5: %s", type);
return PLUGIN_HANDLED;
}
public cmd_kickSignal(id)
{
log_to_file(g_debugFilename, "6");
server_cmd("kick #%d ^"%L^"", get_user_userid(id), id, "NO_ENTRY");
}
// ---------------
// -- Events/Forwards --
// ---------------
public client_infochanged(id)
{
log_to_file(g_debugFilename, "7");
if(!is_user_connected(id) || get_pcvar_num(cvar_mode) == 0)
return PLUGIN_CONTINUE;
static newname[32], oldname[32];
get_user_name(id, oldname, 31);
get_user_info(id, "name", newname, 31);
if(!equali(newname, oldname))
checkPlayerAccess(id);
return PLUGIN_CONTINUE;
}
// ----
// -- Main --
// ----
checkPlayerAccess(id)
{
log_to_file(g_debugFilename, "8");
new modeValue = get_pcvar_num(cvar_mode);
if(!g_isSQLOk || modeValue == 0)
{
log_to_file(g_debugFilename, "9: %d %d", (g_isSQLOk ? 1 : 0), modeValue);
if(modeValue == 2)
client_cmd(id, "%s", g_cmdLoopback);
return PLUGIN_CONTINUE;
}
log_to_file(g_debugFilename, "9");
static table[32], type[12];
SQL_GetAffinity(type, 11);
get_pcvar_string(cvar_sql_table, table, 31);
//Collect all information about the user
static authid[32], ip[16], name[32];
get_user_authid(id, authid, 31);
get_user_ip(id, ip, 15, 1);
get_user_name(id, name, 31);
replace_all(name, 31, "'", "");
//Different queries for SQLite and MySQL (HATE!)
if(equali(type, "sqlite"))
formatex(g_queryHolder, (sizeof g_queryHolder) - 1, "SELECT password, access, flags FROM %s WHERE (flags LIKE '%%c%%' AND auth = '%s') OR (flags LIKE '%%d%%' AND auth = '%s') OR (flags LIKE '%%b%%' AND auth = '%s')", table, authid, ip, name);
else
formatex(g_queryHolder, (sizeof g_queryHolder) - 1, "SELECT `password`, `access`, `flags` FROM `%s` WHERE (`flags` LIKE '%%c%%' AND `auth` = '%s') OR (`flags` LIKE '%%d%%' AND `auth` = '%s') OR (`flags` LIKE '%%b%%' AND `auth` = '%s')", table, authid, ip, name);
//Pack the id and the control number into the query
new data[2];
data[0] = id;
data[1] = g_playerControl[id];
SQL_ThreadQuery(g_loginData, "callback_checkPlayerAccess", g_queryHolder, data, 2);
log_to_file(g_debugFilename, "10");
return PLUGIN_CONTINUE;
}
public callback_checkPlayerAccess(failstate, Handle:queryHandle, errorMessage[], errorNumber, data[], size)
{
log_to_file(g_debugFilename, "11");
new id = data[0];
if(!threadedQueryErrorHandler(failstate, errorNumber, errorMessage))
{
log_to_file(g_debugFilename, "12: %s (%d)", errorMessage, errorNumber);
if(get_pcvar_num(cvar_mode) == 2)
client_cmd(id, "%s", g_cmdLoopback);
return PLUGIN_HANDLED;
}
log_to_file(g_debugFilename, "13: %d %d", g_playerControl[id], data[1]);
//This is how we know the current user is the same one that was queried for
if(g_playerControl[id] != data[1])
return PLUGIN_HANDLED;
new resultAmount = SQL_NumResults(queryHandle);
log_to_file(g_debugFilename, "14: %d", resultAmount);
//If the user wasn't found, kick if amx_mode is 2, or give default access
if(resultAmount == 0)
{
if(get_pcvar_num(cvar_mode) == 2)
client_cmd(id, "%s", g_cmdLoopback);
else
{
log_to_file(g_debugFilename, "15");
static stringDefaultAccess[32];
get_pcvar_string(cvar_default_access, stringDefaultAccess, 31);
new defaultAccess;
if(strlen(stringDefaultAccess) == 0)
defaultAccess = read_flags("z");
else
defaultAccess = read_flags(stringDefaultAccess);
if(defaultAccess)
set_user_flags(id, defaultAccess);
}
return PLUGIN_HANDLED;
}
//Loop and check each row from the database against the user
static password[32], access[32], flags[32];
for(new a = 0; a < resultAmount; ++a)
{
SQL_ReadResult(queryHandle, 0, password, 31);
SQL_ReadResult(queryHandle, 1, access, 31);
SQL_ReadResult(queryHandle, 2, flags, 31);
new successFlags = parseAccess(id, password, access, read_flags(flags));
if(successFlags & 2)
{
log_to_file(g_debugFilename, "16");
client_cmd(id, "echo ^"* %L^"", id, "PAS_ACC");
}
if(successFlags & 1)
{
log_to_file(g_debugFilename, "17");
static name[32], authid[32], ip[16];
get_user_name(id, name, 31);
get_user_authid(id, authid, 31);
get_user_ip(id, ip, 15, 1);
log_amx("Login: ^"%s<%d><%s><>^" became an admin (access ^"%s^") (address ^"%s^")", name, get_user_userid(id), authid, access, ip);
client_cmd(id, "echo ^"* %L^"", id, "PRIV_SET");
return PLUGIN_HANDLED;
}
if(successFlags & 4)
{
log_to_file(g_debugFilename, "18");
client_cmd(id, "echo ^"* %L^"", id, "INV_PAS");
}
if(successFlags & 8)
{
log_to_file(g_debugFilename, "19");
static name[32], authid[32], ip[16];
get_user_name(id, name, 31);
get_user_authid(id, authid, 31);
get_user_ip(id, ip, 15, 1);
log_amx("Login: ^"%s<%d><%s><>^" kicked due to invalid password (address ^"%s^")", name, get_user_userid(id), authid, ip);
client_cmd(id, "%s", g_cmdLoopback);
return PLUGIN_HANDLED;
}
SQL_NextRow(queryHandle);
}
if(get_pcvar_num(cvar_mode) == 2)
client_cmd(id, "%s", g_cmdLoopback);
return PLUGIN_HANDLED;
}
parseAccess(id, databasePassword[], access[], flags)
{
// 1 - Privileges set
// 2 - Password accepted
// 4 - Invalid password
// 8 - Kick
log_to_file(g_debugFilename, "99: %s %s %d", databasePassword, access, flags);
new successFlags = 0;
//All checking has been done, just give the client the rights
if(flags & FLAG_NOPASS)
{
log_to_file(g_debugFilename, "98");
set_user_flags(id, read_flags(access));
successFlags = 1;
} else
{
//Get the user's password
static passwordField[32], userPassword[32];
get_pcvar_string(cvar_password_field, passwordField, 31);
get_user_info(id, passwordField, userPassword, 31);
log_to_file(g_debugFilename, "97: %s %s", passwordField, userPassword);
//Check it against the databases password
if(equal(userPassword, databasePassword))
{
set_user_flags(id, read_flags(access));
successFlags = 3;
} else
if(flags & FLAG_KICK)
successFlags = 12;
else
successFlags = 4;
}
return successFlags;
}
// ------
// -- Stocks --
// ------
stock bool:connectionErrorHandler(errorNumber, errorMessage[])
{
log_amx("Unable to connect to database: %s (%d)", errorMessage, errorNumber);
g_isSQLOk = false;
return false;
}
stock bool:threadedQueryErrorHandler(failstate, errorNumber, errorMessage[])
{
if(failstate == TQUERY_CONNECT_FAILED)
return connectionErrorHandler(errorNumber, errorMessage);
if(failstate == TQUERY_QUERY_FAILED)
{
log_amx("Unable to query database: %s (%d)", errorMessage, errorNumber);
g_isSQLOk = false;
return false;
}
if(errorNumber)
{
log_amx("Error while querying database: %s (%d)", errorMessage, errorNumber);
g_isSQLOk = false;
return false;
}
return true;
}
//From mysqlx.inc with an extra timeout parameter
stock Handle:SQL_MakeStdTuple2(timeout)
{
static host[64], user[32], pass[32], db[128];
static get_type[12], set_type[12];
get_cvar_string("amx_sql_host", host, 63);
get_cvar_string("amx_sql_user", user, 31);
get_cvar_string("amx_sql_pass", pass, 31);
get_cvar_string("amx_sql_type", set_type, 11);
get_cvar_string("amx_sql_db", db, 127);
SQL_GetAffinity(get_type, 12);
if (!equali(get_type, set_type))
{
if (!SQL_SetAffinity(set_type))
{
log_amx("Failed to set affinity from %s to %s.", get_type, set_type);
}
}
return SQL_MakeDbTuple(host, user, pass, db, timeout);
}