Reimplement some functions

This commit is contained in:
KimLS 2017-12-24 23:21:17 -08:00
parent 7a778c549f
commit 0ec53eff52
11 changed files with 195 additions and 146 deletions

View File

@ -224,7 +224,7 @@ uint32 Database::CreateAccount(const char* name, const char* password, int16 sta
return results.LastInsertedID(); return results.LastInsertedID();
} }
bool Database::DeleteAccount(const char *loginserver, const char* name) { bool Database::DeleteAccount(const char* name, const char *loginserver) {
std::string query = StringFormat("DELETE FROM account WHERE name='%s' AND ls_id='%s'", name, loginserver); std::string query = StringFormat("DELETE FROM account WHERE name='%s' AND ls_id='%s'", name, loginserver);
Log(Logs::General, Logs::World_Server, "Account Attempting to be deleted:'%s:%s'", loginserver, name); Log(Logs::General, Logs::World_Server, "Account Attempting to be deleted:'%s:%s'", loginserver, name);

View File

@ -174,7 +174,7 @@ public:
/* Account Related */ /* Account Related */
bool DeleteAccount(const char *loginserver, const char* name); bool DeleteAccount(const char *name, const char* loginserver);
bool GetLiveChar(uint32 account_id, char* cname); bool GetLiveChar(uint32 account_id, char* cname);
bool SetAccountStatus(const char* name, int16 status); bool SetAccountStatus(const char* name, int16 status);
bool SetLocalPassword(uint32 accid, const char* password); bool SetLocalPassword(uint32 accid, const char* password);

View File

@ -196,6 +196,19 @@ void find_replace(std::string& string_subject, const std::string& search_string,
} }
} }
void ParseAccountString(const std::string &s, std::string &account, std::string &loginserver)
{
auto split = SplitString(s, '.');
if (split.size() == 2) {
loginserver = split[0];
account = split[1];
}
else if(split.size() == 1) {
loginserver = "eqemu";
account = split[0];
}
}
//Const char based //Const char based
// normal strncpy doesnt put a null term on copied strings, this one does // normal strncpy doesnt put a null term on copied strings, this one does

View File

@ -34,6 +34,7 @@ void ToLowerString(std::string &s);
void ToUpperString(std::string &s); void ToUpperString(std::string &s);
std::string JoinString(const std::vector<std::string>& ar, const std::string &delim); std::string JoinString(const std::vector<std::string>& ar, const std::string &delim);
void find_replace(std::string& string_subject, const std::string& search_string, const std::string& replace_string); void find_replace(std::string& string_subject, const std::string& search_string, const std::string& replace_string);
void ParseAccountString(const std::string &s, std::string &account, std::string &loginserver);
//const char based //const char based

View File

@ -180,8 +180,6 @@ void Client::Handle_SessionReady(const char* data, unsigned int size)
void Client::Handle_Login(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) { if (status != cs_waiting_for_login) {
Log(Logs::General, Logs::Error, "Login received after already having logged in."); Log(Logs::General, Logs::Error, "Login received after already having logged in.");
return; return;
@ -242,47 +240,15 @@ void Client::Handle_Login(const char* data, unsigned int size)
user = components[1]; user = components[1];
} }
ParseAccountString(user, user, db_loginserver);
if (server.db->GetLoginDataFromAccountInfo(user, db_loginserver, db_account_password_hash, db_account_id) == false) { if (server.db->GetLoginDataFromAccountInfo(user, db_loginserver, db_account_password_hash, db_account_id) == false) {
status = cs_creating_account; status = cs_creating_account;
AttemptLoginAccountCreation(user, cred, db_loginserver); AttemptLoginAccountCreation(user, cred, db_loginserver);
return; return;
} }
else { else {
if (eqcrypt_verify_hash(user, cred, db_account_password_hash, mode)) { result = VerifyLoginHash(user, db_loginserver, cred, db_account_password_hash);
result = true;
}
else
{
if (server.options.IsUpdatingInsecurePasswords()) {
auto len = db_account_password_hash.length();
int start = 0;
int end = 0;
switch (len) {
case 32:
start = 1;
end = 4;
break;
case 40:
start = 5;
end = 8;
break;
case 128:
start = 9;
end = 12;
break;
}
if (start != 0) {
for (int i = start; i <= end; ++i) {
if (eqcrypt_verify_hash(user, cred, db_account_password_hash, i)) {
result = true;
server.db->UpdateLoginHash(user, db_loginserver, eqcrypt_hash(user, cred, mode));
break;
}
}
}
}
}
} }
} }
} }
@ -432,6 +398,50 @@ void Client::DoFailedLogin()
status = cs_failed_to_login; status = cs_failed_to_login;
} }
bool Client::VerifyLoginHash(const std::string &user, const std::string &loginserver, const std::string &cred, const std::string &hash)
{
auto mode = server.options.GetEncryptionMode();
if (eqcrypt_verify_hash(user, cred, hash, mode)) {
return true;
}
else {
if (server.options.IsUpdatingInsecurePasswords()) {
if (mode < EncryptionModeArgon2) {
mode = EncryptionModeArgon2;
}
if (hash.length() == 32) { //md5 is insecure
for (int i = EncryptionModeMD5; i <= EncryptionModeMD5Triple; ++i) {
if (i != mode && eqcrypt_verify_hash(user, cred, hash, i)) {
server.db->UpdateLoginHash(user, loginserver, eqcrypt_hash(user, cred, mode));
return true;
}
}
}
else if (hash.length() == 40) { //sha1 is insecure
for (int i = EncryptionModeSHA; i <= EncryptionModeSHATriple; ++i) {
if (i != mode && eqcrypt_verify_hash(user, cred, hash, i)) {
server.db->UpdateLoginHash(user, loginserver, eqcrypt_hash(user, cred, mode));
return true;
}
}
}
else if (hash.length() == 128) { //sha2-512 is insecure
for (int i = EncryptionModeSHA512; i <= EncryptionModeSHA512Triple; ++i) {
if (i != mode && eqcrypt_verify_hash(user, cred, hash, i)) {
server.db->UpdateLoginHash(user, loginserver, eqcrypt_hash(user, cred, mode));
return true;
}
}
}
//argon2 is still secure
//scrypt is still secure
}
}
return false;
}
void Client::DoSuccessfulLogin(const std::string &user, int db_account_id, const std::string &db_loginserver) void Client::DoSuccessfulLogin(const std::string &user, int db_account_id, const std::string &db_loginserver)
{ {
stored_user.clear(); stored_user.clear();

View File

@ -141,6 +141,11 @@ public:
*/ */
void DoFailedLogin(); void DoFailedLogin();
/**
* Verifies a login hash, will also attempt to update a login hash if needed.
*/
bool VerifyLoginHash(const std::string &user, const std::string &loginserver, const std::string &cred, const std::string &hash);
/** /**
* Does a successful login * Does a successful login
*/ */

View File

@ -7,6 +7,8 @@
#include <sodium.h> #include <sodium.h>
#endif #endif
#include "encryption.h"
const char* eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char* buffer_out, bool enc) { const char* eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char* buffer_out, bool enc) {
DES_key_schedule k; DES_key_schedule k;
DES_cblock v; DES_cblock v;
@ -100,34 +102,34 @@ std::string eqcrypt_scrypt(const std::string &msg)
std::string eqcrypt_hash(const std::string &username, const std::string &password, int mode) { std::string eqcrypt_hash(const std::string &username, const std::string &password, int mode) {
switch (mode) switch (mode)
{ {
case 1: case EncryptionModeMD5:
return eqcrypt_md5(password); return eqcrypt_md5(password);
case 2: case EncryptionModeMD5PassUser:
return eqcrypt_md5(password + ":" + username); return eqcrypt_md5(password + ":" + username);
case 3: case EncryptionModeMD5UserPass:
return eqcrypt_md5(username + ":" + password); return eqcrypt_md5(username + ":" + password);
case 4: case EncryptionModeMD5Triple:
return eqcrypt_md5(eqcrypt_md5(username) + eqcrypt_md5(password)); return eqcrypt_md5(eqcrypt_md5(username) + eqcrypt_md5(password));
case 5: case EncryptionModeSHA:
return eqcrypt_sha1(password); return eqcrypt_sha1(password);
case 6: case EncryptionModeSHAPassUser:
return eqcrypt_sha1(password + ":" + username); return eqcrypt_sha1(password + ":" + username);
case 7: case EncryptionModeSHAUserPass:
return eqcrypt_sha1(username + ":" + password); return eqcrypt_sha1(username + ":" + password);
case 8: case EncryptionModeSHATriple:
return eqcrypt_sha1(eqcrypt_sha1(username) + eqcrypt_sha1(password)); return eqcrypt_sha1(eqcrypt_sha1(username) + eqcrypt_sha1(password));
case 9: case EncryptionModeSHA512:
return eqcrypt_sha512(password); return eqcrypt_sha512(password);
case 10: case EncryptionModeSHA512PassUser:
return eqcrypt_sha512(password + ":" + username); return eqcrypt_sha512(password + ":" + username);
case 11: case EncryptionModeSHA512UserPass:
return eqcrypt_sha512(username + ":" + password); return eqcrypt_sha512(username + ":" + password);
case 12: case EncryptionModeSHA512Triple:
return eqcrypt_sha512(eqcrypt_sha512(username) + eqcrypt_sha512(password)); return eqcrypt_sha512(eqcrypt_sha512(username) + eqcrypt_sha512(password));
#ifdef ENABLE_SECURITY #ifdef ENABLE_SECURITY
case 13: case EncryptionModeArgon2:
return eqcrypt_argon2(password); return eqcrypt_argon2(password);
case 14: case EncryptionModeSCrypt:
return eqcrypt_scrypt(password); return eqcrypt_scrypt(password);
#endif #endif
//todo bcrypt? pbkdf2? //todo bcrypt? pbkdf2?

View File

@ -2,6 +2,24 @@
#include <string> #include <string>
enum EncryptionMode
{
EncryptionModeMD5 = 1,
EncryptionModeMD5PassUser = 2,
EncryptionModeMD5UserPass = 3,
EncryptionModeMD5Triple = 4,
EncryptionModeSHA = 5,
EncryptionModeSHAPassUser = 6,
EncryptionModeSHAUserPass = 7,
EncryptionModeSHATriple = 8,
EncryptionModeSHA512 = 9,
EncryptionModeSHA512PassUser = 10,
EncryptionModeSHA512UserPass = 11,
EncryptionModeSHA512Triple = 12,
EncryptionModeArgon2 = 13,
EncryptionModeSCrypt = 14
};
const char* eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char* buffer_out, bool enc); 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); 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); bool eqcrypt_verify_hash(const std::string &username, const std::string &password, const std::string &pwhash, int mode);

View File

@ -19,14 +19,7 @@ struct EQ::Net::ConsoleLoginStatus CheckLogin(const std::string& username, const
std::string prefix = "eqemu"; std::string prefix = "eqemu";
std::string raw_user = ""; std::string raw_user = "";
auto split = SplitString(username, '.'); ParseAccountString(username, raw_user, prefix);
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()); ret.account_id = database.CheckLogin(raw_user.c_str(), password.c_str(), prefix.c_str());
@ -399,14 +392,7 @@ void ConsoleSetPass(EQ::Net::ConsoleServerConnection* connection, const std::str
std::string prefix = "eqemu"; std::string prefix = "eqemu";
std::string raw_user = ""; std::string raw_user = "";
auto split = SplitString(args[0], '.'); ParseAccountString(args[0], raw_user, prefix);
if (split.size() == 2) {
prefix = split[0];
raw_user = split[1];
}
else {
raw_user = split[0];
}
int16 tmpstatus = 0; int16 tmpstatus = 0;
uint32 tmpid = database.GetAccountIDByName(raw_user.c_str(), prefix.c_str(), &tmpstatus); uint32 tmpid = database.GetAccountIDByName(raw_user.c_str(), prefix.c_str(), &tmpstatus);

View File

@ -213,24 +213,28 @@ int main(int argc, char** argv) {
} }
} }
else if (strcasecmp(argv[1], "adduser") == 0) { else if (strcasecmp(argv[1], "adduser") == 0) {
//TODO: REIMPLEMENT if (argc == 5) {
//if (argc == 5) { if (Seperator::IsNumber(argv[4])) {
// if (Seperator::IsNumber(argv[4])) { if (atoi(argv[4]) >= 0 && atoi(argv[4]) <= 255) {
// if (atoi(argv[4]) >= 0 && atoi(argv[4]) <= 255) { std::string user;
// if (database.CreateAccount(argv[2], argv[3], atoi(argv[4])) == 0) { std::string loginserver;
// std::cerr << "database.CreateAccount failed." << std::endl;
// return 1; ParseAccountString(argv[2], user, loginserver);
// }
// else { if (database.CreateAccount(argv[2], argv[3], atoi(argv[4]), loginserver.c_str(), 0) == 0) {
// std::cout << "Account created: Username='" << argv[2] << "', Password='" << argv[3] << "', status=" << argv[4] << std::endl; std::cerr << "database.CreateAccount failed." << std::endl;
// return 0; return 1;
// } }
// } else {
// } std::cout << "Account created: Username='" << argv[2] << "', Password='" << argv[3] << "', status=" << argv[4] << std::endl;
//} return 0;
//std::cout << "Usage: world adduser username password flag" << std::endl; }
//std::cout << "flag = 0, 1 or 2" << std::endl; }
//return 0; }
}
std::cout << "Usage: world adduser username password flag" << std::endl;
std::cout << "flag = 0, 1 or 2" << std::endl;
return 0;
} }
else if (strcasecmp(argv[1], "flag") == 0) { else if (strcasecmp(argv[1], "flag") == 0) {
if (argc == 4) { if (argc == 4) {

View File

@ -1957,33 +1957,40 @@ void command_shutdown(Client *c, const Seperator *sep)
void command_delacct(Client *c, const Seperator *sep) void command_delacct(Client *c, const Seperator *sep)
{ {
//TODO: REIMPLEMENT if (sep->arg[1][0] == 0)
// if(sep->arg[1][0] == 0) c->Message(0, "Format: #delacct accountname");
// c->Message(0, "Format: #delacct accountname"); else {
// else std::string user;
// if (database.DeleteAccount(sep->arg[1])) std::string loginserver;
// c->Message(0, "The account was deleted."); ParseAccountString(sep->arg[1], user, loginserver);
// else
// c->Message(0, "Unable to delete account."); if (database.DeleteAccount(user.c_str(), loginserver.c_str()))
c->Message(0, "The account was deleted.");
else
c->Message(0, "Unable to delete account.");
}
} }
void command_setpass(Client *c, const Seperator *sep) void command_setpass(Client *c, const Seperator *sep)
{ {
//TODO: REIMPLEMENT if(sep->argnum != 2)
//if(sep->argnum != 2) c->Message(0, "Format: #setpass accountname password");
// c->Message(0, "Format: #setpass accountname password"); else {
//else { std::string user;
// int16 tmpstatus = 0; std::string loginserver;
// uint32 tmpid = database.GetAccountIDByName(sep->arg[1], &tmpstatus); ParseAccountString(sep->arg[1], user, loginserver);
// if (!tmpid)
// c->Message(0, "Error: Account not found"); int16 tmpstatus = 0;
// else if (tmpstatus > c->Admin()) uint32 tmpid = database.GetAccountIDByName(user.c_str(), loginserver.c_str(), &tmpstatus);
// c->Message(0, "Cannot change password: Account's status is higher than yours"); if (!tmpid)
// else if (database.SetLocalPassword(tmpid, sep->arg[2])) c->Message(0, "Error: Account not found");
// c->Message(0, "Password changed."); else if (tmpstatus > c->Admin())
// else c->Message(0, "Cannot change password: Account's status is higher than yours");
// c->Message(0, "Error changing password."); else if (database.SetLocalPassword(tmpid, sep->arg[2]))
//} c->Message(0, "Password changed.");
else
c->Message(0, "Error changing password.");
}
} }
void command_setlsinfo(Client *c, const Seperator *sep) void command_setlsinfo(Client *c, const Seperator *sep)
@ -4416,42 +4423,45 @@ void command_uptime(Client *c, const Seperator *sep)
void command_flag(Client *c, const Seperator *sep) void command_flag(Client *c, const Seperator *sep)
{ {
//TODO: REIMPLEMENT if(sep->arg[2][0] == 0) {
// if(sep->arg[2][0] == 0) { if (!c->GetTarget() || (c->GetTarget() && c->GetTarget() == c)) {
// if (!c->GetTarget() || (c->GetTarget() && c->GetTarget() == c)) { c->UpdateAdmin();
// c->UpdateAdmin(); c->Message(0, "Refreshed your admin flag from DB.");
// c->Message(0, "Refreshed your admin flag from DB."); } else if (c->GetTarget() && c->GetTarget() != c && c->GetTarget()->IsClient()) {
// } else if (c->GetTarget() && c->GetTarget() != c && c->GetTarget()->IsClient()) { c->GetTarget()->CastToClient()->UpdateAdmin();
// c->GetTarget()->CastToClient()->UpdateAdmin(); c->Message(0, "%s's admin flag has been refreshed.", c->GetTarget()->GetName());
// c->Message(0, "%s's admin flag has been refreshed.", c->GetTarget()->GetName()); c->GetTarget()->Message(0, "%s refreshed your admin flag.", c->GetName());
// c->GetTarget()->Message(0, "%s refreshed your admin flag.", c->GetName()); }
// } }
// } else if (!sep->IsNumber(1) || atoi(sep->arg[1]) < -2 || atoi(sep->arg[1]) > 255 || strlen(sep->arg[2]) == 0)
// else if (!sep->IsNumber(1) || atoi(sep->arg[1]) < -2 || atoi(sep->arg[1]) > 255 || strlen(sep->arg[2]) == 0) c->Message(0, "Usage: #flag [status] [acctname]");
// c->Message(0, "Usage: #flag [status] [acctname]");
// else if (c->Admin() < commandChangeFlags) {
// else if (c->Admin() < commandChangeFlags) { //this check makes banning players by less than this level
////this check makes banning players by less than this level //impossible, but i'll leave it in anyways
////impossible, but i'll leave it in anyways c->Message(0, "You may only refresh your own flag, doing so now.");
// c->Message(0, "You may only refresh your own flag, doing so now."); c->UpdateAdmin();
// c->UpdateAdmin(); }
// } else {
// else { if (atoi(sep->arg[1]) > c->Admin())
// if (atoi(sep->arg[1]) > c->Admin()) c->Message(0, "You cannot set people's status to higher than your own");
// c->Message(0, "You cannot set people's status to higher than your own"); else if (atoi(sep->arg[1]) < 0 && c->Admin() < commandBanPlayers)
// else if (atoi(sep->arg[1]) < 0 && c->Admin() < commandBanPlayers) c->Message(0, "You have too low of status to suspend/ban");
// c->Message(0, "You have too low of status to suspend/ban"); else if (!database.SetAccountStatus(sep->argplus[2], atoi(sep->arg[1])))
// else if (!database.SetAccountStatus(sep->argplus[2], atoi(sep->arg[1]))) c->Message(0, "Unable to set GM Flag.");
// c->Message(0, "Unable to set GM Flag."); else {
// else { c->Message(0, "Set GM Flag on account.");
// c->Message(0, "Set GM Flag on account.");
// auto pack = new ServerPacket(ServerOP_FlagUpdate, 6); std::string user;
// *((uint32*) pack->pBuffer) = database.GetAccountIDByName(sep->argplus[2]); std::string loginserver;
// *((int16*) &pack->pBuffer[4]) = atoi(sep->arg[1]); ParseAccountString(sep->argplus[2], user, loginserver);
// worldserver.SendPacket(pack);
// delete pack; ServerPacket pack(ServerOP_FlagUpdate, 6);
// } *((uint32*) pack.pBuffer) = database.GetAccountIDByName(user.c_str(), loginserver.c_str());
// } *((int16*) &pack.pBuffer[4]) = atoi(sep->arg[1]);
worldserver.SendPacket(&pack);
}
}
} }
void command_time(Client *c, const Seperator *sep) void command_time(Client *c, const Seperator *sep)