Core/RA: Calculate password hash internally instead of sending plaintext password to mysql.

Convert tabs to spaces.

--HG--
branch : trunk
This commit is contained in:
Machiavelli
2010-12-10 09:02:59 +01:00
parent e3c68e4ada
commit 4f468f9552
3 changed files with 221 additions and 218 deletions
@@ -35,59 +35,59 @@
RARunnable::RARunnable() : m_Reactor(NULL) RARunnable::RARunnable() : m_Reactor(NULL)
{ {
ACE_Reactor_Impl* imp = 0; ACE_Reactor_Impl* imp = 0;
#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) #if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL)
imp = new ACE_Dev_Poll_Reactor(); imp = new ACE_Dev_Poll_Reactor();
imp->max_notify_iterations (128); imp->max_notify_iterations (128);
imp->restart (1); imp->restart (1);
#else #else
imp = new ACE_TP_Reactor(); imp = new ACE_TP_Reactor();
imp->max_notify_iterations (128); imp->max_notify_iterations (128);
#endif #endif
m_Reactor = new ACE_Reactor (imp, 1); m_Reactor = new ACE_Reactor (imp, 1);
} }
RARunnable::~RARunnable() RARunnable::~RARunnable()
{ {
delete m_Reactor; delete m_Reactor;
} }
void RARunnable::run() void RARunnable::run()
{ {
if (!sConfig.GetBoolDefault("Ra.Enable", false)) if (!sConfig.GetBoolDefault("Ra.Enable", false))
return; return;
ACE_Acceptor<RASocket, ACE_SOCK_ACCEPTOR> acceptor; ACE_Acceptor<RASocket, ACE_SOCK_ACCEPTOR> acceptor;
uint16 raport = sConfig.GetIntDefault("Ra.Port", 3443); uint16 raport = sConfig.GetIntDefault("Ra.Port", 3443);
std::string stringip = sConfig.GetStringDefault("Ra.IP", "0.0.0.0"); std::string stringip = sConfig.GetStringDefault("Ra.IP", "0.0.0.0");
ACE_INET_Addr listen_addr(raport, stringip.c_str()); ACE_INET_Addr listen_addr(raport, stringip.c_str());
if (acceptor.open(listen_addr, m_Reactor) == -1) if (acceptor.open(listen_addr, m_Reactor) == -1)
{ {
sLog.outError("Trinity RA can not bind to port %d on %s", raport, stringip.c_str()); sLog.outError("Trinity RA can not bind to port %d on %s", raport, stringip.c_str());
return; return;
} }
sLog.outString("Starting Trinity RA on port %d on %s", raport, stringip.c_str()); sLog.outString("Starting Trinity RA on port %d on %s", raport, stringip.c_str());
while (!World::IsStopped()) while (!World::IsStopped())
{ {
// don't be too smart to move this outside the loop // don't be too smart to move this outside the loop
// the run_reactor_event_loop will modify interval // the run_reactor_event_loop will modify interval
ACE_Time_Value interval(0, 100000); ACE_Time_Value interval(0, 100000);
if (m_Reactor->run_reactor_event_loop(interval) == -1) if (m_Reactor->run_reactor_event_loop(interval) == -1)
break; break;
} }
sLog.outStaticDebug("Trinity RA thread exiting"); sLog.outStaticDebug("Trinity RA thread exiting");
} }
@@ -34,7 +34,7 @@ public:
void run(); void run();
private: private:
ACE_Reactor* m_Reactor; ACE_Reactor* m_Reactor;
}; };
+191 -188
View File
@@ -28,10 +28,11 @@
#include "RASocket.h" #include "RASocket.h"
#include "Util.h" #include "Util.h"
#include "World.h" #include "World.h"
#include "SHA1.h"
RASocket::RASocket() RASocket::RASocket()
{ {
iMinLevel = sConfig.GetIntDefault("RA.MinLevel", 3); iMinLevel = sConfig.GetIntDefault("RA.MinLevel", 3);
} }
RASocket::~RASocket() RASocket::~RASocket()
@@ -40,289 +41,291 @@ RASocket::~RASocket()
int RASocket::open(void *) int RASocket::open(void *)
{ {
ACE_INET_Addr remote_addr; ACE_INET_Addr remote_addr;
if (peer().get_remote_addr(remote_addr) == -1) if (peer().get_remote_addr(remote_addr) == -1)
{ {
sLog.outError("RASocket::open: peer().get_remote_addr error is %s", ACE_OS::strerror(errno)); sLog.outError("RASocket::open: peer().get_remote_addr error is %s", ACE_OS::strerror(errno));
return -1; return -1;
} }
sLog.outRemote("Incoming connection from %s", remote_addr.get_host_addr()); sLog.outRemote("Incoming connection from %s", remote_addr.get_host_addr());
return activate(); return activate();
} }
int RASocket::handle_close(ACE_HANDLE, ACE_Reactor_Mask) int RASocket::handle_close(ACE_HANDLE, ACE_Reactor_Mask)
{ {
sLog.outRemote("Closing connection"); sLog.outRemote("Closing connection");
peer().close_reader(); peer().close_reader();
wait(); wait();
destroy(); destroy();
return 0; return 0;
} }
int RASocket::send(const std::string& line) int RASocket::send(const std::string& line)
{ {
return peer().send(line.c_str(), line.length()) == line.length() ? 0 : -1; return peer().send(line.c_str(), line.length()) == line.length() ? 0 : -1;
} }
int RASocket::recv_line(ACE_Message_Block& buffer) int RASocket::recv_line(ACE_Message_Block& buffer)
{ {
char byte; char byte;
for (;;) for (;;)
{ {
ssize_t n = peer().recv(&byte, sizeof(byte)); ssize_t n = peer().recv(&byte, sizeof(byte));
if (n < 0) if (n < 0)
{ {
return -1; return -1;
} }
if (n == 0) if (n == 0)
{ {
// EOF, connection was closed // EOF, connection was closed
errno = ECONNRESET; errno = ECONNRESET;
return -1; return -1;
} }
ACE_ASSERT(n == sizeof(byte)); ACE_ASSERT(n == sizeof(byte));
if (byte == '\n') if (byte == '\n')
break; break;
else if (byte == '\r') /* Ignore CR */ else if (byte == '\r') /* Ignore CR */
continue; continue;
else if (buffer.copy(&byte, sizeof(byte)) == -1) else if (buffer.copy(&byte, sizeof(byte)) == -1)
return -1; return -1;
} }
const char null_term = '\0'; const char null_term = '\0';
if (buffer.copy(&null_term, sizeof(null_term)) == -1) if (buffer.copy(&null_term, sizeof(null_term)) == -1)
return -1; return -1;
return 0; return 0;
} }
int RASocket::recv_line(std::string& out_line) int RASocket::recv_line(std::string& out_line)
{ {
char buf[4096]; char buf[4096];
ACE_Data_Block db(sizeof (buf), ACE_Data_Block db(sizeof (buf),
ACE_Message_Block::MB_DATA, ACE_Message_Block::MB_DATA,
buf, buf,
0, 0,
0, 0,
ACE_Message_Block::DONT_DELETE, ACE_Message_Block::DONT_DELETE,
0); 0);
ACE_Message_Block message_block(&db, ACE_Message_Block message_block(&db,
ACE_Message_Block::DONT_DELETE, ACE_Message_Block::DONT_DELETE,
0); 0);
if (recv_line(message_block) == -1) if (recv_line(message_block) == -1)
{ {
sLog.outRemote("Recv error %s", ACE_OS::strerror(errno)); sLog.outRemote("Recv error %s", ACE_OS::strerror(errno));
return -1; return -1;
} }
out_line = message_block.rd_ptr(); out_line = message_block.rd_ptr();
return 0; return 0;
} }
int RASocket::process_command(const std::string& command) int RASocket::process_command(const std::string& command)
{ {
if (command.length() == 0) if (command.length() == 0)
return 0; return 0;
sLog.outRemote("Got command: %s", command.c_str()); sLog.outRemote("Got command: %s", command.c_str());
// handle quit, exit and logout commands to terminate connection // handle quit, exit and logout commands to terminate connection
if (command == "quit" || command == "exit" || command == "logout") { if (command == "quit" || command == "exit" || command == "logout") {
(void) send("Bye\r\n"); (void) send("Bye\r\n");
return -1; return -1;
} }
CliCommandHolder* cmd = new CliCommandHolder(this, command.c_str(), &RASocket::zprint, &RASocket::commandFinished); CliCommandHolder* cmd = new CliCommandHolder(this, command.c_str(), &RASocket::zprint, &RASocket::commandFinished);
sWorld.QueueCliCommand(cmd); sWorld.QueueCliCommand(cmd);
// wait for result // wait for result
ACE_Message_Block* mb; ACE_Message_Block* mb;
for (;;) for (;;)
{ {
if (getq(mb) == -1) if (getq(mb) == -1)
return -1; return -1;
if (mb->msg_type() == ACE_Message_Block::MB_BREAK) if (mb->msg_type() == ACE_Message_Block::MB_BREAK)
{ {
mb->release(); mb->release();
break; break;
} }
if (peer().send(mb->rd_ptr(), mb->length()) != mb->length()) if (peer().send(mb->rd_ptr(), mb->length()) != mb->length())
{ {
mb->release(); mb->release();
return -1; return -1;
} }
mb->release(); mb->release();
} }
return 0; return 0;
} }
int RASocket::check_access_level(const std::string& user) int RASocket::check_access_level(const std::string& user)
{ {
std::string safe_user = user; std::string safe_user = user;
AccountMgr::normalizeString(safe_user); AccountMgr::normalizeString(safe_user);
LoginDatabase.escape_string(safe_user); LoginDatabase.escape_string(safe_user);
QueryResult 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'", safe_user.c_str()); QueryResult 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'", safe_user.c_str());
if (!result) if (!result)
{ {
sLog.outRemote("User %s does not exist in database", user.c_str()); sLog.outRemote("User %s does not exist in database", user.c_str());
return -1; return -1;
} }
Field *fields = result->Fetch(); Field *fields = result->Fetch();
if (fields[1].GetUInt32() < iMinLevel) if (fields[1].GetUInt32() < iMinLevel)
{ {
sLog.outRemote("User %s has no privilege to login", user.c_str()); sLog.outRemote("User %s has no privilege to login", user.c_str());
return -1; return -1;
} }
else if (fields[2].GetInt32() != -1) else if (fields[2].GetInt32() != -1)
{ {
sLog.outRemote("User %s has to be assigned on all realms (with RealmID = '-1')", user.c_str()); sLog.outRemote("User %s has to be assigned on all realms (with RealmID = '-1')", user.c_str());
return -1; return -1;
} }
return 0; return 0;
} }
int RASocket::check_password(const std::string& user, const std::string& pass) int RASocket::check_password(const std::string& user, const std::string& pass)
{ {
std::string safe_user = user; std::string safe_user = user;
AccountMgr::normalizeString(safe_user); AccountMgr::normalizeString(safe_user);
LoginDatabase.escape_string(safe_user); LoginDatabase.escape_string(safe_user);
std::string safe_pass = pass; std::string safe_pass = pass;
AccountMgr::normalizeString(safe_pass); AccountMgr::normalizeString(safe_pass);
LoginDatabase.escape_string(safe_pass); LoginDatabase.escape_string(safe_pass);
QueryResult check = LoginDatabase.PQuery( std::string hash = sAccountMgr.CalculateShaPassHash(safe_user, safe_pass);
"SELECT 1 FROM account WHERE username = '%s' AND sha_pass_hash=SHA1(CONCAT('%s',':','%s'))",
safe_user.c_str(), safe_user.c_str(), safe_pass.c_str());
if (!check) QueryResult check = LoginDatabase.PQuery(
{ "SELECT 1 FROM account WHERE username = '%s' AND sha_pass_hash = '%s'",
sLog.outRemote("Wrong password for user: %s", user.c_str()); safe_user.c_str(), hash.c_str());
return -1;
}
return 0; if (!check)
{
sLog.outRemote("Wrong password for user: %s", user.c_str());
return -1;
}
return 0;
} }
int RASocket::authenticate() int RASocket::authenticate()
{ {
if (send(std::string("Username: ")) == -1) if (send(std::string("Username: ")) == -1)
return -1; return -1;
std::string user; std::string user;
if (recv_line(user) == -1) if (recv_line(user) == -1)
return -1; return -1;
if (send(std::string("Password: ")) == -1) if (send(std::string("Password: ")) == -1)
return -1; return -1;
std::string pass; std::string pass;
if (recv_line(pass) == -1) if (recv_line(pass) == -1)
return -1; return -1;
sLog.outRemote("Login attempt for user: %s", user.c_str()); sLog.outRemote("Login attempt for user: %s", user.c_str());
if (check_access_level(user) == -1) if (check_access_level(user) == -1)
return -1; return -1;
if (check_password(user, pass) == -1) if (check_password(user, pass) == -1)
return -1; return -1;
sLog.outRemote("User login: %s", user.c_str()); sLog.outRemote("User login: %s", user.c_str());
return 0; return 0;
} }
int RASocket::svc(void) int RASocket::svc(void)
{ {
if (send("Authentication required\r\n") == -1) if (send("Authentication required\r\n") == -1)
return -1; return -1;
if (authenticate() == -1) if (authenticate() == -1)
{ {
(void) send("Authentication failed\r\n"); (void) send("Authentication failed\r\n");
return -1; return -1;
} }
// send motd // send motd
if (send(std::string(sWorld.GetMotd()) + "\r\n") == -1) if (send(std::string(sWorld.GetMotd()) + "\r\n") == -1)
return -1; return -1;
for(;;) for(;;)
{ {
// show prompt // show prompt
const char* tc_prompt = "TC> "; const char* tc_prompt = "TC> ";
if (peer().send(tc_prompt, strlen(tc_prompt)) != strlen(tc_prompt)) if (peer().send(tc_prompt, strlen(tc_prompt)) != strlen(tc_prompt))
return -1; return -1;
std::string line; std::string line;
if (recv_line(line) == -1) if (recv_line(line) == -1)
return -1; return -1;
if (process_command(line) == -1) if (process_command(line) == -1)
return -1; return -1;
} }
return 0; return 0;
} }
void RASocket::zprint(void* callbackArg, const char * szText) void RASocket::zprint(void* callbackArg, const char * szText)
{ {
if (!szText || !callbackArg) if (!szText || !callbackArg)
return; return;
RASocket* socket = static_cast<RASocket*>(callbackArg); RASocket* socket = static_cast<RASocket*>(callbackArg);
size_t sz = strlen(szText); size_t sz = strlen(szText);
ACE_Message_Block* mb = new ACE_Message_Block(sz); ACE_Message_Block* mb = new ACE_Message_Block(sz);
mb->copy(szText, sz); mb->copy(szText, sz);
if (socket->putq(mb, const_cast<ACE_Time_Value*>(&ACE_Time_Value::zero)) == -1) if (socket->putq(mb, const_cast<ACE_Time_Value*>(&ACE_Time_Value::zero)) == -1)
{ {
sLog.outRemote("Failed to enqueue message, queue is full or closed. Error is %s", ACE_OS::strerror(errno)); sLog.outRemote("Failed to enqueue message, queue is full or closed. Error is %s", ACE_OS::strerror(errno));
mb->release(); mb->release();
} }
} }
void RASocket::commandFinished(void* callbackArg, bool /*success*/) void RASocket::commandFinished(void* callbackArg, bool /*success*/)
{ {
if (!callbackArg) if (!callbackArg)
return; return;
RASocket* socket = static_cast<RASocket*>(callbackArg); RASocket* socket = static_cast<RASocket*>(callbackArg);
ACE_Message_Block* mb = new ACE_Message_Block(); ACE_Message_Block* mb = new ACE_Message_Block();
mb->msg_type(ACE_Message_Block::MB_BREAK); mb->msg_type(ACE_Message_Block::MB_BREAK);
// the message is 0 size control message to tell that command output is finished // the message is 0 size control message to tell that command output is finished
// hence we don't put timeout, because it shouldn't increase queue size and shouldn't block // hence we don't put timeout, because it shouldn't increase queue size and shouldn't block
if (socket->putq(mb) == -1) if (socket->putq(mb) == -1)
{ {
// getting here is bad, command can't be marked as complete // getting here is bad, command can't be marked as complete
sLog.outRemote("Failed to enqueue command end message. Error is %s", ACE_OS::strerror(errno)); sLog.outRemote("Failed to enqueue command end message. Error is %s", ACE_OS::strerror(errno));
mb->release(); mb->release();
} }
} }