/*
===========
ClientConnect

Called when a player begins connecting to the server.
Called again for every map change or tournement restart.

The session information will be valid after exit.

Return NULL if the client should be allowed, otherwise return
a string with the reason for denial.

Otherwise, the client will be sent the current gamestate
and will eventually get to ClientBegin.

firstTime will be qtrue the very first time a client connects
to the server machine, but qfalse on map changes and tournement
restarts.
============
*/
char *ClientConnect( int clientNum, qboolean firstTime )
{
  char      *value;
  gclient_t *client;
  char      userinfo[ MAX_INFO_STRING ];
  gentity_t *ent;
  char      guid[ 33 ];
  char      reason[ MAX_STRING_CHARS ] = {""};

  ent = &g_entities[ clientNum ];
  client = &level.clients[ clientNum ];
  ent->client = client;
  memset( client, 0, sizeof( *client ) );

  trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );

  value = Info_ValueForKey( userinfo, "cl_guid" );
  Q_strncpyz( guid, value, sizeof( guid ) );

  // check for admin ban
  if( G_admin_ban_check( userinfo, reason, sizeof( reason ) ) )
  {
    return va( "%s", reason );
  }


  // IP filtering
  // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=500
  // recommanding PB based IP / GUID banning, the builtin system is pretty limited
  // check to see if they are on the banned IP list
  value = Info_ValueForKey( userinfo, "ip" );
  Q_strncpyz( client->pers.ip, value, sizeof( client->pers.ip ) );
  if( G_FilterPacket( value ) )
    return "You are banned from this server.";

  // check for a password
  value = Info_ValueForKey( userinfo, "password" );

  if( g_password.string[ 0 ] && Q_stricmp( g_password.string, "none" ) &&
      strcmp( g_password.string, value ) != 0 )
    return "Invalid password";

  // add guid to session so we don't have to keep parsing userinfo everywhere
  if( !guid[0] )
  {
    Q_strncpyz( client->pers.guid, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
      sizeof( client->pers.guid ) );
  }
  else
  {
    Q_strncpyz( client->pers.guid, guid, sizeof( client->pers.guid ) );
  }
  // check for local client
  if( !strcmp( client->pers.ip, "localhost" ) )
    client->pers.localClient = qtrue;
  client->pers.adminLevel = G_admin_level( ent );

  client->pers.connected = CON_CONNECTING;

  // read or initialize the session data
  if( firstTime || level.newSession )
    G_InitSessionData( client, userinfo );

  G_ReadSessionData( client );

  // get and distribute relevent paramters
  ClientUserinfoChanged( clientNum );
  G_LogPrintf( "ClientConnect: %i [%s] (%s) \"%s\"\n", clientNum,
   client->pers.ip, client->pers.guid, client->pers.netname );

  // don't do the "xxx connected" messages if they were caried over from previous level
  if( firstTime )
    trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " connected\n\"", client->pers.netname ) );

  // count current clients and rank for scoreboard
  CalculateRanks( );
  G_admin_namelog_update( client, qfalse );
  return NULL;
}
Ejemplo n.º 2
0
/*
===========
ClientConnect

Called when a player begins connecting to the server.
Called again for every map change or tournement restart.

The session information will be valid after exit.

Return NULL if the client should be allowed, otherwise return
a string with the reason for denial.

Otherwise, the client will be sent the current gamestate
and will eventually get to ClientBegin.

firstTime will be qtrue the very first time a client connects
to the server machine, but qfalse on map changes and tournement
restarts.
============
*/
char *ClientConnect( int clientNum, qboolean firstTime )
{
  char      *value;
  gclient_t *client;
  char      userinfo[ MAX_INFO_STRING ];
  gentity_t *ent;
  char      guid[ 33 ];
  char      ip[ 16 ] = {""};
  char      reason[ MAX_STRING_CHARS ] = {""};
  int       i;
  int       retval = 0;

  ent = &g_entities[ clientNum ];

  trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );

  value = Info_ValueForKey( userinfo, "cl_guid" );
  Q_strncpyz( guid, value, sizeof( guid ) );

  // check for admin ban
  if( G_admin_ban_check( userinfo, reason, sizeof( reason ) ) )
  {
    return va( "%s", reason );
  }


  // IP filtering
  // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=500
  // recommanding PB based IP / GUID banning, the builtin system is pretty limited
  // check to see if they are on the banned IP list
  value = Info_ValueForKey( userinfo, "ip" );
  i = 0;
  while( *value && i < sizeof( ip ) - 2 )
  {
    if( *value != '.' && ( *value < '0' || *value > '9' ) )
      break;
    ip[ i++ ] = *value;
    value++;
  }
  ip[ i ] = '\0';
  if( G_FilterPacket( value ) )
    return "You are banned from this server.";

  // check for a password
  value = Info_ValueForKey( userinfo, "password" );

  if( g_password.string[ 0 ] && Q_stricmp( g_password.string, "none" ) &&
      strcmp( g_password.string, value ) != 0 )
    return "Invalid password";

  // they can connect
  ent->client = level.clients + clientNum;
  client = ent->client;

  memset( client, 0, sizeof(*client) );

  // add guid to session so we don't have to keep parsing userinfo everywhere
  if( !guid[0] )
  {
    Q_strncpyz( client->pers.guid, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
      sizeof( client->pers.guid ) );
  }
  else
  {
    Q_strncpyz( client->pers.guid, guid, sizeof( client->pers.guid ) );
  }
  Q_strncpyz( client->pers.ip, ip, sizeof( client->pers.ip ) );
  client->pers.adminLevel = G_admin_level( ent );

  client->pers.connected = CON_CONNECTING;

  // read or initialize the session data
  if( firstTime || level.newSession )
    G_InitSessionData( client, userinfo );

  G_ReadSessionData( client );

  if( firstTime )
    client->pers.firstConnect = qtrue;
  else
    client->pers.firstConnect = qfalse;

  // get and distribute relevent paramters
  ClientUserinfoChanged( clientNum );
  
  G_admin_set_adminname( ent );
  
  if( g_decolourLogfiles.integer )
  {
   char    decoloured[ MAX_STRING_CHARS ] = "";   
   if( g_decolourLogfiles.integer == 1 )
   {
     Com_sprintf( decoloured, sizeof(decoloured), " (\"%s^7\")", client->pers.netname );
     G_DecolorString( decoloured, decoloured );
     G_LogPrintfColoured( "ClientConnect: %i [%s] (%s) \"%s^7\"%s\n", clientNum,
        client->pers.ip, client->pers.guid, client->pers.netname, decoloured );
   }
   else
   {
      G_LogPrintf( "ClientConnect: %i [%s] (%s) \"%s^7\"%s\n", clientNum,
          client->pers.ip, client->pers.guid, client->pers.netname, decoloured );
   }
  }
  else
  {
    G_LogPrintf( "ClientConnect: %i [%s] (%s) \"%s^7\"\n", clientNum,
      client->pers.ip, client->pers.guid, client->pers.netname );
  }
  
  if( client->pers.adminLevel )
  { 
     G_LogPrintf( "ClientAuth: %i [%s] \"%s^7\" authenticated to admin level %i using GUID %s (^7%s)\n", clientNum, client->pers.ip, client->pers.netname, client->pers.adminLevel, client->pers.guid, client->pers.adminName );
  }

  // don't do the "xxx connected" messages if they were caried over from previous level
	
	retval = G_admin_global_check(userinfo);
	if((retval & GLOBAL_FORCESPEC) ||
	   (retval & GLOBAL_MUTE) ||
	   (retval & GLOBAL_DENYBUILD)){trap_SendServerCommand( -1, va( "print \"^3!global: ^7%s^7 has restrictions\n\"", client->pers.netname ) );}
	else if(retval & GLOBAL_WHITELIST){trap_SendServerCommand( -1, va( "print \"^3!global: ^7%s^7 is whitelisted\n\"", client->pers.netname ) );}	
	if(retval & GLOBAL_FORCESPEC){client->pers.specd = qtrue;}
	if(retval & GLOBAL_MUTE){client->pers.muted = qtrue;}
	if(retval & GLOBAL_DENYBUILD){client->pers.denyBuild = qtrue;}
	
  if( firstTime )
    trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " connected\n\"", client->pers.netname ) );

  // count current clients and rank for scoreboard
  CalculateRanks( );
  G_admin_namelog_update( client, qfalse );
  

  // if this is after !restart keepteams or !restart switchteams, apply said selection
  if ( client->sess.restartTeam != PTE_NONE ) {
    G_ChangeTeam( ent, client->sess.restartTeam );
    client->sess.restartTeam = PTE_NONE;
  }

  
  return NULL;
}