View Single Post
Old 26/02/2012, 07:29 PM   #2141
Beta Tester
JernejL's Avatar
Join Date: Jan 2006
Location: Slovenia
Posts: 580
Reputation: 418
Default Re: [REL] MySQL Plugin (R7 - 25/02/12)

Ok, ANOTHER example of using cache response the proper way.

This not only uses the cache, but also shows how to SECURE your server against a race condition attack - each query ran for a player can return later when another player gets the same slot - but how do we know the result is for the correct player (and not just the player slot)?

Well, like this:

pawn Code:
#define checkcinc if (!IsPlayerConnected(PlayerID)) return; if (CINC[PlayerID] != ccinc) { printf("error: query collision, result for player %s (%d) is not for this player. (got: %d should be: %d)", pNickname[PlayerID], PlayerID, ccinc, CINC[PlayerID]); return; }

    #define mysql_counted_query queryballance++;mysql_function_query


    new queryballance; // counts number of queries in the queue.

OnPlayerConnect(playerid) {
    CINC[playerid]++; // invalidate all that came before

OnPlayerDisconnect(playerid) {
    CINC[playerid]++; // invalidate all responses from now on (we might still wish to act on some until next player reuses this slot) this also prevents incorrectly handling responses when there is no player using the slot.

forward OS_ADMINLIST(PlayerID, ccinc);
public OS_ADMINLIST(PlayerID, ccinc) {
    static admintextlist[1000];
    new ResBuffer[1024];
    admintextlist = "LVL\tName\n";
    new rows, fields; cache_get_data(rows, fields);
    for (new i = 0; i < rows; i++) {
        cache_get_field_content(i, "admintxt", ResBuffer, dbhandle);
        strcat(admintextlist, ResBuffer, sizeof(admintextlist));
        strcat(admintextlist, "\n", sizeof(admintextlist));
    ShowPlayerDialog(PlayerID, dialog_action_do_nothing, DIALOG_STYLE_MSGBOX, "Admin list (Last 14 days)", admintextlist, "Ok", "");

stock listadmins(PlayerID) {
// list all admins active during last 2 months.
    new sql[510] = "SELECT concat(cast(a.adminlevel as char), '\t', a.nickname) as admintxt FROM account a where a.adminlevel > 1 and datediff(now(), a.modified) < 14 order by a.adminlevel desc, a.modified desc";
    mysql_counted_query(dbhandle, sql, true, "OS_ADMINLIST", "ii", PlayerID, CINC[PlayerID]);

So.. if this wasn't secured in this way, a admin could run cmd to get the admin list, disconnect and another player after getting same slot id would get the admin list shown on screen if the player had lucky timing or the database has been lagged due to a deliberate attack or another cause.
Please, do no message me anymore, i'm no longer part of sa-mp scene.

I will not reply to private messages.
JernejL is offline   Reply With Quote