diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 80ba883b4..4f629c493 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -75,10 +75,10 @@ ChatCommand * ChatHandler::getCommandTable() { "create", SEC_CONSOLE, true, &ChatHandler::HandleAccountCreateCommand, "", NULL }, { "delete", SEC_CONSOLE, true, &ChatHandler::HandleAccountDeleteCommand, "", NULL }, { "onlinelist", SEC_CONSOLE, true, &ChatHandler::HandleAccountOnlineListCommand, "", NULL }, - { "lock", SEC_PLAYER, false, &ChatHandler::HandleAccountLockCommand, "", NULL }, + { "lock", SEC_PLAYER, true, &ChatHandler::HandleAccountLockCommand, "", NULL }, { "set", SEC_ADMINISTRATOR, true, NULL, "", accountSetCommandTable }, - { "password", SEC_PLAYER, false, &ChatHandler::HandleAccountPasswordCommand, "", NULL }, - { "", SEC_PLAYER, false, &ChatHandler::HandleAccountCommand, "", NULL }, + { "password", SEC_PLAYER, true, &ChatHandler::HandleAccountPasswordCommand, "", NULL }, + { "", SEC_PLAYER, true, &ChatHandler::HandleAccountCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; @@ -703,10 +703,20 @@ const char *ChatHandler::GetMangosString(int32 entry) const return m_session->GetMangosString(entry); } +uint32 ChatHandler::GetAccountId() const +{ + return m_session->GetAccountId(); +} + +AccountTypes ChatHandler::GetAccessLevel() const +{ + return m_session->GetSecurity(); +} + bool ChatHandler::isAvailable(ChatCommand const& cmd) const { // check security level only for simple command (without child commands) - return m_session->GetSecurity() >= (AccountTypes)cmd.SecurityLevel; + return GetAccessLevel() >= (AccountTypes)cmd.SecurityLevel; } bool ChatHandler::HasLowerSecurity(Player* target, uint64 guid, bool strong) @@ -733,12 +743,8 @@ bool ChatHandler::HasLowerSecurityAccount(WorldSession* target, uint32 target_ac { AccountTypes target_sec; - // allow everything from console and RA console - if (!m_session) - return false; - // ignore only for non-players for non strong checks (when allow apply command at least to same sec level) - if (m_session->GetSecurity() > SEC_PLAYER && !strong && !sWorld.getConfig(CONFIG_BOOL_GM_LOWER_SECURITY)) + if (GetAccessLevel() > SEC_PLAYER && !strong && !sWorld.getConfig(CONFIG_BOOL_GM_LOWER_SECURITY)) return false; if (target) @@ -748,7 +754,7 @@ bool ChatHandler::HasLowerSecurityAccount(WorldSession* target, uint32 target_ac else return true; // caller must report error for (target==NULL && target_account==0) - if (m_session->GetSecurity() < target_sec || (strong && m_session->GetSecurity() <= target_sec)) + if (GetAccessLevel() < target_sec || (strong && GetAccessLevel() <= target_sec)) { SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); SetSentErrorMessage(true); @@ -890,14 +896,19 @@ bool ChatHandler::ExecuteCommandInTable(ChatCommand *table, const char* text, co if(table[i].SecurityLevel > SEC_PLAYER) { // chat case - if(m_session) + if (m_session) { Player* p = m_session->GetPlayer(); uint64 sel_guid = p->GetSelection(); - sLog.outCommand(m_session->GetAccountId(),"Command: %s [Player: %s (Account: %u) X: %f Y: %f Z: %f Map: %u Selected: %s (GUID: %u)]", - fullcmd.c_str(),p->GetName(),m_session->GetAccountId(),p->GetPositionX(),p->GetPositionY(),p->GetPositionZ(),p->GetMapId(), + sLog.outCommand(GetAccountId(),"Command: %s [Player: %s (Account: %u) X: %f Y: %f Z: %f Map: %u Selected: %s (GUID: %u)]", + fullcmd.c_str(),p->GetName(),GetAccountId(),p->GetPositionX(),p->GetPositionY(),p->GetPositionZ(),p->GetMapId(), GetLogNameForGuid(sel_guid),GUID_LOPART(sel_guid)); } + else // 0 account -> console + { + sLog.outCommand(GetAccountId(),"Command: %s [Account: %u from %s]", + fullcmd.c_str(),GetAccountId(),GetAccountId() ? "RA-connection" : "Console"); + } } } // some commands have custom error messages. Don't send the default one in these cases. @@ -2253,10 +2264,24 @@ const char *CliHandler::GetMangosString(int32 entry) const return sObjectMgr.GetMangosStringForDBCLocale(entry); } +uint32 CliHandler::GetAccountId() const +{ + return m_accountId; +} + +AccountTypes CliHandler::GetAccessLevel() const +{ + return m_loginAccessLevel; +} + bool CliHandler::isAvailable(ChatCommand const& cmd) const { // skip non-console commands in console case - return cmd.AllowConsole; + if (!cmd.AllowConsole) + return false; + + // normal case + return GetAccessLevel() >= (AccountTypes)cmd.SecurityLevel; } void CliHandler::SendSysMessage(const char *str) diff --git a/src/game/Chat.h b/src/game/Chat.h index abe53ae23..da0563e01 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -78,6 +78,8 @@ class ChatHandler bool hasStringAbbr(const char* name, const char* part); // function with different implementation for chat/console + virtual uint32 GetAccountId() const; + virtual AccountTypes GetAccessLevel() const; virtual bool isAvailable(ChatCommand const& cmd) const; virtual std::string GetNameLink() const { return GetNameLink(m_session->GetPlayer()); } virtual bool needReportToTarget(Player* chr) const; @@ -554,10 +556,13 @@ class CliHandler : public ChatHandler { public: typedef void Print(void*, char const*); - explicit CliHandler(void* callbackArg, Print* zprint) : m_callbackArg(callbackArg), m_print(zprint) {} + explicit CliHandler(uint32 accountId, AccountTypes accessLevel, void* callbackArg, Print* zprint) + : m_accountId(accountId), m_loginAccessLevel(accessLevel), m_callbackArg(callbackArg), m_print(zprint) {} // overwrite functions const char *GetMangosString(int32 entry) const; + uint32 GetAccountId() const; + AccountTypes GetAccessLevel() const; bool isAvailable(ChatCommand const& cmd) const; void SendSysMessage(const char *str); std::string GetNameLink() const; @@ -566,6 +571,8 @@ class CliHandler : public ChatHandler int GetSessionDbLocaleIndex() const; private: + uint32 m_accountId; + AccountTypes m_loginAccessLevel; void* m_callbackArg; Print* m_print; }; diff --git a/src/game/Level0.cpp b/src/game/Level0.cpp index a265405a5..747651936 100644 --- a/src/game/Level0.cpp +++ b/src/game/Level0.cpp @@ -55,7 +55,7 @@ bool ChatHandler::HandleCommandsCommand(const char* /*args*/) bool ChatHandler::HandleAccountCommand(const char* /*args*/) { - AccountTypes gmlevel = m_session->GetSecurity(); + AccountTypes gmlevel = GetAccessLevel(); PSendSysMessage(LANG_ACCOUNT_LEVEL, uint32(gmlevel)); return true; } @@ -134,7 +134,7 @@ bool ChatHandler::HandleSaveCommand(const char* /*args*/) Player *player=m_session->GetPlayer(); // save GM account without delay and output message (testing, etc) - if(m_session->GetSecurity() > SEC_PLAYER) + if(GetAccessLevel() > SEC_PLAYER) { player->SaveToDB(); SendSysMessage(LANG_PLAYER_SAVED); @@ -179,6 +179,10 @@ bool ChatHandler::HandleGMListIngameCommand(const char* /*args*/) bool ChatHandler::HandleAccountPasswordCommand(const char* args) { + // allow use from RA, but not from console (not have associated account id) + if (!GetAccountId()) + return false; + if(!*args) return false; @@ -200,14 +204,14 @@ bool ChatHandler::HandleAccountPasswordCommand(const char* args) return false; } - if (!sAccountMgr.CheckPassword (m_session->GetAccountId(), password_old)) + if (!sAccountMgr.CheckPassword (GetAccountId(), password_old)) { SendSysMessage (LANG_COMMAND_WRONGOLDPASSWORD); SetSentErrorMessage (true); return false; } - AccountOpResult result = sAccountMgr.ChangePassword(m_session->GetAccountId(), password_new); + AccountOpResult result = sAccountMgr.ChangePassword(GetAccountId(), password_new); switch(result) { @@ -230,6 +234,10 @@ bool ChatHandler::HandleAccountPasswordCommand(const char* args) bool ChatHandler::HandleAccountLockCommand(const char* args) { + // allow use from RA, but not from console (not have associated account id) + if (!GetAccountId()) + return false; + if (!*args) { SendSysMessage(LANG_USE_BOL); @@ -239,14 +247,14 @@ bool ChatHandler::HandleAccountLockCommand(const char* args) std::string argstr = (char*)args; if (argstr == "on") { - loginDatabase.PExecute( "UPDATE account SET locked = '1' WHERE id = '%d'",m_session->GetAccountId()); + loginDatabase.PExecute( "UPDATE account SET locked = '1' WHERE id = '%d'",GetAccountId()); PSendSysMessage(LANG_COMMAND_ACCLOCKLOCKED); return true; } if (argstr == "off") { - loginDatabase.PExecute( "UPDATE account SET locked = '0' WHERE id = '%d'",m_session->GetAccountId()); + loginDatabase.PExecute( "UPDATE account SET locked = '0' WHERE id = '%d'",GetAccountId()); PSendSysMessage(LANG_COMMAND_ACCLOCKUNLOCKED); return true; } diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp index cda65abc7..8679791cc 100644 --- a/src/game/Level2.cpp +++ b/src/game/Level2.cpp @@ -2169,7 +2169,7 @@ bool ChatHandler::HandlePInfoCommand(const char* args) username = fields[0].GetCppString(); security = (AccountTypes)fields[1].GetUInt32(); - if(!m_session || m_session->GetSecurity() >= security) + if(GetAccessLevel() >= security) { last_ip = fields[2].GetCppString(); last_login = fields[3].GetCppString(); diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index ff510c81b..b3492009f 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -961,7 +961,7 @@ bool ChatHandler::HandleAccountSetGmLevelCommand(const char* args) return false; /// account can't set security to same or grater level, need more power GM or console - AccountTypes plSecurity = m_session ? m_session->GetSecurity() : SEC_CONSOLE; + AccountTypes plSecurity = GetAccessLevel(); if (AccountTypes(gm) >= plSecurity ) { SendSysMessage(LANG_YOURS_SECURITY_IS_LOW); @@ -5991,7 +5991,7 @@ bool ChatHandler::HandleInstanceListBindsCommand(const char* /*args*/) if (const MapEntry* entry = sMapStore.LookupEntry(itr->first)) { PSendSysMessage("map: %d (%s) inst: %d perm: %s diff: %d canReset: %s TTR: %s", - itr->first, entry->name[m_session->GetSessionDbcLocale()], save->GetInstanceId(), itr->second.perm ? "yes" : "no", + itr->first, entry->name[GetSessionDbcLocale()], save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); } else @@ -6014,7 +6014,7 @@ bool ChatHandler::HandleInstanceListBindsCommand(const char* /*args*/) if (const MapEntry* entry = sMapStore.LookupEntry(itr->first)) { PSendSysMessage("map: %d (%s) inst: %d perm: %s diff: %d canReset: %s TTR: %s", - itr->first, entry->name[m_session->GetSessionDbcLocale()], save->GetInstanceId(), itr->second.perm ? "yes" : "no", + itr->first, entry->name[GetSessionDbcLocale()], save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); } else @@ -6067,7 +6067,7 @@ bool ChatHandler::HandleInstanceUnbindCommand(const char* args) if (const MapEntry* entry = sMapStore.LookupEntry(itr->first)) { PSendSysMessage("unbinding map: %d (%s) inst: %d perm: %s diff: %d canReset: %s TTR: %s", - itr->first, entry->name[m_session->GetSessionDbcLocale()], save->GetInstanceId(), itr->second.perm ? "yes" : "no", + itr->first, entry->name[GetSessionDbcLocale()], save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); } else @@ -6197,7 +6197,7 @@ bool ChatHandler::HandleAccountSetAddonCommand(const char* args) // Let set addon state only for lesser (strong) security level // or to self account - if (m_session && m_session->GetAccountId () != account_id && + if (GetAccountId() && GetAccountId () != account_id && HasLowerSecurityAccount (NULL,account_id,true)) return false; diff --git a/src/game/World.cpp b/src/game/World.cpp index b1605d594..ada384d59 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -1819,7 +1819,7 @@ void World::UpdateSessions( uint32 diff ) } } -// This handles the issued and queued CLI commands +// This handles the issued and queued CLI/RA commands void World::ProcessCliCommands() { CliCommandHolder::Print* zprint = NULL; @@ -1830,7 +1830,7 @@ void World::ProcessCliCommands() sLog.outDebug("CLI command under processing..."); zprint = command->m_print; callbackArg = command->m_callbackArg; - CliHandler handler(callbackArg, zprint); + CliHandler handler(command->m_cliAccountId, command->m_cliAccessLevel, callbackArg, zprint); handler.ParseCommands(command->m_command); if(command->m_commandFinished) diff --git a/src/game/World.h b/src/game/World.h index 6711ff61f..72642d34d 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -375,13 +375,15 @@ struct CliCommandHolder typedef void Print(void*, const char*); typedef void CommandFinished(void*, bool success); + uint32 m_cliAccountId; // 0 for console and real account id for RA/soap + AccountTypes m_cliAccessLevel; void* m_callbackArg; char *m_command; Print* m_print; CommandFinished* m_commandFinished; - CliCommandHolder(void* callbackArg, const char *command, Print* zprint, CommandFinished* commandFinished) - : m_callbackArg(callbackArg), m_print(zprint), m_commandFinished(commandFinished) + CliCommandHolder(uint32 accountId, AccountTypes cliAccessLevel, void* callbackArg, const char *command, Print* zprint, CommandFinished* commandFinished) + : m_cliAccountId(accountId), m_cliAccessLevel(cliAccessLevel), m_callbackArg(callbackArg), m_print(zprint), m_commandFinished(commandFinished) { size_t len = strlen(command)+1; m_command = new char[len]; diff --git a/src/mangosd/CliRunnable.cpp b/src/mangosd/CliRunnable.cpp index 132a63647..d7496406c 100644 --- a/src/mangosd/CliRunnable.cpp +++ b/src/mangosd/CliRunnable.cpp @@ -348,7 +348,7 @@ void CliRunnable::run() continue; } - sWorld.QueueCliCommand(new CliCommandHolder(NULL, command.c_str(), &utf8print, &commandFinished)); + sWorld.QueueCliCommand(new CliCommandHolder(0, SEC_CONSOLE, NULL, command.c_str(), &utf8print, &commandFinished)); } else if (feof(stdin)) { diff --git a/src/mangosd/MaNGOSsoap.cpp b/src/mangosd/MaNGOSsoap.cpp index adef52553..fe358d28d 100644 --- a/src/mangosd/MaNGOSsoap.cpp +++ b/src/mangosd/MaNGOSsoap.cpp @@ -123,7 +123,7 @@ int ns1__executeCommand(soap* soap, char* command, char** result) // commands are executed in the world thread. We have to wait for them to be completed { // CliCommandHolder will be deleted from world, accessing after queueing is NOT save - CliCommandHolder* cmd = new CliCommandHolder(&connection, command, &SOAPCommand::print, &SOAPCommand::commandFinished); + CliCommandHolder* cmd = new CliCommandHolder(accountId, SEC_CONSOLE, &connection, command, &SOAPCommand::print, &SOAPCommand::commandFinished); sWorld.QueueCliCommand(cmd); } diff --git a/src/mangosd/RASocket.cpp b/src/mangosd/RASocket.cpp index 873289171..17e6c2266 100644 --- a/src/mangosd/RASocket.cpp +++ b/src/mangosd/RASocket.cpp @@ -42,7 +42,8 @@ stage(NONE) { ///- Get the config parameters bSecure = sConfig.GetBoolDefault( "RA.Secure", true ); - iMinLevel = sConfig.GetIntDefault( "RA.MinLevel", SEC_ADMINISTRATOR ); + bStricted = sConfig.GetBoolDefault( "RA.Stricted", false ); + iMinLevel = AccountTypes(sConfig.GetIntDefault( "RA.MinLevel", SEC_ADMINISTRATOR )); reference_counting_policy ().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED); } @@ -198,30 +199,32 @@ int RASocket::handle_input(ACE_HANDLE) } sendf("\r\n"); sendf(sObjectMgr.GetMangosStringForDBCLocale(LANG_RA_USER)); + break; } - else - { - AccountTypes sec = sAccountMgr.GetSecurity(accId); - ///- if gmlevel is too low, deny access - if (sec < iMinLevel) + accAccessLevel = sAccountMgr.GetSecurity(accId); + + ///- if gmlevel is too low, deny access + if (accAccessLevel < iMinLevel) + { + sendf("-Not enough privileges.\r\n"); + sLog.outRALog("User %s has no privilege.",szLogin.c_str()); + if(bSecure) { - sendf("-Not enough privileges.\r\n"); - sLog.outRALog("User %s has no privilege.",szLogin.c_str()); - if(bSecure) - { - handle_output(); - return -1; - } - sendf("\r\n"); - sendf(sObjectMgr.GetMangosStringForDBCLocale(LANG_RA_USER)); - } - else - { - stage=LG; - sendf(sObjectMgr.GetMangosStringForDBCLocale(LANG_RA_PASS)); + handle_output(); + return -1; } + sendf("\r\n"); + sendf(sObjectMgr.GetMangosStringForDBCLocale(LANG_RA_USER)); + break; } + + ///- allow by remotely connected admin use console level commands dependent from config setting + if (accAccessLevel >= SEC_ADMINISTRATOR && !bStricted) + accAccessLevel = SEC_CONSOLE; + + stage=LG; + sendf(sObjectMgr.GetMangosStringForDBCLocale(LANG_RA_PASS)); break; } ///
  • If the input is '' (and the user already gave his username) @@ -261,7 +264,7 @@ int RASocket::handle_input(ACE_HANDLE) return -1; else { - CliCommandHolder* cmd = new CliCommandHolder(this, inputBuffer, &RASocket::zprint, &RASocket::commandFinished); + CliCommandHolder* cmd = new CliCommandHolder(accId, accAccessLevel, this, inputBuffer, &RASocket::zprint, &RASocket::commandFinished); sWorld.QueueCliCommand(cmd); pendingCommands.acquire(); } diff --git a/src/mangosd/RASocket.h b/src/mangosd/RASocket.h index e2e9b567d..ae200acc4 100644 --- a/src/mangosd/RASocket.h +++ b/src/mangosd/RASocket.h @@ -77,10 +77,11 @@ class RASocket: protected RAHandler uint32 outputBufferLen; uint32 accId; + AccountTypes accAccessLevel; bool bSecure; //kick on wrong pass, non exist. user OR user with no priv //will protect from DOS, bruteforce attacks - //some 'smart' protection must be added for more security - uint8 iMinLevel; + bool bStricted; // not allow execute console only commands (SEC_CONSOLE) remotly + AccountTypes iMinLevel; enum { NONE, //initial value diff --git a/src/mangosd/mangosd.conf.dist.in b/src/mangosd/mangosd.conf.dist.in index c52602b84..43e415994 100644 --- a/src/mangosd/mangosd.conf.dist.in +++ b/src/mangosd/mangosd.conf.dist.in @@ -1,7 +1,7 @@ ##################################### # MaNGOS Configuration file # ##################################### -ConfVersion=2008080101 +ConfVersion=2010030401 ################################################################################################################### # CONNECTIONS AND DIRECTORIES @@ -1373,12 +1373,21 @@ Network.TcpNodelay = 1 # # Ra.Port # Default remote console port +# Default: 3443 # # Ra.MinLevel # Minimum level that's required to login,3 by default +# Default: 3 (Administrator) # # Ra.Secure # Kick client on wrong pass +# 0 - off +# Default: 1 - on +# +# Ra.Stricted +# Not allow execute console level only commands remotly by RA +# 0 - off +# Default: 1 - on # # # SOAP.Enable @@ -1402,6 +1411,7 @@ Ra.IP = 0.0.0.0 Ra.Port = 3443 Ra.MinLevel = 3 Ra.Secure = 1 +Ra.Stricted = 1 SOAP.Enabled = 0 SOAP.IP = 127.0.0.1 diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 96ebd1e0c..676093f10 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "9517" + #define REVISION_NR "9518" #endif // __REVISION_NR_H__