mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 22:01:30 +00:00
Rework login credential functions
This commit is contained in:
parent
7f7a4b0f2d
commit
d8da52796b
@ -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:
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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())
|
||||
{
|
||||
|
||||
@ -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 <memory>
|
||||
#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.
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
@ -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; }
|
||||
|
||||
/**
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
/**
|
||||
|
||||
@ -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 <openssl/des.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#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 <sodium.h>
|
||||
#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;
|
||||
}
|
||||
@ -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 <windows.h>
|
||||
#include <string>
|
||||
|
||||
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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.");
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user