2008-10-02 16:23:55 -05:00
/*
2009-02-04 12:42:26 +01:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2008-10-14 11:57:03 -05:00
*
2010-01-16 20:19:18 +03:00
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
2008-10-02 16:23:55 -05:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
2008-11-15 11:56:59 -06:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-02 16:23:55 -05:00
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
2008-11-15 11:56:59 -06:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-10-02 16:23:55 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/** \file
2008-10-14 11:57:03 -05:00
\ingroup Trinityd
2008-10-02 16:23:55 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
#include "Common.h"
2009-06-04 21:41:07 +02:00
#include "Config/ConfigEnv.h"
2008-10-02 16:23:55 -05:00
#include "Database/DatabaseEnv.h"
2009-06-04 21:41:07 +02:00
#include "AccountMgr.h"
2008-10-02 16:23:55 -05:00
#include "Log.h"
#include "RASocket.h"
#include "Util.h"
2009-06-04 21:41:07 +02:00
#include "World.h"
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// \todo Make this thread safe if in the future 2 admins should be able to log at the same time.
SOCKET r ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
#define dropclient {Sendf("I'm busy right now, come back later."); \
SetCloseAndDelete(); \
return; \
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint32 iSession = 0 ; ///< Session number (incremented each time a new connection is made)
unsigned int iUsers = 0 ; ///< Number of active administrators
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
typedef int ( * pPrintf )( const char * ,...);
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
void ParseCommand ( CliCommandHolder :: Print * , char * command );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// RASocket constructor
RASocket :: RASocket ( ISocketHandler & h ) : TcpSocket ( h )
{
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Increment the session number
iSess = iSession ++ ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Get the config parameters
bSecure = sConfig . GetBoolDefault ( "RA.Secure" , true );
iMinLevel = sConfig . GetIntDefault ( "RA.MinLevel" , 3 );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Initialize buffer and data
iInputLength = 0 ;
buff = new char [ RA_BUFF_SIZE ];
stage = NONE ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// RASocket destructor
RASocket ::~ RASocket ()
{
///- Delete buffer and decrease active admins count
delete [] buff ;
2009-10-17 15:51:44 -07:00
2009-03-20 22:17:39 +01:00
sLog . outRemote ( "Connection was closed. \n " );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if ( stage == OK )
iUsers -- ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Accept an incoming connection
void RASocket :: OnAccept ()
{
std :: string ss = GetRemoteAddress ();
2009-03-20 22:17:39 +01:00
sLog . outRemote ( "Incoming connection from %s. \n " , ss . c_str ());
2008-10-02 16:23:55 -05:00
///- If there is already an active admin, drop the connection
if ( iUsers )
dropclient
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Else print Motd
Sendf ( "%s \r\n " , sWorld . GetMotd ());
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Read data from the network
void RASocket :: OnRead ()
{
///- Read data and check input length
TcpSocket :: OnRead ();
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
unsigned int sz = ibuf . GetLength ();
if ( iInputLength + sz >= RA_BUFF_SIZE )
{
2009-03-20 22:17:39 +01:00
sLog . outRemote ( "Input buffer overflow, possible DOS attack. \n " );
2008-10-02 16:23:55 -05:00
SetCloseAndDelete ();
return ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- If there is already an active admin (other than you), drop the connection
if ( stage != OK && iUsers )
dropclient
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
char * inp = new char [ sz + 1 ];
ibuf . Read ( inp , sz );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// \todo Can somebody explain this 'Linux bugfix'?
if ( stage == NONE )
if ( sz > 4 ) //linux remote telnet
if ( memcmp ( inp , "USER " , 5 ))
{
delete [] inp ; return ;
printf ( "lin bugfix" );
} //linux bugfix
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Discard data after line break or line feed
bool gotenter = false ;
unsigned int y = 0 ;
2009-10-17 16:20:24 -07:00
for (; y < sz ; y ++ )
2008-10-02 16:23:55 -05:00
if ( inp [ y ] == '\r' || inp [ y ] == '\n' )
{
gotenter = true ;
break ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//No buffer overflow (checked above)
memcpy ( & buff [ iInputLength ], inp , y );
iInputLength += y ;
delete [] inp ;
if ( gotenter )
{
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
buff [ iInputLength ] = 0 ;
iInputLength = 0 ;
switch ( stage )
{
/// <ul> <li> If the input is 'USER <username>'
case NONE :
if ( ! memcmp ( buff , "USER " , 5 )) //got "USER" cmd
{
szLogin =& buff [ 5 ];
2009-10-17 15:51:44 -07:00
2009-12-21 21:08:29 -06:00
///- Get the password from the account table
2008-10-02 16:23:55 -05:00
std :: string login = szLogin ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Convert Account name to Upper Format
2009-05-21 19:06:09 +02:00
AccountMgr :: normalizeString ( login );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Escape the Login to allow quotes in names
2009-07-31 11:29:28 +08:00
loginDatabase . escape_string ( login );
2009-10-17 15:51:44 -07:00
2010-01-23 14:45:58 +01:00
QueryResult_AutoPtr result = loginDatabase . PQuery ( "SELECT a.id, aa.gmlevel, aa.RealmID FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = '%s'" , login . c_str ());
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- If the user is not found, deny access
if ( ! result )
{
Sendf ( "-No such user. \r\n " );
2009-03-20 22:17:39 +01:00
sLog . outRemote ( "User %s does not exist. \n " , szLogin . c_str ());
2008-10-02 16:23:55 -05:00
if ( bSecure ) SetCloseAndDelete ();
}
else
{
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//szPass=fields[0].GetString();
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- if gmlevel is too low, deny access
2009-12-23 00:36:28 -03:00
if ( fields [ 1 ]. GetUInt32 () < iMinLevel || fields [ 1 ]. GetUInt32 () == NULL )
2008-10-02 16:23:55 -05:00
{
Sendf ( "-Not enough privileges. \r\n " );
2009-03-20 22:17:39 +01:00
sLog . outRemote ( "User %s has no privilege. \n " , szLogin . c_str ());
2008-10-02 16:23:55 -05:00
if ( bSecure ) SetCloseAndDelete ();
2009-12-25 11:43:39 +01:00
}
else if ( fields [ 2 ]. GetInt32 () != - 1 )
2009-12-22 22:27:15 -06:00
{
///- if RealmID isn't -1, deny access
Sendf ( "-Not enough privileges. \r\n " );
sLog . outRemote ( "User %s has to be assigned on all realms (with RealmID = '-1'). \n " , szLogin . c_str ());
if ( bSecure ) SetCloseAndDelete ();
2009-12-25 11:43:39 +01:00
}
else
2008-10-02 16:23:55 -05:00
{
stage = LG ;
}
}
}
break ;
///<li> If the input is 'PASS <password>' (and the user already gave his username)
case LG :
if ( ! memcmp ( buff , "PASS " , 5 )) //got "PASS" cmd
{ //login+pass ok
///- If password is correct, increment the number of active administrators
std :: string login = szLogin ;
std :: string pw = & buff [ 5 ];
2009-10-17 15:51:44 -07:00
2009-05-21 19:06:09 +02:00
AccountMgr :: normalizeString ( login );
AccountMgr :: normalizeString ( pw );
2009-07-31 11:29:28 +08:00
loginDatabase . escape_string ( login );
loginDatabase . escape_string ( pw );
2009-10-17 15:51:44 -07:00
2010-01-23 14:45:58 +01:00
QueryResult_AutoPtr check = loginDatabase . PQuery (
2009-07-26 16:59:11 +02:00
"SELECT 1 FROM account WHERE username = '%s' AND sha_pass_hash=SHA1(CONCAT('%s',':','%s'))" ,
login . c_str (), login . c_str (), pw . c_str ());
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if ( check )
{
r = GetSocket ();
stage = OK ;
++ iUsers ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
Sendf ( "+Logged in. \r\n " );
2009-03-20 22:17:39 +01:00
sLog . outRemote ( "User %s has logged in. \n " , szLogin . c_str ());
2008-10-12 17:35:16 -05:00
Sendf ( "TC>" );
2008-10-02 16:23:55 -05:00
}
else
{
///- Else deny access
Sendf ( "-Wrong pass. \r\n " );
2009-03-20 22:17:39 +01:00
sLog . outRemote ( "User %s has failed to log in. \n " , szLogin . c_str ());
2008-10-02 16:23:55 -05:00
if ( bSecure ) SetCloseAndDelete ();
}
}
break ;
///<li> If user is logged, parse and execute the command
case OK :
if ( strlen ( buff ))
{
2009-03-20 22:17:39 +01:00
sLog . outRemote ( "Got '%s' cmd. \n " , buff );
2008-10-26 13:32:42 -05:00
sWorld . QueueCliCommand ( & RASocket :: zprint , buff );
2008-10-02 16:23:55 -05:00
}
else
2008-10-12 17:35:16 -05:00
Sendf ( "TC>" );
2008-10-02 16:23:55 -05:00
break ;
///</ul>
};
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Output function
2008-10-26 13:32:42 -05:00
void RASocket :: zprint ( const char * szText )
2008-10-02 16:23:55 -05:00
{
2008-10-26 13:32:42 -05:00
if ( ! szText )
return ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
#ifdef RA_CRYPT
2009-10-17 15:51:44 -07:00
2008-11-15 11:56:59 -06:00
char * megabuffer = strdup ( szText );
2008-10-26 13:32:42 -05:00
unsigned int sz = strlen ( megabuffer );
Encrypt ( megabuffer , sz );
2008-11-15 11:56:59 -06:00
send ( r , megabuffer , sz , 0 );
2008-10-02 16:23:55 -05:00
delete [] megabuffer ;
2009-10-17 15:51:44 -07:00
2008-11-15 11:56:59 -06:00
#else
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
unsigned int sz = strlen ( szText );
send ( r , szText , sz , 0 );
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
#endif
2008-10-02 16:23:55 -05:00
}