plugins/admin-sql-prefetch.sp
author David Anderson <dvander@alliedmods.net>
Fri Jul 11 06:51:21 2008 +0000 (2008-07-11)
branchrefac-jit
changeset 2192 7602d7fb60d9
parent 2168 c24a6fa957db
child 2289 44045ead61cd
permissions -rw-r--r--
fixed a compat regression, forgot msvc does funky things with overloaded virtual calls
dvander@2168
     1
/**
dvander@2168
     2
 * vim: set ts=4 :
dvander@2168
     3
 * =============================================================================
dvander@2168
     4
 * SourceMod SQL Admins Plugin (Prefetch)
dvander@2168
     5
 * Prefetches admins from an SQL database without threading.
dvander@2168
     6
 *
dvander@2168
     7
 * SourceMod (C)2004-2008 AlliedModders LLC.  All rights reserved.
dvander@2168
     8
 * =============================================================================
dvander@2168
     9
 *
dvander@2168
    10
 * This program is free software; you can redistribute it and/or modify it under
dvander@2168
    11
 * the terms of the GNU General Public License, version 3.0, as published by the
dvander@2168
    12
 * Free Software Foundation.
dvander@2168
    13
 * 
dvander@2168
    14
 * This program is distributed in the hope that it will be useful, but WITHOUT
dvander@2168
    15
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@2168
    16
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
dvander@2168
    17
 * details.
dvander@2168
    18
 *
dvander@2168
    19
 * You should have received a copy of the GNU General Public License along with
dvander@2168
    20
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@2168
    21
 *
dvander@2168
    22
 * As a special exception, AlliedModders LLC gives you permission to link the
dvander@2168
    23
 * code of this program (as well as its derivative works) to "Half-Life 2," the
dvander@2168
    24
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
dvander@2168
    25
 * by the Valve Corporation.  You must obey the GNU General Public License in
dvander@2168
    26
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
dvander@2168
    27
 * this exception to all derivative works.  AlliedModders LLC defines further
dvander@2168
    28
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
dvander@2168
    29
 * or <http://www.sourcemod.net/license.php>.
dvander@2168
    30
 *
dvander@2168
    31
 * Version: $Id$
dvander@2168
    32
 */
dvander@2168
    33
dvander@2168
    34
/* We like semicolons */
dvander@2168
    35
#pragma semicolon 1
dvander@2168
    36
dvander@2168
    37
#include <sourcemod>
dvander@2168
    38
dvander@2168
    39
public Plugin:myinfo = 
dvander@2168
    40
{
dvander@2168
    41
	name = "SQL Admins (Prefetch)",
dvander@2168
    42
	author = "AlliedModders LLC",
dvander@2168
    43
	description = "Reads all admins from SQL",
dvander@2168
    44
	version = SOURCEMOD_VERSION,
dvander@2168
    45
	url = "http://www.sourcemod.net/"
dvander@2168
    46
};
dvander@2168
    47
dvander@2168
    48
public OnRebuildAdminCache(AdminCachePart:part)
dvander@2168
    49
{
dvander@2168
    50
	/* First try to get a database connection */
dvander@2168
    51
	decl String:error[255];
dvander@2168
    52
	new Handle:db;
dvander@2168
    53
	
dvander@2168
    54
	if (SQL_CheckConfig("admins"))
dvander@2168
    55
	{
dvander@2168
    56
		db = SQL_Connect("admins", true, error, sizeof(error));
dvander@2168
    57
	} else {
dvander@2168
    58
		db = SQL_Connect("default", true, error, sizeof(error));
dvander@2168
    59
	}
dvander@2168
    60
	
dvander@2168
    61
	if (db == INVALID_HANDLE)
dvander@2168
    62
	{
dvander@2168
    63
		LogError("Could not connect to database \"default\": %s", error);
dvander@2168
    64
		return;
dvander@2168
    65
	}
dvander@2168
    66
	
dvander@2168
    67
	if (part == AdminCache_Overrides)
dvander@2168
    68
	{
dvander@2168
    69
		FetchOverrides(db);
dvander@2168
    70
	} else if (part == AdminCache_Groups) {
dvander@2168
    71
		FetchGroups(db);
dvander@2168
    72
	} else if (part == AdminCache_Admins) {
dvander@2168
    73
		FetchUsers(db);
dvander@2168
    74
	}
dvander@2168
    75
	
dvander@2168
    76
	CloseHandle(db);
dvander@2168
    77
}
dvander@2168
    78
dvander@2168
    79
FetchUserGroups(Handle:hQuery, AdminId:adm, id)
dvander@2168
    80
{
dvander@2168
    81
	SQL_BindParamInt(hQuery, 0, id);
dvander@2168
    82
	if (!SQL_Execute(hQuery))
dvander@2168
    83
	{
dvander@2168
    84
		decl String:error[255];
dvander@2168
    85
		SQL_GetError(hQuery, error, sizeof(error));
dvander@2168
    86
		LogError("FetchUserGroups() statement execute failed: %s", error);
dvander@2168
    87
		return;
dvander@2168
    88
	}
dvander@2168
    89
	
dvander@2168
    90
	decl String:name[80];
dvander@2168
    91
	new GroupId:gid;
dvander@2168
    92
	while (SQL_FetchRow(hQuery))
dvander@2168
    93
	{
dvander@2168
    94
		SQL_FetchString(hQuery, 0, name, sizeof(name));
dvander@2168
    95
		
dvander@2168
    96
		if ((gid = FindAdmGroup(name)) == INVALID_GROUP_ID)
dvander@2168
    97
		{
dvander@2168
    98
			/* Group wasn't found, don't bother with it.  */
dvander@2168
    99
			continue;
dvander@2168
   100
		}
dvander@2168
   101
		
dvander@2168
   102
		#if defined _DEBUG
dvander@2168
   103
		PrintToServer("Found admin group (%d, %d, %d)", id, gid, adm);
dvander@2168
   104
		#endif
dvander@2168
   105
		
dvander@2168
   106
		AdminInheritGroup(adm, gid);
dvander@2168
   107
	}
dvander@2168
   108
}
dvander@2168
   109
dvander@2168
   110
FetchUsers(Handle:db)
dvander@2168
   111
{
dvander@2168
   112
	decl String:query[255], String:error[255];
dvander@2168
   113
	new Handle:hQuery, Handle:hGroupQuery;
dvander@2168
   114
	
dvander@2168
   115
	Format(query, sizeof(query), "SELECT id, authtype, identity, password, flags, name, immunity FROM sm_admins");
dvander@2168
   116
	if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
dvander@2168
   117
	{
dvander@2168
   118
		SQL_GetError(db, error, sizeof(error));
dvander@2168
   119
		LogError("FetchUsers() query failed: %s", query);
dvander@2168
   120
		LogError("Query error: %s", error);
dvander@2168
   121
		return;
dvander@2168
   122
	}
dvander@2168
   123
	
dvander@2168
   124
	/* If this fails it's non-fatal */
dvander@2168
   125
	Format(query,
dvander@2168
   126
		sizeof(query), 
dvander@2168
   127
		"SELECT g.name FROM sm_admins_groups ag JOIN sm_groups g ON ag.group_id = g.id WHERE ag.admin_id = ? ORDER BY inherit_order ASC");
dvander@2168
   128
	if ((hGroupQuery = SQL_PrepareQuery(db, query, error, sizeof(error))) == INVALID_HANDLE)
dvander@2168
   129
	{
dvander@2168
   130
		LogError("FetchUsers() group query preparation failed: %s", query);
dvander@2168
   131
		LogError("Query error: %s", error);
dvander@2168
   132
	}
dvander@2168
   133
	
dvander@2168
   134
	decl String:authtype[16];
dvander@2168
   135
	decl String:identity[80];
dvander@2168
   136
	decl String:password[80];
dvander@2168
   137
	decl String:flags[32];
dvander@2168
   138
	decl String:name[80];
dvander@2168
   139
	new immunity;
dvander@2168
   140
	new AdminId:adm, id;
dvander@2168
   141
	
dvander@2168
   142
	while (SQL_FetchRow(hQuery))
dvander@2168
   143
	{
dvander@2168
   144
		id = SQL_FetchInt(hQuery, 0);
dvander@2168
   145
		SQL_FetchString(hQuery, 1, authtype, sizeof(authtype));
dvander@2168
   146
		SQL_FetchString(hQuery, 2, identity, sizeof(identity));
dvander@2168
   147
		SQL_FetchString(hQuery, 3, password, sizeof(password));
dvander@2168
   148
		SQL_FetchString(hQuery, 4, flags, sizeof(flags));
dvander@2168
   149
		SQL_FetchString(hQuery, 5, name, sizeof(name));
dvander@2168
   150
		immunity = SQL_FetchInt(hQuery, 6);
dvander@2168
   151
		
dvander@2168
   152
		/* Use a pre-existing admin if we can */
dvander@2168
   153
		if ((adm = FindAdminByIdentity(authtype, identity)) == INVALID_ADMIN_ID)
dvander@2168
   154
		{
dvander@2168
   155
			adm = CreateAdmin(name);
dvander@2168
   156
			if (!BindAdminIdentity(adm, authtype, identity))
dvander@2168
   157
			{
dvander@2168
   158
				LogError("Could not bind prefetched SQL admin (authtype \"%s\") (identity \"%s\")", authtype, identity);
dvander@2168
   159
				continue;
dvander@2168
   160
			}
dvander@2168
   161
		}
dvander@2168
   162
		
dvander@2168
   163
		#if defined _DEBUG
dvander@2168
   164
		PrintToServer("Found SQL admin (%d,%s,%s,%s,%s,%s,%d):%d", id, authtype, identity, password, flags, name, immunity, adm);
dvander@2168
   165
		#endif
dvander@2168
   166
		
dvander@2168
   167
		/* See if this admin wants a password */
dvander@2168
   168
		if (password[0] != '\0')
dvander@2168
   169
		{
dvander@2168
   170
			SetAdminPassword(adm, password);
dvander@2168
   171
		}
dvander@2168
   172
		
dvander@2168
   173
		/* Apply each flag */
dvander@2168
   174
		new len = strlen(flags);
dvander@2168
   175
		new AdminFlag:flag;
dvander@2168
   176
		for (new i=0; i<len; i++)
dvander@2168
   177
		{
dvander@2168
   178
			if (!FindFlagByChar(flags[i], flag))
dvander@2168
   179
			{
dvander@2168
   180
				continue;
dvander@2168
   181
			}
dvander@2168
   182
			SetAdminFlag(adm, flag, true);
dvander@2168
   183
		}
dvander@2168
   184
dvander@2168
   185
		SetAdminImmunityLevel(adm, immunity);
dvander@2168
   186
		
dvander@2168
   187
		/* Look up groups */
dvander@2168
   188
		if (hGroupQuery != INVALID_HANDLE)
dvander@2168
   189
		{
dvander@2168
   190
			FetchUserGroups(hGroupQuery, adm, id);
dvander@2168
   191
		}
dvander@2168
   192
	}
dvander@2168
   193
	
dvander@2168
   194
	CloseHandle(hGroupQuery);
dvander@2168
   195
	CloseHandle(hQuery);
dvander@2168
   196
}
dvander@2168
   197
dvander@2168
   198
FetchGroups(Handle:db)
dvander@2168
   199
{
dvander@2168
   200
	decl String:query[255];
dvander@2168
   201
	new Handle:hQuery;
dvander@2168
   202
	
dvander@2168
   203
	Format(query, sizeof(query), "SELECT flags, name, immunity_level FROM sm_groups");
dvander@2168
   204
dvander@2168
   205
	if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
dvander@2168
   206
	{
dvander@2168
   207
		decl String:error[255];
dvander@2168
   208
		SQL_GetError(db, error, sizeof(error));
dvander@2168
   209
		LogError("FetchGroups() query failed: %s", query);
dvander@2168
   210
		LogError("Query error: %s", error);
dvander@2168
   211
		return;
dvander@2168
   212
	}
dvander@2168
   213
	
dvander@2168
   214
	/* Now start fetching groups */
dvander@2168
   215
	decl String:flags[32];
dvander@2168
   216
	decl String:name[128];
dvander@2168
   217
	new immunity;
dvander@2168
   218
	while (SQL_FetchRow(hQuery))
dvander@2168
   219
	{
dvander@2168
   220
		SQL_FetchString(hQuery, 0, flags, sizeof(flags));
dvander@2168
   221
		SQL_FetchString(hQuery, 1, name, sizeof(name));
dvander@2168
   222
		immunity = SQL_FetchInt(hQuery, 2);
dvander@2168
   223
		
dvander@2168
   224
#if defined _DEBUG
dvander@2168
   225
		PrintToServer("Adding group (%d, %s, %s)", immunity, flags, name);
dvander@2168
   226
#endif
dvander@2168
   227
		
dvander@2168
   228
		/* Find or create the group */
dvander@2168
   229
		new GroupId:gid;
dvander@2168
   230
		if ((gid = FindAdmGroup(name)) == INVALID_GROUP_ID)
dvander@2168
   231
		{
dvander@2168
   232
			gid = CreateAdmGroup(name);
dvander@2168
   233
		}
dvander@2168
   234
		
dvander@2168
   235
		/* Add flags from the database to the group */
dvander@2168
   236
		new num_flag_chars = strlen(flags);
dvander@2168
   237
		for (new i=0; i<num_flag_chars; i++)
dvander@2168
   238
		{
dvander@2168
   239
			decl AdminFlag:flag;
dvander@2168
   240
			if (!FindFlagByChar(flags[i], flag))
dvander@2168
   241
			{
dvander@2168
   242
				continue;
dvander@2168
   243
			}
dvander@2168
   244
			SetAdmGroupAddFlag(gid, flag, true);
dvander@2168
   245
		}
dvander@2168
   246
		
dvander@2168
   247
		/* Set the immunity level this group has */
dvander@2168
   248
		SetAdmGroupImmunityLevel(gid, immunity);
dvander@2168
   249
	}
dvander@2168
   250
	
dvander@2168
   251
	CloseHandle(hQuery);
dvander@2168
   252
	
dvander@2168
   253
	/** 
dvander@2168
   254
	 * Get immunity in a big lump.  This is a nasty query but it gets the job done.
dvander@2168
   255
	 */
dvander@2168
   256
	new len = 0;
dvander@2168
   257
	len += Format(query[len], sizeof(query)-len, "SELECT g1.name, g2.name FROM sm_group_immunity gi");
dvander@2168
   258
	len += Format(query[len], sizeof(query)-len, " LEFT JOIN sm_groups g1 ON g1.id = gi.group_id ");
dvander@2168
   259
	len += Format(query[len], sizeof(query)-len, " LEFT JOIN sm_groups g2 ON g2.id = gi.other_id");
dvander@2168
   260
	
dvander@2168
   261
	if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
dvander@2168
   262
	{
dvander@2168
   263
		decl String:error[255];
dvander@2168
   264
		SQL_GetError(db, error, sizeof(error));
dvander@2168
   265
		LogError("FetchGroups() query failed: %s", query);
dvander@2168
   266
		LogError("Query error: %s", error);
dvander@2168
   267
		return;
dvander@2168
   268
	}
dvander@2168
   269
	
dvander@2168
   270
	while (SQL_FetchRow(hQuery))
dvander@2168
   271
	{
dvander@2168
   272
		decl String:group1[80];
dvander@2168
   273
		decl String:group2[80];
dvander@2168
   274
		new GroupId:gid1, GroupId:gid2;
dvander@2168
   275
		
dvander@2168
   276
		SQL_FetchString(hQuery, 0, group1, sizeof(group1));
dvander@2168
   277
		SQL_FetchString(hQuery, 1, group2, sizeof(group2));
dvander@2168
   278
		
dvander@2168
   279
		if (((gid1 = FindAdmGroup(group1)) == INVALID_GROUP_ID)
dvander@2168
   280
			|| (gid2 = FindAdmGroup(group2)) == INVALID_GROUP_ID)
dvander@2168
   281
		{
dvander@2168
   282
			continue;
dvander@2168
   283
		}
dvander@2168
   284
		
dvander@2168
   285
		SetAdmGroupImmuneFrom(gid1, gid2);
dvander@2168
   286
#if defined _DEBUG
dvander@2168
   287
		PrintToServer("SetAdmGroupImmuneFrom(%d, %d)", gid1, gid2);
dvander@2168
   288
#endif
dvander@2168
   289
	}
dvander@2168
   290
	
dvander@2168
   291
	CloseHandle(hQuery);
dvander@2168
   292
	
dvander@2168
   293
	/**
dvander@2168
   294
	 * Fetch overrides in a lump query.
dvander@2168
   295
	 */
dvander@2168
   296
	Format(query, sizeof(query), "SELECT g.name, go.type, go.name, go.access FROM sm_group_overrides go LEFT JOIN sm_groups g ON go.group_id = g.id");
dvander@2168
   297
	
dvander@2168
   298
	if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
dvander@2168
   299
	{
dvander@2168
   300
		decl String:error[255];
dvander@2168
   301
		SQL_GetError(db, error, sizeof(error));
dvander@2168
   302
		LogError("FetchGroups() query failed: %s", query);
dvander@2168
   303
		LogError("Query error: %s", error);
dvander@2168
   304
		return;
dvander@2168
   305
	}
dvander@2168
   306
	
dvander@2168
   307
	decl String:type[16];
dvander@2168
   308
	decl String:cmd[64];
dvander@2168
   309
	decl String:access[16];
dvander@2168
   310
	while (SQL_FetchRow(hQuery))
dvander@2168
   311
	{
dvander@2168
   312
		SQL_FetchString(hQuery, 0, name, sizeof(name));
dvander@2168
   313
		SQL_FetchString(hQuery, 1, type, sizeof(type));
dvander@2168
   314
		SQL_FetchString(hQuery, 2, cmd, sizeof(cmd));
dvander@2168
   315
		SQL_FetchString(hQuery, 3, access, sizeof(access));
dvander@2168
   316
		
dvander@2168
   317
		new GroupId:gid;
dvander@2168
   318
		if ((gid = FindAdmGroup(name)) == INVALID_GROUP_ID)
dvander@2168
   319
		{
dvander@2168
   320
			continue;
dvander@2168
   321
		}
dvander@2168
   322
				
dvander@2168
   323
		new OverrideType:o_type = Override_Command;
dvander@2168
   324
		if (StrEqual(type, "group"))
dvander@2168
   325
		{
dvander@2168
   326
			o_type = Override_CommandGroup;
dvander@2168
   327
		}
dvander@2168
   328
		
dvander@2168
   329
		new OverrideRule:o_rule = Command_Deny;
dvander@2168
   330
		if (StrEqual(access, "allow"))
dvander@2168
   331
		{
dvander@2168
   332
			o_rule = Command_Allow;
dvander@2168
   333
		}
dvander@2168
   334
				
dvander@2168
   335
		#if defined _DEBUG
dvander@2168
   336
		PrintToServer("AddAdmGroupCmdOverride(%d, %s, %d, %d)", gid, cmd, o_type, o_rule);
dvander@2168
   337
		#endif
dvander@2168
   338
		
dvander@2168
   339
		AddAdmGroupCmdOverride(gid, cmd, o_type, o_rule);
dvander@2168
   340
	}
dvander@2168
   341
	
dvander@2168
   342
	CloseHandle(hQuery);
dvander@2168
   343
}
dvander@2168
   344
dvander@2168
   345
FetchOverrides(Handle:db)
dvander@2168
   346
{
dvander@2168
   347
	decl String:query[255];
dvander@2168
   348
	new Handle:hQuery;
dvander@2168
   349
	
dvander@2168
   350
	Format(query, sizeof(query), "SELECT type, name, flags FROM sm_overrides");
dvander@2168
   351
dvander@2168
   352
	if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
dvander@2168
   353
	{
dvander@2168
   354
		decl String:error[255];
dvander@2168
   355
		SQL_GetError(db, error, sizeof(error));
dvander@2168
   356
		LogError("FetchOverrides() query failed: %s", query);
dvander@2168
   357
		LogError("Query error: %s", error);
dvander@2168
   358
		return;
dvander@2168
   359
	}
dvander@2168
   360
	
dvander@2168
   361
	decl String:type[64];
dvander@2168
   362
	decl String:name[64];
dvander@2168
   363
	decl String:flags[32];
dvander@2168
   364
	new flag_bits;
dvander@2168
   365
	while (SQL_FetchRow(hQuery))
dvander@2168
   366
	{
dvander@2168
   367
		SQL_FetchString(hQuery, 0, type, sizeof(type));
dvander@2168
   368
		SQL_FetchString(hQuery, 1, name, sizeof(name));
dvander@2168
   369
		SQL_FetchString(hQuery, 2, flags, sizeof(flags));
dvander@2168
   370
		
dvander@2168
   371
#if defined _DEBUG
dvander@2168
   372
		PrintToServer("Adding override (%s, %s, %s)", type, name, flags);
dvander@2168
   373
#endif
dvander@2168
   374
		
dvander@2168
   375
		flag_bits = ReadFlagString(flags);
dvander@2168
   376
		if (StrEqual(type, "command"))
dvander@2168
   377
		{
dvander@2168
   378
			AddCommandOverride(name, Override_Command, flag_bits);
dvander@2168
   379
		} else if (StrEqual(type, "group")) {
dvander@2168
   380
			AddCommandOverride(name, Override_CommandGroup, flag_bits);
dvander@2168
   381
		}
dvander@2168
   382
	}
dvander@2168
   383
	
dvander@2168
   384
	CloseHandle(hQuery);
dvander@2168
   385
}
dvander@2168
   386