From d8da52796b60110a8f898d30ea68e43c5df383fa Mon Sep 17 00:00:00 2001 From: KimLS Date: Mon, 31 Oct 2016 21:19:48 -0700 Subject: [PATCH] Rework login credential functions --- .travis.yml | 4 +- loginserver/CMakeLists.txt | 16 +- loginserver/client.cpp | 136 +++++++++-------- loginserver/client.h | 11 +- loginserver/client_manager.cpp | 10 -- loginserver/client_manager.h | 5 - loginserver/database.h | 2 + loginserver/database_mysql.cpp | 47 ++++++ loginserver/database_mysql.h | 2 + loginserver/encryption.cpp | 262 +++++++++++++++++---------------- loginserver/encryption.h | 105 +------------ loginserver/login_server.h | 14 +- loginserver/main.cpp | 42 ++---- loginserver/options.h | 17 ++- loginserver/server_manager.cpp | 4 +- loginserver/server_manager.h | 2 +- loginserver/world_server.cpp | 5 - 17 files changed, 297 insertions(+), 387 deletions(-) diff --git a/.travis.yml b/.travis.yml index 74e5701ae..b0f603c4f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,10 @@ addons: - libboost-dev - liblua5.1-0-dev - zlib1g-dev + - uuid-dev + - libssl-dev script: - - cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_ENABLE_BOTS=ON + - cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_ENABLE_BOTS=ON -DEQEMU_BUILD_LOGIN=ON - make -j8 - ./bin/tests branches: diff --git a/loginserver/CMakeLists.txt b/loginserver/CMakeLists.txt index ac1f4320b..df06e7572 100644 --- a/loginserver/CMakeLists.txt +++ b/loginserver/CMakeLists.txt @@ -6,16 +6,12 @@ SET(eqlogin_sources config.cpp database_mysql.cpp database_postgresql.cpp + encryption.cpp main.cpp server_manager.cpp world_server.cpp ) -IF(MSVC OR MINGW) - ADD_DEFINITIONS(-DNOMINMAX) - SET(eqlogin_sources ${eqlogin_sources} encryption.cpp) -ENDIF(MSVC OR MINGW) - SET(eqlogin_headers client.h client_manager.h @@ -24,7 +20,6 @@ SET(eqlogin_headers database_mysql.h database_postgresql.h encryption.h - eq_crypto_api.h login_server.h login_structures.h options.h @@ -32,15 +27,14 @@ SET(eqlogin_headers world_server.h ) -IF(UNIX) - SET(EQEMU_UNIX_ENC_LIBRARY_LOC "${CMAKE_SOURCE_DIR}/dependencies" CACHE PATH "Location of EQEmuAuthCrypto and cryptopp") - LINK_DIRECTORIES(${EQEMU_UNIX_ENC_LIBRARY_LOC}) -ENDIF(UNIX) +FIND_PACKAGE(OpenSSL REQUIRED) + +INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) ADD_EXECUTABLE(loginserver ${eqlogin_sources} ${eqlogin_headers}) INSTALL(TARGETS loginserver RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) -TARGET_LINK_LIBRARIES(loginserver ${SERVER_LIBS}) +TARGET_LINK_LIBRARIES(loginserver ${SERVER_LIBS} ${OPENSSL_LIBRARIES}) SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) diff --git a/loginserver/client.cpp b/loginserver/client.cpp index b3535490a..443eaaa5e 100644 --- a/loginserver/client.cpp +++ b/loginserver/client.cpp @@ -78,12 +78,17 @@ bool Client::Process() } case OP_ServerListRequest: { + if (app->Size() < 4) { + Log.Out(Logs::General, Logs::Error, "Server List Request received but it is too small, discarding."); + break; + } + if(server.options.IsTraceOn()) { Log.Out(Logs::General, Logs::Login_Server, "Server list request received from client."); } - SendServerListPacket(); + SendServerListPacket(*(uint32_t*)app->pBuffer); break; } case OP_PlayEverquestRequest: @@ -126,14 +131,6 @@ void Client::Handle_SessionReady(const char* data, unsigned int size) return; } - unsigned int mode = *((unsigned int*)data); - if(mode == (unsigned int)lm_from_world) - { - Log.Out(Logs::General, Logs::Login_Server, "Session ready indicated logged in from world(unsupported feature), disconnecting."); - connection->Close(); - return; - } - status = cs_waiting_for_login; /** @@ -175,6 +172,8 @@ void Client::Handle_SessionReady(const char* data, unsigned int size) void Client::Handle_Login(const char* data, unsigned int size) { + auto mode = server.options.GetEncryptionMode(); + if(status != cs_waiting_for_login) { Log.Out(Logs::General, Logs::Error, "Login received after already having logged in."); return; @@ -187,68 +186,69 @@ void Client::Handle_Login(const char* data, unsigned int size) status = cs_logged_in; - std::string entered_username; - std::string entered_password_hash_result; - char *login_packet_buffer = nullptr; unsigned int db_account_id = 0; std::string db_account_password_hash; -#ifdef WIN32 - login_packet_buffer = server.eq_crypto->DecryptUsernamePassword(data, size, server.options.GetEncryptionMode()); - - int login_packet_buffer_length = strlen(login_packet_buffer); - entered_password_hash_result.assign(login_packet_buffer, login_packet_buffer_length); - entered_username.assign((login_packet_buffer + login_packet_buffer_length + 1), strlen(login_packet_buffer + login_packet_buffer_length + 1)); - - if(server.options.IsTraceOn()) { - Log.Out(Logs::General, Logs::Debug, "User: %s", entered_username.c_str()); - Log.Out(Logs::General, Logs::Debug, "Hash: %s", entered_password_hash_result.c_str()); + std::string outbuffer; + outbuffer.resize(size - 12); + if (outbuffer.length() == 0) { + Log.OutF(Logs::General, Logs::Debug, "Corrupt buffer sent to server, no length."); + return; } - server.eq_crypto->DeleteHeap(login_packet_buffer); -#else - login_packet_buffer = DecryptUsernamePassword(data, size, server.options.GetEncryptionMode()); - - int login_packet_buffer_length = strlen(login_packet_buffer); - entered_password_hash_result.assign(login_packet_buffer, login_packet_buffer_length); - entered_username.assign((login_packet_buffer + login_packet_buffer_length + 1), strlen(login_packet_buffer + login_packet_buffer_length + 1)); - - if(server.options.IsTraceOn()) { - Log.Out(Logs::General, Logs::Debug, "User: %s", entered_username.c_str()); - Log.Out(Logs::General, Logs::Debug, "Hash: %s", entered_password_hash_result.c_str()); + auto r = eqcrypt_block(data + 10, size - 12, &outbuffer[0], 0); + if (r == nullptr) { + Log.OutF(Logs::General, Logs::Debug, "Failed to decrypt eqcrypt block"); + return; } - _HeapDeleteCharBuffer(login_packet_buffer); -#endif + std::string cred; - bool result; - if(server.db->GetLoginDataFromAccountName(entered_username, 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.config->GetVariable("options", "auto_create_accounts").compare("TRUE") == 0 && - server.db->CreateLoginData(entered_username, entered_password_hash_result, db_account_id) == true - ){ - Log.Out(Logs::General, Logs::Error, "User %s does not exist in the database, so we created it...", entered_username.c_str()); - result = true; - } - else{ - Log.Out(Logs::General, Logs::Error, "Error logging in, user %s does not exist in the database.", entered_username.c_str()); - result = false; + std::string user(&outbuffer[0]); + if (user.length() >= outbuffer.length()) { + Log.OutF(Logs::General, Logs::Debug, "Corrupt buffer sent to server, preventing buffer overflow."); + return; + } + + 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); } } else { - if(db_account_password_hash.compare(entered_password_hash_result) == 0) { - result = true; - } - else { - result = false; + 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 + ) { + Log.OutF(Logs::General, Logs::Error, "User {0} does not exist in the database, so we created it...", user); + result = true; + } + else { + Log.OutF(Logs::General, Logs::Error, "Error logging in, user %s 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 */ - if(result) { + if (result) { server.client_manager->RemoveExistingClient(db_account_id); @@ -259,7 +259,7 @@ void Client::Handle_Login(const char* data, unsigned int size) GenerateKey(); account_id = db_account_id; - account_name = entered_username; + account_name = user; EQApplicationPacket *outapp = new EQApplicationPacket(OP_LoginAccepted, 10 + 80); const LoginLoginRequest_Struct* llrs = (const LoginLoginRequest_Struct *)data; @@ -293,19 +293,15 @@ void Client::Handle_Login(const char* data, unsigned int size) login_failed_attempts->unknown12[0] = 0x01; memcpy(login_failed_attempts->key, key.c_str(), key.size()); -#ifdef WIN32 - unsigned int e_size; - char *encrypted_buffer = server.eq_crypto->Encrypt((const char*)login_failed_attempts, 75, e_size); - memcpy(login_accepted->encrypt, encrypted_buffer, 80); - server.eq_crypto->DeleteHeap(encrypted_buffer); -#else - unsigned int e_size; - char *encrypted_buffer = Encrypt((const char*)login_failed_attempts, 75, e_size); - memcpy(login_accepted->encrypt, encrypted_buffer, 80); - _HeapDeleteCharBuffer(encrypted_buffer); -#endif + char encrypted_buffer[80] = { 0 }; + auto rc = eqcrypt_block((const char*)login_failed_attempts, 75, encrypted_buffer, 1); + if (rc == nullptr) { + Log.OutF(Logs::General, Logs::Debug, "Failed to encrypt eqcrypt block"); + } - if(server.options.IsDumpOutPacketsOn()) { + memcpy(login_accepted->encrypt, encrypted_buffer, 80); + + if (server.options.IsDumpOutPacketsOn()) { DumpPacket(outapp); } @@ -323,7 +319,7 @@ void Client::Handle_Login(const char* data, unsigned int size) llas->unknown5 = llrs->unknown5; memcpy(llas->unknown6, FailedLoginResponseData, sizeof(FailedLoginResponseData)); - if(server.options.IsDumpOutPacketsOn()) { + if (server.options.IsDumpOutPacketsOn()) { DumpPacket(outapp); } @@ -355,9 +351,9 @@ void Client::Handle_Play(const char* data) server.server_manager->SendUserToWorldRequest(server_id_in, account_id); } -void Client::SendServerListPacket() +void Client::SendServerListPacket(uint32 seq) { - EQApplicationPacket *outapp = server.server_manager->CreateServerListPacket(this); + EQApplicationPacket *outapp = server.server_manager->CreateServerListPacket(this, seq); if(server.options.IsDumpOutPacketsOn()) { diff --git a/loginserver/client.h b/loginserver/client.h index e60de7f56..9721bc439 100644 --- a/loginserver/client.h +++ b/loginserver/client.h @@ -21,9 +21,6 @@ #include "../common/global_define.h" #include "../common/opcodemgr.h" #include "../common/random.h" -#ifndef WIN32 -#include "eq_crypto_api.h" -#endif #include #include "../common/eq_stream_intf.h" @@ -41,12 +38,6 @@ enum LSClientStatus cs_logged_in }; -enum LoginMode -{ - lm_initial = 2, - lm_from_world = 3 -}; - /** * Client class, controls a single client and it's * connection to the login server. @@ -87,7 +78,7 @@ public: /** * Sends a server list packet to the client. */ - void SendServerListPacket(); + void SendServerListPacket(uint32 seq); /** * Sends the input packet to the client and clears our play response states. diff --git a/loginserver/client_manager.cpp b/loginserver/client_manager.cpp index fa16365d3..1cabc1b74 100644 --- a/loginserver/client_manager.cpp +++ b/loginserver/client_manager.cpp @@ -125,16 +125,6 @@ void ClientManager::ProcessDisconnect() } } -void ClientManager::UpdateServerList() -{ - auto iter = clients.begin(); - while(iter != clients.end()) - { - (*iter)->SendServerListPacket(); - ++iter; - } -} - void ClientManager::RemoveExistingClient(unsigned int account_id) { auto iter = clients.begin(); diff --git a/loginserver/client_manager.h b/loginserver/client_manager.h index 04d276861..7e05737a2 100644 --- a/loginserver/client_manager.h +++ b/loginserver/client_manager.h @@ -45,11 +45,6 @@ public: */ void Process(); - /** - * Sends a new server list to every client. - */ - void UpdateServerList(); - /** * Removes a client with a certain account id. */ diff --git a/loginserver/database.h b/loginserver/database.h index b7e9f9d24..1c39f68cc 100644 --- a/loginserver/database.h +++ b/loginserver/database.h @@ -44,6 +44,8 @@ public: */ virtual bool GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id) { 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 CreateLoginData(std::string name, std::string &password, unsigned int &id) { return false; } /** diff --git a/loginserver/database_mysql.cpp b/loginserver/database_mysql.cpp index d11e38cb7..082128654 100644 --- a/loginserver/database_mysql.cpp +++ b/loginserver/database_mysql.cpp @@ -22,6 +22,7 @@ #include "database_mysql.h" #include "login_server.h" #include "../common/eqemu_logsys.h" +#include "../common/string_util.h" extern EQEmuLogSys Log; extern LoginServer server; @@ -96,6 +97,52 @@ 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) +{ + if (!database) + { + return false; + } + + MYSQL_RES *res; + MYSQL_ROW row; + std::stringstream query(std::stringstream::in | std::stringstream::out); + query << "SELECT tbllogintokens.Id, tbllogintokens.IpAddress, tbllogintokenclaims.Name, tbllogintokenclaims.Value FROM tbllogintokens "; + query << "JOIN tbllogintokenclaims ON tbllogintokens.Id = tbllogintokenclaims.TokenId WHERE tbllogintokens.Expires > NOW() AND tbllogintokens.Id='"; + query << EscapeString(token) << "' AND tbllogintokens.IpAddress='" << EscapeString(ip) << "'"; + + if (mysql_query(database, query.str().c_str()) != 0) + { + Log.Out(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str()); + return false; + } + + res = mysql_use_result(database); + + bool found_username = false; + bool found_login_id = false; + if (res) + { + while ((row = mysql_fetch_row(res)) != nullptr) + { + if (strcmp(row[2], "username") == 0) { + user = row[3]; + found_username = true; + continue; + } + + if (strcmp(row[2], "login_server_id") == 0) { + db_account_id = atoi(row[3]); + found_login_id = true; + continue; + } + } + + mysql_free_result(res); + } + + return found_username && found_login_id; +} bool DatabaseMySQL::CreateLoginData(std::string name, std::string &password, unsigned int &id) { diff --git a/loginserver/database_mysql.h b/loginserver/database_mysql.h index 5cadff34a..38caa7007 100644 --- a/loginserver/database_mysql.h +++ b/loginserver/database_mysql.h @@ -59,6 +59,8 @@ public: */ virtual bool GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id); + virtual bool GetLoginTokenDataFromToken(const std::string &token, const std::string &ip, unsigned int &db_account_id, std::string &user); + virtual bool CreateLoginData(std::string name, std::string &password, unsigned int &id); /** diff --git a/loginserver/encryption.cpp b/loginserver/encryption.cpp index 3c9ebd49f..33eedaef6 100644 --- a/loginserver/encryption.cpp +++ b/loginserver/encryption.cpp @@ -1,145 +1,159 @@ -/* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net) - - 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; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY except by those people which sell it, which - are required to give you total support for your newly bought product; - without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the 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 - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#include "../common/global_define.h" -#include "encryption.h" +#include +#include +#include +#include #include - -#include "../common/eqemu_logsys.h" -extern EQEmuLogSys Log; - -bool Encryption::LoadCrypto(std::string name) -{ - if(!Load(name.c_str())) - { - Log.Out(Logs::General, Logs::Error, "Failed to load %s from the operating system.", name.c_str()); - return false; - } - else - { - encrypt_func = (DLLFUNC_Encrypt)GetSym("Encrypt"); - if(encrypt_func == NULL) - { - Log.Out(Logs::General, Logs::Error, "Failed to attach Encrypt."); - Unload(); - return false; - } - decrypt_func = (DLLFUNC_DecryptUsernamePassword)GetSym("DecryptUsernamePassword"); - if(decrypt_func == NULL) - { - Log.Out(Logs::General, Logs::Error, "Failed to attach DecryptUsernamePassword."); - Unload(); - return false; - } - delete_func = (DLLFUNC_HeapDelete)GetSym("_HeapDeleteCharBuffer"); - if(delete_func == NULL) - { - Log.Out(Logs::General, Logs::Error, "Failed to attach _HeapDeleteCharBuffer."); - Unload(); - return false; - } - } - return true; -} - -char *Encryption::DecryptUsernamePassword(const char* encrypted_buffer, unsigned int buffer_size, int mode) -{ - if(decrypt_func) - { - return decrypt_func(encrypted_buffer, buffer_size, mode); - } - return NULL; -} - -char *Encryption::Encrypt(const char* buffer, unsigned int buffer_size, unsigned int &out_size) -{ - if(encrypt_func) - { - return encrypt_func(buffer, buffer_size, out_size); - } - return NULL; -} - -void Encryption::DeleteHeap(char *buffer) -{ - if(delete_func) - { - delete_func(buffer); - } -} - -bool Encryption::Load(const char *name) -{ - SetLastError(0); -#ifdef UNICODE - int name_length = strlen(name); - int wide_length = MultiByteToWideChar(CP_ACP, 0, name, name_length+1, 0, 0); - WCHAR *wide_string = new WCHAR[wide_length]; - MultiByteToWideChar(CP_ACP, 0, name, name_length+1, wide_string, wide_length); - - h_dll = LoadLibrary(wide_string); - delete[] wide_string; -#else - h_dll = LoadLibrary(name); +#ifdef ENABLE_SECURITY +#include #endif - if(h_dll == NULL) - { - return false; - } - else - { - SetLastError(0); +const char* eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char* buffer_out, bool enc) { + DES_key_schedule k; + DES_cblock v; + + memset(&k, 0, sizeof(DES_key_schedule)); + memset(&v, 0, sizeof(DES_cblock)); + + if (!enc && buffer_in_sz && buffer_in_sz % 8 != 0) { + return nullptr; } - return true; + DES_ncbc_encrypt((const unsigned char*)buffer_in, (unsigned char*)buffer_out, (long)buffer_in_sz, &k, &v, enc); + return buffer_out; } -void Encryption::Unload() +std::string eqcrypt_md5(const std::string &msg) { + std::string ret; + unsigned char md5_digest[16]; + char tmp[4]; + + MD5((const unsigned char*)msg.c_str(), msg.length(), md5_digest); + + for (int i = 0; i < 16; ++i) { + sprintf(&tmp[0], "%02x", md5_digest[i]); + ret.push_back(tmp[0]); + ret.push_back(tmp[1]); + } + + return ret; +} + +std::string eqcrypt_sha1(const std::string &msg) { + std::string ret; + unsigned char sha_digest[20]; + char tmp[4]; + + SHA1((const unsigned char*)msg.c_str(), msg.length(), sha_digest); + + for (int i = 0; i < 20; ++i) { + sprintf(&tmp[0], "%02x", sha_digest[i]); + ret.push_back(tmp[0]); + ret.push_back(tmp[1]); + } + + return ret; +} + +std::string eqcrypt_sha512(const std::string &msg) { + std::string ret; + unsigned char sha_digest[64]; + char tmp[4]; + + SHA512((const unsigned char*)msg.c_str(), msg.length(), sha_digest); + + for (int i = 0; i < 64; ++i) { + sprintf(&tmp[0], "%02x", sha_digest[i]); + ret.push_back(tmp[0]); + ret.push_back(tmp[1]); + } + + return ret; +} + +#ifdef ENABLE_SECURITY + +std::string eqcrypt_argon2(const std::string &msg) { - if(h_dll) - { - FreeLibrary(h_dll); - h_dll = NULL; + std::string ret; + ret.resize(crypto_pwhash_STRBYTES); + + if (crypto_pwhash_str(&ret[0], &msg[0], msg.length(), crypto_pwhash_OPSLIMIT_SENSITIVE, crypto_pwhash_MEMLIMIT_SENSITIVE) != 0) { + return ""; } + + return ret; } -bool Encryption::GetSym(const char *name, void **sym) +std::string eqcrypt_scrypt(const std::string &msg) { - if(Loaded()) - { - *sym = GetProcAddress(h_dll, name); - return(*sym != NULL); + std::string ret; + ret.resize(crypto_pwhash_scryptsalsa208sha256_STRBYTES); + + if (crypto_pwhash_scryptsalsa208sha256_str(&ret[0], &msg[0], msg.length(), + crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE, crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE) != 0) { + return ""; } - else + + return ret; +} + +#endif + +std::string eqcrypt_hash(const std::string &username, const std::string &password, int mode) { + switch (mode) { - return false; + case 1: + return eqcrypt_md5(password); + case 2: + return eqcrypt_md5(password + ":" + username); + case 3: + return eqcrypt_md5(username + ":" + password); + case 4: + return eqcrypt_md5(eqcrypt_md5(username) + eqcrypt_md5(password)); + case 5: + return eqcrypt_sha1(password); + case 6: + return eqcrypt_sha1(password + ":" + username); + case 7: + return eqcrypt_sha1(username + ":" + password); + case 8: + return eqcrypt_sha1(eqcrypt_sha1(username) + eqcrypt_sha1(password)); + case 9: + return eqcrypt_sha512(password); + case 10: + return eqcrypt_sha512(password + ":" + username); + case 11: + return eqcrypt_sha512(username + ":" + password); + case 12: + return eqcrypt_sha512(eqcrypt_sha512(username) + eqcrypt_sha512(password)); +#ifdef ENABLE_SECURITY + case 13: + return eqcrypt_argon2(password); + case 14: + return eqcrypt_scrypt(password); +#endif + //todo bcrypt? pbkdf2? + default: + return ""; + break; } } -void *Encryption::GetSym(const char *name) -{ - if(Loaded()) +bool eqcrypt_verify_hash(const std::string &username, const std::string &password, const std::string &pwhash, int mode) { + switch (mode) { - return GetProcAddress(h_dll, name); - } - else +#ifdef ENABLE_SECURITY + case 13: + return crypto_pwhash_str_verify(&pwhash[0], &password[0], password.length()) == 0; + case 14: + return crypto_pwhash_scryptsalsa208sha256_str_verify(&pwhash[0], &password[0], password.length()) == 0; +#endif + default: { - return NULL; + auto hash = eqcrypt_hash(username, password, mode); + return hash.compare(pwhash) == 0; + } } -} + return false; +} \ No newline at end of file diff --git a/loginserver/encryption.h b/loginserver/encryption.h index 7ca2374b2..fe27ce28a 100644 --- a/loginserver/encryption.h +++ b/loginserver/encryption.h @@ -1,104 +1,7 @@ -/* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net) +#pragma once - 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; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY except by those people which sell it, which - are required to give you total support for your newly bought product; - without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the 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 - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#ifndef EQEMU_ENCRYPTION_H -#define EQEMU_ENCRYPTION_H - -#ifdef WIN32 -#include #include -typedef char*(*DLLFUNC_DecryptUsernamePassword)(const char*, unsigned int, int); -typedef char*(*DLLFUNC_Encrypt)(const char*, unsigned int, unsigned int&); -typedef void(*DLLFUNC_HeapDelete)(char*); - -/** -* Basic windows encryption plugin. -* Handles the managment of the plugin. -*/ -class Encryption -{ -public: - /** - * Constructor, sets all member pointers to nullptr. - */ - Encryption() : h_dll(nullptr), encrypt_func(nullptr), decrypt_func(nullptr), delete_func(nullptr) { }; - - /** - * Destructor, if it's loaded it unloads this library. - */ - ~Encryption() { if(Loaded()) { Unload(); } } - - /** - * Returns true if the dll is loaded, otherwise false. - */ - inline bool Loaded() { return (h_dll != nullptr); } - - /** - * Loads the plugin. - * True if there are no errors, false if there was an error. - */ - bool LoadCrypto(std::string name); - - /** - * Wrapper around the plugin's decrypt function. - */ - char* DecryptUsernamePassword(const char* encryptedBuffer, unsigned int bufferSize, int mode); - - /** - * Wrapper around the plugin's encrypt function. - */ - char* Encrypt(const char* buffer, unsigned int bufferSize, unsigned int &outSize); - - /** - * Wrapper around the plugin's delete function. - */ - void DeleteHeap(char* buffer); - -private: - /** - * Loads the named dll into memory. - * Returns true if there were no errors, otherwise return false. - */ - bool Load(const char *name); - - /** - * Frees the dll from memory if it's loaded. - */ - void Unload(); - - /** - * Similar in function to *sym = GetProcAddress(h_dll, name). - * Returns true if there were no errors, false otherwise. - */ - bool GetSym(const char *name, void **sym); - - /** - * Similar in function to return GetProcAddress(h_dll, name). - * Returns a pointer to the function if it is found, null on an error. - */ - void *GetSym(const char *name); - - HINSTANCE h_dll; - DLLFUNC_Encrypt encrypt_func; - DLLFUNC_DecryptUsernamePassword decrypt_func; - DLLFUNC_HeapDelete delete_func; -}; - -#endif -#endif - +const char* eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char* buffer_out, bool enc); +std::string eqcrypt_hash(const std::string &username, const std::string &password, int mode); +bool eqcrypt_verify_hash(const std::string &username, const std::string &password, const std::string &pwhash, int mode); diff --git a/loginserver/login_server.h b/loginserver/login_server.h index 1f0743a46..7760b7efb 100644 --- a/loginserver/login_server.h +++ b/loginserver/login_server.h @@ -34,25 +34,13 @@ struct LoginServer { public: - /** - * I don't really like how this looks with all the ifdefs... - * but it's the most trivial way to do this. - */ -#ifdef WIN32 - LoginServer() : config(nullptr), db(nullptr), eq_crypto(nullptr), server_manager(nullptr) { } -#else - LoginServer() : config(nullptr), db(nullptr) { } -#endif + LoginServer() : config(nullptr), db(nullptr), server_manager(nullptr) { } Config *config; Database *db; Options options; ServerManager *server_manager; ClientManager *client_manager; - -#ifdef WIN32 - Encryption *eq_crypto; -#endif }; #endif diff --git a/loginserver/main.cpp b/loginserver/main.cpp index 7bd842a40..79f3a9987 100644 --- a/loginserver/main.cpp +++ b/loginserver/main.cpp @@ -67,6 +67,15 @@ int main() if (server.config->GetVariable("options", "dump_packets_out").compare("TRUE") == 0) server.options.DumpOutPackets(true); + if (server.config->GetVariable("security", "allow_token_login").compare("TRUE") == 0) + server.options.AllowTokenLogin(true); + + if (server.config->GetVariable("security", "allow_password_login").compare("FALSE") == 0) + server.options.AllowPasswordLogin(false); + + if (server.config->GetVariable("options", "auto_create_accounts").compare("TRUE") == 0) + server.options.AutoCreateAccounts(true); + std::string mode = server.config->GetVariable("security", "mode"); if (mode.size() > 0) server.options.EncryptionMode(atoi(mode.c_str())); @@ -127,24 +136,6 @@ int main() return 1; } -#if WIN32 - //initialize our encryption. - Log.Out(Logs::General, Logs::Login_Server, "Encryption Initialize."); - server.eq_crypto = new Encryption(); - if (server.eq_crypto->LoadCrypto(server.config->GetVariable("security", "plugin"))) { - Log.Out(Logs::General, Logs::Login_Server, "Encryption Loaded Successfully."); - } - else { - //We can't run without encryption, cleanup and exit. - Log.Out(Logs::General, Logs::Error, "Encryption Failed to Load."); - Log.Out(Logs::General, Logs::Login_Server, "Database System Shutdown."); - delete server.db; - Log.Out(Logs::General, Logs::Login_Server, "Config System Shutdown."); - delete server.config; - return 1; - } -#endif - //create our server manager. Log.Out(Logs::General, Logs::Login_Server, "Server Manager Initialize."); server.server_manager = new ServerManager(); @@ -152,11 +143,6 @@ int main() //We can't run without a server manager, cleanup and exit. Log.Out(Logs::General, Logs::Error, "Server Manager Failed to Start."); -#ifdef WIN32 - Log.Out(Logs::General, Logs::Login_Server, "Encryption System Shutdown."); - delete server.eq_crypto; -#endif - Log.Out(Logs::General, Logs::Login_Server, "Database System Shutdown."); delete server.db; Log.Out(Logs::General, Logs::Login_Server, "Config System Shutdown."); @@ -173,11 +159,6 @@ int main() Log.Out(Logs::General, Logs::Login_Server, "Server Manager Shutdown."); delete server.server_manager; -#ifdef WIN32 - Log.Out(Logs::General, Logs::Login_Server, "Encryption System Shutdown."); - delete server.eq_crypto; -#endif - Log.Out(Logs::General, Logs::Login_Server, "Database System Shutdown."); delete server.db; Log.Out(Logs::General, Logs::Login_Server, "Config System Shutdown."); @@ -207,11 +188,6 @@ int main() Log.Out(Logs::General, Logs::Login_Server, "Server Manager Shutdown."); delete server.server_manager; -#ifdef WIN32 - Log.Out(Logs::General, Logs::Login_Server, "Encryption System Shutdown."); - delete server.eq_crypto; -#endif - Log.Out(Logs::General, Logs::Login_Server, "Database System Shutdown."); delete server.db; Log.Out(Logs::General, Logs::Login_Server, "Config System Shutdown."); diff --git a/loginserver/options.h b/loginserver/options.h index 76fe22e1d..f215e443b 100644 --- a/loginserver/options.h +++ b/loginserver/options.h @@ -35,7 +35,10 @@ public: dump_out_packets(false), encryption_mode(5), local_network("127.0.0.1"), - reject_duplicate_servers(false) { } + reject_duplicate_servers(false), + allow_password_login(true), + allow_token_login(false), + auto_create_accounts(false) { } /** * Sets allow_unregistered. @@ -157,6 +160,15 @@ public: */ inline bool IsRejectingDuplicateServers() { return reject_duplicate_servers; } + inline void AllowTokenLogin(bool b) { allow_token_login = b; } + inline bool IsTokenLoginAllowed() const { return allow_token_login; } + + inline void AllowPasswordLogin(bool b) { allow_password_login = b; } + inline bool IsPasswordLoginAllowed() const { return allow_password_login; } + + inline void AutoCreateAccounts(bool b) { auto_create_accounts = b; } + inline bool CanAutoCreateAccounts() const { return auto_create_accounts; } + private: bool allow_unregistered; bool trace; @@ -164,6 +176,9 @@ private: bool dump_in_packets; bool dump_out_packets; bool reject_duplicate_servers; + bool allow_token_login; + bool allow_password_login; + bool auto_create_accounts; int encryption_mode; std::string local_network; std::string account_table; diff --git a/loginserver/server_manager.cpp b/loginserver/server_manager.cpp index cdde5670e..6625e2ca5 100644 --- a/loginserver/server_manager.cpp +++ b/loginserver/server_manager.cpp @@ -83,7 +83,7 @@ WorldServer* ServerManager::GetServerByAddress(const std::string &addr, int port return nullptr; } -EQApplicationPacket *ServerManager::CreateServerListPacket(Client *c) +EQApplicationPacket *ServerManager::CreateServerListPacket(Client *c, uint32 seq) { unsigned int packet_size = sizeof(ServerListHeader_Struct); unsigned int server_count = 0; @@ -116,7 +116,7 @@ EQApplicationPacket *ServerManager::CreateServerListPacket(Client *c) EQApplicationPacket *outapp = new EQApplicationPacket(OP_ServerListResponse, packet_size); ServerListHeader_Struct *server_list = (ServerListHeader_Struct*)outapp->pBuffer; - server_list->Unknown1 = 0x00000004; + server_list->Unknown1 = seq; server_list->Unknown2 = 0x00000000; server_list->Unknown3 = 0x01650000; diff --git a/loginserver/server_manager.h b/loginserver/server_manager.h index 76d50ab2f..cc86f5641 100644 --- a/loginserver/server_manager.h +++ b/loginserver/server_manager.h @@ -52,7 +52,7 @@ public: /** * Creates a server list packet for the client. */ - EQApplicationPacket *CreateServerListPacket(Client *c); + EQApplicationPacket *CreateServerListPacket(Client *c, uint32 seq); /** * Checks to see if there is a server exists with this name, ignoring option. diff --git a/loginserver/world_server.cpp b/loginserver/world_server.cpp index 9421cce5f..488c64465 100644 --- a/loginserver/world_server.cpp +++ b/loginserver/world_server.cpp @@ -490,11 +490,6 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) } server.db->UpdateWorldRegistration(GetRuntimeID(), long_name, GetConnection()->Handle()->RemoteIP()); - - if(is_server_authorized) - { - server.client_manager->UpdateServerList(); - } } void WorldServer::Handle_LSStatus(ServerLSStatus_Struct *s)