summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorM. Kristall <mkpdev@gmail.com>2007-09-25 06:44:19 +0000
committerM. Kristall <mkpdev@gmail.com>2007-09-25 06:44:19 +0000
commited1a89fccdb41810c4d634005a1b1b1ac8f40c8f (patch)
tree0f1886244fd7d39b79245e9fe44521044864c387
parent8534520221091bc0e6a5127b674de8c6a55d07a8 (diff)
* (bug 3307) use boundary checking to prevent potential buffer overflow
* (bug 2969) limit number of players to g_maxGameClients * use G_TeamCommand() for team vote messages
-rw-r--r--src/game/g_admin.c32
-rw-r--r--src/game/g_cmds.c101
-rw-r--r--src/game/g_local.h4
-rw-r--r--src/game/g_main.c10
4 files changed, 65 insertions, 82 deletions
diff --git a/src/game/g_admin.c b/src/game/g_admin.c
index 4200d3cb..cffefc54 100644
--- a/src/game/g_admin.c
+++ b/src/game/g_admin.c
@@ -699,7 +699,7 @@ static void admin_log( gentity_t *admin, char *cmd, int skiparg )
if( G_SayArgc() > 1 + skiparg )
{
G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- if( G_ClientNumbersFromString( name, pids ) == 1 )
+ if( G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) == 1 )
{
victim = &g_entities[ pids[ 0 ] ];
}
@@ -1603,7 +1603,7 @@ static qboolean admin_create_ban( gentity_t *ent,
qboolean G_admin_kick( gentity_t *ent, int skiparg )
{
- int pids[ MAX_CLIENTS ];
+ int pids[ MAX_CLIENTS ], found;
char name[ MAX_NAME_LENGTH ], *reason, err[ MAX_STRING_CHARS ];
int minargc;
gentity_t *vic;
@@ -1619,9 +1619,9 @@ qboolean G_admin_kick( gentity_t *ent, int skiparg )
}
G_SayArgv( 1 + skiparg, name, sizeof( name ) );
reason = G_SayConcatArgs( 2 + skiparg );
- if( G_ClientNumbersFromString( name, pids ) != 1 )
+ if( ( found = G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) ) != 1 )
{
- G_MatchOnePlayer( pids, err, sizeof( err ) );
+ G_MatchOnePlayer( pids, found, err, sizeof( err ) );
ADMP( va( "^3!kick: ^7%s\n", err ) );
return qfalse;
}
@@ -1902,7 +1902,7 @@ qboolean G_admin_unban( gentity_t *ent, int skiparg )
qboolean G_admin_putteam( gentity_t *ent, int skiparg )
{
- int pids[ MAX_CLIENTS ];
+ int pids[ MAX_CLIENTS ], found;
char name[ MAX_NAME_LENGTH ], team[ 7 ], err[ MAX_STRING_CHARS ];
gentity_t *vic;
pTeam_t teamnum = PTE_NONE;
@@ -1916,9 +1916,9 @@ qboolean G_admin_putteam( gentity_t *ent, int skiparg )
return qfalse;
}
- if( G_ClientNumbersFromString( name, pids ) != 1 )
+ if( ( found = G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) ) != 1 )
{
- G_MatchOnePlayer( pids, err, sizeof( err ) );
+ G_MatchOnePlayer( pids, found, err, sizeof( err ) );
ADMP( va( "^3!putteam: ^7%s\n", err ) );
return qfalse;
}
@@ -2001,7 +2001,7 @@ qboolean G_admin_map( gentity_t *ent, int skiparg )
qboolean G_admin_mute( gentity_t *ent, int skiparg )
{
- int pids[ MAX_CLIENTS ];
+ int pids[ MAX_CLIENTS ], found;
char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
char command[ MAX_ADMIN_CMD_LEN ], *cmd;
gentity_t *vic;
@@ -2016,9 +2016,9 @@ qboolean G_admin_mute( gentity_t *ent, int skiparg )
if( cmd && *cmd == '!' )
cmd++;
G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- if( G_ClientNumbersFromString( name, pids ) != 1 )
+ if( ( found = G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) ) != 1 )
{
- G_MatchOnePlayer( pids, err, sizeof( err ) );
+ G_MatchOnePlayer( pids, found, err, sizeof( err ) );
ADMP( va( "^3!mute: ^7%s\n", err ) );
return qfalse;
}
@@ -2061,7 +2061,7 @@ qboolean G_admin_mute( gentity_t *ent, int skiparg )
qboolean G_admin_denybuild( gentity_t *ent, int skiparg )
{
- int pids[ MAX_CLIENTS ];
+ int pids[ MAX_CLIENTS ], found;
char name[ MAX_NAME_LENGTH ], err[ MAX_STRING_CHARS ];
char command[ MAX_ADMIN_CMD_LEN ], *cmd;
gentity_t *vic;
@@ -2076,9 +2076,9 @@ qboolean G_admin_denybuild( gentity_t *ent, int skiparg )
return qfalse;
}
G_SayArgv( 1 + skiparg, name, sizeof( name ) );
- if( G_ClientNumbersFromString( name, pids ) != 1 )
+ if( ( found = G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) ) != 1 )
{
- G_MatchOnePlayer( pids, err, sizeof( err ) );
+ G_MatchOnePlayer( pids, found, err, sizeof( err ) );
ADMP( va( "^3!%s: ^7%s\n", cmd, err ) );
return qfalse;
}
@@ -2725,7 +2725,7 @@ qboolean G_admin_spec999( gentity_t *ent, int skiparg )
qboolean G_admin_rename( gentity_t *ent, int skiparg )
{
- int pids[ MAX_CLIENTS ];
+ int pids[ MAX_CLIENTS ], found;
char name[ MAX_NAME_LENGTH ];
char newname[ MAX_NAME_LENGTH ];
char oldname[ MAX_NAME_LENGTH ];
@@ -2742,9 +2742,9 @@ qboolean G_admin_rename( gentity_t *ent, int skiparg )
G_SayArgv( 1 + skiparg, name, sizeof( name ) );
s = G_SayConcatArgs( 2 + skiparg );
Q_strncpyz( newname, s, sizeof( newname ) );
- if( G_ClientNumbersFromString( name, pids ) != 1 )
+ if( ( found = G_ClientNumbersFromString( name, pids, MAX_CLIENTS ) ) != 1 )
{
- G_MatchOnePlayer( pids, err, sizeof( err ) );
+ G_MatchOnePlayer( pids, found, err, sizeof( err ) );
ADMP( va( "^3!rename: ^7%s\n", err ) );
return qfalse;
}
diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index dac9a9a5..4b82b9e8 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -126,41 +126,36 @@ G_MatchOnePlayer
This is a companion function to G_ClientNumbersFromString()
-returns qtrue if the int array plist only has one client id, false otherwise
-In the case of false, err will be populated with an error message.
+err will be populated with an error message.
==================
*/
-qboolean G_MatchOnePlayer( int *plist, char *err, int len )
+void G_MatchOnePlayer( int *plist, int num, char *err, int len )
{
gclient_t *cl;
- int *p;
+ int i;
char line[ MAX_NAME_LENGTH + 10 ] = {""};
err[ 0 ] = '\0';
- if( plist[ 0 ] == -1 )
+ if( num == 0 )
{
Q_strcat( err, len, "no connected player by that name or slot #" );
- return qfalse;
}
- if( plist[ 1 ] != -1 )
+ else if( num > 1 )
{
Q_strcat( err, len, "more than one player name matches. "
"be more specific or use the slot #:\n" );
- for( p = plist; *p != -1; p++ )
+ for( i = 0; i < num; i++ )
{
- cl = &level.clients[ *p ];
- if( cl->pers.connected == CON_CONNECTED )
- {
- Com_sprintf( line, sizeof( line ), "%2i - %s^7\n",
- *p, cl->pers.netname );
- if( strlen( err ) + strlen( line ) > len )
- break;
- Q_strcat( err, len, line );
- }
+ cl = &level.clients[ plist[ i ] ];
+ if( cl->pers.connected == CON_DISCONNECTED )
+ continue;
+ Com_sprintf( line, sizeof( line ), "%2i - %s^7\n",
+ plist[ i ], cl->pers.netname );
+ if( strlen( err ) + strlen( line ) > len )
+ break;
+ Q_strcat( err, len, line );
}
- return qfalse;
}
- return qtrue;
}
/*
@@ -168,40 +163,29 @@ qboolean G_MatchOnePlayer( int *plist, char *err, int len )
G_ClientNumbersFromString
Sets plist to an array of integers that represent client numbers that have
-names that are a partial match for s. List is terminated by a -1.
+names that are a partial match for s.
-Returns number of matching clientids.
+Returns number of matching clientids up to max.
==================
*/
-int G_ClientNumbersFromString( char *s, int *plist )
+int G_ClientNumbersFromString( char *s, int *plist, int max )
{
gclient_t *p;
int i, found = 0;
- char n2[ MAX_NAME_LENGTH ] = {""};
- char s2[ MAX_NAME_LENGTH ] = {""};
- qboolean is_slot = qtrue;
-
- *plist = -1;
+ char n2[ MAX_NAME_LENGTH ] = {""};
+ char s2[ MAX_NAME_LENGTH ] = {""};
// if a number is provided, it might be a slot #
- for( i = 0; i < (int)strlen( s ); i++ )
+ for( i = 0; s[ i ] && isdigit( s[ i ] ); i++ );
+ if( !s[ i ] )
{
- if( s[i] < '0' || s[i] > '9' )
- {
- is_slot = qfalse;
- break;
- }
- }
-
- if( is_slot ) {
i = atoi( s );
- if( i >= 0 && i < level.maxclients ) {
+ if( i >= 0 && i < level.maxclients )
+ {
p = &level.clients[ i ];
- if( p->pers.connected == CON_CONNECTED ||
- p->pers.connected == CON_CONNECTING )
+ if( p->pers.connected != CON_DISCONNECTED )
{
- *plist++ = i;
- *plist = -1;
+ *plist = i;
return 1;
}
}
@@ -213,11 +197,10 @@ int G_ClientNumbersFromString( char *s, int *plist )
G_SanitiseName( s, s2 );
if( strlen( s2 ) < 1 )
return 0;
- for( i = 0; i < level.maxclients; i++ )
+ for( i = 0; i < level.maxclients && found <= max; i++ )
{
p = &level.clients[ i ];
- if(p->pers.connected != CON_CONNECTED
- && p->pers.connected != CON_CONNECTING)
+ if( p->pers.connected == CON_DISCONNECTED )
{
continue;
}
@@ -228,7 +211,6 @@ int G_ClientNumbersFromString( char *s, int *plist )
found++;
}
}
- *plist = -1;
return found;
}
@@ -676,6 +658,14 @@ void Cmd_Team_f( gentity_t *ent )
if( !Q_stricmp( s, "spectate" ) )
team = PTE_NONE;
+ else if( !force && oldteam == PTE_NONE && g_maxGameClients.integer &&
+ level.numPlayingClients >= g_maxGameClients.integer )
+ {
+ trap_SendServerCommand( ent-g_entities, va( "print \"The maximum number of "
+ "playing clients has been reached (g_maxGameClients = %d)\n\"",
+ g_maxGameClients.integer ) );
+ return;
+ }
else if( !Q_stricmp( s, "aliens" ) )
{
if( level.alienTeamLocked )
@@ -1051,7 +1041,7 @@ void Cmd_CallVote_f( gentity_t *ent )
return;
}
- if( G_ClientNumbersFromString( arg2, clientNums ) == 1 )
+ if( G_ClientNumbersFromString( arg2, clientNums, MAX_CLIENTS ) == 1 )
{
// there was only one partial name match
clientNum = clientNums[ 0 ];
@@ -1281,7 +1271,7 @@ void Cmd_CallTeamVote_f( gentity_t *ent )
return;
}
- if( G_ClientNumbersFromString( arg2, clientNums ) == 1 )
+ if( G_ClientNumbersFromString( arg2, clientNums, MAX_CLIENTS ) == 1 )
{
// there was only one partial name match
clientNum = clientNums[ 0 ];
@@ -1393,15 +1383,8 @@ void Cmd_CallTeamVote_f( gentity_t *ent )
}
ent->client->pers.voteCount++;
- for( i = 0 ; i < level.maxclients ; i++ )
- {
- if( level.clients[ i ].pers.connected == CON_DISCONNECTED )
- continue;
-
- if( level.clients[ i ].ps.stats[ STAT_PTEAM ] == team )
- trap_SendServerCommand( i, va("print \"%s " S_COLOR_WHITE
- "called a team vote\n\"", ent->client->pers.netname ) );
- }
+ G_TeamCommand( team, va( "print \"%s " S_COLOR_WHITE "called a team vote\n\"",
+ ent->client->pers.netname ) );
// start the voting, the caller autoamtically votes yes
level.teamVoteTime[ cs_offset ] = level.time;
@@ -2593,7 +2576,7 @@ void Cmd_Follow_f( gentity_t *ent )
ent->client->sess.spectatorState == SPECTATOR_FOLLOW )
{
trap_Argv( 1, arg, sizeof( arg ) );
- if( G_ClientNumbersFromString( arg, pids ) == 1 )
+ if( G_ClientNumbersFromString( arg, pids, MAX_CLIENTS ) == 1 )
{
i = pids[ 0 ];
}
@@ -2758,7 +2741,7 @@ static void Cmd_Ignore_f( gentity_t *ent )
}
Q_strncpyz( name, ConcatArgs( 1 ), sizeof( name ) );
- matches = G_ClientNumbersFromString( name, pids );
+ matches = G_ClientNumbersFromString( name, pids, MAX_CLIENTS );
if( matches < 1 )
{
trap_SendServerCommand( ent-g_entities, va( "print \"[skipnotify]"
@@ -3102,7 +3085,7 @@ void G_PrivateMessage( gentity_t *ent )
G_SayArgv( 1+skipargs, name, sizeof( name ) );
msg = G_SayConcatArgs( 2+skipargs );
- pcount = G_ClientNumbersFromString( name, pids );
+ pcount = G_ClientNumbersFromString( name, pids, MAX_CLIENTS );
if( ent )
{
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 59e39eec..45f649d0 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -696,8 +696,8 @@ void Cmd_Score_f( gentity_t *ent );
void G_StopFollowing( gentity_t *ent );
qboolean G_FollowNewClient( gentity_t *ent, int dir );
void G_ToggleFollow( gentity_t *ent );
-qboolean G_MatchOnePlayer( int *plist, char *err, int len );
-int G_ClientNumbersFromString( char *s, int *plist );
+void G_MatchOnePlayer( int *plist, int num, char *err, int len );
+int G_ClientNumbersFromString( char *s, int *plist, int max );
int G_SayArgc( void );
qboolean G_SayArgv( int n, char *buffer, int bufferLength );
char *G_SayConcatArgs( int start );
diff --git a/src/game/g_main.c b/src/game/g_main.c
index 14986dbb..84209315 100644
--- a/src/game/g_main.c
+++ b/src/game/g_main.c
@@ -148,9 +148,10 @@ static cvarTable_t gameCvarTable[ ] =
// latched vars
{ &g_maxclients, "sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse },
- { &g_maxGameClients, "g_maxGameClients", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse },
// change anytime vars
+ { &g_maxGameClients, "g_maxGameClients", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse },
+
{ &g_timelimit, "timelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
{ &g_suddenDeathTime, "g_suddenDeathTime", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
@@ -2106,21 +2107,20 @@ void CheckTeamVote( int team )
if( level.time - level.teamVoteTime[ cs_offset ] >= VOTE_TIME )
{
- trap_SendServerCommand( -1, "print \"Team vote failed\n\"" );
+ G_TeamCommand( team, "print \"Team vote failed\n\"" );
}
else
{
if( level.teamVoteYes[ cs_offset ] > level.numteamVotingClients[ cs_offset ] / 2 )
{
// execute the command, then remove the vote
- trap_SendServerCommand( -1, "print \"Team vote passed\n\"" );
- //
+ G_TeamCommand( team, "print \"Team vote passed\n\"" );
trap_SendConsoleCommand( EXEC_APPEND, va( "%s\n", level.teamVoteString[ cs_offset ] ) );
}
else if( level.teamVoteNo[ cs_offset ] >= level.numteamVotingClients[ cs_offset ] / 2 )
{
// same behavior as a timeout
- trap_SendServerCommand( -1, "print \"Team vote failed\n\"" );
+ G_TeamCommand( team, "print \"Team vote failed\n\"" );
}
else
{