#include #include #include #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); }