diff --git a/common/database.cpp b/common/database.cpp index 188c243e7..8926ed4de 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -86,7 +86,7 @@ Database::~Database() Return the account id or zero if no account matches. Zero will also be returned if there is a database error. */ -uint32 Database::CheckLogin(const char* name, const char* password, int16* oStatus) { +uint32 Database::CheckLogin(const char* name, const char* password, const char *loginserver, int16* oStatus) { if(strlen(name) >= 50 || strlen(password) >= 50) return(0); @@ -97,9 +97,10 @@ uint32 Database::CheckLogin(const char* name, const char* password, int16* oStat DoEscapeString(tmpUN, name, strlen(name)); DoEscapeString(tmpPW, password, strlen(password)); - std::string query = StringFormat("SELECT id, status FROM account WHERE name='%s' AND password is not null " + std::string query = StringFormat("SELECT id, status FROM account WHERE name='%s' AND ls_id='%s' AND password is not null " "and length(password) > 0 and (password='%s' or password=MD5('%s'))", - tmpUN, tmpPW, tmpPW); + tmpUN, EscapeString(loginserver).c_str(), tmpPW, tmpPW); + auto results = QueryDatabase(query); if (!results.Success()) @@ -788,11 +789,12 @@ uint32 Database::GetAccountIDByChar(uint32 char_id) { return atoi(row[0]); } -uint32 Database::GetAccountIDByName(const char* accname, int16* status, uint32* lsid) { +uint32 Database::GetAccountIDByName(const char* accname, const char *loginserver, int16* status, uint32* lsid) { if (!isAlphaNumeric(accname)) return 0; - std::string query = StringFormat("SELECT `id`, `status`, `lsaccount_id` FROM `account` WHERE `name` = '%s' LIMIT 1", accname); + std::string query = StringFormat("SELECT `id`, `status`, `lsaccount_id` FROM `account` WHERE `name` = '%s' AND `ls_id`='%s' LIMIT 1", + EscapeString(accname).c_str(), EscapeString(loginserver).c_str()); auto results = QueryDatabase(query); if (!results.Success()) { diff --git a/common/database.h b/common/database.h index 6cdb9fddc..471e59a31 100644 --- a/common/database.h +++ b/common/database.h @@ -127,7 +127,7 @@ public: uint32 GetAccountIDByChar(const char* charname, uint32* oCharID = 0); uint32 GetAccountIDByChar(uint32 char_id); - uint32 GetAccountIDByName(const char* accname, int16* status = 0, uint32* lsid = 0); + uint32 GetAccountIDByName(const char* accname, const char *loginserver, int16* status = 0, uint32* lsid = 0); uint32 GetCharacterID(const char *name); uint32 GetCharacterInfo(const char* iName, uint32* oAccID = 0, uint32* oZoneID = 0, uint32* oInstanceID = 0, float* oX = 0, float* oY = 0, float* oZ = 0); uint32 GetGuildIDByCharID(uint32 char_id); @@ -182,7 +182,7 @@ public: int16 CheckStatus(uint32 account_id); - uint32 CheckLogin(const char* name, const char* password, int16* oStatus = 0); + uint32 CheckLogin(const char* name, const char* password, const char *loginserver, int16* oStatus = 0); uint32 CreateAccount(const char* name, const char* password, int16 status, const char* loginserver, uint32 lsaccount_id); uint32 GetAccountIDFromLSID(const std::string& iLoginServer, uint32 iLSID, char* oAccountName = 0, int16* oStatus = 0); uint8 GetAgreementFlag(uint32 acctid); diff --git a/common/eqemu_config.cpp b/common/eqemu_config.cpp index 15bc90302..96980f834 100644 --- a/common/eqemu_config.cpp +++ b/common/eqemu_config.cpp @@ -70,10 +70,6 @@ void EQEmuConfig::do_world(TiXmlElement *ele) if (text) { LoginLegacy = atoi(text) > 0 ? true : false; } - text = ParseTextBlock(sub_ele, "name", true); - if (text) { - LoginName = text; - } text = ParseTextBlock(sub_ele, "account", true); if (text) { LoginAccount = text; @@ -101,10 +97,6 @@ void EQEmuConfig::do_world(TiXmlElement *ele) if (text) { loginconfig->LoginLegacy = atoi(text) > 0 ? true : false; } - text = ParseTextBlock(sub_ele, "name", true); - if (text) { - loginconfig->LoginName = text; - } text = ParseTextBlock(sub_ele, "account", true); if (text) { loginconfig->LoginAccount = text; @@ -402,9 +394,6 @@ std::string EQEmuConfig::GetByName(const std::string &var_name) const if (var_name == "LoginLegacy") { return (itoa(LoginLegacy ? 1 : 0)); } - if (var_name == "LoginName") { - return LoginName; - } if (var_name == "Locked") { return (Locked ? "true" : "false"); } @@ -537,7 +526,6 @@ void EQEmuConfig::Dump() const std::cout << "LoginPassword = " << LoginPassword << std::endl; std::cout << "LoginPort = " << LoginPort << std::endl; std::cout << "LoginLegacy = " << LoginLegacy << std::endl; - std::cout << "LoginName = " << LoginName << std::endl; std::cout << "Locked = " << Locked << std::endl; std::cout << "WorldTCPPort = " << WorldTCPPort << std::endl; std::cout << "WorldIP = " << WorldIP << std::endl; diff --git a/common/eqemu_config.h b/common/eqemu_config.h index da2479661..0f51f550f 100644 --- a/common/eqemu_config.h +++ b/common/eqemu_config.h @@ -27,7 +27,6 @@ struct LoginConfig { std::string LoginPassword; uint16 LoginPort; bool LoginLegacy; - std::string LoginName; }; class EQEmuConfig : public XMLParser @@ -45,7 +44,6 @@ class EQEmuConfig : public XMLParser std::string LoginPassword; uint16 LoginPort; bool LoginLegacy; - std::string LoginName; uint32 LoginCount; LinkedList loginlist; bool Locked; @@ -136,7 +134,6 @@ class EQEmuConfig : public XMLParser LoginHost = "login.eqemulator.net"; LoginPort = 5998; LoginLegacy = false; - LoginName = "eqemu"; // World Locked = false; WorldTCPPort = 9000; diff --git a/common/servertalk.h b/common/servertalk.h index f5965cd74..5bd2692f9 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -142,14 +142,15 @@ #define ServerOP_ClientVersionSummary 0x0215 #define ServerOP_LSInfo 0x1000 #define ServerOP_LSStatus 0x1001 -#define ServerOP_LSClientAuth 0x1002 +#define ServerOP_LSClientAuthLeg 0x1002 #define ServerOP_LSFatalError 0x1003 #define ServerOP_SystemwideMessage 0x1005 #define ServerOP_ListWorlds 0x1006 #define ServerOP_PeerConnect 0x1007 #define ServerOP_NewLSInfo 0x1008 #define ServerOP_LSRemoteAddr 0x1009 -#define ServerOP_LSAccountUpdate 0x100A +#define ServerOP_LSAccountUpdate 0x100A +#define ServerOP_LSClientAuth 0x100B #define ServerOP_EncapPacket 0x2007 // Packet within a packet #define ServerOP_WorldListUpdate 0x2008 @@ -169,8 +170,10 @@ #define ServerOP_LSPlayerJoinWorld 0x3007 #define ServerOP_LSPlayerZoneChange 0x3008 -#define ServerOP_UsertoWorldReq 0xAB00 -#define ServerOP_UsertoWorldResp 0xAB01 +#define ServerOP_UsertoWorldReqLeg 0xAB00 +#define ServerOP_UsertoWorldRespLeg 0xAB01 +#define ServerOP_UsertoWorldReq 0xAB02 +#define ServerOP_UsertoWorldResp 0xAB03 #define ServerOP_LauncherConnectInfo 0x3000 #define ServerOP_LauncherZoneRequest 0x3001 @@ -512,6 +515,23 @@ struct ServerLSPlayerZoneChange_Struct { }; struct ClientAuth_Struct { + uint32 lsaccount_id; // ID# in login server's db + char lsname[64]; + char name[30]; // username in login server's db + char key[30]; // the Key the client will present + uint8 lsadmin; // login server admin level + int16 worldadmin; // login's suggested worldadmin level setting for this user, up to the world if they want to obey it + uint32 ip; + uint8 local; // 1 if the client is from the local network + + template + void serialize(Archive &ar) + { + ar(lsaccount_id, lsname, name, key, lsadmin, worldadmin, ip, local); + } +}; + +struct ClientAuthLegacy_Struct { uint32 lsaccount_id; // ID# in login server's db char name[30]; // username in login server's db char key[30]; // the Key the client will present @@ -651,12 +671,29 @@ struct ServerSyncWorldList_Struct { bool placeholder; }; +struct UsertoWorldRequestLegacy_Struct { + uint32 lsaccountid; + uint32 worldid; + uint32 FromID; + uint32 ToID; + char IPAddr[64]; +}; + struct UsertoWorldRequest_Struct { uint32 lsaccountid; uint32 worldid; uint32 FromID; uint32 ToID; char IPAddr[64]; + char login[64]; +}; + +struct UsertoWorldResponseLegacy_Struct { + uint32 lsaccountid; + uint32 worldid; + int8 response; // -3) World Full, -2) Banned, -1) Suspended, 0) Denied, 1) Allowed + uint32 FromID; + uint32 ToID; }; struct UsertoWorldResponse_Struct { @@ -665,6 +702,7 @@ struct UsertoWorldResponse_Struct { int8 response; // -3) World Full, -2) Banned, -1) Suspended, 0) Denied, 1) Allowed uint32 FromID; uint32 ToID; + char login[64]; }; // generic struct to be used for alot of simple zone->world questions diff --git a/loginserver/CMakeLists.txt b/loginserver/CMakeLists.txt index df06e7572..1561aa537 100644 --- a/loginserver/CMakeLists.txt +++ b/loginserver/CMakeLists.txt @@ -5,7 +5,6 @@ SET(eqlogin_sources client_manager.cpp config.cpp database_mysql.cpp - database_postgresql.cpp encryption.cpp main.cpp server_manager.cpp @@ -18,7 +17,6 @@ SET(eqlogin_headers config.h database.h database_mysql.h - database_postgresql.h encryption.h login_server.h login_structures.h diff --git a/loginserver/client.cpp b/loginserver/client.cpp index 602967e38..ea2951d5f 100644 --- a/loginserver/client.cpp +++ b/loginserver/client.cpp @@ -219,37 +219,38 @@ void Client::Handle_Login(const char* data, unsigned int size) bool result = false; if (outbuffer[0] == 0 && outbuffer[1] == 0) { - if (server.options.IsTokenLoginAllowed()) { - cred = (&outbuffer[2 + user.length()]); - result = server.db->GetLoginTokenDataFromToken(cred, connection->GetRemoteAddr(), db_account_id, user); - } + //if (server.options.IsTokenLoginAllowed()) { + // cred = (&outbuffer[2 + user.length()]); + // result = server.db->GetLoginTokenDataFromToken(cred, connection->GetRemoteAddr(), db_account_id, user); + //} } else { - if (server.options.IsPasswordLoginAllowed()) { - cred = (&outbuffer[1 + user.length()]); - if (server.db->GetLoginDataFromAccountName(user, db_account_password_hash, db_account_id) == false) { - /* If we have auto_create_accounts enabled in the login.ini, we will process the creation of an account on our own*/ - if ( - server.options.CanAutoCreateAccounts() && - server.db->CreateLoginData(user, eqcrypt_hash(user, cred, mode), db_account_id) == true - ) { - LogF(Logs::General, Logs::Error, "User {0} does not exist in the database, so we created it...", user); - result = true; - } - else { - LogF(Logs::General, Logs::Error, "Error logging in, user {0} does not exist in the database.", user); - result = false; - } - } - else { - if (eqcrypt_verify_hash(user, cred, db_account_password_hash, mode)) { - result = true; - } - else { - result = false; - } - } - } + //if (server.options.IsPasswordLoginAllowed()) { + // result = false; + // //cred = (&outbuffer[1 + user.length()]); + // //if (server.db->GetLoginDataFromAccountName(user, db_account_password_hash, db_account_id) == false) { + // // /* If we have auto_create_accounts enabled in the login.ini, we will process the creation of an account on our own*/ + // // if ( + // // server.options.CanAutoCreateAccounts() && + // // server.db->CreateLoginData(user, eqcrypt_hash(user, cred, mode), db_account_id) == true + // // ) { + // // LogF(Logs::General, Logs::Error, "User {0} does not exist in the database, so we created it...", user); + // // result = true; + // // } + // // else { + // // LogF(Logs::General, Logs::Error, "Error logging in, user {0} does not exist in the database.", user); + // // result = false; + // // } + // //} + // //else { + // // if (eqcrypt_verify_hash(user, cred, db_account_password_hash, mode)) { + // // result = true; + // // } + // // else { + // // result = false; + // // } + // //} + //} } /* Login Accepted */ diff --git a/loginserver/client.h b/loginserver/client.h index b9bfe0494..35ba3a1f0 100644 --- a/loginserver/client.h +++ b/loginserver/client.h @@ -129,6 +129,7 @@ private: std::string account_name; unsigned int account_id; + std::string loginserver_name; unsigned int play_server_id; unsigned int play_sequence_id; std::string key; diff --git a/loginserver/database.h b/loginserver/database.h index 5dd7f7037..26eb45623 100644 --- a/loginserver/database.h +++ b/loginserver/database.h @@ -21,7 +21,6 @@ #include #define EQEMU_MYSQL_ENABLED -//#define EQEMU_POSTGRESQL_ENABLED /** * Base database class, intended to be extended. @@ -42,9 +41,9 @@ public: * Needed for client login procedure. * Returns true if the record was found, false otherwise. */ - virtual bool GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id) { return false; } + virtual bool GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id, std::string &loginserver) { return false; } - virtual bool GetLoginTokenDataFromToken(const std::string &token, const std::string &ip, unsigned int &db_account_id, std::string &user) { return false; } + virtual bool GetLoginTokenDataFromToken(const std::string &token, const std::string &ip, unsigned int &db_account_id, std::string &db_loginserver, std::string &user) { return false; } virtual bool CreateLoginData(const std::string &name, const std::string &password, unsigned int &id) { return false; } diff --git a/loginserver/database_mysql.cpp b/loginserver/database_mysql.cpp index b40c77a0f..6e1b2cf12 100644 --- a/loginserver/database_mysql.cpp +++ b/loginserver/database_mysql.cpp @@ -59,7 +59,7 @@ DatabaseMySQL::~DatabaseMySQL() } } -bool DatabaseMySQL::GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id) +bool DatabaseMySQL::GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id, std::string &loginserver) { if (!database) { @@ -96,7 +96,7 @@ bool DatabaseMySQL::GetLoginDataFromAccountName(std::string name, std::string &p return false; } -bool DatabaseMySQL::GetLoginTokenDataFromToken(const std::string &token, const std::string &ip, unsigned int &db_account_id, std::string &user) +bool DatabaseMySQL::GetLoginTokenDataFromToken(const std::string &token, const std::string &ip, unsigned int &db_account_id, std::string &db_loginserver, std::string &user) { if (!database) { @@ -120,6 +120,7 @@ bool DatabaseMySQL::GetLoginTokenDataFromToken(const std::string &token, const s bool found_username = false; bool found_login_id = false; + bool found_login_server_name = false; if (res) { while ((row = mysql_fetch_row(res)) != nullptr) @@ -135,12 +136,18 @@ bool DatabaseMySQL::GetLoginTokenDataFromToken(const std::string &token, const s found_login_id = true; continue; } + + if (strcmp(row[2], "login_server_name") == 0) { + db_loginserver = row[3]; + found_login_server_name = true; + continue; + } } mysql_free_result(res); } - return found_username && found_login_id; + return found_username && found_login_id && found_login_server_name; } bool DatabaseMySQL::CreateLoginData(const std::string &name, const std::string &password, unsigned int &id) diff --git a/loginserver/database_mysql.h b/loginserver/database_mysql.h index fc791b229..6edf0f1ce 100644 --- a/loginserver/database_mysql.h +++ b/loginserver/database_mysql.h @@ -57,9 +57,9 @@ public: * Needed for client login procedure. * Returns true if the record was found, false otherwise. */ - virtual bool GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id); + virtual bool GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id, std::string &loginserver); - virtual bool GetLoginTokenDataFromToken(const std::string &token, const std::string &ip, unsigned int &db_account_id, std::string &user); + virtual bool GetLoginTokenDataFromToken(const std::string &token, const std::string &ip, unsigned int &db_account_id, std::string &db_loginserver, std::string &user); virtual bool CreateLoginData(const std::string &name, const std::string &password, unsigned int &id); diff --git a/loginserver/database_postgresql.cpp b/loginserver/database_postgresql.cpp index 4b6242e63..e67e47467 100644 --- a/loginserver/database_postgresql.cpp +++ b/loginserver/database_postgresql.cpp @@ -53,7 +53,7 @@ DatabasePostgreSQL::~DatabasePostgreSQL() } } -bool DatabasePostgreSQL::GetLoginDataFromAccountName(string name, string &password, unsigned int &id) +bool DatabasePostgreSQL::GetLoginDataFromAccountName(string name, string &password, unsigned int &id, std::string &loginserver) { if(!db) { diff --git a/loginserver/database_postgresql.h b/loginserver/database_postgresql.h index 0cd5c3ee8..9d195920e 100644 --- a/loginserver/database_postgresql.h +++ b/loginserver/database_postgresql.h @@ -57,7 +57,7 @@ public: * Needed for client login procedure. * Returns true if the record was found, false otherwise. */ - virtual bool GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id); + virtual bool GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id, std::string &loginserver); /** * Retrieves the world registration from the long and short names provided. diff --git a/loginserver/login_server.h b/loginserver/login_server.h index 7760b7efb..a5d780ebb 100644 --- a/loginserver/login_server.h +++ b/loginserver/login_server.h @@ -21,7 +21,6 @@ #include "config.h" #include "database.h" #include "database_mysql.h" -#include "database_postgresql.h" #include "encryption.h" #include "options.h" #include "server_manager.h" diff --git a/loginserver/main.cpp b/loginserver/main.cpp index a77ec395f..7fd047903 100644 --- a/loginserver/main.cpp +++ b/loginserver/main.cpp @@ -116,17 +116,6 @@ int main() server.config->GetVariable("database", "db")); #endif } - else if (server.config->GetVariable("database", "subsystem").compare("PostgreSQL") == 0) { -#ifdef EQEMU_POSTGRESQL_ENABLED - Log(Logs::General, Logs::Login_Server, "PostgreSQL Database Init."); - server.db = (Database*)new DatabasePostgreSQL( - server.config->GetVariable("database", "user"), - server.config->GetVariable("database", "password"), - server.config->GetVariable("database", "host"), - server.config->GetVariable("database", "port"), - server.config->GetVariable("database", "db")); -#endif - } /* Make sure our database got created okay, otherwise cleanup and exit. */ if (!server.db) { diff --git a/loginserver/server_manager.cpp b/loginserver/server_manager.cpp index 550dba806..0a059ec93 100644 --- a/loginserver/server_manager.cpp +++ b/loginserver/server_manager.cpp @@ -213,11 +213,11 @@ void ServerManager::SendUserToWorldRequest(unsigned int server_id, unsigned int while (iter != world_servers.end()) { if ((*iter)->GetRuntimeID() == server_id) { EQ::Net::DynamicPacket outapp; - outapp.Resize(sizeof(UsertoWorldRequest_Struct)); - UsertoWorldRequest_Struct *utwr = (UsertoWorldRequest_Struct*)outapp.Data(); + outapp.Resize(sizeof(UsertoWorldRequestLegacy_Struct)); + UsertoWorldRequestLegacy_Struct *utwr = (UsertoWorldRequestLegacy_Struct*)outapp.Data(); utwr->worldid = server_id; utwr->lsaccountid = client_account_id; - (*iter)->GetConnection()->Send(ServerOP_UsertoWorldReq, outapp); + (*iter)->GetConnection()->Send(ServerOP_UsertoWorldReqLeg, outapp); found = true; if (server.options.IsDumpInPacketsOn()) { diff --git a/loginserver/world_server.cpp b/loginserver/world_server.cpp index 55fc03b7b..02254f223 100644 --- a/loginserver/world_server.cpp +++ b/loginserver/world_server.cpp @@ -39,6 +39,7 @@ WorldServer::WorldServer(std::shared_ptr c) c->OnMessage(ServerOP_NewLSInfo, std::bind(&WorldServer::ProcessNewLSInfo, this, std::placeholders::_1, std::placeholders::_2)); c->OnMessage(ServerOP_LSStatus, std::bind(&WorldServer::ProcessLSStatus, this, std::placeholders::_1, std::placeholders::_2)); + c->OnMessage(ServerOP_UsertoWorldRespLeg, std::bind(&WorldServer::ProcessUsertoWorldRespLeg, this, std::placeholders::_1, std::placeholders::_2)); c->OnMessage(ServerOP_UsertoWorldResp, std::bind(&WorldServer::ProcessUsertoWorldResp, this, std::placeholders::_1, std::placeholders::_2)); c->OnMessage(ServerOP_LSAccountUpdate, std::bind(&WorldServer::ProcessLSAccountUpdate, this, std::placeholders::_1, std::placeholders::_2)); } @@ -116,6 +117,93 @@ void WorldServer::ProcessLSStatus(uint16_t opcode, const EQ::Net::Packet &p) Handle_LSStatus(ls_status); } +void WorldServer::ProcessUsertoWorldRespLeg(uint16_t opcode, const EQ::Net::Packet &p) +{ + if (server.options.IsWorldTraceOn()) + { + Log(Logs::General, Logs::Netcode, "Application packet received from server: 0x%.4X, (size %u)", opcode, p.Length()); + } + + if (server.options.IsDumpInPacketsOn()) + { + DumpPacket(opcode, p); + } + + if (p.Length() < sizeof(UsertoWorldResponseLegacy_Struct)) + { + Log(Logs::General, Logs::Error, "Recieved application packet from server that had opcode ServerOP_UsertoWorldResp, " + "but was too small. Discarded to avoid buffer overrun."); + return; + } + + //I don't use world trace for this and here is why: + //Because this is a part of the client login procedure it makes tracking client errors + //While keeping world server spam with multiple servers connected almost impossible. + if (server.options.IsTraceOn()) + { + Log(Logs::General, Logs::Netcode, "User-To-World Response received."); + } + + UsertoWorldResponseLegacy_Struct *utwr = (UsertoWorldResponseLegacy_Struct*)p.Data(); + Log(Logs::General, Logs::Debug, "Trying to find client with user id of %u.", utwr->lsaccountid); + Client *c = server.client_manager->GetClient(utwr->lsaccountid); + if (c) + { + Log(Logs::General, Logs::Debug, "Found client with user id of %u and account name of %s.", utwr->lsaccountid, c->GetAccountName().c_str()); + EQApplicationPacket *outapp = new EQApplicationPacket(OP_PlayEverquestResponse, sizeof(PlayEverquestResponse_Struct)); + PlayEverquestResponse_Struct *per = (PlayEverquestResponse_Struct*)outapp->pBuffer; + per->Sequence = c->GetPlaySequence(); + per->ServerNumber = c->GetPlayServerID(); + Log(Logs::General, Logs::Debug, "Found sequence and play of %u %u", c->GetPlaySequence(), c->GetPlayServerID()); + + Log(Logs::General, Logs::Netcode, "[Size: %u] %s", outapp->size, DumpPacketToString(outapp).c_str()); + + if (utwr->response > 0) + { + per->Allowed = 1; + SendClientAuth(c->GetConnection()->GetRemoteAddr(), c->GetAccountName(), c->GetKey(), c->GetAccountID()); + } + + switch (utwr->response) + { + case 1: + per->Message = 101; + break; + case 0: + per->Message = 326; + break; + case -1: + per->Message = 337; + break; + case -2: + per->Message = 338; + break; + case -3: + per->Message = 303; + break; + } + + if (server.options.IsTraceOn()) + { + Log(Logs::General, Logs::Netcode, "Sending play response with following data, allowed %u, sequence %u, server number %u, message %u", + per->Allowed, per->Sequence, per->ServerNumber, per->Message); + Log(Logs::General, Logs::Netcode, "[Size: %u] %s", outapp->size, DumpPacketToString(outapp).c_str()); + } + + if (server.options.IsDumpOutPacketsOn()) + { + DumpPacket(outapp); + } + + c->SendPlayResponse(outapp); + delete outapp; + } + else + { + Log(Logs::General, Logs::Error, "Recieved User-To-World Response for %u but could not find the client referenced!.", utwr->lsaccountid); + } +} + void WorldServer::ProcessUsertoWorldResp(uint16_t opcode, const EQ::Net::Packet &p) { if (server.options.IsWorldTraceOn()) @@ -501,7 +589,7 @@ void WorldServer::Handle_LSStatus(ServerLSStatus_Struct *s) void WorldServer::SendClientAuth(std::string ip, std::string account, std::string key, unsigned int account_id) { EQ::Net::DynamicPacket outapp; - ClientAuth_Struct client_auth; + ClientAuthLegacy_Struct client_auth; client_auth.lsaccount_id = account_id; strncpy(client_auth.name, account.c_str(), 30); strncpy(client_auth.key, key.c_str(), 30); @@ -523,10 +611,10 @@ void WorldServer::SendClientAuth(std::string ip, std::string account, std::strin } outapp.PutSerialize(0, client_auth); - connection->Send(ServerOP_LSClientAuth, outapp); + connection->Send(ServerOP_LSClientAuthLeg, outapp); if (server.options.IsDumpInPacketsOn()) { - DumpPacket(ServerOP_LSClientAuth, outapp); + DumpPacket(ServerOP_LSClientAuthLeg, outapp); } } diff --git a/loginserver/world_server.h b/loginserver/world_server.h index bce7b27eb..83c42d27f 100644 --- a/loginserver/world_server.h +++ b/loginserver/world_server.h @@ -133,6 +133,7 @@ private: */ void ProcessNewLSInfo(uint16_t opcode, const EQ::Net::Packet &p); void ProcessLSStatus(uint16_t opcode, const EQ::Net::Packet &p); + void ProcessUsertoWorldRespLeg(uint16_t opcode, const EQ::Net::Packet &p); void ProcessUsertoWorldResp(uint16_t opcode, const EQ::Net::Packet &p); void ProcessLSAccountUpdate(uint16_t opcode, const EQ::Net::Packet &p); diff --git a/world/cliententry.cpp b/world/cliententry.cpp index 9949de55c..cb0234ad8 100644 --- a/world/cliententry.cpp +++ b/world/cliententry.cpp @@ -31,18 +31,21 @@ extern LoginServerList loginserverlist; extern ClientList client_list; extern volatile bool RunLoops; -ClientListEntry::ClientListEntry(const char* iLoginServer, uint32 in_id, uint32 iLSID, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin, uint32 ip, uint8 local) +ClientListEntry::ClientListEntry(uint32 in_id, uint32 iLSID, const char *iLoginServerName, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin, uint32 ip, uint8 local) : id(in_id) { ClearVars(true); pIP = ip; pLSID = iLSID; - if(iLSID > 0) - paccountid = database.GetAccountIDFromLSID(iLoginServer, iLSID, paccountname, &padmin); + if (iLSID > 0) { + + paccountid = database.GetAccountIDFromLSID(iLoginServerName, iLSID, paccountname, &padmin); + } + strn0cpy(plsname, iLoginName, sizeof(plsname)); strn0cpy(plskey, iLoginKey, sizeof(plskey)); - strn0cpy(pLoginServer, iLoginServer, sizeof(pLoginServer)); + strn0cpy(pLoginServer, iLoginServerName, sizeof(pLoginServer)); pworldadmin = iWorldAdmin; plocal=(local==1); @@ -258,7 +261,7 @@ bool ClientListEntry::CheckStale() { } bool ClientListEntry::CheckAuth(uint32 iLSID, const char* iKey) { - if (strncmp(plskey, iKey, 10) == 0) { + if (pLSID == iLSID && strncmp(plskey, iKey, 10) == 0) { if (paccountid == 0 && LSID() > 0) { int16 tmpStatus = WorldConfig::get()->DefaultStatus; paccountid = database.CreateAccount(plsname, 0, tmpStatus, pLoginServer, LSID()); diff --git a/world/cliententry.h b/world/cliententry.h index 365552a0a..ca2f5e07d 100644 --- a/world/cliententry.h +++ b/world/cliententry.h @@ -21,7 +21,7 @@ struct ServerClientList_Struct; class ClientListEntry { public: - ClientListEntry(const char* iLoginServer, uint32 id, uint32 iLSID, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin = 0, uint32 ip = 0, uint8 local=0); + ClientListEntry(uint32 id, uint32 iLSID, const char *iLoginServerName, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin = 0, uint32 ip = 0, uint8 local=0); ClientListEntry(uint32 id, ZoneServer* iZS, ServerClientList_Struct* scl, int8 iOnline); ~ClientListEntry(); bool CheckStale(); diff --git a/world/clientlist.cpp b/world/clientlist.cpp index 06fa2f405..14aeb5766 100644 --- a/world/clientlist.cpp +++ b/world/clientlist.cpp @@ -349,8 +349,8 @@ void ClientList::SendCLEList(const int16& admin, const char* to, WorldTCPConnect } -void ClientList::CLEAdd(const char* iLoginServer, uint32 iLSID, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin, uint32 ip, uint8 local) { - auto tmp = new ClientListEntry(iLoginServer, GetNextCLEID(), iLSID, iLoginName, iLoginKey, iWorldAdmin, ip, local); +void ClientList::CLEAdd(uint32 iLSID, const char *iLoginServerName, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin, uint32 ip, uint8 local) { + auto tmp = new ClientListEntry(GetNextCLEID(), iLSID, iLoginServerName, iLoginName, iLoginKey, iWorldAdmin, ip, local); clientlist.Append(tmp); } diff --git a/world/clientlist.h b/world/clientlist.h index 361218241..be6bd5042 100644 --- a/world/clientlist.h +++ b/world/clientlist.h @@ -61,7 +61,7 @@ public: void EnforceSessionLimit(uint32 iLSAccountID); void CLCheckStale(); void CLEKeepAlive(uint32 numupdates, uint32* wid); - void CLEAdd(const char* iLoginServer, uint32 iLSID, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin = 0, uint32 ip = 0, uint8 local=0); + void CLEAdd(uint32 iLSID, const char* iLoginServerName, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin = 0, uint32 ip = 0, uint8 local=0); void UpdateClientGuild(uint32 char_id, uint32 guild_id); int GetClientCount(); diff --git a/world/console.cpp b/world/console.cpp index 5237e9b0d..ab7097244 100644 --- a/world/console.cpp +++ b/world/console.cpp @@ -15,18 +15,30 @@ extern ZSList zoneserver_list; extern LoginServerList loginserverlist; struct EQ::Net::ConsoleLoginStatus CheckLogin(const std::string& username, const std::string& password) { - //TODO REIMPLEMENT struct EQ::Net::ConsoleLoginStatus ret; - //ret.account_id = database.CheckLogin(username.c_str(), password.c_str()); - //if (ret.account_id == 0) { - // return ret; - //} - // - //char account_name[64]; - //database.GetAccountName(ret.account_id, account_name); - // - //ret.account_name = account_name; - //ret.status = database.CheckStatus(ret.account_id); + std::string prefix = "eqemu"; + std::string raw_user = ""; + + auto split = SplitString(username, ':'); + if (split.size() == 2) { + prefix = split[0]; + raw_user = split[1]; + } + else { + raw_user = split[0]; + } + + ret.account_id = database.CheckLogin(raw_user.c_str(), password.c_str(), prefix.c_str()); + + if (ret.account_id == 0) { + return ret; + } + + char account_name[64]; + database.GetAccountName(ret.account_id, account_name); + + ret.account_name = account_name; + ret.status = database.CheckStatus(ret.account_id); return ret; } @@ -380,23 +392,33 @@ void ConsoleFlag(EQ::Net::ConsoleServerConnection* connection, const std::string } void ConsoleSetPass(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector& args) { - //TODO: REIMPLEMENT - - //if (args.size() != 2) { - // connection->SendLine("Format: setpass accountname password"); - //} - //else { - // int16 tmpstatus = 0; - // uint32 tmpid = database.GetAccountIDByName(args[0].c_str(), &tmpstatus); - // if (!tmpid) - // connection->SendLine("Error: Account not found"); - // else if (tmpstatus > connection->Admin()) - // connection->SendLine("Cannot change password: Account's status is higher than yours"); - // else if (database.SetLocalPassword(tmpid, args[1].c_str())) - // connection->SendLine("Password changed."); - // else - // connection->SendLine("Error changing password."); - //} + if (args.size() != 2) { + connection->SendLine("Format: setpass accountname password"); + } + else { + std::string prefix = "eqemu"; + std::string raw_user = ""; + + auto split = SplitString(args[0], ':'); + if (split.size() == 2) { + prefix = split[0]; + raw_user = split[1]; + } + else { + raw_user = split[0]; + } + + int16 tmpstatus = 0; + uint32 tmpid = database.GetAccountIDByName(raw_user.c_str(), prefix.c_str(), &tmpstatus); + if (!tmpid) + connection->SendLine("Error: Account not found"); + else if (tmpstatus > connection->Admin()) + connection->SendLine("Cannot change password: Account's status is higher than yours"); + else if (database.SetLocalPassword(tmpid, args[1].c_str())) + connection->SendLine("Password changed."); + else + connection->SendLine("Error changing password."); + } } void ConsoleVersion(EQ::Net::ConsoleServerConnection* connection, const std::string& command, const std::vector& args) { diff --git a/world/login_server.cpp b/world/login_server.cpp index fe3c33e28..b01e9d933 100644 --- a/world/login_server.cpp +++ b/world/login_server.cpp @@ -41,7 +41,7 @@ extern uint32 numzones; extern uint32 numplayers; extern volatile bool RunLoops; -LoginServer::LoginServer(const char *Name, const char* iAddress, uint16 iPort, const char* Account, const char* Password, bool legacy) +LoginServer::LoginServer(const char* iAddress, uint16 iPort, const char* Account, const char* Password, bool legacy) { strn0cpy(LoginServerAddress, iAddress, 256); LoginServerPort = iPort; @@ -49,27 +49,26 @@ LoginServer::LoginServer(const char *Name, const char* iAddress, uint16 iPort, c LoginPassword = Password; CanAccountUpdate = false; IsLegacy = legacy; - LoginName = Name; Connect(); } LoginServer::~LoginServer() { } -void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p) { +void LoginServer::ProcessUsertoWorldReqLeg(uint16_t opcode, EQ::Net::Packet &p) { const WorldConfig *Config = WorldConfig::get(); Log(Logs::Detail, Logs::World_Server, "Recevied ServerPacket from LS OpCode 0x04x", opcode); - UsertoWorldRequest_Struct* utwr = (UsertoWorldRequest_Struct*)p.Data(); - uint32 id = database.GetAccountIDFromLSID(LoginName, utwr->lsaccountid); + UsertoWorldRequestLegacy_Struct* utwr = (UsertoWorldRequestLegacy_Struct*)p.Data(); + uint32 id = database.GetAccountIDFromLSID("eqemu", utwr->lsaccountid); int16 status = database.CheckStatus(id); auto outpack = new ServerPacket; - outpack->opcode = ServerOP_UsertoWorldResp; - outpack->size = sizeof(UsertoWorldResponse_Struct); + outpack->opcode = ServerOP_UsertoWorldRespLeg; + outpack->size = sizeof(UsertoWorldResponseLegacy_Struct); outpack->pBuffer = new uchar[outpack->size]; memset(outpack->pBuffer, 0, outpack->size); - UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*)outpack->pBuffer; + UsertoWorldResponseLegacy_Struct* utwrs = (UsertoWorldResponseLegacy_Struct*)outpack->pBuffer; utwrs->lsaccountid = utwr->lsaccountid; utwrs->ToID = utwr->FromID; @@ -98,6 +97,69 @@ void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p) { delete outpack; } +void LoginServer::ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p) { + const WorldConfig *Config = WorldConfig::get(); + Log(Logs::Detail, Logs::World_Server, "Recevied ServerPacket from LS OpCode 0x04x", opcode); + + UsertoWorldRequest_Struct* utwr = (UsertoWorldRequest_Struct*)p.Data(); + uint32 id = database.GetAccountIDFromLSID(utwr->login, utwr->lsaccountid); + int16 status = database.CheckStatus(id); + + auto outpack = new ServerPacket; + outpack->opcode = ServerOP_UsertoWorldResp; + outpack->size = sizeof(UsertoWorldResponse_Struct); + outpack->pBuffer = new uchar[outpack->size]; + memset(outpack->pBuffer, 0, outpack->size); + UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*)outpack->pBuffer; + utwrs->lsaccountid = utwr->lsaccountid; + utwrs->ToID = utwr->FromID; + strn0cpy(utwrs->login, utwr->login, 64); + + if (Config->Locked == true) + { + if ((status == 0 || status < 100) && (status != -2 || status != -1)) + utwrs->response = 0; + if (status >= 100) + utwrs->response = 1; + } + else { + utwrs->response = 1; + } + + int32 x = Config->MaxClients; + if ((int32)numplayers >= x && x != -1 && x != 255 && status < 80) + utwrs->response = -3; + + if (status == -1) + utwrs->response = -1; + if (status == -2) + utwrs->response = -2; + + utwrs->worldid = utwr->worldid; + SendPacket(outpack); + delete outpack; +} + +void LoginServer::ProcessLSClientAuthLeg(uint16_t opcode, EQ::Net::Packet &p) { + const WorldConfig *Config = WorldConfig::get(); + Log(Logs::Detail, Logs::World_Server, "Recevied ServerPacket from LS OpCode 0x04x", opcode); + + try { + auto slsca = p.GetSerialize(0); + + if (RuleI(World, AccountSessionLimit) >= 0) { + // Enforce the limit on the number of characters on the same account that can be + // online at the same time. + client_list.EnforceSessionLimit(slsca.lsaccount_id); + } + + client_list.CLEAdd(slsca.lsaccount_id, "eqemu", slsca.name, slsca.key, slsca.worldadmin, slsca.ip, slsca.local); + } + catch (std::exception &ex) { + LogF(Logs::General, Logs::Error, "Error parsing LSClientAuth packet from world.\n{0}", ex.what()); + } +} + void LoginServer::ProcessLSClientAuth(uint16_t opcode, EQ::Net::Packet &p) { const WorldConfig *Config = WorldConfig::get(); Log(Logs::Detail, Logs::World_Server, "Recevied ServerPacket from LS OpCode 0x04x", opcode); @@ -111,7 +173,7 @@ void LoginServer::ProcessLSClientAuth(uint16_t opcode, EQ::Net::Packet &p) { client_list.EnforceSessionLimit(slsca.lsaccount_id); } - client_list.CLEAdd(LoginName.c_str(), slsca.lsaccount_id, slsca.name, slsca.key, slsca.worldadmin, slsca.ip, slsca.local); + client_list.CLEAdd(slsca.lsaccount_id, slsca.lsname, slsca.name, slsca.key, slsca.worldadmin, slsca.ip, slsca.local); } catch (std::exception &ex) { LogF(Logs::General, Logs::Error, "Error parsing LSClientAuth packet from world.\n{0}", ex.what()); @@ -184,7 +246,9 @@ bool LoginServer::Connect() { } }); + legacy_client->OnMessage(ServerOP_UsertoWorldReqLeg, std::bind(&LoginServer::ProcessUsertoWorldReqLeg, this, std::placeholders::_1, std::placeholders::_2)); legacy_client->OnMessage(ServerOP_UsertoWorldReq, std::bind(&LoginServer::ProcessUsertoWorldReq, this, std::placeholders::_1, std::placeholders::_2)); + legacy_client->OnMessage(ServerOP_LSClientAuthLeg, std::bind(&LoginServer::ProcessLSClientAuthLeg, this, std::placeholders::_1, std::placeholders::_2)); legacy_client->OnMessage(ServerOP_LSClientAuth, std::bind(&LoginServer::ProcessLSClientAuth, this, std::placeholders::_1, std::placeholders::_2)); legacy_client->OnMessage(ServerOP_LSFatalError, std::bind(&LoginServer::ProcessLSFatalError, this, std::placeholders::_1, std::placeholders::_2)); legacy_client->OnMessage(ServerOP_SystemwideMessage, std::bind(&LoginServer::ProcessSystemwideMessage, this, std::placeholders::_1, std::placeholders::_2)); @@ -210,7 +274,9 @@ bool LoginServer::Connect() { } }); + client->OnMessage(ServerOP_UsertoWorldReqLeg, std::bind(&LoginServer::ProcessUsertoWorldReqLeg, this, std::placeholders::_1, std::placeholders::_2)); client->OnMessage(ServerOP_UsertoWorldReq, std::bind(&LoginServer::ProcessUsertoWorldReq, this, std::placeholders::_1, std::placeholders::_2)); + client->OnMessage(ServerOP_LSClientAuthLeg, std::bind(&LoginServer::ProcessLSClientAuthLeg, this, std::placeholders::_1, std::placeholders::_2)); client->OnMessage(ServerOP_LSClientAuth, std::bind(&LoginServer::ProcessLSClientAuth, this, std::placeholders::_1, std::placeholders::_2)); client->OnMessage(ServerOP_LSFatalError, std::bind(&LoginServer::ProcessLSFatalError, this, std::placeholders::_1, std::placeholders::_2)); client->OnMessage(ServerOP_SystemwideMessage, std::bind(&LoginServer::ProcessSystemwideMessage, this, std::placeholders::_1, std::placeholders::_2)); diff --git a/world/login_server.h b/world/login_server.h index 0063f40a4..3bcc8dedf 100644 --- a/world/login_server.h +++ b/world/login_server.h @@ -31,7 +31,7 @@ class LoginServer{ public: - LoginServer(const char *, const char*, uint16, const char*, const char*, bool legacy); + LoginServer(const char*, uint16, const char*, const char*, bool legacy); ~LoginServer(); bool Connect(); @@ -45,8 +45,10 @@ public: bool CanUpdate() { return CanAccountUpdate; } private: + void ProcessUsertoWorldReqLeg(uint16_t opcode, EQ::Net::Packet &p); void ProcessUsertoWorldReq(uint16_t opcode, EQ::Net::Packet &p); void ProcessLSClientAuth(uint16_t opcode, EQ::Net::Packet &p); + void ProcessLSClientAuthLeg(uint16_t opcode, EQ::Net::Packet &p); void ProcessLSFatalError(uint16_t opcode, EQ::Net::Packet &p); void ProcessSystemwideMessage(uint16_t opcode, EQ::Net::Packet &p); void ProcessLSRemoteAddr(uint16_t opcode, EQ::Net::Packet &p); @@ -62,6 +64,5 @@ private: std::string LoginPassword; bool CanAccountUpdate; bool IsLegacy; - std::string LoginName; }; #endif diff --git a/world/login_server_list.cpp b/world/login_server_list.cpp index 1b9eecee3..fb273cbe8 100644 --- a/world/login_server_list.cpp +++ b/world/login_server_list.cpp @@ -49,9 +49,9 @@ LoginServerList::LoginServerList() { LoginServerList::~LoginServerList() { } -void LoginServerList::Add(const char* Name, const char* iAddress, uint16 iPort, const char* Account, const char* Password, bool Legacy) +void LoginServerList::Add(const char* iAddress, uint16 iPort, const char* Account, const char* Password, bool Legacy) { - auto loginserver = new LoginServer(Name, iAddress, iPort, Account, Password, Legacy); + auto loginserver = new LoginServer(iAddress, iPort, Account, Password, Legacy); m_list.push_back(std::unique_ptr(loginserver)); } diff --git a/world/login_server_list.h b/world/login_server_list.h index 26a0a4b53..d1b29a8cf 100644 --- a/world/login_server_list.h +++ b/world/login_server_list.h @@ -15,7 +15,7 @@ public: LoginServerList(); ~LoginServerList(); - void Add(const char*, const char*, uint16, const char*, const char*, bool); + void Add(const char*, uint16, const char*, const char*, bool); bool SendInfo(); bool SendStatus(); diff --git a/world/net.cpp b/world/net.cpp index 3b7f7b79f..2c04b9d10 100644 --- a/world/net.cpp +++ b/world/net.cpp @@ -157,7 +157,7 @@ int main(int argc, char** argv) { // add login server config to list if (Config->LoginCount == 0) { if (Config->LoginHost.length()) { - loginserverlist.Add(Config->LoginName.c_str(), Config->LoginHost.c_str(), Config->LoginPort, Config->LoginAccount.c_str(), Config->LoginPassword.c_str(), Config->LoginLegacy); + loginserverlist.Add(Config->LoginHost.c_str(), Config->LoginPort, Config->LoginAccount.c_str(), Config->LoginPassword.c_str(), Config->LoginLegacy); Log(Logs::General, Logs::World_Server, "Added loginserver %s:%i", Config->LoginHost.c_str(), Config->LoginPort); } } @@ -166,7 +166,7 @@ int main(int argc, char** argv) { LinkedListIterator iterator(loginlist); iterator.Reset(); while (iterator.MoreElements()) { - loginserverlist.Add(iterator.GetData()->LoginName.c_str(), iterator.GetData()->LoginHost.c_str(), iterator.GetData()->LoginPort, iterator.GetData()->LoginAccount.c_str(), iterator.GetData()->LoginPassword.c_str(), + loginserverlist.Add(iterator.GetData()->LoginHost.c_str(), iterator.GetData()->LoginPort, iterator.GetData()->LoginAccount.c_str(), iterator.GetData()->LoginPassword.c_str(), iterator.GetData()->LoginLegacy); Log(Logs::General, Logs::World_Server, "Added loginserver %s:%i", iterator.GetData()->LoginHost.c_str(), iterator.GetData()->LoginPort); iterator.Advance();