All pastes #474891 Raw Edit

Something

public text v1 · immutable
·published 2007-05-07 01:58 UTC
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);
}